Revision: 29281
          http://sourceforge.net/p/bibdesk/svn/29281
Author:   hofman
Date:     2025-07-17 16:36:29 +0000 (Thu, 17 Jul 2025)
Log Message:
-----------
Get commit errors from text fields in editorr separately from fake delegate 
methods. Present the errors in the control delegate methods. Also use the 
errors in commitEditingAndReturnError:, so it does not display the errors in a 
sheet or dialog.

Modified Paths:
--------------
    trunk/bibdesk/BDSKEditor.m

Modified: trunk/bibdesk/BDSKEditor.m
===================================================================
--- trunk/bibdesk/BDSKEditor.m  2025-07-15 09:33:52 UTC (rev 29280)
+++ trunk/bibdesk/BDSKEditor.m  2025-07-17 16:36:29 UTC (rev 29281)
@@ -124,6 +124,9 @@
 - (void)fileURLDidChange:(NSNotification *)notification;
 - (void)needsToBeFiledDidChange:(NSNotification *)notification;
 
+- (BOOL)control:(NSControl *)control didFailToFormatString:(NSString *)string 
errorDescription:(NSString *)errorString error:(NSError **)error;
+- (BOOL)control:(NSControl *)control isValidObject:(id)obj error:(NSError 
**)error;
+
 - (void)recordChangingField:(NSString *)fieldName toValue:(NSString *)value;
 
 - (void)openParentItemForField:(NSString *)field;
@@ -409,7 +412,50 @@
 
 - (BOOL)commitEditing
 {
-    return [self commitEditingAndReturnError:NULL];
+    NSResponder *firstResponder = [[self window] firstResponder];
+    
+    /*
+     Need to finalize text field cells being edited or the abstract/annote 
text views, since the
+     text views bypass the normal undo mechanism for speed, and won't cause 
the doc to be marked
+     dirty on subsequent edits.
+     */
+    if([firstResponder isKindOfClass:[NSText class]]){
+        
+        NSTextView *textView = (NSTextView *)firstResponder;
+        NSInteger editedRow = -1;
+        NSArray *selection = [textView selectedRanges];
+        if ([textView isFieldEditor]) {
+            firstResponder = (NSResponder *)[textView delegate];
+            editedRow = [tableView rowForView:textView];
+        }
+        
+        editorFlags.didSetupFields = NO; // if we we rebuild the fields, the 
selection will become meaningless
+        
+        // check textviews for balanced braces as needed
+        if (currentEditedView && [self validateCurrentEditedView] == NO)
+            return NO;
+        
+        // commit edits (formatters may refuse to allow this)
+        if ([[self window] makeFirstResponder:[self window]] == NO)
+            return NO;
+        
+        // for inherited fields, we should do something here to make sure the 
user doesn't have to go through the warning sheet
+        
+        if (editorFlags.didSetupFields == NO || editedRow == -1) {
+            if (editedRow != -1) {
+                if (editedRow < [tableView numberOfRows]) {
+                    [tableView editColumn:1 row:editedRow withEvent:nil 
select:NO];
+                    [(NSTextView *)[[self textFieldAtRow:editedRow] 
currentEditor] setSafeSelectedRanges:selection];
+                }
+            } else if ([[self window] makeFirstResponder:firstResponder]) {
+                if ([firstResponder isKindOfClass:[NSTextField class]])
+                    textView = (NSTextView *)[(NSTextField *)firstResponder 
currentEditor];
+                [textView setSafeSelectedRanges:selection];
+            }
+        }
+        
+    }
+    return YES;
 }
 
 - (BOOL)commitEditingAndReturnError:(NSError **)error
@@ -425,24 +471,69 @@
        if([firstResponder isKindOfClass:[NSText class]]){
         
         NSTextView *textView = (NSTextView *)firstResponder;
+        NSTextField *textField = nil;
                NSInteger editedRow = -1;
                NSArray *selection = [textView selectedRanges];
         if ([textView isFieldEditor]) {
             firstResponder = (NSResponder *)[textView delegate];
+            if ([firstResponder isKindOfClass:[NSTextField class]])
+                textField = (NSTextField *)firstResponder;
             editedRow = [tableView rowForView:textView];
         }
         
-               editorFlags.didSetupFields = NO; // if we we rebuild the 
fields, the selection will become meaningless
-        
-        // check textviews for balanced braces as needed
-        if (currentEditedView && [self validateCurrentEditedView] == NO) {
-            if (error)
-                *error = [NSError localErrorWithCode:kBDSKFailedToCommit 
localizedDescription:NSLocalizedString(@"Failed to commit edits", @"Error 
message")];
+        if (textField) {
+            
+            BOOL valid = YES;
+            NSString *obj = nil;
+            NSFormatter *formatter = [textField formatter];
+            
+            if (formatter) {
+                NSString *errorString = nil;
+                NSString *string = [textView string];
+                valid = [formatter getObjectValue:&obj forString:string 
errorDescription:&errorString];
+                if (valid == NO) {
+                    valid = [self control:textField 
didFailToFormatString:string errorDescription:errorString error:error];
+                    if (valid == NO)
+                        return NO;
+                }
+            } else {
+                obj = [textView string];
+            }
+            valid = [self control:textField isValidObject:obj error:error];
+            
+            if (valid == NO) {
+                if (error && [*error localizedRecoveryOptions]) {
+                    // no recovery possible, so just make it an unrecoverable 
error
+                    NSError *err = [NSError 
mutableLocalErrorWithCode:kBDSKFailedToCommit localizedDescription:[*error 
localizedDescription]];
+                    NSString *errString = [*error localizedRecoverySuggestion];
+                    NSRange r = [errString rangeOfString:@"."];
+                    if (r.location != NSNotFound)
+                        errString = [errString substringToIndex:NSMaxRange(r)];
+                    [err setValue:errString 
forKey:NSLocalizedRecoverySuggestionErrorKey];
+                    *error = err;
+                }
+                return NO;
+            }
+            
+        } else if (currentEditedView && [self validateCurrentEditedView] == 
NO) {
+            // the string of the edited textView has unbalanced braces
+            
+            if (error) {
+                NSError *err = [NSError 
mutableLocalErrorWithCode:kBDSKFailedToCommit 
localizedDescription:NSLocalizedString(@"Failed to commit edits", @"Error 
message")];
+                [err setValue:NSLocalizedString(@"The value you entered 
contains unbalanced braces and cannot be saved.", @"Informative text in alert 
dialog") forKey:NSLocalizedRecoverySuggestionErrorKey];
+                *error = err;
+            }
             return NO;
+            
         }
         
+        // commit should now succeed without errors
+        
+               editorFlags.didSetupFields = NO; // if we we rebuild the 
fields, the selection will become meaningless
+        
         // commit edits (formatters may refuse to allow this)
         if ([[self window] makeFirstResponder:[self window]] == NO) {
+            // should not be reached, we should have found errors above
             if (error)
                 *error = [NSError localErrorWithCode:kBDSKFailedToCommit 
localizedDescription:NSLocalizedString(@"Failed to commit edits", @"Error 
message")];
             return NO;
@@ -457,8 +548,8 @@
                     [(NSTextView *)[[self textFieldAtRow:editedRow] 
currentEditor] setSafeSelectedRanges:selection];
                 }
             } else if ([[self window] makeFirstResponder:firstResponder]) {
-                if ([firstResponder isKindOfClass:[NSTextField class]])
-                    textView = (NSTextView *)[(NSTextField *)firstResponder 
currentEditor];
+                if (textField)
+                    textView = (NSTextView *)[textField currentEditor];
                 [textView setSafeSelectedRanges:selection];
             }
         }
@@ -1899,23 +1990,21 @@
     // Don't show an annoying warning. This fails only when invalid cite key 
characters are used, which are simply removed by the formatter.
 }
 
-// send by the formatter when formatting in getObjectValue... failed
-- (BOOL)control:(NSControl *)control didFailToFormatString:(NSString *)aString 
errorDescription:(NSString *)error{
+- (BOOL)control:(NSControl *)control didFailToFormatString:(NSString *)aString 
errorDescription:(NSString *)errorString error:(NSError **)error {
     if (editorFlags.isEditable == NO)
         return YES;
     
-       BOOL accept = NO;
+    NSError *err = nil;
     
-    if (nil == error) {
+    if (nil == errorString) {
         // shouldn't get here
+        err = [NSError mutableLocalErrorWithCode:kBDSKFailedToCommit 
localizedDescription:NSLocalizedString(@"Invalid Value", @"Message in alert 
dialog when entering an invalid value")];
         NSLog(@"%@:%d formatter failed for unknown reason", 
__FILENAMEASNSSTRING__, __LINE__);
     } else if (control == citeKeyField) {
         // !!! may have to revisit this with strict invalid keys?
         // this may occur if the cite key formatter fails to format
-        NSAlert *alert = [[NSAlert alloc] init];
-        [alert setMessageText:NSLocalizedString(@"Invalid Cite Key", @"Message 
in alert dialog when enetring invalid cite key")];
-        [alert setInformativeText:error];
-        [alert beginSheetModalForWindow:[self window] completionHandler:NULL];
+        err = [NSError mutableLocalErrorWithCode:kBDSKFailedToCommit 
localizedDescription:NSLocalizedString(@"Invalid Cite Key", @"Message in alert 
dialog when enetring invalid cite key")];
+        [err setValue:errorString 
forKey:NSLocalizedRecoverySuggestionErrorKey];
         
     } else {
         
@@ -1925,36 +2014,56 @@
             NSString *fieldName = [fields objectAtIndex:row];
             if ([fieldName isEqualToString:BDSKCrossrefString]) {
                 // this may occur if the cite key formatter fails to format
-                NSAlert *alert = [[NSAlert alloc] init];
-                [alert setMessageText:NSLocalizedString(@"Invalid Crossref 
Key", @"Message in alert dialog when entering invalid Crossref key")];
-                [alert setInformativeText:error];
-                
-                [alert beginSheetModalForWindow:[self window] 
completionHandler:NULL];
+                err = [NSError mutableLocalErrorWithCode:kBDSKFailedToCommit 
localizedDescription:NSLocalizedString(@"Invalid Crossref Key", @"Message in 
alert dialog when entering invalid Crossref key")];
+                [err setValue:errorString 
forKey:NSLocalizedRecoverySuggestionErrorKey];
             } else if ([fieldName isCitationField]) {
                 // this may occur if the citation formatter fails to format
-                NSAlert *alert = [[NSAlert alloc] init];
-                [alert setMessageText:NSLocalizedString(@"Invalid Citation 
Key", @"Message in alert dialog when entering invalid Crossref key")];
-                [alert setInformativeText:error];
-                
-                [alert beginSheetModalForWindow:[self window] 
completionHandler:NULL];
+                err = [NSError mutableLocalErrorWithCode:kBDSKFailedToCommit 
localizedDescription:NSLocalizedString(@"Invalid Citation Key", @"Message in 
alert dialog when entering invalid Crossref key")];
+                [err setValue:errorString 
forKey:NSLocalizedRecoverySuggestionErrorKey];
             } else if (NO == [tableCellFormatter editAsComplexString]) {
                 // this is a simple string, an error means that there are 
unbalanced braces
-                NSAlert *alert = [[NSAlert alloc] init];
-                [alert setMessageText:NSLocalizedString(@"Invalid Value", 
@"Message in alert dialog when entering an invalid value")];
-                [alert setInformativeText:NSLocalizedString(@"The value you 
entered contains unbalanced braces and cannot be saved.", @"Informative text in 
alert dialog")];
-                
-                [alert beginSheetModalForWindow:[self window] 
completionHandler:NULL];
+                err = [NSError mutableLocalErrorWithCode:kBDSKFailedToCommit 
localizedDescription:NSLocalizedString(@"Invalid Value", @"Message in alert 
dialog when entering an invalid value")];
+                [err setValue:NSLocalizedString(@"The value you entered 
contains unbalanced braces and cannot be saved.", @"Informative text in alert 
dialog") forKey:NSLocalizedRecoverySuggestionErrorKey];
+            } else {
+                err = [NSError 
mutableLocalErrorWithCode:kBDSKComplexStringError 
localizedDescription:NSLocalizedString(@"Invalid Value", @"Message in alert 
dialog when entering an invalid value")];
+                [err setValue:errorString 
forKey:NSLocalizedRecoverySuggestionErrorKey];
             }
         }
-       }
+    }
+    
+    if (error)
+        *error = err;
+    return NO;
+}
+
+// send by the formatter when formatting in getObjectValue... failed
+- (BOOL)control:(NSControl *)control didFailToFormatString:(NSString *)aString 
errorDescription:(NSString *)error{
+    if (editorFlags.isEditable == NO)
+        return YES;
+    
+    NSError *err = nil;
+    BOOL accept = [self control:control didFailToFormatString:aString 
errorDescription:error error:&err];
+    
+    if (accept == NO) {
+        if (err && [err code] != kBDSKComplexStringError)
+            [self presentError:err modalForWindow:[self window] delegate:nil 
didPresentSelector:NULL contextInfo:NULL];
+        else
+            NSBeep();
+    }
+    
     return accept;
 }
 
-- (BOOL)control:(NSControl *)control isValidObject:(id)obj {
+- (BOOL)attemptRecoveryFromError:(NSError *)error 
optionIndex:(NSUInteger)recoveryOptionIndex {
+    return (recoveryOptionIndex == 0);
+}
+
+- (BOOL)control:(NSControl *)control isValidObject:(id)obj error:(NSError 
**)error {
     if (editorFlags.isEditable == NO)
         return YES;
     
     BOOL isValid = YES;
+    NSError *err = nil;
     
     if (control == citeKeyField) {
         
@@ -1965,21 +2074,12 @@
         // check for fragile invalid characters, as the formatter doesn't do 
this
         if (r.location != NSNotFound) {
             
-            NSAlert *alert = [[NSAlert alloc] init];
-            [alert setMessageText:NSLocalizedString(@"Invalid Value", 
@"Message in alert dialog when entering an invalid value")];
-            [alert setInformativeText:NSLocalizedString(@"The cite key you 
entered contains characters that could be invalid in TeX. Do you want to keep 
them or remove them?", @"Informative text in alert dialog")];
-            [alert addButtonWithTitle:NSLocalizedString(@"Remove", @"Button 
title")];
-            [alert addButtonWithTitle:NSLocalizedString(@"Keep", @"Button 
title")];
+            err = [NSError mutableLocalErrorWithCode:kBDSKFailedToCommit 
localizedDescription:NSLocalizedString(@"Invalid Value", @"Message in alert 
dialog when entering an invalid value")];
+            [err setValue:NSLocalizedString(@"The cite key you entered 
contains characters that could be invalid in TeX. Do you want to keep them or 
remove them?", @"Informative text in alert dialog") 
forKey:NSLocalizedRecoverySuggestionErrorKey];
+            [err setValue:self forKey:NSRecoveryAttempterErrorKey];
+            [err setValue:@[NSLocalizedString(@"Remove", @"Button title"), 
NSLocalizedString(@"Keep", @"Button title")] 
forKey:NSLocalizedRecoveryOptionsErrorKey];
+            isValid = NO;
             
-            NSInteger rv = [alert runModal];
-            
-            if (rv == NSAlertFirstButtonReturn) {
-                [control setStringValue:[obj 
stringByReplacingCharactersInSet:invalidSet withString:@""]];
-                isValid = NO;
-            } else {
-                 [citeKeyField setStringValue:[control stringValue]];
-            }
-            
         } else {
             
             // check whether we won't crossref to the new citekey
@@ -1990,11 +2090,8 @@
                 message = NSLocalizedString(@"Cannot set this cite key as this 
would lead to a crossreff chain.", @"Informative text in alert dialog");
             
             if (message) {
-                NSAlert *alert = [[NSAlert alloc] init];
-                [alert setMessageText:NSLocalizedString(@"Invalid Value", 
@"Message in alert dialog when entering an invalid value")];
-                [alert setInformativeText:message];
-                
-                [alert beginSheetModalForWindow:[self window] 
completionHandler:NULL];
+                err = [NSError mutableLocalErrorWithCode:kBDSKFailedToCommit 
localizedDescription:NSLocalizedString(@"Invalid Value", @"Message in alert 
dialog when entering an invalid value")];
+                [err setValue:message 
forKey:NSLocalizedRecoverySuggestionErrorKey];
                 isValid = NO;
             }
         }
@@ -2019,20 +2116,37 @@
                     message = NSLocalizedString(@"Cannot set the Crossref 
field, as the current item is cross referenced.", @"Informative text in alert 
dialog");
                 
                 if (message) {
-                    NSAlert *alert = [[NSAlert alloc] init];
-                    [alert setMessageText:NSLocalizedString(@"Invalid Crossref 
Value", @"Message in alert dialog when entering an invalid Crossref key")];
-                    [alert setInformativeText:message];
-                    
-                    [alert beginSheetModalForWindow:[self window] 
completionHandler:NULL];
+                    err = [NSError 
mutableLocalErrorWithCode:kBDSKFailedToCommit 
localizedDescription:NSLocalizedString(@"Invalid Crossref Value", @"Message in 
alert dialog when entering an invalid Crossref key")];
+                    [err setValue:message 
forKey:NSLocalizedRecoverySuggestionErrorKey];
                     isValid = NO;
                 }
             }
         }
     }
-       
-       return isValid;
+    
+    if (isValid == NO && error)
+        *error = err;
+    return isValid;
 }
 
+- (BOOL)control:(NSControl *)control isValidObject:(id)obj {
+    NSError *err = nil;
+    BOOL isValid = [self control:control isValidObject:obj error:&err];
+    
+    if (isValid)
+        return YES;
+    
+    isValid = [self presentError:err];
+    
+    if (control == citeKeyField && [err localizedRecoveryOptions] && isValid 
== NO) {
+        // user said to remove fragile characters
+        NSCharacterSet *invalidSet = [[BDSKTypeManager sharedManager] 
fragileCiteKeyCharacterSet];
+        [control setStringValue:[obj 
stringByReplacingCharactersInSet:invalidSet withString:@""]];
+    }
+    
+    return isValid;
+}
+
 - (void)controlTextDidEndEditing:(NSNotification *)notification{
     [self setEditing:NO];
        

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

Reply via email to