Prevent warning when NSDocument file is programmatically renamed

Ask Question

Asked 12 years, 3 months ago

Modified 3 years ago

Viewed 2k times

6

My application allows the user to rename documents that are currently open. This is trivial, and works fine, with one really annoying bug I can't figure out. When a file is renamed, AppKit (kindly) warns the user the next time they try to save the document. The user says "OK" and everything continues as normal. This makes sense when something external to the application changed the document, but not when it was actually done by the document itself.

The code goes something like this:

-(void)renameDocumentTo:(NSString *)newName {
  NSURL *newURL = [[[self fileURL] URLByDeletingLastPathComponent]
                                   URLByAppendingPathComponent:newName];

  NSFileManager *fileManager = [NSFileManager defaultManager];
  [fileManager moveItemAtURL:[self fileURL] toURL:newURL];
  NSDictionary *attrs = [fileManager attributesForItemAtPath:[newURL path] error:NULL];

  [self setFileURL:newURL];
  [self setFileModificationDate:[attrs fileModificationDate]];
}

One would think that expressly setting the new URL and modification date on the document would be enough, but sadly it's not. Cocoa still generates the warning.

I've tried changing the order (setting the new URL on the document, THEN renaming the file) but this doesn't help.

I've also tried a fix suggested by a user on an old post over at CocoaDev:

[self performSelector:@selector(_resetMoveAndRenameSensing)];

Even this does not stop the warning however, and I'm guessing there has to be a proper way to do this using the documented API. How does Xcode handle things when a user clicks a file on the project tree and renames it to something else. It doesn't warn the user about the rename, since the user actually performed the rename.

What do I need to do?

Share

Follow

edited Feb 16, 2020 at 9:07

Cœur

36.6k2525 gold badges191191 silver badges259259 bronze badges

asked Dec 3, 2010 at 9:17

d11wtq

34.5k1919 gold badges119119 silver badges195195 bronze badges

  • I have started bounty for help with this. I'm really getting nowhere with it unfortunately. A simple test case is just to create a blank document app that opens a .txt file (or anything really), add a menu item whose action renames the opened file to something else (and updates the document objects with the new URL). I'm trying to circumvent the warning when try to save the file the first time after the rename. 

    – d11wtq

     Dec 7, 2010 at 11:27
  • Oh, and this needs to work if the document is currently edited. Saving to disk, closing the document, moving the file and then and re-opening it could have undesirable effects if unsaved changes exist. 

    – d11wtq

     Dec 7, 2010 at 11:28

Add a comment

3 Answers

Sorted by:

                                              Highest score (default)                                                                   Trending (recent votes count more)                                                                   Date modified (newest first)                                                                   Date created (oldest first)                              

3

+100

There isn't much on this in the main docs. Instead, have a look at the 10.5 release notes: Documentation Archive under the heading "NSDocument Checking for Modified Files At Saving Time"

(In the case of Xcode, it has a long history and I wouldn't be surprised if if doesn't use NSDocument for files within the project)

It is worth noting that moving a file does not change its modification date, so calling -setFileModificationDate: is unlikely to have any effect.

So one possibility could be to bypass NSDocument's usual warning like so:

- (void)saveDocument:(id)sender;
{
    if (wasRenamed)
    {
        [self saveToURL:[self fileURL] ofType:[self fileType] forSaveOperation:NSSaveOperation delegate:nil didSaveSelector:nil contextInfo:NULL];
        wasRenamed = NO;
    }
    else
    {
        [super saveDocument:sender];
    }
}

Ideally you also need to check for the possibility of:

  1. Ask app to rename the doc
  2. Renamed file is then modified/moved by another app
  3. User goes to save the doc

At that point you want the usual warning sheet to come up. Could probably be accomplished by something like:

- (void)renameDocumentTo:(NSString *)newName
{
    // Do the rename

    [self setFileURL:newURL];
    wasRenamed = YES; // MUST happen after -setFileURL:
}

- (void)setFileURL:(NSURL *)absoluteURL;
{
    if (![absoluteURL isEqual:[self fileURL]]) wasRenamed = NO;
    [super setFileURL:absoluteURL];
}

- (void)setFileModificationDate:(NSDate *)modificationDate;
{
    if (![modificationDate isEqualToDate:[self fileModificationDate]]) wasRenamed = NO;
    [super setFileModificationDate:modificationDate];
}

Otherwise, your only other choice I can see is to call one of the standard save/write methods with some custom parameters that prompt your document subclass to move the current doc rather than actually save it. Would be trickier I think. Perhaps define your own NSSaveOperationType?

With this technique the doc system should understand that the rename was part of a save-like operation, but it would need quite a bit of experimentation to be sure.

Share

Follow

answered Dec 10, 2010 at 12:38

Mike Abdullah

14.9k22 gold badges5050 silver badges7474 bronze badges

  • Good answer, thanks. I had already tried your second suggestion without success, though it probably can be forced to work, somehow. I think your first suggestion (overriding saveDocument: and using a transient wasRenamed flag) should work well. Just about to test it now. 

    – d11wtq

     Dec 12, 2010 at 13:42

Add a comment

1

Much inspired from @Mike's answer, I got the "moved to" message not to show up anymore by re-routing NSSaveOperation to NSSaveAsOperation. In my NSDocument subclass:

  • I overload saveDocumentWithDelegate:didSaveSelector:contextInfo: to determine the save URL and document type (assigning those to self); if the old fileURL exists, I move that to the new location
  • Inside saveDocumentWithDelegate:didSaveSelector:contextInfo: I redirect the call to [self saveToURL:self.fileURL ofType:self.fileType forSaveOperation:NSSaveAsOperation completionHandler: ...] instead of [super saveDocumentWithDelegate:didSaveSelector:contextInfo:]

This works for me.

Share

Follow

answered Dec 11, 2015 at 7:45

Alessandro

9111 silver badge66 bronze badges

Add a comment

0

Isn't it possible to programmatically answer the question for the user? Or you can save immediately after renaming, this way a user gets every answer in one go.

I see that this problem is up and running for some time, so telling you to read the reference won't do any good i guess..

Hope i helped a little bit although it doesn't fix your problem directly

Share

Follow

猜你喜欢

转载自blog.csdn.net/weixin_42610770/article/details/129575390