Getting filename and path from nsfilewrapper / nstextattachment in NSAttributedString
Asked Answered
N

1

5

I have a basic NSTextView with rich text and graphics enabled (in IB). What I'd like to get is the path and filename of any images dragged in so I can pass those to another class.

I'm new to NSAttributedString but I've got a loop using enumerateAttributesInRange:options:usingBlock: looking for NSAttachmentAttributeName and that's all working fine. But going deeper, I get to the fileWrapper class and it's apparent inability to give me the path of the item.

How would I go about getting the name and path of the NSTextAttachment?

Related: Is there an easier way to get them all then stepping through the attributes?

Thanks much!

Negativism answered 4/2, 2012 at 3:41 Comment(1)
Unfortunately the attributes dictionary returned by NSFileWrapper doesn't provide the full pathname either. The design of NSFileWrapper makes myopic and unfortunate encapsulation assumptions by declining to provide access to the pathname of the original referencing object.Wallin
W
7

While I personally hold the design of NSFileWrapper in contempt, if you just need the data of each attachment you can access it as an NSData instance via NSFileWrapper's regularFileContents method. However, I needed a valid and explicit pathname to the attachment for my application. To get it is much more work than it should be:

You can subclass your NSTextView and override the NSDraggingDestination Protocol method draggingEntered: and you can traverse the NSPasteboardItem objects passed to your application during the dragging operation. I chose to keep the pathname and its inode number in an NSMutableDictionary, as NSFileWrapper can provide you with the inode of the referenced file. Later, when I access the NSTextView contents via an NSAttributedString, I can fetch the pathname of an attachment using the inode as an index.

- (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender {

    // get pasteboard from dragging operation

    NSPasteboard *pasteboard = [sender draggingPasteboard];

    NSArray *pasteboardItems = [pasteboard pasteboardItems];

    for ( NSPasteboardItem *pasteboardItem in pasteboardItems ) {

        // look for a file url type from the pasteboard item

        NSString *draggedURLString = [pasteboardItem stringForType:@"public.file-url"];

        if (draggedURLString != nil) {

            NSURL *draggedURL = [NSURL URLWithString:draggedURLString];

            NSString *draggedPath = [draggedURL path];

            NSLog(@"pathname: %@", draggedPath);

            // do something with the path

            // get file attributes

            NSDictionary *draggedAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:draggedPath error:nil];

            if ( draggedAttributes == nil)
                continue;

            // the NSFileWrapper allows access to the absolute file via NSFileSystemFileNumber
            // put the path and the inode (returned as an NSNumber) into a NSMutableDictionary 

            NSNumber *draggedInode = [draggedAttributes objectForKey:NSFileSystemFileNumber];

            [draggedFiles setObject:draggedPath forKey:draggedInode];
        }

    }

    return [super draggingEntered:sender];
}

One issue with my solution, that doesn't effect my application, is that multiple files dragged into the view (either singly or together) which are hard links to the same file, will only be indexed as the last pathname added to the dictionary which shares the inode. Depending on how the pathnames are utilized by your application this could be an issue.

Wallin answered 16/2, 2012 at 0:29 Comment(2)
Cool, but bummer. In investigating this, I assumed draggingEntered was where I was headed but had not yet put down code. I'll try your example in the next couple of days and let you know. Thanks!Negativism
This appears the only way to go. Thanks for the code examples - it's getting me where I need to go. Accepted this answer.Negativism

© 2022 - 2024 — McMap. All rights reserved.