My app (swift, OSX, Xcode, latest versions of everything) has an NSTextView that I allow the user to type in to. The NSTextView has RichText, graphics, and and NSInspectorBar enabled.
I load/save the contents of the NSTextView to webarchive format (grumble grumble - but I need a portable format that includes images).
So far so good. Everything works... except for a minor detail. When I insert an image into the TextView, it doesn't show up. But it is there, because if I save and load... it appears.
Here's how I insert the image into the NSTextView (I get the path to the image from an NSOpenPanel:
guard let theImage = NSImage(contentsOfURL: openPanel.URL!) else {
showErrorMessage("Unable to load image")
return
}
// self.textEditor is the NSTextView
guard let store = self.textEditor.textStorage else { abort() }
let attachment = NSTextAttachment()
attachment.image = theImage
let attrString = NSAttributedString(attachment: attachment)
let range = self.textEditor.selectedRange()
store.replaceCharactersInRange(range, withAttributedString: attrString)
I think its reasonably straight forward: load the image, add to an attributedString, replace the selected characters with the attributedString.
However nothing appears. No change at all to the NSTextView. If I save the NSTextStorage contents as a webarchive:
guard let store = textEditor.textStorage else { abort() }
let attr: [String: AnyObject] = [NSDocumentTypeDocumentAttribute: NSWebArchiveTextDocumentType]
let data = try store.dataFromRange(NSMakeRange(0, store.length), documentAttributes: attire)
//... save 'data' to DB ...
and then reload them back in:
//... load 'data' from the DB ...
guard let store = textEditor.textStorage else { abort() }
let str = try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute:NSWebArchiveTextDocumentType], documentAttributes: nil)
store.setAttributedString(str)
...the images appear in exactly the right spot.
I'm quite confused by this one. Does anyone have any ideas as to what I am missing?
BTW - I have tried forcing a refresh using:
let frame = self.textEditor.frame
self.textEditor.setNeedsDisplayInRect(frame)
That did not work.
ADVthanksANCE for any advice you can give. Cheers. Paul
Edit: Addendum... I've been messing with NSTextAttachmentCells in the hope that they might work.They fail in a completely different fashion.
If I just replace the image insert code above with:
let cell = NSTextAttachmentCell(imageCell: theImage)
let txtAtt = NSTextAttachment()
txtAtt.attachmentCell = cell
let str = NSAttributedString(attachment: txtAtt)
let range = self.textEditor.selectedRange()
store.replaceCharactersInRange(range, withAttributedString: str)
...then the images do appear immediately upon insertion, and in exactly the right place. But they do not get saved! That is, when I do a save and reload (as per the code above), they do not get included in the webarchive.
Edit^2: So the obvious conclusion from the above is to have both an image attached to the TextAttachment and an image attached to an NSTextAttachmentCell, which is also attached to the TextAttachment. Well... that doesn't work. BUT what does work is this:
let cell = NSTextAttachmentCell(imageCell: theImage)
let txtAtt = NSTextAttachment(data: theImage.TIFFRepresentation, ofType: kUTTypeTIFF as String)
txtAtt.attachmentCell = cell
//txtAtt.image = theImage
let str = NSAttributedString(attachment: txtAtt)
let rng = self.textEditor.selectedRange()
store.replaceCharactersInRange(rng, withAttributedString: str)
That is... I create a TextAttachment, passing data of the TIFF representation of the image. I also create the AttachmentCell. This now works - the insertion is visible and it saves.
Only downside is that TIFF's are huge - the image expands to 3x the memory size.
Can anyone give some ideas as to why this works?