Skip to content

Commit dc2eec2

Browse files
committed
#2658: Perform duplicate database operation on a background thread and display the indeterminate progress indicator.
1 parent 707dc02 commit dc2eec2

File tree

1 file changed

+92
-102
lines changed

1 file changed

+92
-102
lines changed

Source/SPDatabaseDocument.m

Lines changed: 92 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,8 @@
7373
#import "SPGotoDatabaseController.h"
7474
#import "SPFunctions.h"
7575
#import "SPCreateDatabaseInfo.h"
76-
#ifndef SP_CODA /* headers */
7776
#import "SPAppController.h"
7877
#import "SPBundleHTMLOutputController.h"
79-
#endif
8078
#import "SPTableTriggers.h"
8179
#import "SPTableStructure.h"
8280
#import "SPPrintAccessory.h"
@@ -92,10 +90,13 @@
9290
#include <libkern/OSAtomic.h>
9391

9492
// Constants
95-
static NSString *SPCopyDatabaseAction = @"SPCopyDatabase";
9693
static NSString *SPConfirmCopyDatabaseAction = @"SPConfirmCopyDatabase";
9794
static NSString *SPRenameDatabaseAction = @"SPRenameDatabase";
9895
static NSString *SPAlterDatabaseAction = @"SPAlterDatabase";
96+
static NSString *SPSaveDocumentPreferences = @"SPSaveDocumentPreferences";
97+
static NSString *SPNewDatabaseDetails = @"SPNewDatabaseDetails";
98+
static NSString *SPNewDatabaseName = @"SPNewDatabaseName";
99+
static NSString *SPNewDatabaseCopyContent = @"SPNewDatabaseCopyContent";
99100

100101
static int64_t SPDatabaseDocumentInstanceCounter = 0;
101102

@@ -111,6 +112,7 @@ - (void)_processDatabaseChangedBundleTriggerActions;
111112
- (void)_addPreferenceObservers;
112113
- (void)_removePreferenceObservers;
113114

115+
114116
#pragma mark - SPDatabaseViewControllerPrivateAPI
115117

116118
- (void)_loadTabTask:(NSNumber *)tabViewItemIndexNumber;
@@ -873,9 +875,8 @@ Next we need to ask the user to select another connection (from the favourites l
873875
NSLog(@"=================");
874876
}
875877

876-
#ifndef SP_CODA /* operations on whole databases */
877878
/**
878-
* opens the copy database sheet and copies the databsae
879+
* Opens the copy database sheet and copies the databsae.
879880
*/
880881
- (IBAction)copyDatabase:(id)sender
881882
{
@@ -901,13 +902,12 @@ - (IBAction)copyDatabase:(id)sender
901902
[databaseCopyNameField setStringValue:selectedDatabase];
902903
[copyDatabaseMessageField setStringValue:selectedDatabase];
903904

904-
[NSApp beginSheet:databaseCopySheet
905-
modalForWindow:parentWindow
906-
modalDelegate:self
907-
didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
908-
contextInfo:SPCopyDatabaseAction];
905+
[parentWindow beginSheet:databaseCopySheet completionHandler:^(NSInteger returnCode) {
906+
if (returnCode == NSOKButton) {
907+
[self _copyDatabase];
908+
}
909+
}];
909910
}
910-
#endif
911911

912912
/**
913913
* Opens the rename database sheet and renames the databsae.
@@ -1070,17 +1070,15 @@ - (NSArray *)allSystemDatabaseNames
10701070
*/
10711071
- (void)sheetDidEnd:(id)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo
10721072
{
1073-
#ifndef SP_CODA
10741073
// Those that are just setting a return code and don't need to order out the sheet. See SPAlertSheets+beginWaitingAlertSheetWithTitle:
1075-
if ([contextInfo isEqualToString:@"saveDocPrefSheetStatus"]) {
1074+
if ([contextInfo isEqualToString:SPSaveDocumentPreferences]) {
10761075
saveDocPrefSheetStatus = returnCode;
10771076
return;
10781077
}
10791078
else if ([contextInfo isEqualToString:SPConfirmCopyDatabaseAction]) {
10801079
confirmCopyDatabaseReturnCode = returnCode;
10811080
return;
10821081
}
1083-
#endif
10841082

10851083
// Order out current sheet to suppress overlapping of sheets
10861084
if ([sheet respondsToSelector:@selector(orderOut:)]) {
@@ -1095,17 +1093,6 @@ - (void)sheetDidEnd:(id)sheet returnCode:(NSInteger)returnCode contextInfo:(NSSt
10951093
if (returnCode == NSAlertDefaultReturn) {
10961094
[self _removeDatabase];
10971095
}
1098-
#ifdef SP_CODA
1099-
else {
1100-
// Reset chooseDatabaseButton
1101-
if ([[self database] length]) {
1102-
[chooseDatabaseButton selectItemWithTitle:[self database]];
1103-
}
1104-
else {
1105-
[chooseDatabaseButton selectItemAtIndex:0];
1106-
}
1107-
}
1108-
#endif
11091096
}
11101097
// Add a new database
11111098
else if ([contextInfo isEqualToString:@"addDatabase"]) {
@@ -1126,42 +1113,22 @@ - (void)sheetDidEnd:(id)sheet returnCode:(NSInteger)returnCode contextInfo:(NSSt
11261113
[chooseDatabaseButton selectItemAtIndex:0];
11271114
}
11281115
}
1129-
}
1130-
#ifndef SP_CODA
1131-
else if ([contextInfo isEqualToString:SPCopyDatabaseAction]) {
1132-
if (returnCode == NSOKButton) {
1133-
[self _copyDatabase];
1134-
}
11351116
}
1136-
#endif
11371117
else if ([contextInfo isEqualToString:SPRenameDatabaseAction]) {
11381118
if (returnCode == NSOKButton) {
11391119
[self _renameDatabase];
11401120
}
1141-
#ifdef SP_CODA
1142-
else {
1143-
// Reset chooseDatabaseButton
1144-
if ([[self database] length]) {
1145-
[chooseDatabaseButton selectItemWithTitle:[self database]];
1146-
}
1147-
else {
1148-
[chooseDatabaseButton selectItemAtIndex:0];
1149-
}
1150-
}
1151-
#endif
11521121
}
11531122
else if([contextInfo isEqualToString:SPAlterDatabaseAction]) {
11541123
[alterDatabaseCharsetHelper setEnabled:NO];
11551124
if(returnCode == NSOKButton) {
11561125
[self _alterDatabase];
11571126
}
11581127
}
1159-
#ifndef SP_CODA
11601128
// Close error status sheet for OPTIMIZE, CHECK, REPAIR etc.
11611129
else if ([contextInfo isEqualToString:@"statusError"]) {
11621130
if (statusValues) SPClear(statusValues);
11631131
}
1164-
#endif
11651132
}
11661133

11671134
#ifndef SP_CODA /* sheetDidEnd: */
@@ -3332,14 +3299,14 @@ - (void)saveConnectionPanelDidEnd:(NSSavePanel *)panel returnCode:(NSInteger)ret
33323299
- (BOOL)saveDocumentWithFilePath:(NSString *)fileName inBackground:(BOOL)saveInBackground onlyPreferences:(BOOL)saveOnlyPreferences contextInfo:(NSDictionary*)contextInfo
33333300
{
33343301
// Do not save if no connection is/was available
3335-
if(saveInBackground && ([self mySQLVersion] == nil || ![[self mySQLVersion] length])) return NO;
3302+
if (saveInBackground && ([self mySQLVersion] == nil || ![[self mySQLVersion] length])) return NO;
33363303

33373304
NSMutableDictionary *spfDocData_temp = [NSMutableDictionary dictionary];
33383305

3339-
if(fileName == nil) fileName = [[self fileURL] path];
3306+
if (fileName == nil) fileName = [[self fileURL] path];
33403307

33413308
// Store save panel settings or take them from spfDocData
3342-
if(!saveInBackground && contextInfo == nil) {
3309+
if (!saveInBackground && contextInfo == nil) {
33433310
[spfDocData_temp setObject:[NSNumber numberWithBool:([saveConnectionEncrypt state]==NSOnState) ? YES : NO ] forKey:@"encrypted"];
33443311
if([[spfDocData_temp objectForKey:@"encrypted"] boolValue]) {
33453312
[spfDocData_temp setObject:[saveConnectionEncryptString stringValue] forKey:@"e_string"];
@@ -3351,16 +3318,17 @@ - (BOOL)saveDocumentWithFilePath:(NSString *)fileName inBackground:(BOOL)saveInB
33513318
if([[[[customQueryInstance valueForKeyPath:@"textView"] textStorage] string] length]) {
33523319
[spfDocData_temp setObject:[NSNumber numberWithBool:([saveConnectionIncludeQuery state] == NSOnState) ? YES : NO] forKey:@"save_editor_content"];
33533320
}
3354-
} else {
3321+
}
3322+
else {
33553323
// If contextInfo != nil call came from other SPDatabaseDocument while saving it as bundle
33563324
[spfDocData_temp addEntriesFromDictionary:(contextInfo == nil ? spfDocData : contextInfo)];
33573325
}
33583326

33593327
// Update only query favourites, history, etc. by reading the file again
3360-
if(saveOnlyPreferences) {
3328+
if (saveOnlyPreferences) {
33613329

33623330
// Check URL for safety reasons
3363-
if(![[[self fileURL] path] length] || [self isUntitled]) {
3331+
if (![[[self fileURL] path] length] || [self isUntitled]) {
33643332
NSLog(@"Couldn't save data. No file URL found!");
33653333
NSBeep();
33663334
return NO;
@@ -3372,13 +3340,13 @@ - (BOOL)saveDocumentWithFilePath:(NSString *)fileName inBackground:(BOOL)saveInB
33723340

33733341
NSData *pData = [NSData dataWithContentsOfFile:fileName options:NSUncachedRead error:&error];
33743342

3375-
if(pData && !error) {
3343+
if (pData && !error) {
33763344
NSDictionary *pDict = [NSPropertyListSerialization propertyListWithData:pData
33773345
options:NSPropertyListImmutable
33783346
format:NULL
33793347
error:&error];
33803348

3381-
if(pDict && !error) {
3349+
if (pDict && !error) {
33823350
[spf addEntriesFromDictionary:pDict];
33833351
}
33843352
}
@@ -3392,19 +3360,18 @@ - (BOOL)saveDocumentWithFilePath:(NSString *)fileName inBackground:(BOOL)saveInB
33923360
docWindow:parentWindow
33933361
modalDelegate:self
33943362
didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
3395-
contextInfo:@"saveDocPrefSheetStatus"
3363+
contextInfo:SPSaveDocumentPreferences
33963364
infoText:[NSString stringWithFormat:NSLocalizedString(@"Connection data file “%@” couldn't be read. Please try to save the document under a different name.\n\nDetails: %@", @"message error while reading connection data file and suggesting to save it under a differnet name"), [fileName lastPathComponent], [error localizedDescription]]
33973365
returnCode:&saveDocPrefSheetStatus];
33983366

3399-
if(spf) [spf release];
3400-
if(saveDocPrefSheetStatus == NSAlertAlternateReturn) return YES;
3401-
3402-
return NO;
3367+
if (spf) [spf release];
3368+
3369+
return saveDocPrefSheetStatus == NSAlertAlternateReturn;
34033370
}
34043371
}
34053372

34063373
// For dispatching later
3407-
if(![[spf objectForKey:SPFFormatKey] isEqualToString:SPFConnectionContentType]) {
3374+
if (![[spf objectForKey:SPFFormatKey] isEqualToString:SPFConnectionContentType]) {
34083375
NSLog(@"SPF file format is not 'connection'.");
34093376
[spf release];
34103377
return NO;
@@ -3423,7 +3390,8 @@ - (BOOL)saveDocumentWithFilePath:(NSString *)fileName inBackground:(BOOL)saveInB
34233390
error:&error];
34243391

34253392
[spf release];
3426-
if(error) {
3393+
3394+
if (error) {
34273395
NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Error while converting connection data", @"error while converting connection data")
34283396
defaultButton:NSLocalizedString(@"OK", @"OK button")
34293397
alternateButton:nil
@@ -3436,7 +3404,8 @@ - (BOOL)saveDocumentWithFilePath:(NSString *)fileName inBackground:(BOOL)saveInB
34363404
}
34373405

34383406
[plist writeToFile:fileName options:NSAtomicWrite error:&error];
3439-
if(error != nil) {
3407+
3408+
if (error != nil) {
34403409
NSAlert *errorAlert = [NSAlert alertWithError:error];
34413410
[errorAlert runModal];
34423411
return NO;
@@ -3488,6 +3457,7 @@ - (BOOL)saveDocumentWithFilePath:(NSString *)fileName inBackground:(BOOL)saveInB
34883457

34893458
// Determine whether to use encryption when adding the data
34903459
[spfStructure setObject:[spfDocData_temp objectForKey:@"encrypted"] forKey:@"encrypted"];
3460+
34913461
if (![[spfDocData_temp objectForKey:@"encrypted"] boolValue]) {
34923462

34933463
// Convert the content selection to encoded data
@@ -3502,7 +3472,8 @@ - (BOOL)saveDocumentWithFilePath:(NSString *)fileName inBackground:(BOOL)saveInB
35023472
}
35033473

35043474
[spfStructure setObject:spfData forKey:@"data"];
3505-
} else {
3475+
}
3476+
else {
35063477
NSMutableData *dataToEncrypt = [[[NSMutableData alloc] init] autorelease];
35073478
NSKeyedArchiver *archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:dataToEncrypt] autorelease];
35083479
[archiver encodeObject:spfData forKey:@"data"];
@@ -3530,6 +3501,7 @@ - (BOOL)saveDocumentWithFilePath:(NSString *)fileName inBackground:(BOOL)saveInB
35303501
}
35313502

35323503
[plist writeToFile:fileName options:NSAtomicWrite error:&error];
3504+
35333505
if (error != nil){
35343506
NSAlert *errorAlert = [NSAlert alertWithError:error];
35353507
[errorAlert runModal];
@@ -6023,46 +5995,76 @@ - (void)setIsSavedInBundle:(BOOL)savedInBundle
60235995
#pragma mark -
60245996
#pragma mark Private API
60255997

6026-
#ifndef SP_CODA /* whole database operations */
6027-
60285998
/**
6029-
*
6030-
* This method *MUST* be called from the UI thread!
5999+
* Copies the current database (and optionally it's content) on a separate thread.
60316000
*/
6032-
- (void)_copyDatabase
6001+
- (void)_copyDatabase
60336002
{
6034-
if ([[databaseCopyNameField stringValue] isEqualToString:@""]) {
6003+
NSString *newDatabaseName = [databaseCopyNameField stringValue];
6004+
6005+
if ([newDatabaseName isEqualToString:@""]) {
60356006
SPOnewayAlertSheet(NSLocalizedString(@"Error", @"error"), parentWindow, NSLocalizedString(@"Database must have a name.", @"message of panel when no db name is given"));
60366007
return;
60376008
}
6038-
6039-
SPDatabaseCopy *dbActionCopy = [[SPDatabaseCopy alloc] init];
6040-
6041-
[dbActionCopy setConnection:[self getConnection]];
6042-
[dbActionCopy setMessageWindow:parentWindow];
6043-
6044-
BOOL copyWithContent = [copyDatabaseDataButton state] == NSOnState;
6045-
6046-
if ([dbActionCopy copyDatabaseFrom:[self createDatabaseInfo] to:[databaseCopyNameField stringValue] withContent:copyWithContent]) {
6047-
[self selectDatabase:[databaseCopyNameField stringValue] item:nil];
6009+
6010+
NSDictionary *databaseDetails = @{
6011+
SPNewDatabaseDetails : [self createDatabaseInfo],
6012+
SPNewDatabaseName : newDatabaseName,
6013+
SPNewDatabaseCopyContent : @([copyDatabaseDataButton state] == NSOnState)
6014+
};
6015+
6016+
[self startTaskWithDescription:[NSString stringWithFormat:NSLocalizedString(@"Copying database '%@'...", @"Copying database task description"), [self database]]];
6017+
6018+
if ([NSThread isMainThread]) {
6019+
[NSThread detachNewThreadWithName:SPCtxt(@"SPDatabaseDocument copy database task", self)
6020+
target:self
6021+
selector:@selector(_copyDatabaseWithDetails:)
6022+
object:databaseDetails];;
60486023
}
60496024
else {
6050-
SPOnewayAlertSheet(
6051-
NSLocalizedString(@"Unable to copy database", @"unable to copy database message"),
6052-
parentWindow,
6053-
[NSString stringWithFormat:NSLocalizedString(@"An error occured while trying to copy the database '%@' to '%@'.", @"unable to copy database message informative message"), [self database], [databaseCopyNameField stringValue]]
6054-
);
6025+
[self _copyDatabaseWithDetails:databaseDetails];
6026+
}
6027+
}
6028+
6029+
- (void)_copyDatabaseWithDetails:(NSDictionary *)databaseDetails
6030+
{
6031+
@autoreleasepool
6032+
{
6033+
SPDatabaseCopy *databaseCopy = [[SPDatabaseCopy alloc] init];
6034+
6035+
[databaseCopy setConnection:[self getConnection]];
6036+
6037+
NSString *newDatabaseName = databaseDetails[SPNewDatabaseName];
6038+
6039+
BOOL success = [databaseCopy copyDatabaseFrom:databaseDetails[SPNewDatabaseDetails]
6040+
to:newDatabaseName
6041+
withContent:[databaseDetails[SPNewDatabaseCopyContent] boolValue]];
6042+
6043+
[databaseCopy release];
6044+
6045+
// Select newly created database
6046+
[[self onMainThread] selectDatabase:newDatabaseName item:nil];
6047+
6048+
// Update database list
6049+
[[self onMainThread] setDatabases:self];
6050+
6051+
[self endTask];
6052+
6053+
if (!success) {
6054+
SPMainQSync(^{
6055+
SPOnewayAlertSheet(
6056+
NSLocalizedString(@"Unable to copy database", @"unable to copy database message"),
6057+
parentWindow,
6058+
[NSString stringWithFormat:NSLocalizedString(@"An error occured while trying to copy the database '%@' to '%@'.", @"unable to copy database message informative message"),
6059+
[databaseDetails[SPNewDatabaseDetails] databaseName],
6060+
newDatabaseName]
6061+
);
6062+
});
6063+
}
60556064
}
6056-
6057-
[dbActionCopy release];
6058-
6059-
// Update DB list
6060-
[self setDatabases:self];
60616065
}
6062-
#endif
60636066

60646067
/**
6065-
*
60666068
* This method *MUST* be called from the UI thread!
60676069
*/
60686070
- (void)_renameDatabase
@@ -6093,18 +6095,6 @@ - (void)_renameDatabase
60936095
}
60946096

60956097
[dbActionRename release];
6096-
6097-
#ifdef SP_CODA
6098-
if (delegate && [delegate respondsToSelector:@selector(refreshDatabasePopup)]) {
6099-
[delegate performSelector:@selector(refreshDatabasePopup) withObject:nil];
6100-
}
6101-
6102-
if (delegate && [delegate respondsToSelector:@selector(selectDatabaseInPopup:)]) {
6103-
if ([allDatabases count] > 0 ) {
6104-
[delegate performSelector:@selector(selectDatabaseInPopup:) withObject:newDatabaseName];
6105-
}
6106-
}
6107-
#endif
61086098
}
61096099

61106100
/**

0 commit comments

Comments
 (0)