{\rtf0\ansi{\fonttbl\f0\fmodern Courier;\f1\ftech Symbol;\f2\fmodern Ohlfs;}
\margl40
\margr40
{\colortbl;\red0\green0\blue0;}
\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i0\ulnone\fs24\fc0\cf0 //ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//
\i 	
\b FILENAME
\b0 :	
\b\i0 eText.Pasteboard.m\

\b0 //
\i 	
\b SUMMARY
\b0 :	
\b\i0 Implementation of interactions between eText and Pasteboards
\b0 \
//	
\b\i CATEGORY
\b0 :
\i0 	
\b Pasteboard
\b0 \
//	
\b\i PROTOCOLS
\b0 :
\i0 	
\b None
\b0 \
//	
\b\i INTERFACE
\b0 :
\i0 	
\b None
\b0 \
//	
\b\i AUTHOR
\b0 :		
\b\i0 Rohit Khare
\b0 \
//	
\b\i COPYRIGHT
\b0 :	
\f1\i0 с
\f0\b 1993,94 California Institute of Technology, eText Project\

\b0 //ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b\i Implementation Comments
\b0\i0 \
//		All actions should get routed to read/write
\i Selection
\i0 To/From
\i Pasteboard
\i0 .\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b\i History
\b0\i0 \
//	02/12/95:	
\b Changed Pasting policy to prefer creation of annotiations.
\b0 \
//	11/20/94:	
\b Realized that most apps can't handle filename && ASCII, stupidly.
\b0 \
//	11/20/94:	
\b Extended to use writeASCII on copying selections to PBoard.
\b0 \
//	10/31/94:	
\b Added detectors for smartPaste.
\b0 \
//	10/17/94:	
\b Cleaned up for eText5.
\b0 \
//	08/05/94:	
\b Completely Rearchitected for 5.0. RK
\b0 \
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b Imported Interfaces
\b0 \
//\
	#import "
\b eText.Pasteboard.h
\b0 "\
\
#define 
\b eTETFPboardType
\b0   NXUniqueString("
\b eText ETF pasteboard type
\b0 ")\
\

\i @implementation eText(Pasteboard)\

\i0 //ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b Centralized Selection Management
\b0 \
//\
- 
\b readSelectionFromPasteboard
\b0 :pboard \{\
	return [self 
\b readSelectionFromPasteboard
\b0 :pboard 
\b linked
\b0 :
\b NO
\b0 ];\}\
- 
\b readSelectionFromPasteboard
\b0 :pboard 
\b linked
\b0 :(
\b BOOL
\b0 )isLinked \{\
	
\b NXSelPt
\b0  	a,b;\
	
\b NXStream
\b0  	*
\b memstream
\b0 ;\
	NXAtom 		
\b supportedTypes
\b0 [9];\
	NXAtom 		
\b foundType
\b0 ;\
	\
// 
\i 1) is there a selection? what types do we have?\

\i0 	[self 
\b getSel
\b0 :&a :&b];\
	if (!((a.
\b cp
\b0  
\b >= 0
\b0 ) && [self 
\b isEditable
\b0 ]))\
		return 
\b nil
\b0 ;\
\
	// 
\i All possible "Pasteable" types:
\i0 \
	supportedTypes[0] = 
\b eTETFPboardType
\b0 ;\
	supportedTypes[1] = 
\b NXRTFDPboardType
\b0 ;\
	supportedTypes[2] = 
\b NXRTFPboardType
\b0 ;\
	supportedTypes[3] = 
\b NXTabularTextPboardType
\b0 ;\
	supportedTypes[4] = 
\b NXAsciiPboardType
\b0 ;\
	supportedTypes[5] = 
\b NXColorPboardType
\b0 ;\
	supportedTypes[6] = 
\b NXFontPboardType
\b0 ;\
	supportedTypes[7] = 
\b NXRulerPboardType
\b0 ;\
	supportedTypes[8] = 
\b NXFilenamePboardType
\b0 ;\
	supportedTypes[9] = NULL;\
	
\b foundType
\b0  = [pboard 
\b findAvailableTypeFrom
\b0 :
\b supportedTypes
\b0  num:
\b 2
\b0 ];\
	\
// 
\i 2) If we found nothing, try creating an Annotation for it\

\i0 // 
\i 2a) NEW POLICY: If we can create an annotation, && no etf, do it\

\i0 	if (
\b !foundType && 
\b0 [etApp 
\b annotationByPboard
\b0 :
\b pboard
\b0 ]) \{\
		[self 
\b insertAnnotation
\b0 : [[[etApp 
\b annotationByPboard
\b0 :
\b pboard
\b0 ] alloc]\
			  
\b initFromPboard
\b0 :
\b pboard
\b0  
\b inDoc
\b0 :
\b etDoc
\b0  
\b linked
\b0 :
\b isLinked
\b0 ]];\
\
	
\b foundType
\b0  = [pboard 
\b findAvailableTypeFrom
\b0 :
\b supportedTypes
\b0  num:
\b 8
\b0 ];\
\
//
\i  e) If we have filenames, parse them out and instantiate each one.
\i0 \

\b // 
\i NOTE THAT THIS DOESN'T WORK YET!!!!!! FIX ME!\

\b0\i0 	\} else if (foundType == 
\b NXFilenamePboardType
\b0 ) \{\
		NXLogError("
\b eText tried to read an NXFilenamePboardType.
\b0 ");\
		[self insertAnnotation: [[[etApp annotationByPboard:pboard] alloc]\
			  initFromPboard:pboard inDoc:etDoc linked:isLinked]];\
// 
\i 3) do we have RTFD? This is a _very_ special case, and is mutex to ETF\

\i0 	\} else if (foundType == 
\b NXRTFDPboardType
\b0 ) \{\
		// 
\b\i this is really gruesome code. Don't look
\b0\i0 .\
		
\b Text
\b0 		*
\b rtfd
\b0 ;\
		
\b NXRect
\b0 		
\b rect
\b0 ;\
		
\b Class
\b0  		
\b oldHandler
\b0 ;\
		\
		// 
\i unload the old \\NeXTGraphic handler
\i0 \
		
\b oldHandler
\b0  = [eText classForDirective:"
\b NeXTGraphic
\b0 "];\
		// 
\i And load in NeXT's crap. All cause they serialize to a private form.
\i0 \
		[eText 	
\b registerDirective
\b0 :"
\b NeXTGraphic
\b0 " \
				
\b forClass
\b0 :[Text 
\b graphicCellClass
\b0 ]];\
		rect.origin.x = 0; rect.origin.y = 0;\
		rect.size.height = MAXFLOAT; rect.size.width = MAXFLOAT;\
		
\b rtfd
\b0  = [[
\b Text
\b0  alloc] 
\b initFrame
\b0 :&
\b rect
\b0 ]; // 
\i NeXT's Text class
\i0 \
		[rtfd 
\b setMonoFont
\b0 :
\b NO
\b0 ];\
		[rtfd 
\b setGraphicsImportEnabled
\b0 :
\b YES
\b0 ];\
		[rtfd 
\b setSel
\b0 :0 :[rtfd 
\b textLength
\b0 ]];\
		[
\b rtfd
\b0  
\b readSelectionFromPasteboard
\b0 : 
\b pboard
\b0 ]; // 
\i Text
\i0  
\i groks RTFD
\i0 \
		if ([rtfd textLength]) \{\
			
\b NXRTFDError
\b0  
\b ret
\b0 ;\
			\
			
\b ret
\b0 =[rtfd 
\b saveRTFDTo
\b0 :"
\b /tmp/eTextRTFDConversionStoreFile.rtfd
\b0 "\
					  
\b removeBackup
\b0 :YES 
\b errorHandler
\b0 :nil];\
			// 
\i get that crappy NXGraphicCell code out of my kernel NOW!!!
\i0 \
			rtfd = [rtfd 
\b free
\b0 ];\
			[eText 	
\b registerDirective
\b0 :"
\b NeXTGraphic
\b0 " \
					
\b forClass
\b0 :
\b oldHandler
\b0 ];\
					\
			if (ret == 
\b NX_RTFDErrorNone
\b0 ) \{\
				NXAtom oldP,oldT; int start;\
\
				// 
\i now parse in the good stuff
\i0 \
				// 
\i temporarily set this doc's docInfoPath to tempName
\i0 \
				
\b oldP
\b0  = [[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ];\
				
\b oldT
\b0  = [[etDoc 
\b docInfo
\b0 ] 
\b docTitle
\b0 ];\
				start = sp0.cp;\
				[[etDoc 
\b docInfo
\b0 ]\
					
\b setDocPath
\b0 :"
\b /tmp/eTextRTFDConversionStoreFile.rtfd
\b0 "];\
				\
				// 
\i issue a read for the "RTF" part of the data
\i0 \
				[self 
\b undoSelChange
\b0 :"
\b Paste RTFD
\b0 "];\
				[
\b super
\b0  
\b readSelectionFromPasteboard
\b0 :pboard];\
				[self 
\b undoAffectedRange
\b0 :start 
\b to
\b0 :spN.cp];\
				\
				// 
\i preserves the traditional semantics of pasting
\i0 \
				// 
\i since readSelection doesn't move the cursor
\i0 \
				[self 
\b setSel
\b0 :sp0.cp :sp0.cp];\
\
				[[etDoc 
\b docInfo
\b0 ] 
\b setDocPath
\b0 :oldP];\
				[[etDoc 
\b docInfo
\b0 ] 
\b setDocTitle
\b0 :oldT];\
			\}\

\i 			// unfortunately, the objects created may want persistent\
			// access to the files on disk, so we can't nuke them.\
			// There's possibly a bug here relating to the use of a single,\
			// shared ConversionStoreFile to hold all this shit.\
			// Oh, for want of a OOfilesystem with autorelease!\

\i0 		\}\
		// 
\i get that crappy NXGraphicCell code out of my kernel NOW!!!
\i0 \
		[eText 	
\b registerDirective
\b0 :"
\b NeXTGraphic
\b0 " \
				
\b forClass
\b0 :
\b oldHandler
\b0 ];\
// 
\i 4) do we have ETF or RTF (in that preference order?)\

\i0 	\} else if ((foundType == 
\b eTETFPboardType
\b0 ) ||\
			   (foundType == 
\b NXRTFPboardType
\b0 ))\{\
		// 
\i OK, just paste in the ETF/RTF code
\i0 \
		
\b memstream
\b0  = [pboard 
\b readTypeToStream
\b0 :
\b foundType
\b0 ];\
		if (memstream) \{\
			char buf[3]; int 
\b smart
\b0 =0; // 
\i Default is to assume dumbpaste
\i0 \
			int start = sp0.cp;\
			\
			if ([self getSubstring:
\b buf
\b0  start:
\b spN
\b0 .cp length:
\b 1
\b0 ] != -1)\{\
				
\b smart
\b0  = (
\b strchr
\b0 (
\b\fc1\cf1 postSelSmartTable
\b0 , buf[0]
\fc0\cf0 ) ? 0 : 1);\
			\}\
			[self 
\b undoSelChange
\b0 :"
\b Paste ETF/RTF
\b0 "];\
			[self 
\b replaceSelWithRichText
\b0 :
\b memstream
\b0 ]; //
\i  subsumes ETF as well
\i0 .\
			if (!(
\b smart
\b0  &&\
				([self getSubstring:
\b buf
\b0  start:
\b spN
\b0 .cp length:
\b 1
\b0 ] != -1) &&\
				(buf[0] == ' ')))\
				
\b smart = 0
\b0 ;\
			[self 
\b undoAffectedRange
\b0 :start 
\b to
\b0 :(spN.cp + 
\b smart
\b0 )];\
			
\b NXCloseMemory
\b0 (
\b memstream
\b0 , NX_FREEBUFFER);\
		\}\
// 
\i 5) do we have ASCII or Tabular Text?\

\i0 	\}else if ((foundType == 
\b NXAsciiPboardType
\b0 ) ||\
			  (foundType == 
\b NXTabularTextPboardType
\b0 ))\{\
		// 
\i OK, just paste in the ASCII code
\i0 \
		char *data; int len, 
\b start
\b0 =
\b sp0.cp
\b0 ;\
\
		[self 
\b undoSelChange
\b0 :"
\b Paste PlainText
\b0 "];\
		[pboard 
\b readType
\b0 :
\b foundType
\b0  data:&data length:&len];\
		[self 
\b replaceSel
\b0 :data 
\b length
\b0 :len]; // 
\i subsumes TabText as well
\i0 .\
		[pboard 
\b deallocatePasteboardData
\b0 :data length:len];\
		[self 
\b undoAffectedRange
\b0 :start 
\b to
\b0 :spN.cp];\
		return self;\
// 
\i 6) do we have Color data?\

\i0 	\} else if (foundType == 
\b NXColorPboardType
\b0 ) \{\
		[self 
\b setSelColor
\b0 :
\b NXReadColorFromPasteboard
\b0 (pboard)];\
// 
\i 7) do we have Font data?
\i0 	\
// 
\i 8) do we have Ruler data?\

\i0 	\} else if ((foundType == 
\b NXFontPboardType
\b0 ) ||\
				(foundType == 
\b NXRulerPboardType
\b0 )) \{\
		// 
\i this is kind of funky: we pull a little switcheroo on Text
\i0 \
		id		
\b targetPboard
\b0 ;\
		char 	*
\b saveData
\b0 ,*
\b newData
\b0 ;\
		int 	
\b saveLen
\b0 , 
\b newLen
\b0 ;\
		NXAtom	
\b targetType
\b0 [1];\
\
		// 
\i determine the targetPboard
\i0 \
		if (foundType == 
\b NXRulerPboardType
\b0 ) \{\
			targetPboard = [Pasteboard newName:
\b NXRulerPboard
\b0 ];\
			*targetType = 
\b NXRulerPboardType
\b0 ;\
		\} else \{\
			targetPboard = [Pasteboard newName:
\b NXFontPboard
\b0 ];\
			*targetType = 
\b NXFontPboardType
\b0 ;\
		\}\
\
		// 
\i save data from targetPboard
\i0 \
		[
\b targetPboard
\b0  	
\b readType
\b0 :*
\b targetType\

\b0 						data:&saveData length:&saveLen];\
		\
		// 
\i copy data from pboard to targetPboard
\i0 \
		[
\b pboard
\b0 		 	
\b readType
\b0 :*
\b targetType\

\b0 						data:&newData length:&newLen];\
		[
\b targetPboard
\b0  
\b declareTypes
\b0 :
\b targetType
\b0  num:1 owner:nil];\
		[
\b targetPboard
\b0  
\b writeType
\b0 :*
\b targetType
\b0  data:newData length:newLen];\
		\
		// 
\i perform operation
\i0 \
		if (foundType == 
\b NXRulerPboardType
\b0 ) \{\
			[self 
\b pasteRuler
\b0 :self];\
		\} else \{\
			[self 
\b pasteFont
\b0 :self];\
		\}\
		\
		// 
\i restore data to targetPboard
\i0 \
		[
\b targetPboard
\b0  
\b declareTypes
\b0 :
\b targetType
\b0  num:1 owner:nil];\
		[
\b targetPboard
\b0  
\b writeType
\b0 :*
\b targetType
\b0  data:saveData length:saveLen];\
		\
		// 
\i free both datas
\i0 \
		[
\b targetPboard
\b0  
\b deallocatePasteboardData
\b0 :
\b saveData
\b0  length:saveLen];\
		[
\b pboard
\b0  
\b deallocatePasteboardData
\b0 :
\b newData
\b0  length:newLen];\
	\}	\
	return self;\
\}\
- 
\b writeSelectionToPasteboard
\b0 :pboard \{\
	
\b NXSelPt
\b0  	a,b;\
	int 		pos,k,N;\
	
\b NXRun
\b0  		*
\b curr
\b0 ;\
	
\b NXStream
\b0  	*
\b memstream
\b0 ;\
	NXAtom 		
\b supportedTypes
\b0 [5];\
	\
// 
\i 1) is there a selection of nonzero length?\

\i0 	[self 
\b getSel
\b0 :&a :&b];\
	if (!((
\b a.cp >=0
\b0 ) && [self 
\b isEditable
\b0 ] && (
\b b.cp != a.cp
\b0 ))) return 
\b nil
\b0 ;\
\
// 
\i 2) Initialize our pboard\
	// after some extensive experimentation, calling writeSelection does\
	// seem to work after all. The issue is that a real "copy" can have a\
	// "NeXT smart paste pasteboard type" which wstopb cannot. Tests in\
	// Edit reveal that this has no effect. Some keen user may find one though. \

\i0 	supportedTypes[0] = 
\b eTETFPboardType
\b0 ;\
	supportedTypes[1] = 
\b NXRTFPboardType
\b0 ;\
	supportedTypes[2] = 
\b NXAsciiPboardType
\b0 ;\
	supportedTypes[
\b 3
\b0 ] = 
\b NXFilenamePboardType
\b0 ;\
	supportedTypes[
\b 3
\b0 ] = 
\b NULL
\b0 ;\
	supportedTypes[4] = NULL;\
	[
\b pboard
\b0  
\b declareTypes
\b0 :
\b supportedTypes
\b0  num:
\b\fs36 3
\b0\fs24  owner:
\b nil
\b0 ];\
	\
	
\b memstream
\b0  = 
\b NXOpenMemory
\b0 (NULL,0,NX_READWRITE);\
	if (memstream) \{\
		[self 
\b writeETF
\b0 :
\b memstream
\b0  
\b from
\b0 :sp0.cp 
\b to
\b0 :spN.cp];\
		[pboard 
\b writeType
\b0 :
\b eTETFPboardType
\b0  
\b fromStream
\b0 :
\b memstream
\b0 ];\
		
\b NXCloseMemory
\b0 (
\b memstream
\b0 , NX_FREEBUFFER);\
	\}\
\
	
\b memstream
\b0  = 
\b NXOpenMemory
\b0 (NULL,0,NX_READWRITE);\
	if (memstream) \{\
		[self 
\b writeRTF
\b0 :memstream 
\b from
\b0 :sp0.cp 
\b to
\b0 :spN.cp];\
		[pboard 
\b writeType
\b0 :
\b NXRTFPboardType
\b0  
\b fromStream
\b0 :
\b memstream
\b0 ];\
		
\b NXCloseMemory
\b0 (
\b memstream
\b0 , NX_FREEBUFFER);\
	\}\
\
	
\b memstream
\b0  = 
\b NXOpenMemory
\b0 (NULL,0,NX_READWRITE);\
	if (memstream) \{\
		[self 
\b writeASCII
\b0 :memstream 
\b from
\b0 :sp0.cp 
\b to
\b0 :spN.cp];\
		[pboard 
\b writeType
\b0 :
\b NXAsciiPboardType
\b0  
\b fromStream
\b0 :
\b memstream
\b0 ];\
		
\b NXCloseMemory
\b0 (
\b memstream
\b0 , NX_FREEBUFFER);\
	\}\
			\

\i //	[pboard 
\b writeType
\b0 :
\b NXFilenamePboardType
\b0  
\b data
\b0 :[[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ]\
//			
\b length
\b0 :
\b strlen
\b0 ([[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ])
\b +1
\b0 ];\

\i0 \
// 
\i 3) are there Annotations in our selection?\

\i0 	pos=0;\
	N = theRuns->chunk.used/sizeof(NXRun);\
	curr = theRuns->runs;\
	for (k=0; ((k < N) && (b.cp > pos)); k++) \{\
		if ((curr->info) && (a.cp <= pos) && \
			[curr->
\b info
\b0  
\b respondsTo
\b0 :@selector(
\b addToPboard:
\b0 )]) \
			[curr->
\b info
\b0  
\b addToPboard
\b0 :
\b pboard
\b0 ];\

\i 			// this is kosher because a second addType of the same type fails.\
			// but a second writeType:of a different type might!\

\i0 		pos += curr->chars;\
		curr++;\
	\}\
	return self;\
\}\
- (
\b BOOL
\b0 )
\b writeSelectionToPasteboard
\b0 :pboard 
\b types
\b0 :(
\b NXAtom
\b0  *)types\
\{\
	id retVal;\
	int 
\b numTypes
\b0  = 
\b 0
\b0 ;\
	\
	retVal=[self 
\b writeSelectionToPasteboard
\b0 :pboard];\
	// 
\i now check to see that one of _types_ is on the pboard to return YES
\i0 \
	while(types && types[numTypes])\{ \

\i 	
\i0 	if (types[numTypes] == 
\b NXFilenamePboardType
\b0 ) \{\
			if (retVal)\
				[pboard 
\b addTypes
\b0 :&(types[numTypes]) num:
\b 1
\b0  owner:
\b nil
\b0 ];\
			else \
				[pboard 
\b declareTypes
\b0 :&(types[numTypes]) num:
\b 1
\b0  owner:
\b nil
\b0 ];\
			[pboard 
\b writeType
\b0 :
\b NXFilenamePboardType
\b0  
\b data
\b0 :[[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ]\
					
\b length
\b0 :
\b strlen
\b0 ([[etDoc 
\b docInfo
\b0 ] 
\b docPath
\b0 ])
\b +1
\b0 ];\
		\}\
		
\b numTypes++
\b0 ;						// 
\i Counter\
	
\i0 \}\
	
\b return
\b0  ([pboard 
\b findAvailableTypeFrom
\b0 :
\b types
\b0  
\b num
\b0 :
\b numTypes
\b0 ] ? 
\b YES
\b0  :
\b  NO
\b0 );\
\}\
\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b Dropping
\b0 \
//\
- (
\b NXDragOperation
\b0 )
\b draggingEntered
\b0 :(id <NXDraggingInfo>)sender \{\
	return [self 
\b draggingUpdated
\b0 :sender];\}\
- (
\b NXDragOperation
\b0 )
\b draggingUpdated
\b0 :(id <NXDraggingInfo>)sender \{\
	NXSelPt 		a,b;\
	NXPoint 		p;\
	NXCoord 		l,r,t,bot;\
	
\b NXDragOperation
\b0  
\b sourceMask
\b0  = [sender 
\b draggingSourceOperationMask
\b0 ];\
	\
	// 
\i Check for self-drags
\i0 \
	[self 
\b getMarginLeft
\b0 :&l right:&r top:&t bottom:&bot]; \
	
\b p
\b0  = [sender 
\b draggingLocation
\b0 ];\
	if ((
\b p.x
\b0  < (
\b l + SCROLLWIDTH
\b0 )) && ([sender 
\b draggingSource
\b0 ] == 
\b self
\b0 ))\
		return 
\b NX_DragOperationNone
\b0 ;\
	\
	// 
\i Check that the selection exists and isEditable
\i0 \
	[self getSel:&a :&b];\
	if (!((
\b a.cp >=0
\b0 ) && [self 
\b isEditable
\b0 ]))\
		return 
\b NX_DragOperationNone
\b0 ;\
	\

\i 	// It would be really nice to check whether the dragging Source is an\
	// Annotation and is *within* the current selection (auto-destruct!)\
	// Instead, it is the responsibility of each Annotation (see eTImage)\
	// Also, consider laying the image in the window at the insertionPoint\

\i0 	\
	if (sourceMask & 
\b NX_DragOperationLink
\b0 ) \{\
		return NX_DragOperationLink;\
	\} else if (sourceMask & 
\b NX_DragOperationCopy
\b0 ) \{\
		return NX_DragOperationCopy;\
	\} else if (sourceMask & 
\b NX_DragOperationGeneric
\b0 ) \{\
		return NX_DragOperationGeneric;\
	\}\
	return 
\b NX_DragOperationNone
\b0 ;\
\}\
- (
\b BOOL
\b0 )
\b prepareForDragOperation
\b0 :(id <NXDraggingInfo>)sender \{\

\i 	// Future Feature: slide to the insertion point? NXSelPt sp0?\
	// Edit implementation: remove the temp image of *entered/exit\

\i0 	return 
\b YES
\b0 ;\
\}\
- (
\b BOOL
\b0 )
\b performDragOperation
\b0 :(id <NXDraggingInfo>)sender \{\
	[self 
\b readSelectionFromPasteboard
\b0 :[sender 
\b draggingPasteboard
\b0 ] \
	
\b linked
\b0 :([sender 
\b draggingSourceOperationMask
\b0 ] & 
\b NX_DragOperationLink
\b0 )];\
	return 
\b YES
\b0 ;\
\}\
- 
\b concludeDragOperation
\b0 :(id <NXDraggingInfo>)sender \{\
	[[self 
\b window
\b0 ] 
\b makeKeyAndOrderFront
\b0 :self];\
	return self;\
\}\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b Changing Fonts
\b0 \
//\
- 
\b acceptFont
\b0 :(Font *)fontA 
\b atPoint
\b0 :(NXPoint *)p \{\
	id font;\
	\
	if ([fontA 
\b matrix
\b0 ] != 
\b NX_FLIPPEDMATRIX
\b0 )\
		
\b font
\b0  = [Font 
\b newFont
\b0 :[fontA name] \
						size:[fontA pointSize] \
					  matrix:
\b NX_FLIPPEDMATRIX
\b0 ];\
	else 
\b font
\b0  = fontA;\
	\
	if (sp0.cp == spN.cp)		// 
\i "insert" a font at a flashing caret.\

\i0 		[self 
\b setSel
\b0 :sp0.cp :(sp0.cp+1)];\
	[self 
\b setSelFont
\b0 :
\b font
\b0 ];	// 
\i undo is in setSelFont:
\i0 \
	//
\i [self 
\b setSel
\b0 :sp0.cp :spN.cp]; Remind Text object where the selection is!
\i0 \
	return self;\
\}\
- 
\b replaceFont
\b0 :(Font *)oldFontA 
\b with
\b0 :(Font *)newFontA \{\
	id 		oldFont, newFont;\
	int  	k,N;\
	NXRun 	*curr;\
	\
	// 
\i First, check that the font matrices are in order
\i0 \
	if ([oldFontA 
\b matrix
\b0 ] != 
\b NX_FLIPPEDMATRIX
\b0 )\
		
\b oldFont
\b0  = [Font 
\b newFont
\b0 :[
\b oldFontA
\b0  name] \
						size:[
\b oldFontA
\b0  pointSize] \
					  matrix:
\b NX_FLIPPEDMATRIX
\b0 ];\
	else 
\b oldFont
\b0  = oldFontA;\
	\
	if ([newFontA 
\b matrix
\b0 ] != 
\b NX_FLIPPEDMATRIX
\b0 )\
		
\b newFont
\b0  = [Font 
\b newFont
\b0 :[
\b newFontA
\b0  name] \
						size:[
\b newFontA
\b0  pointSize] \
					  matrix:
\b NX_FLIPPEDMATRIX
\b0 ];\
	else 
\b newFont
\b0  = newFontA;\
\
	// 
\i Freeze the display, Loop over all the NXRuns, recalc
\i0 \
	[[self window] 
\b disableFlushWindow
\b0 ];\
	
\b N
\b0  = 
\b theRuns
\b0 ->chunk.
\b used
\b0 /sizeof(NXRun);\
	
\b curr
\b0  = theRuns->
\b runs
\b0 ;\
	for (k=0; 
\b k < N
\b0 ; k++) \{\
		if (
\b curr->font
\b0  == 
\b oldFont
\b0 )
\b \
			curr->font 
\b0 = 
\b newFont
\b0 ; \
		curr++;\
	\}	\
	[self 
\b calcLine
\b0 ];\
	[[[[self window] 
\b display
\b0 ] 
\b reenableFlushWindow
\b0 ] 
\b\fc1\cf1 flushWindowIfNeeded
\b0\fc0\cf0 ];\
	return self;\
\}\
\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b Edit Menu
\b0 \
//\
- 
\b copy
\b0 :sender \{\
	[self 
\b writeSelectionToPasteboard
\b0 :[Pasteboard newName:
\b NXGeneralPboard
\b0 ]];\
	return self;\
\}\
- 
\b paste
\b0 :sender \{\
	return [self 
\b readSelectionFromPasteboard
\b0 :[Pasteboard newName:
\b NXGeneralPboard
\b0 ]];\
\}\
- 
\b clear
\b0 :sender \{\
	return [self 
\b delete
\b0 :sender];\}\
- 
\b delete
\b0 :sender \{\
	id retval;\
	if (
\b sp0
\b0 .cp 
\b ==
\b0  
\b spN
\b0 .cp) return 
\b nil
\b0 ;\
	[self 
\b undoSelChange
\b0 :"
\b Delete Selection
\b0 "];\
	retval = [super 
\b delete
\b0 :sender];\
  	[self 
\b undoAffectedRange
\b0 :
\b sp0
\b0 .cp 
\b to
\b0 :
\b sp0
\b0 .cp];\
	return retval;\
\}\
\
//ппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп\
//	
\b Services Menu
\b0 \
//\
- 
\b validRequestorForSendType
\b0 :(NXAtom)typeSent\
			   
\b andReturnType
\b0 :(NXAtom)typeReturned\
\{\

\i 	// OK, so sue me, we can't advertise that we send images and audio\
	// by actually confirming it dynamically -- that's too damn expensive\
	// Originally, we only checked if the sent type was one of:\
	// NXFilenamePboardType,NXAsciiPboardType,NXRTFPboardType\
	// Now, we just say what the hell and return self.\
	// If the requestor actually wanted audio data and the selection is\
	// text, tough luck. But this way, EqB's Edit Equation works...\

\i0 	if (
\b typeReturned
\b0  && (
\b !
\b0 [self 
\b isEditable
\b0 ])) return 
\b nil
\b0 ;\
	return 
\b self
\b0 ;\
\}\
\

\i @end
}
