diff options
author | Max <post@wickenrode.com> | 2015-11-02 04:18:08 +0100 |
---|---|---|
committer | Max <post@wickenrode.com> | 2015-11-02 04:18:08 +0100 |
commit | 7c7660b66d4c47a43de8b1a42dba6c787b44c0cc (patch) | |
tree | 0fce614edcf1df2ff87db9908c8b837a0ac37e0b | |
parent | f02fb787063caabe246a0ee420394f5676c55a9c (diff) | |
download | sequelpro-7c7660b66d4c47a43de8b1a42dba6c787b44c0cc.tar.gz sequelpro-7c7660b66d4c47a43de8b1a42dba6c787b44c0cc.tar.bz2 sequelpro-7c7660b66d4c47a43de8b1a42dba6c787b44c0cc.zip |
Add a visual indication for the defaults in the encoding/collation menus in table structure view (final part of #2237)
-rw-r--r-- | Interfaces/English.lproj/DBView.xib | 20 | ||||
-rw-r--r-- | Source/SPPillAttachmentCell.h | 53 | ||||
-rw-r--r-- | Source/SPPillAttachmentCell.m | 113 | ||||
-rw-r--r-- | Source/SPTableStructureDelegate.m | 126 | ||||
-rw-r--r-- | sequel-pro.xcodeproj/project.pbxproj | 6 |
5 files changed, 316 insertions, 2 deletions
diff --git a/Interfaces/English.lproj/DBView.xib b/Interfaces/English.lproj/DBView.xib index b89ada7b..d7f22211 100644 --- a/Interfaces/English.lproj/DBView.xib +++ b/Interfaces/English.lproj/DBView.xib @@ -1675,7 +1675,7 @@ <nil key="NSMenuItem"/> <bool key="NSMenuItemRespectAlignment">YES</bool> <object class="NSMenu" key="NSMenu" id="856601787"> - <string key="NSTitle">OtherViews</string> + <string key="NSTitle">encodingPopupMenu</string> <array class="NSMutableArray" key="NSMenuItems"/> </object> <int key="NSSelectedIndex">-1</int> @@ -1717,7 +1717,7 @@ <nil key="NSMenuItem"/> <bool key="NSMenuItemRespectAlignment">YES</bool> <object class="NSMenu" key="NSMenu" id="65801928"> - <string key="NSTitle">OtherViews</string> + <string key="NSTitle">collationPopupMenu</string> <array class="NSMutableArray" key="NSMenuItems"/> </object> <int key="NSSelectedIndex">-1</int> @@ -17353,6 +17353,22 @@ AAEAAQAAAT0AAwAAAAEAAgAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA</bytes> <object class="IBConnectionRecord"> <object class="IBOutletConnection" key="connection"> <string key="label">delegate</string> + <reference key="source" ref="856601787"/> + <reference key="destination" ref="239767357"/> + </object> + <string key="id">Jbs-NM-Lzb</string> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">delegate</string> + <reference key="source" ref="65801928"/> + <reference key="destination" ref="239767357"/> + </object> + <string key="id">Dcc-ay-7AU</string> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">delegate</string> <reference key="source" ref="828624540"/> <reference key="destination" ref="188482031"/> </object> diff --git a/Source/SPPillAttachmentCell.h b/Source/SPPillAttachmentCell.h new file mode 100644 index 00000000..78fe80c2 --- /dev/null +++ b/Source/SPPillAttachmentCell.h @@ -0,0 +1,53 @@ +// +// SPPillAttachmentCell.h +// sequel-pro +// +// Created by Max Lohrmann on 01.11.15. +// Copyright (c) 2015 Max Lohrmann. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// More info at <https://github.com/sequelpro/sequelpro> + +#import <Foundation/Foundation.h> + +/** + * This is a simple TextAttachmentCell which takes the stringValue + * and displays it in a "pill", much like the tokens in an NSTokenTextField. + * + * It is designed to be used with static labels rather than inside user input text fields. + * + * To use it: + * + * NSTextAttachment *attachment = [[NSTextAttachment alloc] init]; + * SPPillAttachmentCell *cell = [[SPPillAttachmentCell alloc] init]; + * [cell setStringValue:@"..."]; + * [attachment setAttachmentCell:[cell autorelease]; + * NSAttributedString *att = [NSAttributedString attributedStringWithAttachment:[attachment autorelease]]; + * [otherAttributedString appendAttributedString:att]; + * + */ +@interface SPPillAttachmentCell : NSTextAttachmentCell { + NSColor *_borderColor; + NSGradient *_gradient; +} +@end diff --git a/Source/SPPillAttachmentCell.m b/Source/SPPillAttachmentCell.m new file mode 100644 index 00000000..77f6c734 --- /dev/null +++ b/Source/SPPillAttachmentCell.m @@ -0,0 +1,113 @@ +// +// SPPillAttachmentCell.m +// sequel-pro +// +// Created by Max Lohrmann on 01.11.15. +// Copyright (c) 2015 Max Lohrmann. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// More info at <https://github.com/sequelpro/sequelpro> + +#import "SPPillAttachmentCell.h" + + +@implementation SPPillAttachmentCell + +- (id)init +{ + if(self = [super init]) { + _borderColor = [[NSColor colorWithCalibratedRed:168/255.0 green:184/255.0 blue:249/255.0 alpha: 1] retain]; + _gradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithCalibratedRed:199/255.0 green:216/255.0 blue:244/255.0 alpha: 1] + endingColor:[NSColor colorWithCalibratedRed:217/255.0 green:229/255.0 blue:247/255.0 alpha: 1]]; + } + return self; +} + +- (void)dealloc +{ + SPClear(_borderColor); + SPClear(_gradient); + + [super dealloc]; +} + +- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView +{ + [self drawWithFrame:cellFrame inView:controlView characterIndex:NSNotFound]; +} + +- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView characterIndex:(NSUInteger)charIndex +{ + [self drawWithFrame:cellFrame inView:controlView characterIndex:charIndex layoutManager:nil]; +} + +- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView characterIndex:(NSUInteger)charIndex layoutManager:(NSLayoutManager *)layoutManager +{ + CGFloat bRadius = cellFrame.size.height/2.0; + NSBezierPath* rectanglePath = [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(cellFrame,1,1) xRadius:bRadius yRadius:bRadius]; + [_gradient drawInBezierPath: rectanglePath angle: -90]; + [_borderColor setStroke]; + [rectanglePath setLineWidth:1.0]; + [rectanglePath stroke]; + + [self drawInteriorWithFrame:cellFrame inView:controlView]; +} + +- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView +{ + NSString* textContent = [self stringValue]; + NSMutableParagraphStyle* rectangleStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy]; + [rectangleStyle setAlignment:NSCenterTextAlignment]; + + NSMutableDictionary *rectangleFontAttributes = [NSMutableDictionary dictionaryWithDictionary:[self attributes]]; + [rectangleFontAttributes setObject:[rectangleStyle autorelease] forKey:NSParagraphStyleAttributeName]; + + //cellFrame.origin.y += [[self font] descender]; + [textContent drawInRect:cellFrame withAttributes:rectangleFontAttributes]; +} + +- (NSPoint)cellBaselineOffset +{ + //Not used in menu + return NSMakePoint(0, [[self font] descender]-1); +} + +- (NSRect)cellFrameForTextContainer:(NSTextContainer *)textContainer proposedLineFragment:(NSRect)lineFrag glyphPosition:(NSPoint)position characterIndex:(NSUInteger)charIndex +{ + NSSize sz = [self cellSize]; + CGFloat offset = (lineFrag.size.height - sz.height) / 2; + return NSMakeRect(0, [[self font] descender]+offset, sz.width+(2*12), sz.height); +} + +- (NSSize)cellSize +{ + //Not used in menu + return [[self stringValue] sizeWithAttributes:[self attributes]]; +} + +- (NSDictionary *)attributes +{ + return @{NSFontAttributeName: [self font],NSForegroundColorAttributeName: [NSColor controlTextColor]}; +} + +@end diff --git a/Source/SPTableStructureDelegate.m b/Source/SPTableStructureDelegate.m index 4bfd84c8..62485b26 100644 --- a/Source/SPTableStructureDelegate.m +++ b/Source/SPTableStructureDelegate.m @@ -38,9 +38,27 @@ #import "SPTableStructureLoading.h" #import "SPServerSupport.h" #import "SPTablesList.h" +#import "SPPillAttachmentCell.h" #import <SPMySQL/SPMySQL.h> +struct _cmpMap { + NSString *title; // the title of the "pill" + NSString *tooltipPart; // the tooltip of the menuitem + NSString *cmpWith; // the string to match against +}; + +/** + * This function will compare the representedObject of every item in menu against + * every map->cmpWith. If they match it will append a pill-like (similar to a TokenFieldCell's token) + * element labelled map->title to the menu item's title. If map->tooltipPart is set, + * it will also be added to the menu item's tooltip. + * + * This is used with the encoding/collation popup menus to add visual indicators for the + * table-level and default encoding/collation. + */ +static void _BuildMenuWithPills(NSMenu *menu,struct _cmpMap *map,size_t mapEntries); + @interface SPTableStructure (PrivateAPI) - (void)sheetDidEnd:(id)sheet returnCode:(NSInteger)returnCode contextInfo:(NSString *)contextInfo; @@ -69,6 +87,7 @@ NSString *columnEncoding = [rowData objectForKey:@"encodingName"]; NSString *columnCollation = [rowData objectForKey:@"collationName"]; // loadTable: has already inferred it, if not set explicit +#warning Building the collation menu here is a big performance hog. This should be done in menuNeedsUpdate: below! NSPopUpButtonCell *collationCell = [tableColumn dataCell]; [collationCell removeAllItems]; [collationCell addItemWithTitle:@"dummy"]; @@ -698,4 +717,111 @@ return @""; } +#pragma mark - +#pragma mark Menu delegate methods (encoding/collation dropdown menu) + +- (void)menuNeedsUpdate:(NSMenu *)menu +{ + //NOTE: NSTableView will usually copy the menu and call this method on the copy. Matching with == won't work! + + //walk through the menu and clear the attributedTitle if set. This will remove the gray color from the default items + for(NSMenuItem *item in [menu itemArray]) { + if([item attributedTitle]) { + [item setAttributedTitle:nil]; + } + } + + NSDictionary *rowData = NSArrayObjectAtIndex(tableFields, [tableSourceView selectedRow]); + + if([[menu title] isEqualToString:@"encodingPopupMenu"]) { + NSString *tableEncoding = [tableDataInstance tableEncoding]; + //NSString *databaseEncoding = [databaseDataInstance getDatabaseDefaultCharacterSet]; + //NSString *serverEncoding = [databaseDataInstance getServerDefaultCharacterSet]; + + struct _cmpMap defaultCmp[] = { + { + NSLocalizedString(@"Table",@"Table Structure : Encoding dropdown : 'item is table default' marker"), + [NSString stringWithFormat:NSLocalizedString(@"This is the default encoding of table “%@”.", @"Table Structure : Encoding dropdown : table marker tooltip"),selectedTable], + tableEncoding + }, + /* //we could, but that might confuse users even more plus there is no inheritance between a columns charset and the db/server default + { + NSLocalizedString(@"Database",@"Table Structure : Encoding dropdown : 'item is database default' marker"), + [NSString stringWithFormat:NSLocalizedString(@"This is the default encoding of database “%@”.", @"Table Structure : Encoding dropdown : database marker tooltip"),[tableDocumentInstance database]], + databaseEncoding + }, + { + NSLocalizedString(@"Server",@"Table Structure : Encoding dropdown : 'item is server default' marker"), + NSLocalizedString(@"This is the default encoding of this server.", @"Table Structure : Encoding dropdown : server marker tooltip"), + serverEncoding + } */ + }; + + _BuildMenuWithPills(menu, defaultCmp, COUNT_OF(defaultCmp)); + } + else if([[menu title] isEqualToString:@"collationPopupMenu"]) { + NSString *encoding = [rowData objectForKey:@"encodingName"]; + NSString *encodingDefaultCollation = [databaseDataInstance getDefaultCollationForEncoding:encoding]; + NSString *tableCollation = [tableDataInstance statusValueForKey:@"Collation"]; + //NSString *databaseCollation = [databaseDataInstance getDatabaseDefaultCollation]; + //NSString *serverCollation = [databaseDataInstance getServerDefaultCollation]; + + struct _cmpMap defaultCmp[] = { + { + NSLocalizedString(@"Default",@"Table Structure : Collation dropdown : 'item is the same as the default collation of the row's charset' marker"), + [NSString stringWithFormat:NSLocalizedString(@"This is the default collation of encoding “%@”.", @"Table Structure : Collation dropdown : default marker tooltip"),encoding], + encodingDefaultCollation + }, + { + NSLocalizedString(@"Table",@"Table Structure : Collation dropdown : 'item is the same as the collation of table' marker"), + [NSString stringWithFormat:NSLocalizedString(@"This is the default collation of table “%@”.", @"Table Structure : Collation dropdown : table marker tooltip"),selectedTable], + tableCollation + }, + /* // see the comment for charset above + { + NSLocalizedString(@"Database",@"Table Structure : Collation dropdown : 'item is the same as the collation of database' marker"), + [NSString stringWithFormat:NSLocalizedString(@"This is the default collation of database “%@”.", @"Table Structure : Collation dropdown : database marker tooltip"),[tableDocumentInstance database]], + databaseCollation + }, + { + NSLocalizedString(@"Server",@"Table Structure : Collation dropdown : 'item is the same as the collation of server' marker"), + NSLocalizedString(@"This is the default collation of this server.", @"Table Structure : Collation dropdown : server marker tooltip"), + serverCollation + } */ + }; + + _BuildMenuWithPills(menu, defaultCmp, COUNT_OF(defaultCmp)); + } +} + @end + +void _BuildMenuWithPills(NSMenu *menu,struct _cmpMap *map,size_t mapEntries) +{ + NSDictionary *baseAttrs = @{NSFontAttributeName:[menu font],NSParagraphStyleAttributeName: [NSParagraphStyle defaultParagraphStyle]}; + + for(NSMenuItem *item in [menu itemArray]) { + NSMutableAttributedString *itemStr = [[NSMutableAttributedString alloc] initWithString:[item title] attributes:baseAttrs]; + NSString *value = [item representedObject]; + + NSMutableArray *tooltipParts = [NSMutableArray array]; + for (unsigned int i = 0; i < mapEntries; ++i) { + struct _cmpMap *cmp = &map[i]; + if([cmp->cmpWith isEqualToString:value]) { + SPPillAttachmentCell *cell = [[SPPillAttachmentCell alloc] init]; + [cell setStringValue:cmp->title]; + NSTextAttachment *attachment = [[NSTextAttachment alloc] init]; + [attachment setAttachmentCell:[cell autorelease]]; + NSAttributedString *attachmentString = [NSAttributedString attributedStringWithAttachment:[attachment autorelease]]; + + [[itemStr mutableString] appendString:@" "]; + [itemStr appendAttributedString:attachmentString]; + + if(cmp->tooltipPart) [tooltipParts addObject:cmp->tooltipPart]; + } + } + if([tooltipParts count]) [item setToolTip:[tooltipParts componentsJoinedByString:@" "]]; + + [item setAttributedTitle:[itemStr autorelease]]; + } +} diff --git a/sequel-pro.xcodeproj/project.pbxproj b/sequel-pro.xcodeproj/project.pbxproj index e836efe3..44fe6ecc 100644 --- a/sequel-pro.xcodeproj/project.pbxproj +++ b/sequel-pro.xcodeproj/project.pbxproj @@ -155,6 +155,7 @@ 17F90E481210B42700274C98 /* SPExportFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 17F90E471210B42700274C98 /* SPExportFile.m */; }; 17F90E4B1210B43A00274C98 /* SPExportFileUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 17F90E4A1210B43A00274C98 /* SPExportFileUtilities.m */; }; 17FDB04C1280778B00DBBBC2 /* SPFontPreviewTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 17FDB04B1280778B00DBBBC2 /* SPFontPreviewTextField.m */; }; + 1A564F74237E2E4958CA593A /* SPPillAttachmentCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A56463D14569A0B56EE8BAC /* SPPillAttachmentCell.m */; }; 296DC89F0F8FD336002A3258 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 296DC89E0F8FD336002A3258 /* WebKit.framework */; }; 296DC8B60F909194002A3258 /* MGTemplateEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = 296DC8A70F909194002A3258 /* MGTemplateEngine.m */; }; 296DC8B70F909194002A3258 /* RegexKitLite.m in Sources */ = {isa = PBXBuildFile; fileRef = 296DC8AB0F909194002A3258 /* RegexKitLite.m */; }; @@ -859,6 +860,8 @@ 17F90E4A1210B43A00274C98 /* SPExportFileUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPExportFileUtilities.m; sourceTree = "<group>"; }; 17FDB04A1280778B00DBBBC2 /* SPFontPreviewTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPFontPreviewTextField.h; sourceTree = "<group>"; }; 17FDB04B1280778B00DBBBC2 /* SPFontPreviewTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPFontPreviewTextField.m; sourceTree = "<group>"; }; + 1A56463D14569A0B56EE8BAC /* SPPillAttachmentCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPPillAttachmentCell.m; sourceTree = "<group>"; }; + 1A564C0C0FFB444D2E5CA447 /* SPPillAttachmentCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPPillAttachmentCell.h; sourceTree = "<group>"; }; 296DC89E0F8FD336002A3258 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = /System/Library/Frameworks/WebKit.framework; sourceTree = "<absolute>"; }; 296DC8A50F909194002A3258 /* MGTemplateMarker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGTemplateMarker.h; sourceTree = "<group>"; }; 296DC8A60F909194002A3258 /* MGTemplateFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGTemplateFilter.h; sourceTree = "<group>"; }; @@ -1441,6 +1444,8 @@ B57747DB0F7A89D0003B34F9 /* SPFavoriteTextFieldCell.m */, BC5750D412A6233900911BA2 /* SPActivityTextFieldCell.h */, BC5750D312A6233900911BA2 /* SPActivityTextFieldCell.m */, + 1A56463D14569A0B56EE8BAC /* SPPillAttachmentCell.m */, + 1A564C0C0FFB444D2E5CA447 /* SPPillAttachmentCell.h */, ); name = Cells; sourceTree = "<group>"; @@ -3348,6 +3353,7 @@ 501B1D181728A3DA0017C92E /* SPCharsetCollationHelper.m in Sources */, 50E217B318174246009D3580 /* SPColorSelectorView.m in Sources */, 50E217B618174280009D3580 /* SPFavoriteColorSupport.m in Sources */, + 1A564F74237E2E4958CA593A /* SPPillAttachmentCell.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; |