aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax <post@wickenrode.com>2015-11-02 04:18:08 +0100
committerMax <post@wickenrode.com>2015-11-02 04:18:08 +0100
commit7c7660b66d4c47a43de8b1a42dba6c787b44c0cc (patch)
tree0fce614edcf1df2ff87db9908c8b837a0ac37e0b
parentf02fb787063caabe246a0ee420394f5676c55a9c (diff)
downloadsequelpro-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.xib20
-rw-r--r--Source/SPPillAttachmentCell.h53
-rw-r--r--Source/SPPillAttachmentCell.m113
-rw-r--r--Source/SPTableStructureDelegate.m126
-rw-r--r--sequel-pro.xcodeproj/project.pbxproj6
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;
};