aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPExportFileUtilities.m
diff options
context:
space:
mode:
Diffstat (limited to 'Source/SPExportFileUtilities.m')
-rw-r--r--Source/SPExportFileUtilities.m142
1 files changed, 112 insertions, 30 deletions
diff --git a/Source/SPExportFileUtilities.m b/Source/SPExportFileUtilities.m
index efa824f8..b23d0b78 100644
--- a/Source/SPExportFileUtilities.m
+++ b/Source/SPExportFileUtilities.m
@@ -30,6 +30,17 @@
#import "SPDatabaseDocument.h"
#import "SPCustomQuery.h"
+typedef enum
+{
+ SPExportErrorCancelExport = 0,
+ SPExportErrorReplaceFiles = 1,
+ SPExportErrorSkipErrorFiles = 2
+} SPExportErrorChoice;
+
+@interface SPExportController (SPExportFileUtilitiesPrivateAPI)
+ - (void)_reopenExportSheet;
+@end
+
@implementation SPExportController (SPExportFileUtilities)
/**
@@ -119,17 +130,18 @@
- (void)errorCreatingExportFileHandles:(NSArray *)files
{
// Get the number of files that already exists as well as couldn't be created because of other reasons
- NSUInteger i = 0;
+ NSUInteger filesAlreadyExisting = 0;
+ NSUInteger filesFailed = 0;
for (SPExportFile *file in files)
{
if ([file exportFileHandleStatus] == SPExportFileHandleExists) {
- i++;
- }
+ filesAlreadyExisting++;
+
// For file handles that we failed to create for some unknown reason, ignore them and remove any
// exporters that are associated with them.
- else if ([file exportFileHandleStatus] == SPExportFileHandleFailed) {
-
+ } else if ([file exportFileHandleStatus] == SPExportFileHandleFailed) {
+ filesFailed++;
for (SPExporter *exporter in exporters)
{
if ([[exporter exportOutputFile] isEqualTo:file]) {
@@ -139,27 +151,72 @@
}
}
- // If all the files failed, show a simplified export dialog
+ NSAlert *alert = [[NSAlert alloc] init];
+ [alert setAlertStyle:NSCriticalAlertStyle];
- // If only some of the files failed, show an export dialog with the option to ignore the failed files.
+ // If files failed because they already existed, show a OS-like dialog.
+ if (filesAlreadyExisting) {
- // For single files, show a dialog very close to the OS dialog
- if (i > 0) {
-
- NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error creating export files", @"export file handle creation error message")
- defaultButton:NSLocalizedString(@"Ignore", @"ignore button")
- alternateButton:NSLocalizedString(@"Overwrite", @"overwrite button")
- otherButton:NSLocalizedString(@"Cancel", @"cancel button")
- informativeTextWithFormat:NSLocalizedString(@"One or more errors occurred while attempting to create the export files. Those that failed to be created for unknown reasons will be ignored.\n\nHow would you like to proceed with the files that already exist at the location you have chosen to export to?", @"export file handle creation error informative message")];
-
- [alert setAlertStyle:NSCriticalAlertStyle];
-
- // Close the progress sheet
- [NSApp endSheet:exportProgressWindow returnCode:0];
- [exportProgressWindow orderOut:self];
+ // Set up a string for use if files had to be skipped.
+ NSString *additionalErrors = filesFailed ? NSLocalizedString(@"\n\n(In addition, one or more errors occurred while attempting to create the export files: %lu could not be created. These files will be ignored.)", @"Additional export file errors") : @"";
+
+ if (filesAlreadyExisting == 1) {
+ [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"“%@” already exists. Do you want to replace it?", @"Export file already exists message"), [[[files objectAtIndex:0] exportFilePath] lastPathComponent]]];
+ [alert setInformativeText:[NSString stringWithFormat:@"%@%@", NSLocalizedString(@"A file with the same name already exists in the target folder. Replacing it will overwrite its current contents.", @"Export file already exists explanatory text"), additionalErrors]];
+ } else if (filesAlreadyExisting == [exportFiles count]) {
+ [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"All the export files already exist. Do you want to replace them?", @"All export files already exist message")]];
+ [alert setInformativeText:[NSString stringWithFormat:@"%@%@", NSLocalizedString(@"Files with the same names already exist in the target folder. Replacing them will overwrite their current contents.", @"All export files already exist explanatory text"), additionalErrors]];
+ } else {
+ [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"%lu files already exist. Do you want to replace them?", @"Export file already exists message"), filesAlreadyExisting]];
+ [alert setInformativeText:[NSString stringWithFormat:@"%@%@", [NSString stringWithFormat:NSLocalizedString(@"%lu files with the same names already exist in the target folder. Replacing them will overwrite their current contents.", @"Some export files already exist explanatory text"), filesAlreadyExisting], additionalErrors]];
+ }
+
+ [alert addButtonWithTitle:NSLocalizedString(@"Replace", @"Replace button")];
+ [[[alert buttons] objectAtIndex:0] setTag:SPExportErrorReplaceFiles];
+ [[[alert buttons] objectAtIndex:0] setKeyEquivalent:@"r"];
+ [[[alert buttons] objectAtIndex:0] setKeyEquivalentModifierMask:NSCommandKeyMask];
+
+ [alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"cancel button")];
+ [[[alert buttons] objectAtIndex:1] setTag:SPExportErrorCancelExport];
+ [[[alert buttons] objectAtIndex:1] setKeyEquivalent:@"\r"];
- [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:files];
+ if ((filesAlreadyExisting + filesFailed) != [exportFiles count]) {
+ [alert addButtonWithTitle:NSLocalizedString(@"Skip existing", @"skip existing button")];
+ [[[alert buttons] objectAtIndex:2] setTag:SPExportErrorSkipErrorFiles];
+ [[[alert buttons] objectAtIndex:2] setKeyEquivalent:@"s"];
+ [[[alert buttons] objectAtIndex:2] setKeyEquivalentModifierMask:NSCommandKeyMask];
+ }
+
+ // If one or multiple files failed, but only due to unhandled errors, show a short dialog
+ } else {
+ if (filesFailed == 1) {
+ [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"“%@” could not be created", @"Export file creation error title"), [[[files objectAtIndex:0] exportFilePath] lastPathComponent]]];
+ [alert setInformativeText:NSLocalizedString(@"An unhandled error occurred when attempting to create the export file. Please check the details and try again.", @"Export file creation error explanatory text")];
+ } else if (filesFailed == [exportFiles count]) {
+ [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"No files could be created", @"All export files creation error title")]];
+ [alert setInformativeText:NSLocalizedString(@"An unhandled error occurred when attempting to create each of the export files. Please check the details and try again.", @"All export files creation error explanatory text")];
+ } else {
+ [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"%lu files could not be created", @"Export files creation error title"), filesFailed]];
+ [alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"An unhandled error occurred when attempting to create %lu of the export files. Please check the details and try again.", @"Export files creation error explanatory text"), filesFailed]];
+ }
+
+
+ [alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"cancel button")];
+ [[[alert buttons] objectAtIndex:0] setTag:SPExportErrorCancelExport];
+
+ if (filesFailed != [exportFiles count]) {
+ [alert addButtonWithTitle:NSLocalizedString(@"Skip problems", @"skip problems button")];
+ [[[alert buttons] objectAtIndex:1] setTag:SPExportErrorSkipErrorFiles];
+ [[[alert buttons] objectAtIndex:1] setKeyEquivalent:@"s"];
+ [[[alert buttons] objectAtIndex:1] setKeyEquivalentModifierMask:NSCommandKeyMask];
+ }
}
+
+ // Close the progress sheet
+ [NSApp endSheet:exportProgressWindow returnCode:0];
+ [exportProgressWindow orderOut:self];
+
+ [alert beginSheetModalForWindow:[tableDocumentInstance parentWindow] modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:files];
}
/**
@@ -170,14 +227,17 @@
NSArray *files = (NSArray *)contextInfo;
// Ignore the files that exist and remove the associated exporters
- if (returnCode == NSAlertDefaultReturn) {
+ if (returnCode == SPExportErrorSkipErrorFiles) {
- for (SPExportFile *file in files)
- {
- for (SPExporter *exporter in exporters)
- {
+ for (SPExportFile *file in files) {
+
+ // Use a numerically controlled loop to avoid mutating the collection while enumerating
+ NSUInteger i;
+ for (i = 0; i < [exporters count]; i++) {
+ SPExporter *exporter = [exporters objectAtIndex:i];
if ([[exporter exportOutputFile] isEqualTo:file]) {
- [exporters removeObject:exporter];
+ [exporters removeObjectAtIndex:i];
+ i--;
}
}
}
@@ -187,6 +247,9 @@
// If we're now left with no exporters, cancel the export operation
if ([exporters count] == 0) {
[exportFiles removeAllObjects];
+
+ // Trigger restoration of the export interface
+ [self performSelector:@selector(_reopenExportSheet) withObject:nil afterDelay:0.1];
}
else {
// Start the export after a short delay to give this sheet a chance to close
@@ -194,7 +257,7 @@
}
}
// Overwrite the files and continue
- else if (returnCode == NSAlertAlternateReturn) {
+ else if (returnCode == SPExportErrorReplaceFiles) {
for (SPExportFile *file in files)
{
@@ -220,7 +283,7 @@
}
// Cancel the entire export operation
- else if (returnCode == NSAlertOtherReturn) {
+ else if (returnCode == SPExportErrorCancelExport) {
// Loop the cached export files and remove those we've already created
for (SPExportFile *file in exportFiles)
@@ -233,7 +296,26 @@
// Finally get rid of all the exporters and files
[exportFiles removeAllObjects];
[exporters removeAllObjects];
+
+ // Trigger restoration of the export interface
+ [self performSelector:@selector(_reopenExportSheet) withObject:nil afterDelay:0.1];
}
}
@end
+
+@implementation SPExportController (SPExportFileUtilitiesPrivateAPI)
+
+/**
+ * Re-open the export sheet without resetting the interface - for use on error.
+ */
+- (void)_reopenExportSheet
+{
+ [NSApp beginSheet:[self window]
+ modalForWindow:[tableDocumentInstance parentWindow]
+ modalDelegate:self
+ didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
+ contextInfo:nil];
+}
+
+@end