source: trunk/macosx/TorrentCell.m @ 3700

Last change on this file since 3700 was 3700, checked in by livings124, 15 years ago

commit some changes that have been sitting in by checkout

  • Property svn:keywords set to Date Rev Author Id
File size: 21.7 KB
Line 
1/******************************************************************************
2 * $Id: TorrentCell.m 3700 2007-11-04 16:12:49Z livings124 $
3 *
4 * Copyright (c) 2006-2007 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#import "TorrentCell.h"
26#import "TorrentTableView.h"
27#import "NSStringAdditions.h"
28#import "CTGradientAdditions.h"
29
30#define BAR_HEIGHT 12.0
31
32#define IMAGE_SIZE_REG 32.0
33#define IMAGE_SIZE_MIN 16.0
34
35//end up being larger than font height
36#define HEIGHT_TITLE 16.0
37#define HEIGHT_STATUS 12.0
38
39#define PADDING_HORIZONAL 2.0
40#define PADDING_ABOVE_IMAGE_REG 9.0
41#define PADDING_BETWEEN_IMAGE_AND_TITLE 5.0
42#define PADDING_BETWEEN_IMAGE_AND_BAR 7.0
43#define PADDING_ABOVE_TITLE 3.0
44#define PADDING_ABOVE_MIN_STATUS 4.0
45#define PADDING_BETWEEN_TITLE_AND_MIN_STATUS 2.0
46#define PADDING_BETWEEN_TITLE_AND_PROGRESS 1.0
47#define PADDING_BETWEEN_PROGRESS_AND_BAR 2.0
48#define PADDING_BETWEEN_TITLE_AND_BAR_MIN 3.0
49#define PADDING_BETWEEN_BAR_AND_STATUS 2.0
50
51#define MAX_PIECES 324
52#define BLANK_PIECE -99
53
54@interface TorrentCell (Private)
55
56// Used to optimize drawing. They contain packed RGBA pixels for every color needed.
57static uint32_t kBlue   = OSSwapBigToHostConstInt32(0x50A0FFFF), //80, 160, 255
58                kBlue1  = OSSwapBigToHostConstInt32(0x84FFFFFF), //204, 255, 255
59                kBlue2  = OSSwapBigToHostConstInt32(0x6BFFFFFF), //153, 255, 255
60                kBlue3  = OSSwapBigToHostConstInt32(0x6B84FFFF), //153, 204, 255
61                kBlue4  = OSSwapBigToHostConstInt32(0x426BFFFF), //102, 153, 255
62                kGray   = OSSwapBigToHostConstInt32(0xE9E9E9FF); //100, 100, 100
63
64- (void) drawBar: (NSRect) barRect;
65- (void) drawRegularBar: (NSRect) barRect;
66- (void) drawPiecesBar: (NSRect) barRect;
67
68- (NSRect) rectForMinimalStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds;
69- (NSRect) rectForTitleWithString: (NSAttributedString *) string basedOnMinimalStatusRect: (NSRect) statusRect
70            inBounds: (NSRect) bounds;
71- (NSRect) rectForProgressWithString: (NSAttributedString *) string inBounds: (NSRect) bounds;
72- (NSRect) rectForStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds;
73
74- (NSAttributedString *) attributedTitleWithColor: (NSColor *) color;
75- (NSAttributedString *) attributedStatusString: (NSString *) string withColor: (NSColor *) color;
76
77@end
78
79@implementation TorrentCell
80
81//only called one, so don't worry about release
82- (id) init
83{
84    if ((self = [super init]))
85        {
86        fDefaults = [NSUserDefaults standardUserDefaults];
87       
88        NSMutableParagraphStyle * paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
89        [paragraphStyle setLineBreakMode: NSLineBreakByTruncatingTail];
90   
91        fTitleAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
92                                [NSFont messageFontOfSize: 12.0], NSFontAttributeName,
93                                paragraphStyle, NSParagraphStyleAttributeName, nil];
94        fStatusAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
95                                [NSFont messageFontOfSize: 9.0], NSFontAttributeName,
96                                paragraphStyle, NSParagraphStyleAttributeName, nil];
97        [paragraphStyle release];
98       
99        fBarOverlayColor = [[NSColor colorWithDeviceWhite: 0.0 alpha: 0.2] retain];
100    }
101        return self;
102}
103
104- (id) copyWithZone: (NSZone *) zone
105{
106    TorrentCell * copy = [super copyWithZone: zone];
107   
108    copy->fBitmap = nil;
109    copy->fPieces = NULL;
110   
111    return copy;
112}
113
114- (void) dealloc
115{
116    [fBitmap release];
117    if (fPieces)
118        free(fPieces);
119   
120    [super dealloc];
121}
122
123- (NSRect) iconRectForBounds: (NSRect) bounds
124{
125    NSRect result = bounds;
126   
127    result.origin.x += PADDING_HORIZONAL;
128   
129    float imageSize;
130    if ([fDefaults boolForKey: @"SmallView"])
131    {
132        imageSize = IMAGE_SIZE_MIN;
133        result.origin.y += (result.size.height - imageSize) * 0.5;
134    }
135    else
136    {
137        imageSize = IMAGE_SIZE_REG;
138        result.origin.y += PADDING_ABOVE_IMAGE_REG;
139    }
140   
141    result.size = NSMakeSize(imageSize, imageSize);
142   
143    return result;
144}
145
146- (NSRect) titleRectForBounds: (NSRect) bounds
147{
148    return [self rectForTitleWithString: [self attributedTitleWithColor: nil]
149            basedOnMinimalStatusRect: [self minimalStatusRectForBounds: bounds] inBounds: bounds];
150}
151
152- (NSRect) minimalStatusRectForBounds: (NSRect) bounds
153{
154    Torrent * torrent = [self representedObject];
155    NSString * string = [fDefaults boolForKey: @"DisplaySmallStatusRegular"]
156                            ? [torrent shortStatusString] : [torrent remainingTimeString];
157    return [self rectForMinimalStatusWithString: [self attributedStatusString: string withColor: nil] inBounds: bounds];
158}
159
160- (NSRect) progressRectForBounds: (NSRect) bounds
161{
162    return [self rectForProgressWithString: [self attributedStatusString: [[self representedObject] progressString] withColor: nil]
163                    inBounds: bounds];
164}
165
166- (NSRect) barRectForBounds: (NSRect) bounds
167{
168    BOOL minimal = [fDefaults boolForKey: @"SmallView"];
169   
170    NSRect result = bounds;
171    result.size.height = BAR_HEIGHT;
172    result.origin.x = PADDING_HORIZONAL + (minimal ? IMAGE_SIZE_MIN : IMAGE_SIZE_REG) + PADDING_BETWEEN_IMAGE_AND_BAR;
173   
174    result.origin.y += PADDING_ABOVE_TITLE + HEIGHT_TITLE;
175    if (minimal)
176        result.origin.y += PADDING_BETWEEN_TITLE_AND_BAR_MIN;
177    else
178        result.origin.y += PADDING_BETWEEN_TITLE_AND_PROGRESS + HEIGHT_STATUS + PADDING_BETWEEN_PROGRESS_AND_BAR;
179   
180    result.size.width = round(NSMaxX(bounds) - result.origin.x - PADDING_HORIZONAL - BUTTONS_TOTAL_WIDTH);
181   
182    return result;
183}
184
185- (NSRect) statusRectForBounds: (NSRect) bounds
186{
187    return [self rectForStatusWithString: [self attributedStatusString: [[self representedObject] statusString] withColor: nil]
188                    inBounds: bounds];
189}
190
191- (NSUInteger) hitTestForEvent: (NSEvent *) event inRect: (NSRect) cellFrame ofView: (NSView *) controlView
192{
193    return NSCellHitContentArea;
194}
195
196- (void) drawInteriorWithFrame: (NSRect) cellFrame inView: (NSView *) controlView
197{
198    [super drawInteriorWithFrame: cellFrame inView: controlView];
199   
200    Torrent * torrent = [self representedObject];
201   
202    BOOL minimal = [fDefaults boolForKey: @"SmallView"];
203   
204    //error image
205    BOOL error = [torrent isError];
206    if (error && !fErrorImage)
207    {
208        fErrorImage = [[NSImage imageNamed: @"Error.png"] copy];
209        [fErrorImage setFlipped: YES];
210    }
211   
212    //icon
213    NSImage * icon = minimal && error ? fErrorImage : [torrent icon];
214    NSRect iconRect = [self iconRectForBounds: cellFrame];
215    [icon drawInRect: iconRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0];
216   
217    if (error && !minimal)
218    {
219        NSRect errorRect = NSMakeRect(NSMaxX(iconRect) - IMAGE_SIZE_MIN, NSMaxY(iconRect) - IMAGE_SIZE_MIN,
220                                        IMAGE_SIZE_MIN, IMAGE_SIZE_MIN);
221        [fErrorImage drawInRect: errorRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0];
222    }
223   
224    //text color
225    NSColor * titleColor, * statusColor;
226    if ([self isHighlighted]
227            && [[self highlightColorWithFrame: cellFrame inView: controlView] isEqual: [NSColor alternateSelectedControlColor]])
228    {
229        titleColor = [NSColor whiteColor];
230        statusColor = [NSColor whiteColor];
231    }
232    else
233    {
234        titleColor = [NSColor controlTextColor];
235        statusColor = [NSColor darkGrayColor];
236    }
237   
238    //minimal status
239    NSRect minimalStatusRect;
240    if (minimal)
241    {
242        NSString * string = [fDefaults boolForKey: @"DisplaySmallStatusRegular"]
243                            ? [torrent shortStatusString] : [torrent remainingTimeString];
244        NSAttributedString * minimalString = [self attributedStatusString: string withColor: statusColor];
245        minimalStatusRect = [self rectForMinimalStatusWithString: minimalString inBounds: cellFrame];
246       
247        [minimalString drawInRect: minimalStatusRect];
248    }
249   
250    //title
251    NSAttributedString * titleString = [self attributedTitleWithColor: titleColor];
252    NSRect titleRect = [self rectForTitleWithString: titleString basedOnMinimalStatusRect: minimalStatusRect inBounds: cellFrame];
253    [titleString drawInRect: titleRect];
254   
255    //progress
256    if (!minimal)
257    {
258        NSAttributedString * progressString = [self attributedStatusString: [torrent progressString] withColor: statusColor];
259        NSRect progressRect = [self rectForProgressWithString: progressString inBounds: cellFrame];
260        [progressString drawInRect: progressRect];
261    }
262   
263    //bar
264    [self drawBar: [self barRectForBounds: cellFrame]];
265   
266    //status
267    if (!minimal)
268    {
269        NSAttributedString * statusString = [self attributedStatusString: [torrent statusString] withColor: statusColor];
270        [statusString drawInRect: [self rectForStatusWithString: statusString inBounds: cellFrame]];
271    }
272}
273
274@end
275
276@implementation TorrentCell (Private)
277
278- (void) drawBar: (NSRect) barRect
279{
280    if ([fDefaults boolForKey: @"PiecesBar"])
281    {
282        NSRect regularBarRect = barRect, piecesBarRect = barRect;
283        regularBarRect.size.height /= 3;
284        piecesBarRect.origin.y += regularBarRect.size.height;
285        piecesBarRect.size.height -= regularBarRect.size.height;
286       
287        [self drawRegularBar: regularBarRect];
288        [self drawPiecesBar: piecesBarRect];
289    }
290    else
291        [self drawRegularBar: barRect];
292   
293    [fBarOverlayColor set];
294    [NSBezierPath strokeRect: NSInsetRect(barRect, 0.5, 0.5)];
295}
296
297- (void) drawRegularBar: (NSRect) barRect
298{
299    Torrent * torrent = [self representedObject];
300   
301    int leftWidth = barRect.size.width;
302    float progress = [torrent progress];
303   
304    if (progress < 1.0)
305    {
306        float rightProgress = 1.0 - progress, progressLeft = [torrent progressLeft];
307        int rightWidth = leftWidth * rightProgress;
308        leftWidth -= rightWidth;
309       
310        if (progressLeft < rightProgress)
311        {
312            int rightNoIncludeWidth = rightWidth * ((rightProgress - progressLeft) / rightProgress);
313            rightWidth -= rightNoIncludeWidth;
314           
315            NSRect noIncludeRect = barRect;
316            noIncludeRect.origin.x += barRect.size.width - rightNoIncludeWidth;
317            noIncludeRect.size.width = rightNoIncludeWidth;
318           
319            if (!fLightGrayGradient)
320                fLightGrayGradient = [[CTGradient progressLightGrayGradient] retain];
321            [fLightGrayGradient fillRect: noIncludeRect angle: -90];
322        }
323       
324        if (rightWidth > 0)
325        {
326            int availableWidth = 0;
327            /*if (![fDefaults boolForKey: @"DisplayProgressBarAvailable"])
328            {
329                //NSLog(@"notAvailableWidth %d rightWidth %d", notAvailableWidth, rightWidth);
330                availableWidth = MAX(0, (float)rightWidth - barRect.size.width * [torrent notAvailableDesired]);
331               
332                if (availableWidth > 0)
333                {
334                    rightWidth -= availableWidth;
335                   
336                    NSRect availableRect = barRect;
337                    availableRect.origin.x += leftWidth;
338                    availableRect.size.width = availableWidth;
339                   
340                    if (!fYellowGradient)
341                        fYellowGradient = [[CTGradient progressYellowGradient] retain];
342                    [fYellowGradient fillRect: availableRect angle: -90];
343                }
344            }*/
345           
346            if (rightWidth > 0)
347            {
348                NSRect includeRect = barRect;
349                includeRect.origin.x += leftWidth + availableWidth;
350                includeRect.size.width = rightWidth;
351               
352                if (!fWhiteGradient)
353                    fWhiteGradient = [[CTGradient progressWhiteGradient] retain];
354                [fWhiteGradient fillRect: includeRect angle: -90];
355            }
356        }
357    }
358   
359    if (leftWidth > 0)
360    {
361        NSRect completeRect = barRect;
362        completeRect.size.width = leftWidth;
363       
364        if ([torrent isActive])
365        {
366            if ([torrent isChecking])
367            {
368                if (!fYellowGradient)
369                    fYellowGradient = [[CTGradient progressYellowGradient] retain];
370                [fYellowGradient fillRect: completeRect angle: -90];
371            }
372            else if ([torrent isSeeding])
373            {
374                int ratioLeftWidth = leftWidth * (1.0 - [torrent progressStopRatio]);
375                leftWidth -= ratioLeftWidth;
376               
377                if (ratioLeftWidth > 0)
378                {
379                    NSRect ratioLeftRect = barRect;
380                    ratioLeftRect.origin.x += leftWidth;
381                    ratioLeftRect.size.width = ratioLeftWidth;
382                   
383                    if (!fLightGreenGradient)
384                        fLightGreenGradient = [[CTGradient progressLightGreenGradient] retain];
385                    [fLightGreenGradient fillRect: ratioLeftRect angle: -90];
386                }
387               
388                if (leftWidth > 0)
389                {
390                    completeRect.size.width = leftWidth;
391                   
392                    if (!fGreenGradient)
393                        fGreenGradient = [[CTGradient progressGreenGradient] retain];
394                    [fGreenGradient fillRect: completeRect angle: -90];
395                }
396            }
397            else
398            {
399                if (!fBlueGradient)
400                    fBlueGradient = [[CTGradient progressBlueGradient] retain];
401                [fBlueGradient fillRect: completeRect angle: -90];
402            }
403        }
404        else
405        {
406            if ([torrent waitingToStart])
407            {
408                if ([torrent progressLeft] <= 0.0)
409                {
410                    if (!fDarkGreenGradient)
411                        fDarkGreenGradient = [[CTGradient progressDarkGreenGradient] retain];
412                    [fDarkGreenGradient fillRect: completeRect angle: -90];
413                }
414                else
415                {
416                    if (!fDarkBlueGradient)
417                        fDarkBlueGradient = [[CTGradient progressDarkBlueGradient] retain];
418                    [fDarkBlueGradient fillRect: completeRect angle: -90];
419                }
420            }
421            else
422            {
423                if (!fGrayGradient)
424                    fGrayGradient = [[CTGradient progressGrayGradient] retain];
425                [fGrayGradient fillRect: completeRect angle: -90];
426            }
427        }
428    }
429}
430
431- (void) drawPiecesBar: (NSRect) barRect
432{
433    if (!fBitmap)
434        fBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: nil
435            pixelsWide: MAX_PIECES pixelsHigh: barRect.size.height bitsPerSample: 8 samplesPerPixel: 4 hasAlpha: YES
436            isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: 0 bitsPerPixel: 0];
437   
438    uint32_t * p;
439    uint8_t * bitmapData = [fBitmap bitmapData];
440    int bytesPerRow = [fBitmap bytesPerRow];
441   
442    if (!fPieces)
443    {
444        fPieces = malloc(MAX_PIECES);
445        int i;
446        for (i = 0; i < MAX_PIECES; i++)
447            fPieces[i] = BLANK_PIECE;
448    }
449   
450    #warning add flashing orange
451   
452    Torrent * torrent = [self representedObject];
453   
454    #warning redo like pieces view
455    int pieceCount = [torrent pieceCount];
456    float * piecePercent = malloc(pieceCount * sizeof(float));
457    [torrent getAmountFinished: piecePercent size: pieceCount];
458   
459    //lines 2 to 14: blue, green, or gray depending on piece availability
460    int i, h, index = 0;
461    float increment = (float)pieceCount / MAX_PIECES, indexValue = 0;
462    uint32_t color;
463    BOOL change;
464    for (i = 0; i < MAX_PIECES; i++)
465    {
466        change = NO;
467        if (piecePercent[index] >= 1.0)
468        {
469            if (fPieces[i] != -1)
470            {
471                color = kBlue;
472                fPieces[i] = -1;
473                change = YES;
474            }
475        }
476        else if (piecePercent[index] <= 0.0)
477        {
478            if (fPieces[i] != 0)
479            {
480                color = kGray;
481                fPieces[i] = 0;
482                change = YES;
483            }
484        }
485        else if (piecePercent[index] <= 0.25)
486        {
487            if (fPieces[i] != 1)
488            {
489                color = kBlue1;
490                fPieces[i] = 1;
491                change = YES;
492            }
493        }
494        else if (piecePercent[index] <= 0.5)
495        {
496            if (fPieces[i] != 2)
497            {
498                color = kBlue2;
499                fPieces[i] = 2;
500                change = YES;
501            }
502        }
503        else if (piecePercent[index] <= 0.75)
504        {
505            if (fPieces[i] != 3)
506            {
507                color = kBlue3;
508                fPieces[i] = 3;
509                change = YES;
510            }
511        }
512        else
513        {
514            if (fPieces[i] != 4)
515            {
516                color = kBlue4;
517                fPieces[i] = 4;
518                change = YES;
519            }
520        }
521       
522        if (change)
523        {
524            //draw vertically
525            p = (uint32_t *)(bitmapData) + i;
526            for (h = 0; h < barRect.size.height; h++)
527            {
528                p[0] = color;
529                p = (uint32_t *)((uint8_t *)p + bytesPerRow);
530            }
531        }
532       
533        indexValue += increment;
534        index = (int)indexValue;
535    }
536   
537    free(piecePercent);
538   
539    //actually draw image
540    NSImage * bar = [[NSImage alloc] initWithSize: [fBitmap size]];
541    [bar setFlipped: YES];
542    [bar addRepresentation: fBitmap];
543   
544    [bar drawInRect: barRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0];
545    [bar release];
546   
547    if (!fTransparentGradient)
548        fTransparentGradient = [[CTGradient progressTransparentGradient] retain];
549    [fTransparentGradient fillRect: barRect angle: -90];
550}
551
552- (NSRect) rectForMinimalStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
553{
554    if (![fDefaults boolForKey: @"SmallView"])
555        return NSZeroRect;
556   
557    NSRect result = bounds;
558    result.size = [string size];
559   
560    result.origin.x += bounds.size.width - result.size.width - PADDING_HORIZONAL;
561    result.origin.y += PADDING_ABOVE_MIN_STATUS;
562   
563    return result;
564}
565
566- (NSRect) rectForTitleWithString: (NSAttributedString *) string basedOnMinimalStatusRect: (NSRect) statusRect
567            inBounds: (NSRect) bounds
568{
569    BOOL minimal = [fDefaults boolForKey: @"SmallView"];
570   
571    NSRect result = bounds;
572    result.origin.y += PADDING_ABOVE_TITLE;
573    result.origin.x += PADDING_HORIZONAL + (minimal ? IMAGE_SIZE_MIN : IMAGE_SIZE_REG) + PADDING_BETWEEN_IMAGE_AND_TITLE;
574   
575    result.size = [string size];
576    result.size.width = MIN(result.size.width, NSMaxX(bounds) - result.origin.x - PADDING_HORIZONAL
577                            - (minimal ? PADDING_BETWEEN_TITLE_AND_MIN_STATUS + statusRect.size.width : 0));
578   
579    return result;
580}
581
582- (NSRect) rectForProgressWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
583{
584    if ([fDefaults boolForKey: @"SmallView"])
585        return NSZeroRect;
586   
587    NSRect result = bounds;
588    result.origin.y += PADDING_ABOVE_TITLE + HEIGHT_TITLE + PADDING_BETWEEN_TITLE_AND_PROGRESS;
589    result.origin.x += PADDING_HORIZONAL + IMAGE_SIZE_REG + PADDING_BETWEEN_IMAGE_AND_TITLE;
590   
591    result.size = [string size];
592    result.size.width = MIN(result.size.width, NSMaxX(bounds) - result.origin.x - PADDING_HORIZONAL);
593   
594    return result;
595}
596
597- (NSRect) rectForStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
598{
599    if ([fDefaults boolForKey: @"SmallView"])
600        return NSZeroRect;
601   
602    NSRect result = bounds;
603    result.origin.y += PADDING_ABOVE_TITLE + HEIGHT_TITLE + PADDING_BETWEEN_TITLE_AND_PROGRESS + HEIGHT_STATUS
604                        + PADDING_BETWEEN_PROGRESS_AND_BAR + BAR_HEIGHT + PADDING_BETWEEN_BAR_AND_STATUS;
605    result.origin.x += PADDING_HORIZONAL + IMAGE_SIZE_REG + PADDING_BETWEEN_IMAGE_AND_TITLE;
606   
607    result.size = [string size];
608    result.size.width = MIN(result.size.width, NSMaxX(bounds) - result.origin.x - PADDING_HORIZONAL);
609   
610    return result;
611}
612
613- (NSAttributedString *) attributedTitleWithColor: (NSColor *) color
614{
615    if (color)
616        [fTitleAttributes setObject: color forKey: NSForegroundColorAttributeName];
617   
618    NSString * title = [[self representedObject] name];
619    return [[[NSAttributedString alloc] initWithString: title attributes: fTitleAttributes] autorelease];
620}
621
622- (NSAttributedString *) attributedStatusString: (NSString *) string withColor: (NSColor *) color
623{
624    if (color)
625        [fStatusAttributes setObject: color forKey: NSForegroundColorAttributeName];
626   
627    return [[[NSAttributedString alloc] initWithString: string attributes: fStatusAttributes] autorelease];
628}
629
630@end
Note: See TracBrowser for help on using the repository browser.