aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrowanbeentje <rowan@beent.je>2009-04-16 23:21:40 +0000
committerrowanbeentje <rowan@beent.je>2009-04-16 23:21:40 +0000
commit93bf3137c544b66a84a5a780264abef960f8a1b9 (patch)
tree9a5a3f9a1bd4712639528a8f26242ea5d6fb0b37
parent4051d858d9e189b7c5bd0919e0bf952cb42898b8 (diff)
downloadsequelpro-93bf3137c544b66a84a5a780264abef960f8a1b9.tar.gz
sequelpro-93bf3137c544b66a84a5a780264abef960f8a1b9.tar.bz2
sequelpro-93bf3137c544b66a84a5a780264abef960f8a1b9.zip
- Implement line numbering for CMTextView:
- Add an implementation of NoodleLineNumberView, by Paul Kim. Slightly tweaked to remove markers. - Add to CMTextView (to enable it for other CMTextView uses, hook up the scrollView outlet to the containing scroll view)
-rw-r--r--Interfaces/English.lproj/Credits.rtf2
-rw-r--r--Interfaces/English.lproj/DBView.xib28
-rw-r--r--Source/CMTextView.h4
-rw-r--r--Source/CMTextView.m6
-rw-r--r--Source/NoodleLineNumberView.h60
-rw-r--r--Source/NoodleLineNumberView.m493
-rw-r--r--sequel-pro.xcodeproj/project.pbxproj6
7 files changed, 584 insertions, 15 deletions
diff --git a/Interfaces/English.lproj/Credits.rtf b/Interfaces/English.lproj/Credits.rtf
index 731fa4d2..2f5301ee 100644
--- a/Interfaces/English.lproj/Credits.rtf
+++ b/Interfaces/English.lproj/Credits.rtf
@@ -1,7 +1,6 @@
{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf430
{\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
{\colortbl;\red255\green255\blue255;\red25\green25\blue25;\red0\green27\blue199;}
-\vieww9000\viewh8400\viewkind0
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\qc\pardirnatural
\f0\b\fs22 \cf2 Current Developers
@@ -40,6 +39,7 @@ Jason Hallford\
Carsten Bl\'fcm\
Andrea Salomoni\
Greg Hulands\
+Paul Kim (NoodleLineNumberView)\
\
\b Artwork
diff --git a/Interfaces/English.lproj/DBView.xib b/Interfaces/English.lproj/DBView.xib
index 60a03b6a..e318b30c 100644
--- a/Interfaces/English.lproj/DBView.xib
+++ b/Interfaces/English.lproj/DBView.xib
@@ -8,7 +8,6 @@
<string key="IBDocument.HIToolboxVersion">353.00</string>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="40"/>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -175,7 +174,6 @@
</object>
<string key="NSFrame">{{1, 1}, {194, 393}}</string>
<reference key="NSSuperview" ref="233472824"/>
- <reference key="NSNextKeyView" ref="251040077"/>
<reference key="NSDocView" ref="251040077"/>
<object class="NSColor" key="NSBGColor" id="1024678221">
<int key="NSColorSpace">6</int>
@@ -207,7 +205,6 @@
</object>
<string key="NSFrameSize">{196, 395}</string>
<reference key="NSSuperview" ref="355288374"/>
- <reference key="NSNextKeyView" ref="73685676"/>
<int key="NSsFlags">530</int>
<reference key="NSVScroller" ref="693168867"/>
<reference key="NSHScroller" ref="656188692"/>
@@ -292,7 +289,6 @@
</object>
<string key="NSFrame">{{1, 1}, {194, 123}}</string>
<reference key="NSSuperview" ref="298226231"/>
- <reference key="NSNextKeyView" ref="347093764"/>
<reference key="NSDocView" ref="347093764"/>
<reference key="NSBGColor" ref="1024678221"/>
<int key="NScvFlags">4</int>
@@ -319,7 +315,6 @@
</object>
<string key="NSFrame">{{0, 404}, {196, 125}}</string>
<reference key="NSSuperview" ref="355288374"/>
- <reference key="NSNextKeyView" ref="685057119"/>
<int key="NSsFlags">530</int>
<reference key="NSVScroller" ref="245346414"/>
<reference key="NSHScroller" ref="353686052"/>
@@ -1246,7 +1241,6 @@
</object>
<string key="NSFrame">{{1, 17}, {625, 289}}</string>
<reference key="NSSuperview" ref="22340145"/>
- <reference key="NSNextKeyView" ref="715508012"/>
<reference key="NSDocView" ref="715508012"/>
<reference key="NSBGColor" ref="1024678221"/>
<int key="NScvFlags">4</int>
@@ -1279,7 +1273,6 @@
</object>
<string key="NSFrame">{{1, 0}, {625, 17}}</string>
<reference key="NSSuperview" ref="22340145"/>
- <reference key="NSNextKeyView" ref="926883367"/>
<reference key="NSDocView" ref="926883367"/>
<reference key="NSBGColor" ref="1024678221"/>
<int key="NScvFlags">4</int>
@@ -1288,7 +1281,6 @@
</object>
<string key="NSFrame">{{-1, 22}, {627, 307}}</string>
<reference key="NSSuperview" ref="220777809"/>
- <reference key="NSNextKeyView" ref="16936123"/>
<int key="NSsFlags">562</int>
<reference key="NSVScroller" ref="943144555"/>
<reference key="NSHScroller" ref="456666876"/>
@@ -1722,7 +1714,6 @@
</object>
<string key="NSFrame">{{1, 17}, {625, 141}}</string>
<reference key="NSSuperview" ref="376224367"/>
- <reference key="NSNextKeyView" ref="584834515"/>
<reference key="NSDocView" ref="584834515"/>
<reference key="NSBGColor" ref="1024678221"/>
<int key="NScvFlags">4</int>
@@ -1755,7 +1746,6 @@
</object>
<string key="NSFrame">{{1, 0}, {625, 17}}</string>
<reference key="NSSuperview" ref="376224367"/>
- <reference key="NSNextKeyView" ref="459548655"/>
<reference key="NSDocView" ref="459548655"/>
<reference key="NSBGColor" ref="1024678221"/>
<int key="NScvFlags">4</int>
@@ -1764,7 +1754,6 @@
</object>
<string key="NSFrame">{{-1, 22}, {627, 159}}</string>
<reference key="NSSuperview" ref="1063281455"/>
- <reference key="NSNextKeyView" ref="794929378"/>
<int key="NSsFlags">562</int>
<reference key="NSVScroller" ref="1019209947"/>
<reference key="NSHScroller" ref="328951385"/>
@@ -3696,7 +3685,7 @@
<string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string>
<string key="NSWindowContentMinSize">{256, 191}</string>
<object class="NSView" key="NSWindowView" id="586457094">
- <reference key="NSNextResponder"/>
+ <nil key="NSNextResponder"/>
<int key="NSvFlags">256</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -4321,7 +4310,6 @@
</object>
</object>
<string key="NSFrameSize">{519, 347}</string>
- <reference key="NSSuperview"/>
</object>
<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
<string key="NSMinSize">{256, 213}</string>
@@ -12602,6 +12590,14 @@ IGRvIHlvdSB3YW50IHRvIGFkZCBmb3IgdGhpcyBmaWVsZD8</string>
</object>
<int key="connectionID">5406</int>
</object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">scrollView</string>
+ <reference key="source" ref="1055190999"/>
+ <reference key="destination" ref="71560786"/>
+ </object>
+ <int key="connectionID">5410</int>
+ </object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@@ -20877,7 +20873,7 @@ Y2hhbmdlIHRoZSBvcmRlcg</string>
</object>
</object>
<nil key="sourceID"/>
- <int key="maxID">5408</int>
+ <int key="maxID">5410</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -20925,6 +20921,10 @@ Y2hhbmdlIHRoZSBvcmRlcg</string>
<object class="IBPartialClassDescription">
<string key="className">CMTextView</string>
<string key="superclassName">NSTextView</string>
+ <object class="NSMutableDictionary" key="outlets">
+ <string key="NS.key.0">scrollView</string>
+ <string key="NS.object.0">NSScrollView</string>
+ </object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">Source/CMTextView.h</string>
diff --git a/Source/CMTextView.h b/Source/CMTextView.h
index b9787dfc..55bff15f 100644
--- a/Source/CMTextView.h
+++ b/Source/CMTextView.h
@@ -22,6 +22,7 @@
// Or mail to <lorenz@textor.ch>
#import <Cocoa/Cocoa.h>
+#import "NoodleLineNumberView.h"
@interface CMTextView : NSTextView {
BOOL autoindentEnabled;
@@ -29,6 +30,9 @@
BOOL autoindentIgnoresEnter;
BOOL autouppercaseKeywordsEnabled;
BOOL delBackwardsWasPressed;
+ NoodleLineNumberView *lineNumberView;
+
+ IBOutlet NSScrollView *scrollView;
}
- (BOOL) isNextCharMarkedBy:(id)attribute;
diff --git a/Source/CMTextView.m b/Source/CMTextView.m
index f0f1567c..427c66d1 100644
--- a/Source/CMTextView.m
+++ b/Source/CMTextView.m
@@ -1277,6 +1277,12 @@ SYNTAX HIGHLIGHTING!
autoindentIgnoresEnter = NO;
autouppercaseKeywordsEnabled = YES;
delBackwardsWasPressed = NO;
+
+ lineNumberView = [[NoodleLineNumberView alloc] initWithScrollView:scrollView];
+ [scrollView setVerticalRulerView:lineNumberView];
+ [scrollView setHasHorizontalRuler:NO];
+ [scrollView setHasVerticalRuler:YES];
+ [scrollView setRulersVisible:YES];
}
- (void)textStorageDidProcessEditing:(NSNotification *)notification
diff --git a/Source/NoodleLineNumberView.h b/Source/NoodleLineNumberView.h
new file mode 100644
index 00000000..ca734a56
--- /dev/null
+++ b/Source/NoodleLineNumberView.h
@@ -0,0 +1,60 @@
+//
+// NoodleLineNumberView.h
+// Line View Test
+//
+// Created by Paul Kim on 9/28/08.
+// Copyright (c) 2008 Noodlesoft, LLC. 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.
+//
+
+#import <Cocoa/Cocoa.h>
+
+@class NoodleLineNumberMarker;
+
+@interface NoodleLineNumberView : NSRulerView
+{
+ // Array of character indices for the beginning of each line
+ NSMutableArray *lineIndices;
+ NSFont *font;
+ NSColor *textColor;
+ NSColor *alternateTextColor;
+ NSColor *backgroundColor;
+}
+
+- (id)initWithScrollView:(NSScrollView *)aScrollView;
+
+- (void)setFont:(NSFont *)aFont;
+- (NSFont *)font;
+
+- (void)setTextColor:(NSColor *)color;
+- (NSColor *)textColor;
+
+- (void)setAlternateTextColor:(NSColor *)color;
+- (NSColor *)alternateTextColor;
+
+- (void)setBackgroundColor:(NSColor *)color;
+- (NSColor *)backgroundColor;
+
+- (unsigned)lineNumberForLocation:(float)location;
+
+@end
diff --git a/Source/NoodleLineNumberView.m b/Source/NoodleLineNumberView.m
new file mode 100644
index 00000000..c5d76187
--- /dev/null
+++ b/Source/NoodleLineNumberView.m
@@ -0,0 +1,493 @@
+//
+// NoodleLineNumberView.m
+// Line View Test
+//
+// Created by Paul Kim on 9/28/08.
+// Copyright (c) 2008 Noodlesoft, LLC. 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.
+//
+
+// This version of the NoodleLineNumberView for Sequel Pro removes marker
+// functionality.
+
+#import "NoodleLineNumberView.h"
+
+#define DEFAULT_THICKNESS 22.0
+#define RULER_MARGIN 5.0
+
+@interface NoodleLineNumberView (Private)
+
+- (NSMutableArray *)lineIndices;
+- (void)invalidateLineIndices;
+- (void)calculateLines;
+- (unsigned)lineNumberForCharacterIndex:(unsigned)index inText:(NSString *)text;
+- (NSDictionary *)textAttributes;
+
+@end
+
+@implementation NoodleLineNumberView
+
+- (id)initWithScrollView:(NSScrollView *)aScrollView
+{
+ if ((self = [super initWithScrollView:aScrollView orientation:NSVerticalRuler]) != nil)
+ {
+ [self setClientView:[aScrollView documentView]];
+ }
+ return self;
+}
+
+- (void)awakeFromNib
+{
+ [self setClientView:[[self scrollView] documentView]];
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ [lineIndices release];
+ [font release];
+
+ [super dealloc];
+}
+
+- (void)setFont:(NSFont *)aFont
+{
+ if (font != aFont)
+ {
+ [font autorelease];
+ font = [aFont retain];
+ }
+}
+
+- (NSFont *)font
+{
+ if (font == nil)
+ {
+ return [NSFont labelFontOfSize:[NSFont systemFontSizeForControlSize:NSMiniControlSize]];
+ }
+ return font;
+}
+
+- (void)setTextColor:(NSColor *)color
+{
+ if (textColor != color)
+ {
+ [textColor autorelease];
+ textColor = [color retain];
+ }
+}
+
+- (NSColor *)textColor
+{
+ if (textColor == nil)
+ {
+ return [NSColor colorWithCalibratedWhite:0.42 alpha:1.0];
+ }
+ return textColor;
+}
+
+- (void)setAlternateTextColor:(NSColor *)color
+{
+ if (alternateTextColor != color)
+ {
+ [alternateTextColor autorelease];
+ alternateTextColor = [color retain];
+ }
+}
+
+- (NSColor *)alternateTextColor
+{
+ if (alternateTextColor == nil)
+ {
+ return [NSColor whiteColor];
+ }
+ return alternateTextColor;
+}
+
+- (void)setBackgroundColor:(NSColor *)color
+{
+ if (backgroundColor != color)
+ {
+ [backgroundColor autorelease];
+ backgroundColor = [color retain];
+ }
+}
+
+- (NSColor *)backgroundColor
+{
+ return backgroundColor;
+}
+
+- (void)setClientView:(NSView *)aView
+{
+ id oldClientView;
+
+ oldClientView = [self clientView];
+
+ if ((oldClientView != aView) && [oldClientView isKindOfClass:[NSTextView class]])
+ {
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:NSTextStorageDidProcessEditingNotification object:[(NSTextView *)oldClientView textStorage]];
+ }
+ [super setClientView:aView];
+ if ((aView != nil) && [aView isKindOfClass:[NSTextView class]])
+ {
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange:) name:NSTextStorageDidProcessEditingNotification object:[(NSTextView *)aView textStorage]];
+
+ [self invalidateLineIndices];
+ }
+}
+
+- (NSMutableArray *)lineIndices
+{
+ if (lineIndices == nil)
+ {
+ [self calculateLines];
+ }
+ return lineIndices;
+}
+
+- (void)invalidateLineIndices
+{
+ [lineIndices release];
+ lineIndices = nil;
+}
+
+- (void)textDidChange:(NSNotification *)notification
+{
+ // Invalidate the line indices. They will be recalculated and recached on demand.
+ [self invalidateLineIndices];
+
+ [self setNeedsDisplay:YES];
+}
+
+- (unsigned)lineNumberForLocation:(float)location
+{
+ unsigned line, count, index, rectCount, i;
+ NSRectArray rects;
+ NSRect visibleRect;
+ NSLayoutManager *layoutManager;
+ NSTextContainer *container;
+ NSRange nullRange;
+ NSMutableArray *lines;
+ id view;
+
+ view = [self clientView];
+ visibleRect = [[[self scrollView] contentView] bounds];
+
+ lines = [self lineIndices];
+
+ location += NSMinY(visibleRect);
+
+ if ([view isKindOfClass:[NSTextView class]])
+ {
+ nullRange = NSMakeRange(NSNotFound, 0);
+ layoutManager = [view layoutManager];
+ container = [view textContainer];
+ count = [lines count];
+
+ for (line = 0; line < count; line++)
+ {
+ index = [[lines objectAtIndex:line] unsignedIntValue];
+
+ rects = [layoutManager rectArrayForCharacterRange:NSMakeRange(index, 0)
+ withinSelectedCharacterRange:nullRange
+ inTextContainer:container
+ rectCount:&rectCount];
+
+ for (i = 0; i < rectCount; i++)
+ {
+ if ((location >= NSMinY(rects[i])) && (location < NSMaxY(rects[i])))
+ {
+ return line + 1;
+ }
+ }
+ }
+ }
+ return NSNotFound;
+}
+
+- (void)calculateLines
+{
+ id view;
+
+ view = [self clientView];
+
+ if ([view isKindOfClass:[NSTextView class]])
+ {
+ unsigned index, numberOfLines, stringLength, lineEnd, contentEnd;
+ NSString *text;
+ float oldThickness, newThickness;
+
+ text = [view string];
+ stringLength = [text length];
+ [lineIndices release];
+ lineIndices = [[NSMutableArray alloc] init];
+
+ index = 0;
+ numberOfLines = 0;
+
+ do
+ {
+ [lineIndices addObject:[NSNumber numberWithUnsignedInt:index]];
+
+ index = NSMaxRange([text lineRangeForRange:NSMakeRange(index, 0)]);
+ numberOfLines++;
+ }
+ while (index < stringLength);
+
+ // Check if text ends with a new line.
+ [text getLineStart:NULL end:&lineEnd contentsEnd:&contentEnd forRange:NSMakeRange([[lineIndices lastObject] unsignedIntValue], 0)];
+ if (contentEnd < lineEnd)
+ {
+ [lineIndices addObject:[NSNumber numberWithUnsignedInt:index]];
+ }
+
+ oldThickness = [self ruleThickness];
+ newThickness = [self requiredThickness];
+ if (fabs(oldThickness - newThickness) > 1)
+ {
+ NSInvocation *invocation;
+
+ // Not a good idea to resize the view during calculations (which can happen during
+ // display). Do a delayed perform (using NSInvocation since arg is a float).
+ invocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(setRuleThickness:)]];
+ [invocation setSelector:@selector(setRuleThickness:)];
+ [invocation setTarget:self];
+ [invocation setArgument:&newThickness atIndex:2];
+
+ [invocation performSelector:@selector(invoke) withObject:nil afterDelay:0.0];
+ }
+ }
+}
+
+- (unsigned)lineNumberForCharacterIndex:(unsigned)index inText:(NSString *)text
+{
+ unsigned left, right, mid, lineStart;
+ NSMutableArray *lines;
+
+ lines = [self lineIndices];
+
+ // Binary search
+ left = 0;
+ right = [lines count];
+
+ while ((right - left) > 1)
+ {
+ mid = (right + left) / 2;
+ lineStart = [[lines objectAtIndex:mid] unsignedIntValue];
+
+ if (index < lineStart)
+ {
+ right = mid;
+ }
+ else if (index > lineStart)
+ {
+ left = mid;
+ }
+ else
+ {
+ return mid;
+ }
+ }
+ return left;
+}
+
+- (NSDictionary *)textAttributes
+{
+ return [NSDictionary dictionaryWithObjectsAndKeys:
+ [self font], NSFontAttributeName,
+ [self textColor], NSForegroundColorAttributeName,
+ nil];
+}
+
+- (float)requiredThickness
+{
+ unsigned lineCount, digits, i;
+ NSMutableString *sampleString;
+ NSSize stringSize;
+
+ lineCount = [[self lineIndices] count];
+ digits = (unsigned)log10(lineCount) + 1;
+ sampleString = [NSMutableString string];
+ for (i = 0; i < digits; i++)
+ {
+ // Use "8" since it is one of the fatter numbers. Anything but "1"
+ // will probably be ok here. I could be pedantic and actually find the fattest
+ // number for the current font but nah.
+ [sampleString appendString:@"8"];
+ }
+
+ stringSize = [sampleString sizeWithAttributes:[self textAttributes]];
+
+ // Round up the value. There is a bug on 10.4 where the display gets all wonky when scrolling if you don't
+ // return an integral value here.
+ return ceilf(MAX(DEFAULT_THICKNESS, stringSize.width + RULER_MARGIN * 2));
+}
+
+- (void)drawHashMarksAndLabelsInRect:(NSRect)aRect
+{
+ id view;
+ NSRect bounds;
+
+ bounds = [self bounds];
+
+ if (backgroundColor != nil)
+ {
+ [backgroundColor set];
+ NSRectFill(bounds);
+
+ [[NSColor colorWithCalibratedWhite:0.58 alpha:1.0] set];
+ [NSBezierPath strokeLineFromPoint:NSMakePoint(NSMaxX(bounds) - 0/5, NSMinY(bounds)) toPoint:NSMakePoint(NSMaxX(bounds) - 0.5, NSMaxY(bounds))];
+ }
+
+ view = [self clientView];
+
+ if ([view isKindOfClass:[NSTextView class]])
+ {
+ NSLayoutManager *layoutManager;
+ NSTextContainer *container;
+ NSRect visibleRect;
+ NSRange range, glyphRange, nullRange;
+ NSString *text, *labelText;
+ unsigned rectCount, index, line, count;
+ NSRectArray rects;
+ float ypos, yinset;
+ NSDictionary *textAttributes, *currentTextAttributes;
+ NSSize stringSize;
+ NSMutableArray *lines;
+
+ layoutManager = [view layoutManager];
+ container = [view textContainer];
+ text = [view string];
+ nullRange = NSMakeRange(NSNotFound, 0);
+
+ yinset = [view textContainerInset].height;
+ visibleRect = [[[self scrollView] contentView] bounds];
+
+ textAttributes = [self textAttributes];
+
+ lines = [self lineIndices];
+
+ // Find the characters that are currently visible
+ glyphRange = [layoutManager glyphRangeForBoundingRect:visibleRect inTextContainer:container];
+ range = [layoutManager characterRangeForGlyphRange:glyphRange actualGlyphRange:NULL];
+
+ // Fudge the range a tad in case there is an extra new line at end.
+ // It doesn't show up in the glyphs so would not be accounted for.
+ range.length++;
+
+ count = [lines count];
+ index = 0;
+
+ for (line = [self lineNumberForCharacterIndex:range.location inText:text]; line < count; line++)
+ {
+ index = [[lines objectAtIndex:line] unsignedIntValue];
+
+ if (NSLocationInRange(index, range))
+ {
+ rects = [layoutManager rectArrayForCharacterRange:NSMakeRange(index, 0)
+ withinSelectedCharacterRange:nullRange
+ inTextContainer:container
+ rectCount:&rectCount];
+
+ if (rectCount > 0)
+ {
+ // Note that the ruler view is only as tall as the visible
+ // portion. Need to compensate for the clipview's coordinates.
+ ypos = yinset + NSMinY(rects[0]) - NSMinY(visibleRect);
+
+ // Line numbers are internally stored starting at 0
+ labelText = [NSString stringWithFormat:@"%d", line + 1];
+
+ stringSize = [labelText sizeWithAttributes:textAttributes];
+
+ currentTextAttributes = textAttributes;
+
+ // Draw string flush right, centered vertically within the line
+ [labelText drawInRect:
+ NSMakeRect(NSWidth(bounds) - stringSize.width - RULER_MARGIN,
+ ypos + (NSHeight(rects[0]) - stringSize.height) / 2.0,
+ NSWidth(bounds) - RULER_MARGIN * 2.0, NSHeight(rects[0]))
+ withAttributes:currentTextAttributes];
+ }
+ }
+ if (index > NSMaxRange(range))
+ {
+ break;
+ }
+ }
+ }
+}
+
+
+#pragma mark NSCoding methods
+
+#define NOODLE_FONT_CODING_KEY @"font"
+#define NOODLE_TEXT_COLOR_CODING_KEY @"textColor"
+#define NOODLE_ALT_TEXT_COLOR_CODING_KEY @"alternateTextColor"
+#define NOODLE_BACKGROUND_COLOR_CODING_KEY @"backgroundColor"
+
+- (id)initWithCoder:(NSCoder *)decoder
+{
+ if ((self = [super initWithCoder:decoder]) != nil)
+ {
+ if ([decoder allowsKeyedCoding])
+ {
+ font = [[decoder decodeObjectForKey:NOODLE_FONT_CODING_KEY] retain];
+ textColor = [[decoder decodeObjectForKey:NOODLE_TEXT_COLOR_CODING_KEY] retain];
+ alternateTextColor = [[decoder decodeObjectForKey:NOODLE_ALT_TEXT_COLOR_CODING_KEY] retain];
+ backgroundColor = [[decoder decodeObjectForKey:NOODLE_BACKGROUND_COLOR_CODING_KEY] retain];
+ }
+ else
+ {
+ font = [[decoder decodeObject] retain];
+ textColor = [[decoder decodeObject] retain];
+ alternateTextColor = [[decoder decodeObject] retain];
+ backgroundColor = [[decoder decodeObject] retain];
+ }
+ }
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)encoder
+{
+ [super encodeWithCoder:encoder];
+
+ if ([encoder allowsKeyedCoding])
+ {
+ [encoder encodeObject:font forKey:NOODLE_FONT_CODING_KEY];
+ [encoder encodeObject:textColor forKey:NOODLE_TEXT_COLOR_CODING_KEY];
+ [encoder encodeObject:alternateTextColor forKey:NOODLE_ALT_TEXT_COLOR_CODING_KEY];
+ [encoder encodeObject:backgroundColor forKey:NOODLE_BACKGROUND_COLOR_CODING_KEY];
+ }
+ else
+ {
+ [encoder encodeObject:font];
+ [encoder encodeObject:textColor];
+ [encoder encodeObject:alternateTextColor];
+ [encoder encodeObject:backgroundColor];
+ }
+}
+
+@end
diff --git a/sequel-pro.xcodeproj/project.pbxproj b/sequel-pro.xcodeproj/project.pbxproj
index 518b1822..13762301 100644
--- a/sequel-pro.xcodeproj/project.pbxproj
+++ b/sequel-pro.xcodeproj/project.pbxproj
@@ -72,6 +72,7 @@
4DECC4900EC2B436008D359E /* MCPKit_bundled.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4DECC3330EC2A170008D359E /* MCPKit_bundled.framework */; };
4DECC4910EC2B436008D359E /* Growl.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4DECC3340EC2A170008D359E /* Growl.framework */; };
58186D210F4CB38900851FE9 /* ConnectionErrorDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 58186D1F0F4CB38900851FE9 /* ConnectionErrorDialog.xib */; };
+ 5841423F0F97E11000A34B47 /* NoodleLineNumberView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5841423E0F97E11000A34B47 /* NoodleLineNumberView.m */; };
584F5F8F0F50ACD800036517 /* table-view-small.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 584F5F8E0F50ACD800036517 /* table-view-small.tiff */; };
5885940F0F7AEE6000ED0E67 /* sparkle-public-key.pem in Resources */ = {isa = PBXBuildFile; fileRef = 5885940E0F7AEE6000ED0E67 /* sparkle-public-key.pem */; };
58C56EF50F438E120035701E /* SPDataCellFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 58C56EF40F438E120035701E /* SPDataCellFormatter.m */; };
@@ -261,6 +262,8 @@
4DECC3330EC2A170008D359E /* MCPKit_bundled.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MCPKit_bundled.framework; path = Frameworks/MCPKit_bundled.framework; sourceTree = "<group>"; };
4DECC3340EC2A170008D359E /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Growl.framework; path = Frameworks/Growl.framework; sourceTree = "<group>"; };
58186D200F4CB38900851FE9 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = Interfaces/English.lproj/ConnectionErrorDialog.xib; sourceTree = "<group>"; };
+ 5841423D0F97E11000A34B47 /* NoodleLineNumberView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NoodleLineNumberView.h; sourceTree = "<group>"; };
+ 5841423E0F97E11000A34B47 /* NoodleLineNumberView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NoodleLineNumberView.m; sourceTree = "<group>"; };
584F5F8E0F50ACD800036517 /* table-view-small.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = "table-view-small.tiff"; sourceTree = "<group>"; };
588593F30F7AEC9500ED0E67 /* package-application.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "package-application.sh"; sourceTree = "<group>"; };
5885940E0F7AEE6000ED0E67 /* sparkle-public-key.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "sparkle-public-key.pem"; sourceTree = "<group>"; };
@@ -543,6 +546,8 @@
17E641810EF01FA8001BC333 /* CMTextView.m */,
58C56EF30F438E120035701E /* SPDataCellFormatter.h */,
58C56EF40F438E120035701E /* SPDataCellFormatter.m */,
+ 5841423D0F97E11000A34B47 /* NoodleLineNumberView.h */,
+ 5841423E0F97E11000A34B47 /* NoodleLineNumberView.m */,
);
name = GUI;
sourceTree = "<group>";
@@ -879,6 +884,7 @@
296DC8BA0F909194002A3258 /* NSArray_DeepMutableCopy.m in Sources */,
296DC8BB0F909194002A3258 /* NSDictionary_DeepMutableCopy.m in Sources */,
296DC8BC0F909194002A3258 /* MGTemplateStandardFilters.m in Sources */,
+ 5841423F0F97E11000A34B47 /* NoodleLineNumberView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};