Revision: 24326 http://sourceforge.net/p/bibdesk/svn/24326 Author: hofman Date: 2019-10-22 14:49:04 +0000 (Tue, 22 Oct 2019) Log Message: ----------- Run all script hooks asynchronously. Perform paper filing using a recursive block, because the Will Auto File script hook may make it asynchronous.
Modified Paths: -------------- trunk/bibdesk/BDSKAppleScript.h trunk/bibdesk/BDSKAppleScript.m trunk/bibdesk/BDSKFiler.m trunk/bibdesk/BDSKScriptHookManager.m Modified: trunk/bibdesk/BDSKAppleScript.h =================================================================== --- trunk/bibdesk/BDSKAppleScript.h 2019-10-22 14:45:24 UTC (rev 24325) +++ trunk/bibdesk/BDSKAppleScript.h 2019-10-22 14:49:04 UTC (rev 24326) @@ -41,12 +41,10 @@ @interface BDSKAppleScript : NSObject { id appleScript; - BOOL synchronous; } + (dispatch_queue_t)appleScriptQueue; -- (id)initWithURL:(NSURL *)url synchronous:(BOOL)sync error:(NSError **)error; - (id)initWithURL:(NSURL *)url error:(NSError **)error; - (id)initWithSource:(NSString *)source; Modified: trunk/bibdesk/BDSKAppleScript.m =================================================================== --- trunk/bibdesk/BDSKAppleScript.m 2019-10-22 14:45:24 UTC (rev 24325) +++ trunk/bibdesk/BDSKAppleScript.m 2019-10-22 14:49:04 UTC (rev 24326) @@ -79,10 +79,10 @@ return [NSError errorWithDomain:@"NSAppleScriptErrorDomain" code:code userInfo:userInfo]; } -- (id)initWithURL:(NSURL *)url synchronous:(BOOL)sync error:(NSError **)error { +- (id)initWithURL:(NSURL *)url error:(NSError **)error { self = [super init]; if (self) { - if (sync == NO && NSUserAppleScriptTaskClass) { + if (NSUserAppleScriptTaskClass) { appleScript = [[NSUserAppleScriptTaskClass alloc] initWithURL:url error:error]; } else { NSDictionary *errorDict = nil; @@ -90,7 +90,6 @@ if (appleScript == nil && error != NULL) *error = errorFromDictionary(errorDict); } - synchronous = sync; if (appleScript == nil) { [self release]; self = nil; @@ -99,16 +98,10 @@ return self; } -- (id)initWithURL:(NSURL *)url error:(NSError **)error { - self = [self initWithURL:url synchronous:NO error:error]; - return self; -} - - (id)initWithSource:(NSString *)source { self = [super init]; if (self) { appleScript = [[NSAppleScript alloc] initWithSource:source]; - synchronous = NO; if (appleScript == nil) { [self release]; self = nil; @@ -125,28 +118,6 @@ - (void)executeWithAppleEvent:(NSAppleEventDescriptor *)event completionHandler:(void (^)(NSAppleEventDescriptor *result, NSError *error))handler { if ([appleScript respondsToSelector:@selector(executeWithAppleEvent:completionHandler:)]) { [appleScript executeWithAppleEvent:event completionHandler:handler]; - } else if (synchronous) { - if (event && [appleScript respondsToSelector:@selector(executeAppleEvent:error:)]) { - dispatch_sync([[self class] appleScriptQueue], ^{ - NSError *error = nil; - NSDictionary *errorDict = nil; - NSAppleEventDescriptor *result = [appleScript executeAppleEvent:event error:&errorDict]; - if (result == nil) - error = errorFromDictionary(errorDict); - if (handler) - handler(result, error); - }); - } else if (event == nil && [appleScript respondsToSelector:@selector(executeAndReturnError:)]) { - dispatch_sync([[self class] appleScriptQueue], ^{ - NSError *error = nil; - NSDictionary *errorDict = nil; - NSAppleEventDescriptor *result = [appleScript executeAndReturnError:&errorDict]; - if (result == nil) - error = errorFromDictionary(errorDict); - if (handler) - handler(result, error); - }); - } } else if (event && [appleScript respondsToSelector:@selector(executeAppleEvent:error:)]) { dispatch_async([[self class] appleScriptQueue], ^{ NSError *error = nil; Modified: trunk/bibdesk/BDSKFiler.m =================================================================== --- trunk/bibdesk/BDSKFiler.m 2019-10-22 14:45:24 UTC (rev 24325) +++ trunk/bibdesk/BDSKFiler.m 2019-10-22 14:49:04 UTC (rev 24326) @@ -185,125 +185,149 @@ [[self window] orderFront:nil]; } - for (id paperInfo in paperInfos) { - BDSKLinkedFile *file = [paperInfo valueForKey:BDSKFilerFileKey]; - BibItem *pub = [paperInfo valueForKey:BDSKFilerPublicationKey]; - NSString *oldPath = nil; - NSString *newPath = nil; + __block void (^filePaperInfo)(NSInteger) = Block_copy(^(NSInteger i){ - if (generate == NO) // new path provided, e.g. undo - newPath = [paperInfo valueForKey:BDSKFilerNewPathKey]; - else if (isLinkedFiles) // initial auto file of file - newPath = [[pub suggestedURLForLinkedFile:file] path]; - else // initial auto file of field - newPath = [[pub suggestedURLForField:field] path]; - if (isLinkedFiles) - oldPath = [file path]; - else if (initial) - oldPath = [[pub localFileURLForField:field] path]; - else - oldPath = [paperInfo valueForKey:BDSKFilerOldPathKey]; + if (i < numberOfPapers) { + // file the i'th paper + + id paperInfo = [paperInfos objectAtIndex:i]; + BDSKLinkedFile *file = [paperInfo valueForKey:BDSKFilerFileKey]; + BibItem *pub = [paperInfo valueForKey:BDSKFilerPublicationKey]; + NSString *oldPath = nil; + NSString *newPath = nil; - if (numberOfPapers > 1) { - [progressIndicator incrementBy:1.0]; - [progressIndicator displayIfNeeded]; - } - - if ([NSString isEmptyString:oldPath]) { + if (generate == NO) // new path provided, e.g. undo + newPath = [paperInfo valueForKey:BDSKFilerNewPathKey]; + else if (isLinkedFiles) // initial auto file of file + newPath = [[pub suggestedURLForLinkedFile:file] path]; + else // initial auto file of field + newPath = [[pub suggestedURLForField:field] path]; if (isLinkedFiles) - [pub removeFileToBeFiled:file]; - continue; - } + oldPath = [file path]; + else if (initial) + oldPath = [[pub localFileURLForField:field] path]; + else + oldPath = [paperInfo valueForKey:BDSKFilerOldPathKey]; - NSMutableDictionary *info = [NSMutableDictionary dictionaryWithCapacity:6]; - [info setValue:file forKey:BDSKFilerFileKey]; - [info setValue:oldPath forKey:BDSKFilerOldPathKey]; - [info setValue:pub forKey:BDSKFilerPublicationKey]; + if (numberOfPapers > 1) { + [progressIndicator incrementBy:1.0]; + [progressIndicator displayIfNeeded]; + } - if (check && NO == (isLinkedFiles ? [pub canSetURLForLinkedFile:file] : [pub canSetURLForField:field])) { - - [info setValue:NSLocalizedString(@"Incomplete information to generate file name.",@"") forKey:BDSKFilerStatusKey]; - [info setValue:[NSNumber numberWithInteger:BDSKIncompleteFieldsErrorMask] forKey:BDSKFilerFlagKey]; - [info setValue:NSLocalizedString(@"Move anyway.",@"") forKey:BDSKFilerFixKey]; - [info setValue:newPath forKey:BDSKFilerNewPathKey]; - [errorInfoDicts addObject:info]; - - } else if ([NSString isEmptyString:newPath] || [oldPath isEqualToString:newPath]) { - - if (isLinkedFiles) - [pub removeFileToBeFiled:file]; - else if ([field isEqualToString:BDSKLocalUrlString]) - [pub setLocalUrlNeedsToBeFiled:NO]; - - } else { - - [[BDSKScriptHookManager sharedManager] runScriptHookWithName:BDSKWillAutoFileScriptHookName - forPublications:[NSArray arrayWithObject:pub] document:doc - field:field oldValues:[NSArray arrayWithObject:oldPath] newValues:[NSArray arrayWithObject:newPath]]; - - NSError *error = nil; - - if (NO == [[NSFileManager defaultManager] moveItemAtURL:[NSURL fileURLWithPath:oldPath isDirectory:NO] toURL:[NSURL fileURLWithPath:newPath isDirectory:NO] force:force error:&error]){ + if ([NSString isEmptyString:oldPath]) { + if (isLinkedFiles) + [pub removeFileToBeFiled:file]; - NSDictionary *errorInfo = [error userInfo]; - [info setValue:[errorInfo objectForKey:NSLocalizedRecoverySuggestionErrorKey] forKey:BDSKFilerFixKey]; - [info setValue:[errorInfo objectForKey:NSLocalizedDescriptionKey] forKey:BDSKFilerStatusKey]; - [info setValue:[NSNumber numberWithInteger:[error code]] forKey:BDSKFilerFlagKey]; + filePaperInfo(i + 1); + return; + } + + NSMutableDictionary *info = [NSMutableDictionary dictionaryWithCapacity:6]; + [info setValue:file forKey:BDSKFilerFileKey]; + [info setValue:oldPath forKey:BDSKFilerOldPathKey]; + [info setValue:pub forKey:BDSKFilerPublicationKey]; + + if (check && NO == (isLinkedFiles ? [pub canSetURLForLinkedFile:file] : [pub canSetURLForField:field])) { + + [info setValue:NSLocalizedString(@"Incomplete information to generate file name.",@"") forKey:BDSKFilerStatusKey]; + [info setValue:[NSNumber numberWithInteger:BDSKIncompleteFieldsErrorMask] forKey:BDSKFilerFlagKey]; + [info setValue:NSLocalizedString(@"Move anyway.",@"") forKey:BDSKFilerFixKey]; [info setValue:newPath forKey:BDSKFilerNewPathKey]; [errorInfoDicts addObject:info]; - } else { + filePaperInfo(i + 1); - // switch them as this is used in undo - [info setValue:oldPath forKey:BDSKFilerNewPathKey]; - [info setValue:newPath forKey:BDSKFilerOldPathKey]; - [fileInfoDicts addObject:info]; + } else if ([NSString isEmptyString:newPath] || [oldPath isEqualToString:newPath]) { - if (isLinkedFiles) { - [file updateWithPath:newPath]; - // make sure the UI is updated - [pub noteFilesChanged:YES]; - } else if (initial) { - // if this is not an initial move, undo should take care of this - NSString *value = [pub fieldValueForFileURL:[NSURL fileURLWithPath:newPath isDirectory:NO] withFormat:[[NSUserDefaults standardUserDefaults] integerForKey:BDSKLocalFileOptionKey]]; - [pub setField:field toValue:value]; - // make sure the undo of the move is paired with setting the field - // the undo group may be broken up due to the script hooks - [[[doc undoManager] prepareWithInvocationTarget:self] movePapers:[NSArray arrayWithObject:info] forField:field fromDocument:doc options:0 actionName:nil]; - if (actionName) - [[doc undoManager] setActionName:actionName]; - } + if (isLinkedFiles) + [pub removeFileToBeFiled:file]; + else if ([field isEqualToString:BDSKLocalUrlString]) + [pub setLocalUrlNeedsToBeFiled:NO]; - [[BDSKScriptHookManager sharedManager] runScriptHookWithName:BDSKDidAutoFileScriptHookName - forPublications:[NSArray arrayWithObject:pub] document:doc - field:field oldValues:[NSArray arrayWithObject:oldPath] newValues:[NSArray arrayWithObject:newPath]]; + filePaperInfo(i + 1); + } else { + + [[BDSKScriptHookManager sharedManager] runScriptHookWithName:BDSKWillAutoFileScriptHookName + forPublications:[NSArray arrayWithObject:pub] document:doc + field:field oldValues:[NSArray arrayWithObject:oldPath] newValues:[NSArray arrayWithObject:newPath] + completionHandler:^{ + + NSError *error = nil; + + if (NO == [[NSFileManager defaultManager] moveItemAtURL:[NSURL fileURLWithPath:oldPath isDirectory:NO] toURL:[NSURL fileURLWithPath:newPath isDirectory:NO] force:force error:&error]){ + + NSDictionary *errorInfo = [error userInfo]; + [info setValue:[errorInfo objectForKey:NSLocalizedRecoverySuggestionErrorKey] forKey:BDSKFilerFixKey]; + [info setValue:[errorInfo objectForKey:NSLocalizedDescriptionKey] forKey:BDSKFilerStatusKey]; + [info setValue:[NSNumber numberWithInteger:[error code]] forKey:BDSKFilerFlagKey]; + [info setValue:newPath forKey:BDSKFilerNewPathKey]; + [errorInfoDicts addObject:info]; + + } else { + + // switch them as this is used in undo + [info setValue:oldPath forKey:BDSKFilerNewPathKey]; + [info setValue:newPath forKey:BDSKFilerOldPathKey]; + [fileInfoDicts addObject:info]; + + if (isLinkedFiles) { + [file updateWithPath:newPath]; + // make sure the UI is updated + [pub noteFilesChanged:YES]; + } else if (initial) { + // if this is not an initial move, undo should take care of this + NSString *value = [pub fieldValueForFileURL:[NSURL fileURLWithPath:newPath isDirectory:NO] withFormat:[[NSUserDefaults standardUserDefaults] integerForKey:BDSKLocalFileOptionKey]]; + [pub setField:field toValue:value]; + // make sure the undo of the move is paired with setting the field + // the undo group may be broken up due to the script hooks + [[[doc undoManager] prepareWithInvocationTarget:self] movePapers:[NSArray arrayWithObject:info] forField:field fromDocument:doc options:0 actionName:nil]; + if (actionName) + [[doc undoManager] setActionName:actionName]; + } + + [[BDSKScriptHookManager sharedManager] runScriptHookWithName:BDSKDidAutoFileScriptHookName + forPublications:[NSArray arrayWithObject:pub] document:doc + field:field oldValues:[NSArray arrayWithObject:oldPath] newValues:[NSArray arrayWithObject:newPath]]; + + } + + // we always do this even when it failed, to avoid retrying at every edit + [pub removeFileToBeFiled:file]; + + filePaperInfo(i + 1); + }]; } - // we always do this even when it failed, to avoid retrying at every edit - [pub removeFileToBeFiled:file]; + } else { + // we've exhauster the paperInfos array, finish up + if (numberOfPapers > 1) + [[self window] orderOut:nil]; + + if ((isLinkedFiles || initial == NO) && [fileInfoDicts count] > 0) { + [[[doc undoManager] prepareWithInvocationTarget:self] movePapers:fileInfoDicts forField:field fromDocument:doc options:0 actionName:nil]; + if (actionName) + [[doc undoManager] setActionName:actionName]; + } + + if ([errorInfoDicts count] > 0) { + BDSKFilerErrorController *errorController = [[[BDSKFilerErrorController alloc] initWithErrors:errorInfoDicts forField:field options:mask actionName:actionName] autorelease]; + [doc addWindowController:errorController]; + [errorController showWindow:nil]; + } + + filing = NO; + + [self runPendingFilingIfNeeded]; + + // this balances the Block_copy, avoids a retain cycle + Block_release(filePaperInfo); } - } + }); - if (numberOfPapers > 1) - [[self window] orderOut:nil]; - - if ((isLinkedFiles || initial == NO) && [fileInfoDicts count] > 0) { - [[[doc undoManager] prepareWithInvocationTarget:self] movePapers:fileInfoDicts forField:field fromDocument:doc options:0 actionName:nil]; - if (actionName) - [[doc undoManager] setActionName:actionName]; - } - - if ([errorInfoDicts count] > 0) { - BDSKFilerErrorController *errorController = [[[BDSKFilerErrorController alloc] initWithErrors:errorInfoDicts forField:field options:mask actionName:actionName] autorelease]; - [doc addWindowController:errorController]; - [errorController showWindow:nil]; - } - - filing = NO; - - [self runPendingFilingIfNeeded]; + // file the first paper, this will recursively call the next one + filePaperInfo(0); } @end Modified: trunk/bibdesk/BDSKScriptHookManager.m =================================================================== --- trunk/bibdesk/BDSKScriptHookManager.m 2019-10-22 14:45:24 UTC (rev 24325) +++ trunk/bibdesk/BDSKScriptHookManager.m 2019-10-22 14:49:04 UTC (rev 24326) @@ -122,9 +122,8 @@ NSLog(@"No script file found for script hook %@.", name); return nil; } else { - BOOL sync = [name isEqualToString:BDSKWillAutoFileScriptHookName]; NSError *error = nil; - script = [[BDSKAppleScript alloc] initWithURL:[NSURL fileURLWithPath:path isDirectory:NO] synchronous:sync error:&error]; + script = [[BDSKAppleScript alloc] initWithURL:[NSURL fileURLWithPath:path isDirectory:NO] error:&error]; if (script == nil) { NSLog(@"Error creating AppleScript: %@", error); return nil; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. _______________________________________________ Bibdesk-commit mailing list Bibdesk-commit@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bibdesk-commit