diff options
-rw-r--r-- | Source/SPAppController.m | 857 | ||||
-rw-r--r-- | Source/SPGrowlController.m | 17 | ||||
-rw-r--r-- | Source/SPWindowController.h | 2 | ||||
-rw-r--r-- | Source/SPWindowController.m | 9 | ||||
-rw-r--r-- | Source/SPWindowManagement.h | 6 | ||||
-rw-r--r-- | Source/SPWindowManagement.m | 56 |
6 files changed, 478 insertions, 469 deletions
diff --git a/Source/SPAppController.m b/Source/SPAppController.m index 35b5ab96..a0f4865f 100644 --- a/Source/SPAppController.m +++ b/Source/SPAppController.m @@ -58,6 +58,12 @@ - (void)_copyDefaultThemes; +- (void)openConnectionFileAtPath:(NSString *)filePath; +- (void)openSQLFileAtPath:(NSString *)filePath; +- (void)openSessionBundleAtPath:(NSString *)filePath; +- (void)openColorThemeFileAtPath:(NSString *)filePath; +- (void)openUserBundleAtPath:(NSString *)filePath; + @end @implementation SPAppController @@ -164,15 +170,15 @@ // If no documents are open, open one if (![self frontDocument]) { - [self newWindow:self]; + SPDatabaseDocument *newConnection = [self makeNewConnectionTabOrWindow]; if (spfDict) { - [[self frontDocument] setState:spfDict]; + [newConnection setState:spfDict]; } // Set autoconnection if appropriate if ([[NSUserDefaults standardUserDefaults] boolForKey:SPAutoConnectToDefault]) { - [[self frontDocument] connect]; + [newConnection connect]; } } } @@ -180,30 +186,13 @@ - (void)externalApplicationWantsToOpenADatabaseConnection:(NSNotification *)notification { - SPWindowController *frontController = nil; - - for (NSWindow *aWindow in [NSApp orderedWindows]) { - if ([[aWindow windowController] isMemberOfClass:[SPWindowController class]]) { - frontController = [aWindow windowController]; - break; - } - } - - // If no window was found or the front most window has no tabs, create a new one - if (!frontController || [[frontController valueForKeyPath:@"tabView"] numberOfTabViewItems] == 1) { - [self newWindow:self]; - // Open the spf file in a new tab if the tab bar is visible - } else if ([[frontController valueForKeyPath:@"tabView"] numberOfTabViewItems] != 1) { - if ([[frontController window] isMiniaturized]) [[frontController window] deminiaturize:self]; - [frontController addNewConnection:self]; - } - NSDictionary *userInfo = [notification userInfo]; NSString *MAMP_SPFVersion = [userInfo objectForKey:@"dataVersion"]; if ([MAMP_SPFVersion isEqualToString:@"1"]) { NSDictionary *spfStructure = [userInfo objectForKey:@"spfData"]; if (spfStructure) { - [[self frontDocument] setState:spfStructure]; + SPDatabaseDocument *frontDoc = [self makeNewConnectionTabOrWindow]; + [frontDoc setState:spfStructure]; } } } @@ -327,426 +316,426 @@ { for (NSString *filePath in filenames) { - //NSString *filePath = [file path]; - + NSString *fileExt = [[filePath pathExtension] lowercaseString]; // Opens a sql file and insert its content into the Custom Query editor - if ([[[filePath pathExtension] lowercaseString] isEqualToString:[SPFileExtensionSQL lowercaseString]]) { - - // Check size and NSFileType - NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil]; - - if (attr) - { - NSNumber *filesize = [attr objectForKey:NSFileSize]; - NSString *filetype = [attr objectForKey:NSFileType]; - if(filetype == NSFileTypeRegular && filesize) - { - // Ask for confirmation if file content is larger than 1MB - if ([filesize unsignedLongValue] > 1000000) - { - NSAlert *alert = [[NSAlert alloc] init]; - [alert addButtonWithTitle:NSLocalizedString(@"OK", @"OK button")]; - [alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"cancel button")]; - - // Show 'Import' button only if there's a connection available - if ([self frontDocument]) - [alert addButtonWithTitle:NSLocalizedString(@"Import", @"import button")]; - - - [alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"Do you really want to load a SQL file with %@ of data into the Query Editor?", @"message of panel asking for confirmation for loading large text into the query editor"), - [NSString stringForByteSize:[filesize longLongValue]]]]; - - [alert setHelpAnchor:filePath]; - [alert setMessageText:NSLocalizedString(@"Warning",@"warning")]; - [alert setAlertStyle:NSWarningAlertStyle]; - - NSUInteger returnCode = [alert runModal]; - - [alert release]; - - if(returnCode == NSAlertSecondButtonReturn) return; // Cancel - else if(returnCode == NSAlertThirdButtonReturn) { // Import - // begin import process - [[[self frontDocument] valueForKeyPath:@"tableDumpInstance"] startSQLImportProcessWithFile:filePath]; - return; - } - } - } - } - - // Attempt to open the file into a string. - NSStringEncoding sqlEncoding; - NSString *sqlString = nil; - - // If the user came from an openPanel use the chosen encoding - if (encodingPopUp) { - sqlEncoding = [[encodingPopUp selectedItem] tag]; - - // Otherwise, attempt to autodetect the encoding - } - else { - sqlEncoding = [[NSFileManager defaultManager] detectEncodingforFileAtPath:filePath]; - } - - NSError *error = nil; - - sqlString = [NSString stringWithContentsOfFile:filePath encoding:sqlEncoding error:&error]; - - if (error != nil) { - NSAlert *errorAlert = [NSAlert alertWithError:error]; - [errorAlert runModal]; - - return; - } - - // if encodingPopUp is defined the filename comes from an openPanel and - // the encodingPopUp contains the chosen encoding; otherwise autodetect encoding - if (encodingPopUp) { - [[NSUserDefaults standardUserDefaults] setInteger:[[encodingPopUp selectedItem] tag] forKey:SPLastSQLFileEncoding]; - } - - // Check if at least one document exists. If not, open one. - if (![self frontDocument]) { - [self newWindow:self]; - [[self frontDocument] initQueryEditorWithString:sqlString]; - } - else { - // Pass query to the Query editor of the current document - [[self frontDocument] doPerformLoadQueryService:sqlString]; - } - - [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:[NSURL fileURLWithPath:filePath]]; - - [[self frontDocument] setSqlFileURL:[NSURL fileURLWithPath:filePath]]; - [[self frontDocument] setSqlFileEncoding:sqlEncoding]; - + if ([fileExt isEqualToString:[SPFileExtensionSQL lowercaseString]]) { + [self openSQLFileAtPath:filePath]; break; // open only the first SQL file - } - else if ([[[filePath pathExtension] lowercaseString] isEqualToString:[SPFileExtensionDefault lowercaseString]]) { + else if ([fileExt isEqualToString:[SPFileExtensionDefault lowercaseString]]) { + [self openConnectionFileAtPath:filePath]; + } + else if ([fileExt isEqualToString:[SPBundleFileExtension lowercaseString]]) { + [self openSessionBundleAtPath:filePath]; + } + else if ([fileExt isEqualToString:[SPColorThemeFileExtension lowercaseString]]) { + [self openColorThemeFileAtPath:filePath]; + } + else if ([fileExt isEqualToString:[SPUserBundleFileExtension lowercaseString]]) { + [self openUserBundleAtPath:filePath]; + } + else { + NSBeep(); + NSLog(@"Only files with the extensions ‘%@’, ‘%@’, ‘%@’ or ‘%@’ are allowed.", SPFileExtensionDefault, SPBundleFileExtension, SPColorThemeFileExtension, SPFileExtensionSQL); + } + } +} - SPWindowController *frontController = nil; +- (void)openConnectionFileAtPath:(NSString *)filePath +{ + SPDatabaseDocument *frontDocument = [self makeNewConnectionTabOrWindow]; + + [frontDocument setStateFromConnectionFile:filePath]; + + [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:[NSURL fileURLWithPath:filePath]]; +} - for (NSWindow *aWindow in [NSApp orderedWindows]) +- (void)openSQLFileAtPath:(NSString *)filePath +{ + // Check size and NSFileType + NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil]; + + SPDatabaseDocument *frontDocument = [self frontDocument]; + + if (attr) + { + NSNumber *filesize = [attr objectForKey:NSFileSize]; + NSString *filetype = [attr objectForKey:NSFileType]; + if(filetype == NSFileTypeRegular && filesize) + { + // Ask for confirmation if file content is larger than 1MB + if ([filesize unsignedLongValue] > 1000000) { - if ([[aWindow windowController] isMemberOfClass:[SPWindowController class]]) { - frontController = [aWindow windowController]; - break; + NSAlert *alert = [[NSAlert alloc] init]; + [alert addButtonWithTitle:NSLocalizedString(@"OK", @"OK button")]; + [alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"cancel button")]; + + // Show 'Import' button only if there's a connection available + if ([self frontDocument]) + [alert addButtonWithTitle:NSLocalizedString(@"Import", @"import button")]; + + + [alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(@"Do you really want to load a SQL file with %@ of data into the Query Editor?", @"message of panel asking for confirmation for loading large text into the query editor"), + [NSString stringForByteSize:[filesize longLongValue]]]]; + + [alert setHelpAnchor:filePath]; + [alert setMessageText:NSLocalizedString(@"Warning",@"warning")]; + [alert setAlertStyle:NSWarningAlertStyle]; + + NSUInteger returnCode = [alert runModal]; + + [alert release]; + + if(returnCode == NSAlertSecondButtonReturn) return; // Cancel + else if(returnCode == NSAlertThirdButtonReturn) { // Import + // begin import process + [[frontDocument valueForKeyPath:@"tableDumpInstance"] startSQLImportProcessWithFile:filePath]; + return; } } - - // If no window was found or the front most window has no tabs, create a new one - if (!frontController || [[frontController valueForKeyPath:@"tabView"] numberOfTabViewItems] == 1) { - [self newWindow:self]; - // Open the spf file in a new tab if the tab bar is visible - } - else if ([[frontController valueForKeyPath:@"tabView"] numberOfTabViewItems] != 1) { - if ([[frontController window] isMiniaturized]) [[frontController window] deminiaturize:self]; - [frontController addNewConnection:self]; - } - - [[self frontDocument] setStateFromConnectionFile:filePath]; - - [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:[NSURL fileURLWithPath:filePath]]; } - else if ([[[filePath pathExtension] lowercaseString] isEqualToString:[SPBundleFileExtension lowercaseString]]) { - - NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; - NSDictionary *spfs = nil; - NSData *pData = [NSData dataWithContentsOfFile:[NSString stringWithFormat:@"%@/info.plist", filePath] options:NSUncachedRead error:&readError]; - - spfs = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; - - if(!spfs || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while reading connection data file", @"error while reading connection data file")] - defaultButton:NSLocalizedString(@"OK", @"OK button") - alternateButton:nil - otherButton:nil - informativeTextWithFormat:NSLocalizedString(@"Connection data file couldn't be read.", @"error while reading connection data file")]; - - [alert setAlertStyle:NSCriticalAlertStyle]; - [alert runModal]; - - if (spfs) [spfs release]; + } + + // Attempt to open the file into a string. + NSStringEncoding sqlEncoding; + NSString *sqlString = nil; + + // If the user came from an openPanel use the chosen encoding + if (encodingPopUp) { + sqlEncoding = [[encodingPopUp selectedItem] tag]; + + // Otherwise, attempt to autodetect the encoding + } + else { + sqlEncoding = [[NSFileManager defaultManager] detectEncodingforFileAtPath:filePath]; + } + + NSError *error = nil; + + sqlString = [NSString stringWithContentsOfFile:filePath encoding:sqlEncoding error:&error]; + + if (error != nil) { + NSAlert *errorAlert = [NSAlert alertWithError:error]; + [errorAlert runModal]; + + return; + } + + // if encodingPopUp is defined the filename comes from an openPanel and + // the encodingPopUp contains the chosen encoding; otherwise autodetect encoding + if (encodingPopUp) { + [[NSUserDefaults standardUserDefaults] setInteger:[[encodingPopUp selectedItem] tag] forKey:SPLastSQLFileEncoding]; + } + + // Check if at least one document exists. If not, open one. + if (!frontDocument) { + frontDocument = [self makeNewConnectionTabOrWindow]; + [frontDocument initQueryEditorWithString:sqlString]; + } + else { + // Pass query to the Query editor of the current document + [frontDocument doPerformLoadQueryService:sqlString]; + } + + [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:[NSURL fileURLWithPath:filePath]]; + + [frontDocument setSqlFileURL:[NSURL fileURLWithPath:filePath]]; + [frontDocument setSqlFileEncoding:sqlEncoding]; +} - return; +- (void)openSessionBundleAtPath:(NSString *)filePath +{ + NSError *readError = nil; + NSString *convError = nil; + NSPropertyListFormat format; + NSDictionary *spfs = nil; + NSData *pData = [NSData dataWithContentsOfFile:[NSString stringWithFormat:@"%@/info.plist", filePath] options:NSUncachedRead error:&readError]; + + spfs = [[NSPropertyListSerialization propertyListFromData:pData + mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; + + if(!spfs || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { + NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while reading connection data file", @"error while reading connection data file")] + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:NSLocalizedString(@"Connection data file couldn't be read.", @"error while reading connection data file")]; + + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert runModal]; + + if (spfs) [spfs release]; + + return; + } + + + if([spfs objectForKey:@"windows"] && [[spfs objectForKey:@"windows"] isKindOfClass:[NSArray class]]) { + + NSFileManager *fileManager = [NSFileManager defaultManager]; + + // Retrieve Save Panel accessory view data for remembering them globally + NSMutableDictionary *spfsDocData = [NSMutableDictionary dictionary]; + [spfsDocData setObject:[NSNumber numberWithBool:[[spfs objectForKey:@"encrypted"] boolValue]] forKey:@"encrypted"]; + [spfsDocData setObject:[NSNumber numberWithBool:[[spfs objectForKey:@"auto_connect"] boolValue]] forKey:@"auto_connect"]; + [spfsDocData setObject:[NSNumber numberWithBool:[[spfs objectForKey:@"save_password"] boolValue]] forKey:@"save_password"]; + [spfsDocData setObject:[NSNumber numberWithBool:[[spfs objectForKey:@"include_session"] boolValue]] forKey:@"include_session"]; + [spfsDocData setObject:[NSNumber numberWithBool:[[spfs objectForKey:@"save_editor_content"] boolValue]] forKey:@"save_editor_content"]; + + // Set global session properties + [SPAppDelegate setSpfSessionDocData:spfsDocData]; + [SPAppDelegate setSessionURL:filePath]; + + // Loop through each defined window in reversed order to reconstruct the last active window + for (NSDictionary *window in [[[spfs objectForKey:@"windows"] reverseObjectEnumerator] allObjects]) + { + // Create a new window controller, and set up a new connection view within it. + SPWindowController *newWindowController = [[SPWindowController alloc] initWithWindowNibName:@"MainWindow"]; + NSWindow *newWindow = [newWindowController window]; + + // If window has more than 1 tab then set setHideForSingleTab to NO + // in order to avoid animation problems while opening tabs + if([[window objectForKey:@"tabs"] count] > 1) + [newWindowController setHideForSingleTab:NO]; + + // The first window should use autosaving; subsequent windows should cascade. + // So attempt to set the frame autosave name; this will succeed for the very + // first window, and fail for others. + BOOL usedAutosave = [newWindow setFrameAutosaveName:@"DBView"]; + + if (!usedAutosave) { + [newWindow setFrameUsingName:@"DBView"]; } - - - if([spfs objectForKey:@"windows"] && [[spfs objectForKey:@"windows"] isKindOfClass:[NSArray class]]) { - - NSFileManager *fileManager = [NSFileManager defaultManager]; - - // Retrieve Save Panel accessory view data for remembering them globally - NSMutableDictionary *spfsDocData = [NSMutableDictionary dictionary]; - [spfsDocData setObject:[NSNumber numberWithBool:[[spfs objectForKey:@"encrypted"] boolValue]] forKey:@"encrypted"]; - [spfsDocData setObject:[NSNumber numberWithBool:[[spfs objectForKey:@"auto_connect"] boolValue]] forKey:@"auto_connect"]; - [spfsDocData setObject:[NSNumber numberWithBool:[[spfs objectForKey:@"save_password"] boolValue]] forKey:@"save_password"]; - [spfsDocData setObject:[NSNumber numberWithBool:[[spfs objectForKey:@"include_session"] boolValue]] forKey:@"include_session"]; - [spfsDocData setObject:[NSNumber numberWithBool:[[spfs objectForKey:@"save_editor_content"] boolValue]] forKey:@"save_editor_content"]; - - // Set global session properties - [SPAppDelegate setSpfSessionDocData:spfsDocData]; - [SPAppDelegate setSessionURL:filePath]; - - // Loop through each defined window in reversed order to reconstruct the last active window - for (NSDictionary *window in [[[spfs objectForKey:@"windows"] reverseObjectEnumerator] allObjects]) - { - // Create a new window controller, and set up a new connection view within it. - SPWindowController *newWindowController = [[SPWindowController alloc] initWithWindowNibName:@"MainWindow"]; - NSWindow *newWindow = [newWindowController window]; - - // If window has more than 1 tab then set setHideForSingleTab to NO - // in order to avoid animation problems while opening tabs - if([[window objectForKey:@"tabs"] count] > 1) - [newWindowController setHideForSingleTab:NO]; - - // The first window should use autosaving; subsequent windows should cascade. - // So attempt to set the frame autosave name; this will succeed for the very - // first window, and fail for others. - BOOL usedAutosave = [newWindow setFrameAutosaveName:@"DBView"]; - - if (!usedAutosave) { - [newWindow setFrameUsingName:@"DBView"]; - } - - if ([window objectForKey:@"frame"]) - { - [newWindow setFrame:NSRectFromString([window objectForKey:@"frame"]) display:NO]; - } - - // Set the window controller as the window's delegate - [newWindow setDelegate:newWindowController]; - - usleep(1000); - - // Show the window - [newWindowController showWindow:self]; - - // Loop through all defined tabs for each window - for (NSDictionary *tab in [window objectForKey:@"tabs"]) - { - NSString *fileName = nil; - BOOL isBundleFile = NO; - - // If isAbsolutePath then take this path directly - // otherwise construct the releative path for the passed spfs file - if ([[tab objectForKey:@"isAbsolutePath"] boolValue]) { - fileName = [tab objectForKey:@"path"]; - } - else { - fileName = [NSString stringWithFormat:@"%@/Contents/%@", filePath, [tab objectForKey:@"path"]]; - isBundleFile = YES; - } - - // Security check if file really exists - if ([fileManager fileExistsAtPath:fileName]) { - - // Add new the tab - if(newWindowController) { - - if ([[newWindowController window] isMiniaturized]) [[newWindowController window] deminiaturize:self]; - [newWindowController addNewConnection:self]; - - [[self frontDocument] setIsSavedInBundle:isBundleFile]; - if (![[self frontDocument] setStateFromConnectionFile:fileName]) { - break; - } - } - - } - else { - NSLog(@"Bundle file “%@” does not exists", fileName); - NSBeep(); + + if ([window objectForKey:@"frame"]) + { + [newWindow setFrame:NSRectFromString([window objectForKey:@"frame"]) display:NO]; + } + + // Set the window controller as the window's delegate + [newWindow setDelegate:newWindowController]; + + usleep(1000); + + // Show the window + [newWindowController showWindow:self]; + + // Loop through all defined tabs for each window + for (NSDictionary *tab in [window objectForKey:@"tabs"]) + { + NSString *fileName = nil; + BOOL isBundleFile = NO; + + // If isAbsolutePath then take this path directly + // otherwise construct the releative path for the passed spfs file + if ([[tab objectForKey:@"isAbsolutePath"] boolValue]) { + fileName = [tab objectForKey:@"path"]; + } + else { + fileName = [NSString stringWithFormat:@"%@/Contents/%@", filePath, [tab objectForKey:@"path"]]; + isBundleFile = YES; + } + + // Security check if file really exists + if ([fileManager fileExistsAtPath:fileName]) { + + // Add new the tab + if(newWindowController) { + + if ([[newWindowController window] isMiniaturized]) [[newWindowController window] deminiaturize:self]; + SPDatabaseDocument *newConnection = [newWindowController addNewConnection]; + + [newConnection setIsSavedInBundle:isBundleFile]; + if (![newConnection setStateFromConnectionFile:fileName]) { + break; } } - - // Select active tab - [newWindowController selectTabAtIndex:[[window objectForKey:@"selectedTabIndex"] intValue]]; - - // Reset setHideForSingleTab - if ([[NSUserDefaults standardUserDefaults] objectForKey:SPAlwaysShowWindowTabBar]) { - [newWindowController setHideForSingleTab:[[NSUserDefaults standardUserDefaults] boolForKey:SPAlwaysShowWindowTabBar]]; - } - else { - [newWindowController setHideForSingleTab:YES]; - } + } - } - - [spfs release]; - - [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:[NSURL fileURLWithPath:filePath]]; - } - else if ([[[filePath pathExtension] lowercaseString] isEqualToString:[SPColorThemeFileExtension lowercaseString]]) { - - NSFileManager *fm = [NSFileManager defaultManager]; - - NSString *themePath = [[NSFileManager defaultManager] applicationSupportDirectoryForSubDirectory:SPThemesSupportFolder error:nil]; - - if (!themePath) return; - - if (![fm fileExistsAtPath:themePath isDirectory:nil]) { - if (![fm createDirectoryAtPath:themePath withIntermediateDirectories:YES attributes:nil error:nil]) { + else { + NSLog(@"Bundle file “%@” does not exists", fileName); NSBeep(); - return; } } - - NSString *newPath = [NSString stringWithFormat:@"%@/%@", themePath, [filePath lastPathComponent]]; - - if (![fm fileExistsAtPath:newPath isDirectory:nil]) { - if (![fm moveItemAtPath:filePath toPath:newPath error:nil]) { - NSBeep(); - return; - } + + // Select active tab + [newWindowController selectTabAtIndex:[[window objectForKey:@"selectedTabIndex"] intValue]]; + + // Reset setHideForSingleTab + if ([[NSUserDefaults standardUserDefaults] objectForKey:SPAlwaysShowWindowTabBar]) { + [newWindowController setHideForSingleTab:[[NSUserDefaults standardUserDefaults] boolForKey:SPAlwaysShowWindowTabBar]]; } else { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while installing color theme file", @"error while installing color theme file")] - defaultButton:NSLocalizedString(@"OK", @"OK button") - alternateButton:nil - otherButton:nil - informativeTextWithFormat:NSLocalizedString(@"The color theme ‘%@’ already exists.", @"the color theme ‘%@’ already exists."), [filePath lastPathComponent]]; - - [alert setAlertStyle:NSCriticalAlertStyle]; - [alert runModal]; - - return; + [newWindowController setHideForSingleTab:YES]; } } - else if ([[[filePath pathExtension] lowercaseString] isEqualToString:[SPUserBundleFileExtension lowercaseString]]) { - - NSFileManager *fm = [NSFileManager defaultManager]; - - NSString *bundlePath = [fm applicationSupportDirectoryForSubDirectory:SPBundleSupportFolder error:nil]; - - if (!bundlePath) return; - - if (![fm fileExistsAtPath:bundlePath isDirectory:nil]) { - if (![fm createDirectoryAtPath:bundlePath withIntermediateDirectories:YES attributes:nil error:nil]) { - NSBeep(); - NSLog(@"Couldn't create folder “%@”", bundlePath); - return; - } - } - - NSString *newPath = [NSString stringWithFormat:@"%@/%@", bundlePath, [filePath lastPathComponent]]; - - NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; - NSDictionary *cmdData = nil; - NSString *infoPath = [NSString stringWithFormat:@"%@/%@", filePath, SPBundleFileName]; - NSData *pData = [NSData dataWithContentsOfFile:infoPath options:NSUncachedRead error:&readError]; - - cmdData = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; + } + + [spfs release]; + + [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:[NSURL fileURLWithPath:filePath]]; +} - if (!cmdData || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - NSLog(@"“%@/%@” file couldn't be read.", filePath, SPBundleFileName); - NSBeep(); - if (cmdData) [cmdData release]; - return; - } - else { - // Check for installed UUIDs - if (![cmdData objectForKey:SPBundleFileUUIDKey]) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while installing Bundle", @"Open Files : Bundle : UUID : Error dialog title")] - defaultButton:NSLocalizedString(@"OK", @"Open Files : Bundle : UUID : OK button") - alternateButton:nil - otherButton:nil - informativeTextWithFormat:NSLocalizedString(@"The Bundle ‘%@’ has no UUID which is necessary to identify installed Bundles.", @"Open Files : Bundle: UUID : UUID-Attribute is missing in bundle's command.plist file"), [filePath lastPathComponent]]; +- (void)openColorThemeFileAtPath:(NSString *)filePath +{ + NSFileManager *fm = [NSFileManager defaultManager]; + + NSString *themePath = [[NSFileManager defaultManager] applicationSupportDirectoryForSubDirectory:SPThemesSupportFolder error:nil]; + + if (!themePath) return; + + if (![fm fileExistsAtPath:themePath isDirectory:nil]) { + if (![fm createDirectoryAtPath:themePath withIntermediateDirectories:YES attributes:nil error:nil]) { + NSBeep(); + return; + } + } + + NSString *newPath = [NSString stringWithFormat:@"%@/%@", themePath, [filePath lastPathComponent]]; + + if (![fm fileExistsAtPath:newPath isDirectory:nil]) { + if (![fm moveItemAtPath:filePath toPath:newPath error:nil]) { + NSBeep(); + return; + } + } + else { + NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while installing color theme file", @"error while installing color theme file")] + defaultButton:NSLocalizedString(@"OK", @"OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:NSLocalizedString(@"The color theme ‘%@’ already exists.", @"the color theme ‘%@’ already exists."), [filePath lastPathComponent]]; + + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert runModal]; + + return; + } +} +- (void)openUserBundleAtPath:(NSString *)filePath +{ + NSFileManager *fm = [NSFileManager defaultManager]; + + NSString *bundlePath = [fm applicationSupportDirectoryForSubDirectory:SPBundleSupportFolder error:nil]; + + if (!bundlePath) return; + + if (![fm fileExistsAtPath:bundlePath isDirectory:nil]) { + if (![fm createDirectoryAtPath:bundlePath withIntermediateDirectories:YES attributes:nil error:nil]) { + NSBeep(); + NSLog(@"Couldn't create folder “%@”", bundlePath); + return; + } + } + + NSString *newPath = [NSString stringWithFormat:@"%@/%@", bundlePath, [filePath lastPathComponent]]; + + NSError *readError = nil; + NSString *convError = nil; + NSPropertyListFormat format; + NSDictionary *cmdData = nil; + NSString *infoPath = [NSString stringWithFormat:@"%@/%@", filePath, SPBundleFileName]; + NSData *pData = [NSData dataWithContentsOfFile:infoPath options:NSUncachedRead error:&readError]; + + cmdData = [[NSPropertyListSerialization propertyListFromData:pData + mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; + + if (!cmdData || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { + NSLog(@"“%@/%@” file couldn't be read.", filePath, SPBundleFileName); + NSBeep(); + if (cmdData) [cmdData release]; + return; + } + else { + // Check for installed UUIDs + if (![cmdData objectForKey:SPBundleFileUUIDKey]) { + NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while installing Bundle", @"Open Files : Bundle : UUID : Error dialog title")] + defaultButton:NSLocalizedString(@"OK", @"Open Files : Bundle : UUID : OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:NSLocalizedString(@"The Bundle ‘%@’ has no UUID which is necessary to identify installed Bundles.", @"Open Files : Bundle: UUID : UUID-Attribute is missing in bundle's command.plist file"), [filePath lastPathComponent]]; + + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert runModal]; + if (cmdData) [cmdData release]; + return; + } + + // Reload Bundles if Sequel Pro didn't run + if (![installedBundleUUIDs count]) { + [self reloadBundles:self]; + } + + if ([[installedBundleUUIDs allKeys] containsObject:[cmdData objectForKey:SPBundleFileUUIDKey]]) { + NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Installing Bundle", @"Open Files : Bundle : Already-Installed : 'Update Bundle' question dialog title")] + defaultButton:NSLocalizedString(@"Update", @"Open Files : Bundle : Already-Installed : Update button") + alternateButton:NSLocalizedString(@"Cancel", @"Open Files : Bundle : Already-Installed : Cancel button") + otherButton:nil + informativeTextWithFormat:NSLocalizedString(@"A Bundle ‘%@’ is already installed. Do you want to update it?", @"Open Files : Bundle : Already-Installed : 'Update Bundle' question dialog message"), [[installedBundleUUIDs objectForKey:[cmdData objectForKey:SPBundleFileUUIDKey]] objectForKey:@"name"]]; + + [alert setAlertStyle:NSCriticalAlertStyle]; + NSInteger answer = [alert runModal]; + + if (answer == NSAlertDefaultReturn) { + NSError *error = nil; + NSString *removePath = [[[installedBundleUUIDs objectForKey:[cmdData objectForKey:SPBundleFileUUIDKey]] objectForKey:@"path"] substringToIndex:([(NSString *)[[installedBundleUUIDs objectForKey:[cmdData objectForKey:SPBundleFileUUIDKey]] objectForKey:@"path"] length]-[SPBundleFileName length]-1)]; + NSString *moveToTrashCommand = [NSString stringWithFormat:@"osascript -e 'tell application \"Finder\" to move (POSIX file \"%@\") to the trash'", removePath]; + + [SPBundleCommandRunner runBashCommand:moveToTrashCommand withEnvironment:nil atCurrentDirectoryPath:nil error:&error]; + + if (error != nil) { + alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while moving “%@” to Trash.", @"Open Files : Bundle : Already-Installed : Delete-Old-Error : Could not delete old bundle before installing new version."), removePath] + defaultButton:NSLocalizedString(@"OK", @"Open Files : Bundle : Already-Installed : Delete-Old-Error : OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:@"%@", [error localizedDescription]]; + [alert setAlertStyle:NSCriticalAlertStyle]; [alert runModal]; if (cmdData) [cmdData release]; return; } - - // Reload Bundles if Sequel Pro didn't run - if (![installedBundleUUIDs count]) { - [self reloadBundles:self]; - } - - if ([[installedBundleUUIDs allKeys] containsObject:[cmdData objectForKey:SPBundleFileUUIDKey]]) { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Installing Bundle", @"Open Files : Bundle : Already-Installed : 'Update Bundle' question dialog title")] - defaultButton:NSLocalizedString(@"Update", @"Open Files : Bundle : Already-Installed : Update button") - alternateButton:NSLocalizedString(@"Cancel", @"Open Files : Bundle : Already-Installed : Cancel button") - otherButton:nil - informativeTextWithFormat:NSLocalizedString(@"A Bundle ‘%@’ is already installed. Do you want to update it?", @"Open Files : Bundle : Already-Installed : 'Update Bundle' question dialog message"), [[installedBundleUUIDs objectForKey:[cmdData objectForKey:SPBundleFileUUIDKey]] objectForKey:@"name"]]; - - [alert setAlertStyle:NSCriticalAlertStyle]; - NSInteger answer = [alert runModal]; - - if (answer == NSAlertDefaultReturn) { - NSError *error = nil; - NSString *removePath = [[[installedBundleUUIDs objectForKey:[cmdData objectForKey:SPBundleFileUUIDKey]] objectForKey:@"path"] substringToIndex:([(NSString *)[[installedBundleUUIDs objectForKey:[cmdData objectForKey:SPBundleFileUUIDKey]] objectForKey:@"path"] length]-[SPBundleFileName length]-1)]; - NSString *moveToTrashCommand = [NSString stringWithFormat:@"osascript -e 'tell application \"Finder\" to move (POSIX file \"%@\") to the trash'", removePath]; - - [SPBundleCommandRunner runBashCommand:moveToTrashCommand withEnvironment:nil atCurrentDirectoryPath:nil error:&error]; - - if (error != nil) { - alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while moving “%@” to Trash.", @"Open Files : Bundle : Already-Installed : Delete-Old-Error : Could not delete old bundle before installing new version."), removePath] - defaultButton:NSLocalizedString(@"OK", @"Open Files : Bundle : Already-Installed : Delete-Old-Error : OK button") - alternateButton:nil - otherButton:nil - informativeTextWithFormat:@"%@", [error localizedDescription]]; - - [alert setAlertStyle:NSCriticalAlertStyle]; - [alert runModal]; - if (cmdData) [cmdData release]; - return; - } - } - else { - if (cmdData) [cmdData release]; - - return; - } - } - } - - if (cmdData) [cmdData release]; - - if (![fm fileExistsAtPath:newPath isDirectory:nil]) { - if (![fm moveItemAtPath:filePath toPath:newPath error:nil]) { - NSBeep(); - NSLog(@"Couldn't move “%@” to “%@”", filePath, newPath); - return; - } - - // Update Bundle Editor if it was already initialized - for (NSWindow *win in [NSApp windows]) - { - if ([[win delegate] class] == [SPBundleEditorController class]) { - [((SPBundleEditorController *)[win delegate]) reloadBundles:nil]; - break; - } - } - - // Update Bundels' menu - [self reloadBundles:self]; - } else { - NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while installing Bundle", @"Open Files : Bundle : Install-Error : error dialog title")] - defaultButton:NSLocalizedString(@"OK", @"Open Files : Bundle : Install-Error : OK button") - alternateButton:nil - otherButton:nil - informativeTextWithFormat:NSLocalizedString(@"The Bundle ‘%@’ already exists.", @"Open Files : Bundle : Install-Error : Destination path already exists error dialog message"), [filePath lastPathComponent]]; - - [alert setAlertStyle:NSCriticalAlertStyle]; - [alert runModal]; - + if (cmdData) [cmdData release]; + return; } } - else { - NSLog(@"Only files with the extensions ‘%@’, ‘%@’, ‘%@’ or ‘%@’ are allowed.", SPFileExtensionDefault, SPBundleFileExtension, SPColorThemeFileExtension, SPFileExtensionSQL); + } + + if (cmdData) [cmdData release]; + + if (![fm fileExistsAtPath:newPath isDirectory:nil]) { + if (![fm moveItemAtPath:filePath toPath:newPath error:nil]) { + NSBeep(); + NSLog(@"Couldn't move “%@” to “%@”", filePath, newPath); + return; } + + // Update Bundle Editor if it was already initialized + for (NSWindow *win in [NSApp windows]) + { + if ([[win delegate] class] == [SPBundleEditorController class]) { + [((SPBundleEditorController *)[win delegate]) reloadBundles:nil]; + break; + } + } + + // Update Bundels' menu + [self reloadBundles:self]; + + } + else { + NSAlert *alert = [NSAlert alertWithMessageText:[NSString stringWithFormat:NSLocalizedString(@"Error while installing Bundle", @"Open Files : Bundle : Install-Error : error dialog title")] + defaultButton:NSLocalizedString(@"OK", @"Open Files : Bundle : Install-Error : OK button") + alternateButton:nil + otherButton:nil + informativeTextWithFormat:NSLocalizedString(@"The Bundle ‘%@’ already exists.", @"Open Files : Bundle : Install-Error : Destination path already exists error dialog message"), [filePath lastPathComponent]]; + + [alert setAlertStyle:NSCriticalAlertStyle]; + [alert runModal]; } } @@ -784,8 +773,7 @@ } // make connection window - [self newTab:nil]; - SPDatabaseDocument *doc = [self frontDocument]; + SPDatabaseDocument *doc = [self makeNewConnectionTabOrWindow]; NSMutableDictionary *details = [NSMutableDictionary dictionary]; @@ -904,7 +892,7 @@ return; } - NSString *activeProcessID = [[(SPWindowController *)[[self frontDocumentWindow] delegate] selectedTableDocument] processID]; + NSString *activeProcessID = [[self frontDocument] processID]; SPDatabaseDocument *processDocument = nil; @@ -912,26 +900,24 @@ // For speed check the front most first otherwise iterate through all if(passedProcessID && [passedProcessID length]) { if([activeProcessID isEqualToString:passedProcessID]) { - processDocument = [(SPWindowController *)[[self frontDocumentWindow] delegate] selectedTableDocument]; + processDocument = [self frontDocument]; } else { - for (NSWindow *aWindow in [NSApp orderedWindows]) { - if([[aWindow windowController] isMemberOfClass:[SPWindowController class]]) { - for(SPDatabaseDocument *doc in [[aWindow windowController] documents]) { - if([doc processID] && [[doc processID] isEqualToString:passedProcessID]) { - processDocument = doc; - break; - } + for (NSWindow *aWindow in [self orderedDatabaseConnectionWindows]) { + for(SPDatabaseDocument *doc in [[aWindow windowController] documents]) { + if([doc processID] && [[doc processID] isEqualToString:passedProcessID]) { + processDocument = doc; + goto break_loop; } } - if(processDocument) break; } + break_loop: /* breaking two levels of foreach */; } } // if no processDoc found and no passedProcessID was passed execute // command at front most doc if(!processDocument && !passedProcessID) - processDocument = [(SPWindowController *)[[self frontDocumentWindow] delegate] selectedTableDocument]; + processDocument = [self frontDocument]; if(processDocument && command) { if([command isEqualToString:@"passToDoc"]) { @@ -1273,19 +1259,15 @@ if(docUUID == nil) doc = [self frontDocument]; else { - BOOL found = NO; - for (NSWindow *aWindow in [NSApp orderedWindows]) { - if([[aWindow windowController] isMemberOfClass:[SPWindowController class]]) { - for(SPDatabaseDocument *d in [[aWindow windowController] documents]) { - if([d processID] && [[d processID] isEqualToString:docUUID]) { - [env addEntriesFromDictionary:[d shellVariables]]; - found = YES; - break; - } + for (NSWindow *aWindow in [self orderedDatabaseConnectionWindows]) { + for(SPDatabaseDocument *d in [[aWindow windowController] documents]) { + if([d processID] && [[d processID] isEqualToString:docUUID]) { + [env addEntriesFromDictionary:[d shellVariables]]; + goto break_loop; } } - if(found) break; } + break_loop: /* breaking two levels of foreach */; } id firstResponder = [[NSApp keyWindow] firstResponder]; @@ -1440,13 +1422,7 @@ */ - (SPDatabaseDocument *) frontDocument { - for (NSWindow *aWindow in [NSApp orderedWindows]) { - if ([[aWindow windowController] isMemberOfClass:[SPWindowController class]]) { - return [[aWindow windowController] selectedTableDocument]; - } - } - - return nil; + return [[self frontController] selectedTableDocument]; } /** @@ -2224,14 +2200,11 @@ } // Iterate through each open window - for (NSWindow *aWindow in [NSApp orderedWindows]) + for (NSWindow *aWindow in [self orderedDatabaseConnectionWindows]) { - if (![[aWindow windowController] isMemberOfClass:[SPWindowController class]]) continue; - // Iterate through each document in the window for (SPDatabaseDocument *doc in [[aWindow windowController] documents]) { - // Kill any BASH commands which are currently active for (NSDictionary* cmd in [doc runningActivities]) { diff --git a/Source/SPGrowlController.m b/Source/SPGrowlController.m index be659041..816196bf 100644 --- a/Source/SPGrowlController.m +++ b/Source/SPGrowlController.m @@ -31,6 +31,7 @@ #import "SPGrowlController.h" #import "SPDatabaseDocument.h" #import "SPWindowController.h" +#import "SPAppController.h" #include <mach/mach_time.h> @@ -167,16 +168,14 @@ static SPGrowlController *sharedGrowlController = nil; NSUInteger documentHash = [[clickContext objectForKey:@"notificationDocumentHash"] unsignedIntegerValue]; // Loop through the windows, looking for the document - for (NSWindow *eachWindow in [NSApp orderedWindows]) + for (NSWindow *eachWindow in [SPAppDelegate orderedDatabaseConnectionWindows]) { - if ([[eachWindow windowController] isKindOfClass:[SPWindowController class]]) { - for (SPDatabaseDocument *eachDocument in [[eachWindow windowController] documents]) - { - if ([eachDocument hash] == documentHash) { - [NSApp activateIgnoringOtherApps:YES]; - [eachDocument makeKeyDocument]; - return; - } + for (SPDatabaseDocument *eachDocument in [[eachWindow windowController] documents]) + { + if ([eachDocument hash] == documentHash) { + [NSApp activateIgnoringOtherApps:YES]; + [eachDocument makeKeyDocument]; + return; } } } diff --git a/Source/SPWindowController.h b/Source/SPWindowController.h index a86a85f9..528c1c84 100644 --- a/Source/SPWindowController.h +++ b/Source/SPWindowController.h @@ -50,6 +50,8 @@ - (IBAction)addNewConnection:(id)sender; - (IBAction)moveSelectedTabInNewWindow:(id)sender; +- (SPDatabaseDocument *)addNewConnection; + /** * @danger THIS IS NOT RETAINED!!! * diff --git a/Source/SPWindowController.m b/Source/SPWindowController.m index 68c89ad8..963919d0 100644 --- a/Source/SPWindowController.m +++ b/Source/SPWindowController.m @@ -104,6 +104,11 @@ enum { */ - (IBAction)addNewConnection:(id)sender { + [self addNewConnection]; +} + +- (SPDatabaseDocument *)addNewConnection +{ // Create a new database connection view SPDatabaseDocument *newTableDocument = [[SPDatabaseDocument alloc] init]; @@ -125,8 +130,8 @@ enum { // Bind the tab bar's progress display to the document [self _updateProgressIndicatorForItem:newItem]; - - [newTableDocument release]; + + return [newTableDocument autorelease]; } /** diff --git a/Source/SPWindowManagement.h b/Source/SPWindowManagement.h index 66f65b6d..4d32d6d4 100644 --- a/Source/SPWindowManagement.h +++ b/Source/SPWindowManagement.h @@ -30,6 +30,8 @@ #import "SPAppController.h" +@class SPWindowController; + /** * @category SPWindowManagement SPWindowManagement.h * @@ -43,6 +45,10 @@ - (IBAction)newTab:(id)sender; - (IBAction)duplicateTab:(id)sender; +- (SPWindowController *)newWindow; +- (SPDatabaseDocument *)makeNewConnectionTabOrWindow; +- (SPWindowController *)frontController; + - (NSWindow *)frontDocumentWindow; - (void)tabDragStarted:(id)sender; diff --git a/Source/SPWindowManagement.m b/Source/SPWindowManagement.m index c30a2826..6225c52f 100644 --- a/Source/SPWindowManagement.m +++ b/Source/SPWindowManagement.m @@ -32,10 +32,16 @@ @implementation SPAppController (SPWindowManagement) + +- (IBAction)newWindow:(id)sender +{ + [self newWindow]; +} + /** * Create a new window, containing a single tab. */ -- (IBAction)newWindow:(id)sender +- (SPWindowController *)newWindow { static NSPoint cascadeLocation = {.x = 0, .y = 0}; @@ -58,7 +64,7 @@ } // Add the connection view - [newWindowController addNewConnection:self]; + [newWindowController addNewConnection]; // Cascade according to the statically stored cascade location. cascadeLocation = [newWindow cascadeTopLeftFromPoint:cascadeLocation]; @@ -69,6 +75,8 @@ // Show the window, and perform frontmost tasks again once the window has drawn [newWindowController showWindow:self]; [[newWindowController selectedTableDocument] didBecomeActiveTabInWindow]; + + return newWindowController; } /** @@ -76,15 +84,7 @@ */ - (IBAction)newTab:(id)sender { - SPWindowController *frontController = nil; - - for (NSWindow *aWindow in [NSApp orderedWindows]) - { - if ([[aWindow windowController] isMemberOfClass:[SPWindowController class]]) { - frontController = [aWindow windowController]; - break; - } - } + SPWindowController *frontController = [self frontController]; // If no window was found, create a new one if (!frontController) { @@ -99,6 +99,25 @@ } } +- (SPDatabaseDocument *)makeNewConnectionTabOrWindow +{ + SPWindowController *frontController = [self frontController]; + + SPDatabaseDocument *frontDocument; + // If no window was found or the front most window has no tabs, create a new one + if (!frontController || [[frontController valueForKeyPath:@"tabView"] numberOfTabViewItems] == 1) { + frontController = [self newWindow]; + frontDocument = [frontController selectedTableDocument]; + } + // Open the spf file in a new tab if the tab bar is visible + else { + if ([[frontController window] isMiniaturized]) [[frontController window] deminiaturize:self]; + frontDocument = [frontController addNewConnection]; + } + + return frontDocument; +} + /** * Duplicate the current connection tab */ @@ -113,7 +132,7 @@ [[self frontDocumentWindow] deminiaturize:self]; } - [[[self frontDocumentWindow] windowController] addNewConnection:self]; + SPDatabaseDocument *newConnection = [[self frontController] addNewConnection]; // Get the state of the previously-frontmost document NSDictionary *allStateDetails = @{ @@ -130,7 +149,7 @@ [frontState setObject:@YES forKey:@"auto_connect"]; // Set the connection on the new tab - [[self frontDocument] setState:frontState]; + [newConnection setState:frontState]; } /** @@ -138,12 +157,17 @@ */ - (NSWindow *)frontDocumentWindow { + return [[self frontController] window]; +} + +- (SPWindowController *)frontController +{ for (NSWindow *aWindow in [NSApp orderedWindows]) { - if ([[aWindow windowController] isMemberOfClass:[SPWindowController class]]) { - return aWindow; + id ctr = [aWindow windowController]; + if ([ctr isMemberOfClass:[SPWindowController class]]) { + return ctr; } } - return nil; } |