From 79b24a37b45ad20b8086e481696c758a76092c4e Mon Sep 17 00:00:00 2001 From: stuconnolly Date: Sat, 13 Mar 2010 13:29:53 +0000 Subject: Lots more printing support enhancements, including: - The ability to print the extended table information view using a new template. - The inclusion of NULL values diaplyed as the user's NULL value placeholder when printing a table's sturcture and indexes. - If enabled in the user's preferences, the inclusion of vertical gridlines in the table views. - Dynamic calculation of page margins based on the paper size of the selected printer as opposed to using hard coded values. - Lots of other little style enhancements. --- .../English.lproj/sequel-pro-print-template.html | 19 ++- .../sequel-pro-table-info-print-template.html | 149 ++++++++++++++++++++ Source/SPConstants.h | 1 + Source/SPConstants.m | 1 + Source/SPExtendedTableInfo.h | 1 + Source/SPExtendedTableInfo.m | 66 ++++++--- Source/SPPrintController.h | 5 +- Source/SPPrintController.m | 154 +++++++++++++-------- Source/TableDocument.m | 4 +- Source/TableSource.m | 46 ++++-- sequel-pro.xcodeproj/project.pbxproj | 4 + 11 files changed, 353 insertions(+), 97 deletions(-) create mode 100644 Resources/sequel-pro-table-info-print-template.html diff --git a/Resources/English.lproj/sequel-pro-print-template.html b/Resources/English.lproj/sequel-pro-print-template.html index 6265a3f8..ba8b31fa 100644 --- a/Resources/English.lproj/sequel-pro-print-template.html +++ b/Resources/English.lproj/sequel-pro-print-template.html @@ -1,5 +1,5 @@ - + Sequel Pro @@ -7,7 +7,7 @@ @@ -84,7 +83,7 @@

-

{{title}}

+

{{heading}}

diff --git a/Resources/sequel-pro-table-info-print-template.html b/Resources/sequel-pro-table-info-print-template.html new file mode 100644 index 00000000..30198ec2 --- /dev/null +++ b/Resources/sequel-pro-table-info-print-template.html @@ -0,0 +1,149 @@ + + + + Sequel Pro + + + + + + + +

{{c.table}}

+ +

+ Connection: {{c.username}}{% if c.username %}@{% /if %}{{c.hostname}}{% if c.port %}:{% /if %}{{c.port}}/{{c.database}}
+ Generated on: {% now | date_format: "dd MMM yyyy 'at' HH:mm:ss" %} by {{c.version}}
+

+ +

{{heading}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type: {{i.type}}
Encoding: {{i.encoding}}
Collation: {{i.collation}}
Create at: {{i.createdAt}}
Updated at: {{i.updatedAt}}
Number of rows: {{i.rowNumber}}
Row format: {{i.rowFormat}}
Avg. row length: {{i.rowAvgLength}}
Auto increment: {{i.rowAutoIncrement}}
Data size: {{i.dataSize}}
Max data size: {{i.maxDataSize}}
Index size: {{i.indexSize}}
Free data size: {{i.sizeFree}}
+ + {% if i.comments.length > 0 %} +

Comments

+ +

{{i.comments}}

+ {% /if %} + +

Create Syntax

+ +
{{i.createSyntax}}
+ + diff --git a/Source/SPConstants.h b/Source/SPConstants.h index c8342a5f..a7409ebc 100644 --- a/Source/SPConstants.h +++ b/Source/SPConstants.h @@ -73,6 +73,7 @@ extern NSString *SPFileExtensionSQL; // Filenames extern NSString *SPHTMLPrintTemplate; +extern NSString *SPHTMLTableInfoPrintTemplate; extern NSString *SPHTMLHelpTemplate; diff --git a/Source/SPConstants.m b/Source/SPConstants.m index a395e11a..7db91664 100644 --- a/Source/SPConstants.m +++ b/Source/SPConstants.m @@ -42,6 +42,7 @@ NSString *SPFileExtensionSQL = @"sql"; // Filenames NSString *SPHTMLPrintTemplate = @"sequel-pro-print-template"; +NSString *SPHTMLTableInfoPrintTemplate = @"sequel-pro-table-info-print-template"; NSString *SPHTMLHelpTemplate = @"sequel-pro-mysql-help-template"; // Preference key constants diff --git a/Source/SPExtendedTableInfo.h b/Source/SPExtendedTableInfo.h index 4c9d1f07..aef1a6c4 100644 --- a/Source/SPExtendedTableInfo.h +++ b/Source/SPExtendedTableInfo.h @@ -73,6 +73,7 @@ // Others - (void)loadTable:(NSString *)table; +- (NSDictionary *)tableInformationForPrinting; // Task interaction - (void)startDocumentTaskForTab:(NSNotification *)aNotification; diff --git a/Source/SPExtendedTableInfo.m b/Source/SPExtendedTableInfo.m index d13de4a7..852b1007 100644 --- a/Source/SPExtendedTableInfo.m +++ b/Source/SPExtendedTableInfo.m @@ -36,7 +36,7 @@ @interface SPExtendedTableInfo (PrivateAPI) -- (NSString *)_formatValueWithKey:(NSString *)key inDictionary:(NSDictionary *)statusDict withLabel:(NSString *)label; +- (NSString *)_formatValueWithKey:(NSString *)key inDictionary:(NSDictionary *)statusDict; @end @@ -236,7 +236,9 @@ [tableCreateSyntaxTextView setEditable:YES]; [tableCreateSyntaxTextView shouldChangeTextInRange:NSMakeRange(0, [[tableCreateSyntaxTextView string] length]) replacementString:@""]; [tableCreateSyntaxTextView setString:@""]; + NSString *createViewSyntax = [[tableDataInstance tableCreateSyntax] createViewSyntaxPrettifier]; + [tableCreateSyntaxTextView shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:createViewSyntax]; [tableCreateSyntaxTextView insertText:createViewSyntax]; [tableCreateSyntaxTextView didChangeText]; @@ -327,20 +329,20 @@ [tableCollationPopUpButton addItemWithTitle:NSLocalizedString(@"Not available", @"not available label")]; } - [tableCreatedAt setStringValue:[self _formatValueWithKey:@"Create_time" inDictionary:statusFields withLabel:@"Created at"]]; - [tableUpdatedAt setStringValue:[self _formatValueWithKey:@"Update_time" inDictionary:statusFields withLabel:@"Updated at"]]; + [tableCreatedAt setStringValue:[NSString stringWithFormat:@"%@%@", NSLocalizedString(@"Created at: ", @"table info created at label"), [self _formatValueWithKey:@"Create_time" inDictionary:statusFields]]]; + [tableUpdatedAt setStringValue:[NSString stringWithFormat:@"%@%@", NSLocalizedString(@"Updated at: ", @"table info updated at label"), [self _formatValueWithKey:@"Update_time" inDictionary:statusFields]]]; // Set row values - [tableRowNumber setStringValue:[self _formatValueWithKey:@"Rows" inDictionary:statusFields withLabel:@"Number of rows"]]; - [tableRowFormat setStringValue:[self _formatValueWithKey:@"Row_format" inDictionary:statusFields withLabel:@"Row format"]]; - [tableRowAvgLength setStringValue:[self _formatValueWithKey:@"Avg_row_length" inDictionary:statusFields withLabel:@"Avg. row length"]]; - [tableRowAutoIncrement setStringValue:[self _formatValueWithKey:@"Auto_increment" inDictionary:statusFields withLabel:@"Auto increment"]]; + [tableRowNumber setStringValue:[NSString stringWithFormat:@"%@%@", NSLocalizedString(@"Number of rows: ", @"table info number of rows label"), [self _formatValueWithKey:@"Rows" inDictionary:statusFields]]]; + [tableRowFormat setStringValue:[NSString stringWithFormat:@"%@%@", NSLocalizedString(@"Row format: ", @"table info row format label"), [self _formatValueWithKey:@"Row_format" inDictionary:statusFields]]]; + [tableRowAvgLength setStringValue:[NSString stringWithFormat:@"%@%@", NSLocalizedString(@"Avg. row length: ", @"table info average row length label"), [self _formatValueWithKey:@"Avg_row_length" inDictionary:statusFields]]]; + [tableRowAutoIncrement setStringValue:[self _formatValueWithKey:@"Auto_increment" inDictionary:statusFields]]; // Set size values - [tableDataSize setStringValue:[self _formatValueWithKey:@"Data_length" inDictionary:statusFields withLabel:@"Data size"]]; - [tableMaxDataSize setStringValue:[self _formatValueWithKey:@"Max_data_length" inDictionary:statusFields withLabel:@"Max data size"]]; - [tableIndexSize setStringValue:[self _formatValueWithKey:@"Index_length" inDictionary:statusFields withLabel:@"Index size"]]; - [tableSizeFree setStringValue:[self _formatValueWithKey:@"Data_free" inDictionary:statusFields withLabel:@"Free data size"]]; + [tableDataSize setStringValue:[NSString stringWithFormat:@"%@%@", NSLocalizedString(@"Data size: ", @"table info data size label"), [self _formatValueWithKey:@"Data_length" inDictionary:statusFields]]]; + [tableMaxDataSize setStringValue:[NSString stringWithFormat:@"%@%@", NSLocalizedString(@"Max data size: ", @"table info max data size label"), [self _formatValueWithKey:@"Max_data_length" inDictionary:statusFields]]]; + [tableIndexSize setStringValue:[NSString stringWithFormat:@"%@%@", NSLocalizedString(@"Index size: ", @"table info index size label"), [self _formatValueWithKey:@"Index_length" inDictionary:statusFields]]]; + [tableSizeFree setStringValue:[NSString stringWithFormat:@"%@%@", NSLocalizedString(@"Free data size: ", @"table info free data size label"), [self _formatValueWithKey:@"Data_free" inDictionary:statusFields]]]; // Set comments [tableCommentsTextView setEditable:YES]; @@ -365,6 +367,35 @@ } } +/** + * + */ +- (NSDictionary *)tableInformationForPrinting +{ + NSMutableDictionary *tableInfo = [NSMutableDictionary dictionary]; + NSDictionary *statusFields = [tableDataInstance statusValues]; + + [tableInfo setObject:[tableTypePopUpButton titleOfSelectedItem] forKey:@"type"]; + [tableInfo setObject:[tableEncodingPopUpButton titleOfSelectedItem] forKey:@"encoding"]; + [tableInfo setObject:[tableCollationPopUpButton titleOfSelectedItem] forKey:@"collation"]; + + [tableInfo setObject:[self _formatValueWithKey:@"Create_time" inDictionary:statusFields] forKey:@"createdAt"]; + [tableInfo setObject:[self _formatValueWithKey:@"Update_time" inDictionary:statusFields] forKey:@"updatedAt"]; + [tableInfo setObject:[self _formatValueWithKey:@"Rows" inDictionary:statusFields] forKey:@"rowNumber"]; + [tableInfo setObject:[self _formatValueWithKey:@"Row_format" inDictionary:statusFields] forKey:@"rowFormat"]; + [tableInfo setObject:[self _formatValueWithKey:@"Avg_row_length" inDictionary:statusFields] forKey:@"rowAvgLength"]; + [tableInfo setObject:[self _formatValueWithKey:@"Auto_increment" inDictionary:statusFields] forKey:@"rowAutoIncrement"]; + [tableInfo setObject:[self _formatValueWithKey:@"Data_length" inDictionary:statusFields] forKey:@"dataSize"]; + [tableInfo setObject:[self _formatValueWithKey:@"Max_data_length" inDictionary:statusFields] forKey:@"maxDataSize"]; + [tableInfo setObject:[self _formatValueWithKey:@"Index_length" inDictionary:statusFields] forKey:@"indexSize"]; + [tableInfo setObject:[self _formatValueWithKey:@"Data_free" inDictionary:statusFields] forKey:@"sizeFree"]; + + [tableInfo setObject:[tableCommentsTextView string] forKey:@"comments"]; + [tableInfo setObject:[tableCreateSyntaxTextView string] forKey:@"createSyntax"]; + + return tableInfo; +} + /** * NSTextView delegate. Used to change the selected table's comment. */ @@ -404,8 +435,7 @@ - (void)startDocumentTaskForTab:(NSNotification *)aNotification { // Only proceed if this view is selected. - if (![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:SPMainToolbarTableInfo]) - return; + if (![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:SPMainToolbarTableInfo]) return; [tableTypePopUpButton setEnabled:NO]; [tableEncodingPopUpButton setEnabled:NO]; @@ -419,13 +449,11 @@ - (void)endDocumentTaskForTab:(NSNotification *)aNotification { // Only proceed if this view is selected. - if (![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:SPMainToolbarTableInfo]) - return; + if (![[tableDocumentInstance selectedToolbarItemIdentifier] isEqualToString:SPMainToolbarTableInfo]) return; NSDictionary *statusFields = [tableDataInstance statusValues]; - if (!selectedTable || ![selectedTable length] || [[statusFields objectForKey:@"Engine"] isEqualToString:@"View"]) - return; + if (!selectedTable || ![selectedTable length] || [[statusFields objectForKey:@"Engine"] isEqualToString:@"View"]) return; // If we are viewing tables in the information_schema database, then disable all controls that cause table // changes as these tables are not modifiable by anyone. @@ -469,7 +497,7 @@ /** * Format and returns the value within the info dictionary with the associated key. */ -- (NSString *)_formatValueWithKey:(NSString *)key inDictionary:(NSDictionary *)infoDict withLabel:(NSString *)label +- (NSString *)_formatValueWithKey:(NSString *)key inDictionary:(NSDictionary *)infoDict { NSString *value = [infoDict objectForKey:key]; @@ -521,7 +549,7 @@ return ([value length] > 0) ? value : NSLocalizedString(@"Not available", @"not available label"); } else { - return [NSString stringWithFormat:@"%@: %@", label, ([value length] > 0) ? value : NSLocalizedString(@"Not available", @"not available label")]; + return ([value length] > 0) ? value : NSLocalizedString(@"Not available", @"not available label"); } } diff --git a/Source/SPPrintController.h b/Source/SPPrintController.h index 8fd1acf8..17b78e35 100644 --- a/Source/SPPrintController.h +++ b/Source/SPPrintController.h @@ -27,7 +27,10 @@ @interface TableDocument (SPPrintController) -- (NSString *)generateHTMLforPrinting; +- (NSString *)generateHTMLForPrinting; +- (NSString *)generateTableInfoHTMLForPrinting; + - (NSArray *)columnNames; +- (NSMutableDictionary *)connectionInformation; @end diff --git a/Source/SPPrintController.m b/Source/SPPrintController.m index 718a203b..f890ad01 100644 --- a/Source/SPPrintController.m +++ b/Source/SPPrintController.m @@ -33,6 +33,7 @@ #import "MGTemplateEngine.h" #import "ICUTemplateMatcher.h" #import "SPConnectionController.h" +#import "SPExtendedTableInfo.h" @implementation TableDocument (SPPrintController) @@ -44,13 +45,28 @@ // Because we need the webFrame loaded (for preview), we've moved the actual printing here NSPrintInfo *printInfo = [self printInfo]; + NSSize paperSize = [printInfo paperSize]; + NSRect printableRect = [printInfo imageablePageBounds]; + + // Calculate page margins + CGFloat marginL = printableRect.origin.x; + CGFloat marginR = paperSize.width - (printableRect.origin.x + printableRect.size.width); + CGFloat marginB = printableRect.origin.y; + CGFloat marginT = paperSize.height - (printableRect.origin.y + printableRect.size.height); + + // Make sure margins are symetric and positive + CGFloat marginLR = MAX(0, MAX(marginL, marginR)); + CGFloat marginTB = MAX(0, MAX(marginT, marginB)); + + // Set the margins + [printInfo setLeftMargin:marginLR]; + [printInfo setRightMargin:marginLR]; + [printInfo setTopMargin:marginTB]; + [printInfo setBottomMargin:marginTB]; + [printInfo setHorizontalPagination:NSFitPagination]; [printInfo setVerticalPagination:NSAutoPagination]; [printInfo setVerticallyCentered:NO]; - [printInfo setTopMargin:30]; - [printInfo setBottomMargin:30]; - [printInfo setLeftMargin:10]; - [printInfo setRightMargin:10]; NSPrintOperation *op = [NSPrintOperation printOperationWithView:[[[printWebView mainFrame] frameView] documentView] printInfo:printInfo]; @@ -81,46 +97,23 @@ */ - (IBAction)printDocument:(id)sender { - [[printWebView mainFrame] loadHTMLString:[self generateHTMLforPrinting] baseURL:nil]; + [[printWebView mainFrame] loadHTMLString:([tableTabView indexOfTabViewItem:[tableTabView selectedTabViewItem]] == 3) ? [self generateTableInfoHTMLForPrinting] :[self generateHTMLForPrinting] baseURL:nil]; } /** * Generates the HTML for the current view that is being printed. */ -- (NSString *)generateHTMLforPrinting +- (NSString *)generateHTMLForPrinting { // Set up template engine with your chosen matcher MGTemplateEngine *engine = [MGTemplateEngine templateEngine]; [engine setMatcher:[ICUTemplateMatcher matcherWithTemplateEngine:engine]]; - NSString *versionForPrint = [NSString stringWithFormat:@"%@ %@ (build %@)", - [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"], - [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"], - [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"] - ]; - - NSMutableDictionary *connection = [[NSMutableDictionary alloc] init]; - - if ([[self user] length]) { - [connection setValue:[self user] forKey:@"username"]; - } - - if ([[self table] length]) { - [connection setValue:[self table] forKey:@"table"]; - } - - - if ([connectionController port] && [[connectionController port] length]) { - [connection setValue:[connectionController port] forKey:@"port"]; - } + NSMutableDictionary *connection = [self connectionInformation]; - [connection setValue:[self host] forKey:@"hostname"]; - [connection setValue:selectedDatabase forKey:@"database"]; - [connection setValue:versionForPrint forKey:@"version"]; - - NSString *title = @""; + NSString *heading = @""; NSArray *rows, *indexes, *indexColumns = nil; NSArray *columns = [self columnNames]; @@ -133,18 +126,16 @@ if ([[tableSource objectForKey:@"structure"] count] > 1) { - title = @"Table Structure"; + heading = NSLocalizedString(@"Table Structure", @"table structure print heading"); rows = [[NSArray alloc] initWithArray: [[tableSource objectForKey:@"structure"] objectsAtIndexes: - [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, [[tableSource objectForKey:@"structure"] count] - 1)] - ] + [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, [[tableSource objectForKey:@"structure"] count] - 1)]] ]; indexes = [[NSArray alloc] initWithArray: [[tableSource objectForKey:@"indexes"] objectsAtIndexes: - [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, [[tableSource objectForKey:@"indexes"] count] - 1)] - ] + [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, [[tableSource objectForKey:@"indexes"] count] - 1)]] ]; indexColumns = [[tableSource objectForKey:@"indexes"] objectAtIndex:0]; @@ -157,12 +148,11 @@ else if ([tableTabView indexOfTabViewItem:[tableTabView selectedTabViewItem]] == 1) { if ([[tableContentInstance currentResult] count] > 1) { - title = @"Table Content"; + heading = NSLocalizedString(@"Table Content", @"table content print heading"); rows = [[NSArray alloc] initWithArray: [[tableContentInstance currentDataResult] objectsAtIndexes: - [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, [[tableContentInstance currentResult] count] - 1)] - ] + [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, [[tableContentInstance currentResult] count] - 1)]] ]; [connection setValue:[tableContentInstance usedQuery] forKey:@"query"]; @@ -172,12 +162,11 @@ else if ([tableTabView indexOfTabViewItem:[tableTabView selectedTabViewItem]] == 2) { if ([[customQueryInstance currentResult] count] > 1) { - title = @"Query Result"; + heading = NSLocalizedString(@"Query Result", @"query result print heading"); rows = [[NSArray alloc] initWithArray: [[customQueryInstance currentResult] objectsAtIndexes: - [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, [[customQueryInstance currentResult] count] - 1)] - ] + [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, [[customQueryInstance currentResult] count] - 1)]] ]; [connection setValue:[customQueryInstance usedQuery] forKey:@"query"]; @@ -187,33 +176,54 @@ else if ([tableTabView indexOfTabViewItem:[tableTabView selectedTabViewItem]] == 4) { if ([[tableRelationsInstance relationDataForPrinting] count] > 1) { - title = @"Table Relations"; + heading = NSLocalizedString(@"Table Relations", @"table relations print heading"); NSArray *data = [tableRelationsInstance relationDataForPrinting]; rows = [[NSArray alloc] initWithArray: [data objectsAtIndexes: - [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, ([data count] - 1))] - ] + [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, ([data count] - 1))]] ]; } } [engine setObject:connection forKey:@"c"]; - [printData setObject:title forKey:@"title"]; + [printData setObject:heading forKey:@"heading"]; [printData setObject:columns forKey:@"columns"]; [printData setObject:rows forKey:@"rows"]; [printData setObject:([prefs boolForKey:SPUseMonospacedFonts]) ? SPDefaultMonospacedFontName : @"Lucida Grande" forKey:@"font"]; - - [connection release]; - + [printData setObject:([prefs boolForKey:SPDisplayTableViewVerticalGridlines]) ? @"1px solid #CCCCCC" : @"none" forKey:@"gridlines"]; + if (rows) [rows release]; // Process the template and display the results. - NSString *result = [engine processTemplateInFileAtPath:[[NSBundle mainBundle] pathForResource:SPHTMLPrintTemplate ofType:@"html"] withVariables:printData]; + return [engine processTemplateInFileAtPath:[[NSBundle mainBundle] pathForResource:SPHTMLPrintTemplate ofType:@"html"] withVariables:printData]; +} + +/** + * Generates the HTML for the table information view that is to be printed. + */ +- (NSString *)generateTableInfoHTMLForPrinting +{ + // Set up template engine with your chosen matcher + MGTemplateEngine *engine = [MGTemplateEngine templateEngine]; + + [engine setMatcher:[ICUTemplateMatcher matcherWithTemplateEngine:engine]]; - return result; + NSMutableDictionary *connection = [self connectionInformation]; + NSMutableDictionary *printData = [NSMutableDictionary dictionary]; + + NSString *heading = NSLocalizedString(@"Table Information", @"table information print heading"); + + [engine setObject:connection forKey:@"c"]; + [engine setObject:[extendedTableInfoInstance tableInformationForPrinting] forKey:@"i"]; + + [printData setObject:heading forKey:@"heading"]; + [printData setObject:[[NSUnarchiver unarchiveObjectWithData:[prefs objectForKey:SPCustomQueryEditorFont]] fontName] forKey:@"font"]; + + // Process the template and display the results. + return [engine processTemplateInFileAtPath:[[NSBundle mainBundle] pathForResource:SPHTMLTableInfoPrintTemplate ofType:@"html"] withVariables:printData]; } /** @@ -225,25 +235,25 @@ // Table source view if ([tableTabView indexOfTabViewItem:[tableTabView selectedTabViewItem]] == 0 - && [[tableSourceInstance tableSourceForPrinting] count] > 0 ) { + && [[tableSourceInstance tableSourceForPrinting] count] > 0) { columns = [[NSArray alloc] initWithArray:[[[tableSourceInstance tableSourceForPrinting] objectForKey:@"structure"] objectAtIndex:0] copyItems:YES]; } // Table content view else if ([tableTabView indexOfTabViewItem:[tableTabView selectedTabViewItem]] == 1 - && [[tableContentInstance currentResult] count] > 0 ) { + && [[tableContentInstance currentResult] count] > 0) { columns = [[NSArray alloc] initWithArray:[[tableContentInstance currentResult] objectAtIndex:0] copyItems:YES]; } // Custom query view else if ([tableTabView indexOfTabViewItem:[tableTabView selectedTabViewItem]] == 2 - && [[customQueryInstance currentResult] count] > 0 ) { + && [[customQueryInstance currentResult] count] > 0) { columns = [[NSArray alloc] initWithArray:[[customQueryInstance currentResult] objectAtIndex:0] copyItems:YES]; } // Table relations view else if ([tableTabView indexOfTabViewItem:[tableTabView selectedTabViewItem]] == 4 - && [[tableRelationsInstance relationDataForPrinting] count] > 0 ) { + && [[tableRelationsInstance relationDataForPrinting] count] > 0) { columns = [[NSArray alloc] initWithArray:[[tableRelationsInstance relationDataForPrinting] objectAtIndex:0] copyItems:YES]; } @@ -253,4 +263,38 @@ return columns; } +/** + * Generates a dictionary of connection information that is used for printing. + */ +- (NSMutableDictionary *)connectionInformation +{ + NSString *versionForPrint = [NSString stringWithFormat:@"%@ %@ (%@ %@)", + [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"], + [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"], + NSLocalizedString(@"build", @"build label"), + [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"] + ]; + + NSMutableDictionary *connection = [NSMutableDictionary dictionary]; + + if ([[self user] length]) { + [connection setValue:[self user] forKey:@"username"]; + } + + if ([[self table] length]) { + [connection setValue:[self table] forKey:@"table"]; + } + + + if ([connectionController port] && [[connectionController port] length]) { + [connection setValue:[connectionController port] forKey:@"port"]; + } + + [connection setValue:[self host] forKey:@"hostname"]; + [connection setValue:selectedDatabase forKey:@"database"]; + [connection setValue:versionForPrint forKey:@"version"]; + + return connection; +} + @end diff --git a/Source/TableDocument.m b/Source/TableDocument.m index 6d082a59..b32cc2bb 100644 --- a/Source/TableDocument.m +++ b/Source/TableDocument.m @@ -2993,9 +2993,7 @@ } if ([menuItem action] == @selector(printDocument:)) { - return (((([self database] != nil) && - ([[tablesListInstance valueForKeyPath:@"tablesListView"] numberOfSelectedRows] == 1)) || - ([tableWindow firstResponder] == customQueryInstance))); + return (([self database] != nil) && ([[tablesListInstance valueForKeyPath:@"tablesListView"] numberOfSelectedRows] == 1)); } if ([menuItem action] == @selector(chooseEncoding:)) { diff --git a/Source/TableSource.m b/Source/TableSource.m index 05eb0c53..e6d2d170 100644 --- a/Source/TableSource.m +++ b/Source/TableSource.m @@ -1123,10 +1123,12 @@ returns a dictionary containing enum/set field names as key and possible values */ - (NSDictionary *)tableSourceForPrinting { - NSInteger i; + NSInteger i, j; NSMutableArray *tempResult = [NSMutableArray array]; NSMutableArray *tempResult2 = [NSMutableArray array]; + NSString *nullValue = [prefs stringForKey:SPNullValue]; + MCPResult *structureQueryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW COLUMNS FROM %@", [selectedTable backtickQuotedString]]]; MCPResult *indexesQueryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SHOW INDEXES FROM %@", [selectedTable backtickQuotedString]]]; @@ -1138,24 +1140,52 @@ returns a dictionary containing enum/set field names as key and possible values [tempResult addObject:[structureQueryResult fetchFieldNames]]; - NSMutableArray *temp = [[[indexesQueryResult fetchFieldNames] mutableCopy] autorelease]; + NSMutableArray *temp = [[indexesQueryResult fetchFieldNames] mutableCopy]; // Remove the 'table' column [temp removeObjectAtIndex:0]; [tempResult2 addObject:temp]; - for (i = 0 ; i < [structureQueryResult numOfRows]; i++) { - [tempResult addObject:[structureQueryResult fetchRowAsArray]]; + [temp release]; + + for (i = 0; i < [structureQueryResult numOfRows]; i++) { + NSMutableArray *row = [[structureQueryResult fetchRowAsArray] mutableCopy]; + + // For every NULL value replace it with the user's NULL value placeholder so we can actually print it + for (j = 0; j < [row count]; j++) + { + if ([[row objectAtIndex:j] isNSNull]) { + + // Replace the NULL instance with an escaped version of the user's placeholder + [row replaceObjectAtIndex:j withObject:(NSString *)CFXMLCreateStringByEscapingEntities(NULL, ((CFStringRef)nullValue), NULL)]; + } + } + + [tempResult addObject:row]; + + [row release]; } - for (i = 0 ; i < [indexesQueryResult numOfRows]; i++) { - NSMutableArray *index = [[[indexesQueryResult fetchRowAsArray] mutableCopy] autorelease]; + for (i = 0; i < [indexesQueryResult numOfRows]; i++) { + NSMutableArray *index = [[indexesQueryResult fetchRowAsArray] mutableCopy]; // Remove the 'table' column values [index removeObjectAtIndex:0]; + // For every NULL value replace it with the user's NULL value placeholder so we can actually print it + for (j = 0; j < [index count]; j++) + { + if ([[index objectAtIndex:j] isNSNull]) { + + // Replace the NULL instance with an escaped version of the user's placeholder + [index replaceObjectAtIndex:j withObject:(NSString *)CFXMLCreateStringByEscapingEntities(NULL, ((CFStringRef)nullValue), NULL)]; + } + } + [tempResult2 addObject:index]; + + [index release]; } return [NSDictionary dictionaryWithObjectsAndKeys:tempResult, @"structure", tempResult2, @"indexes", nil]; @@ -1271,8 +1301,7 @@ Begin a drag and drop operation from the table - copy a single dragged row to th */ - (BOOL)tableView:(NSTableView *)aTableView writeRowsWithIndexes:(NSIndexSet *)rows toPasteboard:(NSPasteboard*)pboard { - - //make sure that the drag operation is started from the right table view + // Make sure that the drag operation is started from the right table view if (aTableView != tableSourceView) return NO; // Check whether a save of the current field row is required. @@ -1285,7 +1314,6 @@ Begin a drag and drop operation from the table - copy a single dragged row to th } else { return NO; } - } /* diff --git a/sequel-pro.xcodeproj/project.pbxproj b/sequel-pro.xcodeproj/project.pbxproj index d159d629..7954e81a 100644 --- a/sequel-pro.xcodeproj/project.pbxproj +++ b/sequel-pro.xcodeproj/project.pbxproj @@ -61,6 +61,7 @@ 17CC97F710B4AC6C0034CD7A /* AboutPanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = 17CC97F510B4AC6C0034CD7A /* AboutPanel.xib */; }; 17CC993B10B4C9C80034CD7A /* License.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 17CC993A10B4C9C80034CD7A /* License.rtf */; }; 17E090E811498FC9007FC1B4 /* SPPrintController.m in Sources */ = {isa = PBXBuildFile; fileRef = 17E090E711498FC9007FC1B4 /* SPPrintController.m */; }; + 17E0937E114AE154007FC1B4 /* sequel-pro-table-info-print-template.html in Resources */ = {isa = PBXBuildFile; fileRef = 17E0937D114AE154007FC1B4 /* sequel-pro-table-info-print-template.html */; }; 17E641460EF01EB5001BC333 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 17E641440EF01EB5001BC333 /* main.m */; }; 17E641560EF01EF6001BC333 /* CustomQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = 17E641490EF01EF6001BC333 /* CustomQuery.m */; }; 17E641570EF01EF6001BC333 /* SPAppController.m in Sources */ = {isa = PBXBuildFile; fileRef = 17E6414B0EF01EF6001BC333 /* SPAppController.m */; }; @@ -413,6 +414,7 @@ 17DA04EA0FC1A7DA00D66140 /* Unit Tests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Unit Tests-Info.plist"; sourceTree = ""; }; 17E090E611498FC9007FC1B4 /* SPPrintController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPPrintController.h; sourceTree = ""; }; 17E090E711498FC9007FC1B4 /* SPPrintController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPPrintController.m; sourceTree = ""; }; + 17E0937D114AE154007FC1B4 /* sequel-pro-table-info-print-template.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "sequel-pro-table-info-print-template.html"; sourceTree = ""; }; 17E641440EF01EB5001BC333 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 17E641450EF01EB5001BC333 /* sequel-pro_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "sequel-pro_Prefix.pch"; sourceTree = ""; }; 17E641480EF01EF6001BC333 /* CustomQuery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomQuery.h; sourceTree = ""; }; @@ -904,6 +906,7 @@ children = ( BCB56192106F88EC00167321 /* sequel-pro-print-template.html */, BC2C8E210FA8C2DB008468C7 /* sequel-pro-mysql-help-template.html */, + 17E0937D114AE154007FC1B4 /* sequel-pro-table-info-print-template.html */, ); name = Templates; sourceTree = ""; @@ -1676,6 +1679,7 @@ BC5AD7FF10FB262F008769E3 /* field-small-square.tiff in Resources */, BC30C011111C98BD002701C9 /* DataMigrationDialog.xib in Resources */, BC962D661144EACA006170BD /* CompletionTokens.plist in Resources */, + 17E0937E114AE154007FC1B4 /* sequel-pro-table-info-print-template.html in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; -- cgit v1.2.3