source: trunk/macosx/TorrentCell.m @ 3791

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

eliminate the second port status dot/text field to avoid confusion

  • Property svn:keywords set to Date Rev Author Id
File size: 21.2 KB
Line 
1/******************************************************************************
2 * $Id: TorrentCell.m 3791 2007-11-11 06:36:32Z 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- (void) drawBar: (NSRect) barRect;
57- (void) drawRegularBar: (NSRect) barRect;
58- (void) drawPiecesBar: (NSRect) barRect;
59
60- (NSRect) rectForMinimalStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds;
61- (NSRect) rectForTitleWithString: (NSAttributedString *) string basedOnMinimalStatusRect: (NSRect) statusRect
62            inBounds: (NSRect) bounds;
63- (NSRect) rectForProgressWithString: (NSAttributedString *) string inBounds: (NSRect) bounds;
64- (NSRect) rectForStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds;
65
66- (NSAttributedString *) attributedTitleWithColor: (NSColor *) color;
67- (NSAttributedString *) attributedStatusString: (NSString *) string withColor: (NSColor *) color;
68
69@end
70
71@implementation TorrentCell
72
73//only called one, so don't worry about release
74- (id) init
75{
76    if ((self = [super init]))
77        {
78        fDefaults = [NSUserDefaults standardUserDefaults];
79       
80        NSMutableParagraphStyle * paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
81        [paragraphStyle setLineBreakMode: NSLineBreakByTruncatingTail];
82   
83        fTitleAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
84                                [NSFont messageFontOfSize: 12.0], NSFontAttributeName,
85                                paragraphStyle, NSParagraphStyleAttributeName, nil];
86        fStatusAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
87                                [NSFont messageFontOfSize: 9.0], NSFontAttributeName,
88                                paragraphStyle, NSParagraphStyleAttributeName, nil];
89        [paragraphStyle release];
90       
91        //store box colors
92        fGrayColor = [[NSColor colorWithCalibratedRed: 0.9 green: 0.9 blue: 0.9 alpha: 1.0] retain];
93        fBlue1Color = [[NSColor colorWithCalibratedRed: 0.8 green: 1.0 blue: 1.0 alpha: 1.0] retain];
94        fBlue2Color = [[NSColor colorWithCalibratedRed: 0.6 green: 1.0 blue: 1.0 alpha: 1.0] retain];
95        fBlue3Color = [[NSColor colorWithCalibratedRed: 0.6 green: 0.8 blue: 1.0 alpha: 1.0] retain];
96        fBlue4Color = [[NSColor colorWithCalibratedRed: 0.4 green: 0.6 blue: 1.0 alpha: 1.0] retain];
97        fBlueColor = [[NSColor colorWithCalibratedRed: 0.0 green: 0.4 blue: 0.8 alpha: 1.0] retain];
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 /= 2.5;
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    {
292        if (fPieces)
293        {
294            free(fPieces);
295            fPieces = NULL;
296            [fBitmap release];
297            fBitmap = nil;
298        }
299       
300        [self drawRegularBar: barRect];
301    }
302   
303    [fBarOverlayColor set];
304    [NSBezierPath strokeRect: NSInsetRect(barRect, 0.5, 0.5)];
305}
306
307- (void) drawRegularBar: (NSRect) barRect
308{
309    Torrent * torrent = [self representedObject];
310   
311    int leftWidth = barRect.size.width;
312    float progress = [torrent progress];
313   
314    if (progress < 1.0)
315    {
316        float rightProgress = 1.0 - progress, progressLeft = [torrent progressLeft];
317        int rightWidth = leftWidth * rightProgress;
318        leftWidth -= rightWidth;
319       
320        if (progressLeft < rightProgress)
321        {
322            int rightNoIncludeWidth = rightWidth * ((rightProgress - progressLeft) / rightProgress);
323            rightWidth -= rightNoIncludeWidth;
324           
325            NSRect noIncludeRect = barRect;
326            noIncludeRect.origin.x += barRect.size.width - rightNoIncludeWidth;
327            noIncludeRect.size.width = rightNoIncludeWidth;
328           
329            if (!fLightGrayGradient)
330                fLightGrayGradient = [[CTGradient progressLightGrayGradient] retain];
331            [fLightGrayGradient fillRect: noIncludeRect angle: -90];
332        }
333       
334        if (rightWidth > 0)
335        {
336            int availableWidth = 0;
337            /*if (![fDefaults boolForKey: @"DisplayProgressBarAvailable"])
338            {
339                //NSLog(@"notAvailableWidth %d rightWidth %d", notAvailableWidth, rightWidth);
340                availableWidth = MAX(0, (float)rightWidth - barRect.size.width * [torrent notAvailableDesired]);
341               
342                if (availableWidth > 0)
343                {
344                    rightWidth -= availableWidth;
345                   
346                    NSRect availableRect = barRect;
347                    availableRect.origin.x += leftWidth;
348                    availableRect.size.width = availableWidth;
349                   
350                    if (!fYellowGradient)
351                        fYellowGradient = [[CTGradient progressYellowGradient] retain];
352                    [fYellowGradient fillRect: availableRect angle: -90];
353                }
354            }*/
355           
356            if (rightWidth > 0)
357            {
358                NSRect includeRect = barRect;
359                includeRect.origin.x += leftWidth + availableWidth;
360                includeRect.size.width = rightWidth;
361               
362                if (!fWhiteGradient)
363                    fWhiteGradient = [[CTGradient progressWhiteGradient] retain];
364                [fWhiteGradient fillRect: includeRect angle: -90];
365            }
366        }
367    }
368   
369    if (leftWidth > 0)
370    {
371        NSRect completeRect = barRect;
372        completeRect.size.width = leftWidth;
373       
374        if ([torrent isActive])
375        {
376            if ([torrent isChecking])
377            {
378                if (!fYellowGradient)
379                    fYellowGradient = [[CTGradient progressYellowGradient] retain];
380                [fYellowGradient fillRect: completeRect angle: -90];
381            }
382            else if ([torrent isSeeding])
383            {
384                int ratioLeftWidth = leftWidth * (1.0 - [torrent progressStopRatio]);
385                leftWidth -= ratioLeftWidth;
386               
387                if (ratioLeftWidth > 0)
388                {
389                    NSRect ratioLeftRect = barRect;
390                    ratioLeftRect.origin.x += leftWidth;
391                    ratioLeftRect.size.width = ratioLeftWidth;
392                   
393                    if (!fLightGreenGradient)
394                        fLightGreenGradient = [[CTGradient progressLightGreenGradient] retain];
395                    [fLightGreenGradient fillRect: ratioLeftRect angle: -90];
396                }
397               
398                if (leftWidth > 0)
399                {
400                    completeRect.size.width = leftWidth;
401                   
402                    if (!fGreenGradient)
403                        fGreenGradient = [[CTGradient progressGreenGradient] retain];
404                    [fGreenGradient fillRect: completeRect angle: -90];
405                }
406            }
407            else
408            {
409                if (!fBlueGradient)
410                    fBlueGradient = [[CTGradient progressBlueGradient] retain];
411                [fBlueGradient fillRect: completeRect angle: -90];
412            }
413        }
414        else
415        {
416            if ([torrent waitingToStart])
417            {
418                if ([torrent progressLeft] <= 0.0)
419                {
420                    if (!fDarkGreenGradient)
421                        fDarkGreenGradient = [[CTGradient progressDarkGreenGradient] retain];
422                    [fDarkGreenGradient fillRect: completeRect angle: -90];
423                }
424                else
425                {
426                    if (!fDarkBlueGradient)
427                        fDarkBlueGradient = [[CTGradient progressDarkBlueGradient] retain];
428                    [fDarkBlueGradient fillRect: completeRect angle: -90];
429                }
430            }
431            else
432            {
433                if (!fGrayGradient)
434                    fGrayGradient = [[CTGradient progressGrayGradient] retain];
435                [fGrayGradient fillRect: completeRect angle: -90];
436            }
437        }
438    }
439}
440
441- (void) drawPiecesBar: (NSRect) barRect
442{
443    if (!fBitmap)
444        fBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: nil
445            pixelsWide: MAX_PIECES pixelsHigh: barRect.size.height bitsPerSample: 8 samplesPerPixel: 4 hasAlpha: YES
446            isPlanar: NO colorSpaceName: NSCalibratedRGBColorSpace bytesPerRow: 0 bitsPerPixel: 0];
447   
448    if (!fPieces)
449    {
450        fPieces = malloc(MAX_PIECES);
451        int i;
452        for (i = 0; i < MAX_PIECES; i++)
453            fPieces[i] = BLANK_PIECE;
454    }
455   
456    #warning add flashing orange
457   
458    Torrent * torrent = [self representedObject];
459   
460    int pieceCount = MIN([torrent pieceCount], MAX_PIECES);
461    float * piecePercent = malloc(pieceCount * sizeof(float));
462    [torrent getAmountFinished: piecePercent size: pieceCount];
463   
464    int i, h, index;
465    float increment = (float)pieceCount / MAX_PIECES;
466    NSColor * pieceColor;
467    for (i = 0; i < MAX_PIECES; i++)
468    {
469        index = i * increment;
470        pieceColor = nil;
471       
472        if (piecePercent[index] >= 1.0)
473        {
474            if (fPieces[i] != -1)
475            {
476                pieceColor = fBlueColor;
477                fPieces[i] = -1;
478            }
479        }
480        else if (piecePercent[index] <= 0.0)
481        {
482            if (fPieces[i] != 0)
483            {
484                pieceColor = fGrayColor;
485                fPieces[i] = 0;
486            }
487        }
488        else if (piecePercent[index] <= 0.25)
489        {
490            if (fPieces[i] != 1)
491            {
492                pieceColor = fBlue1Color;
493                fPieces[i] = 1;
494            }
495        }
496        else if (piecePercent[index] <= 0.5)
497        {
498            if (fPieces[i] != 2)
499            {
500                pieceColor = fBlue2Color;
501                fPieces[i] = 2;
502            }
503        }
504        else if (piecePercent[index] <= 0.75)
505        {
506            if (fPieces[i] != 3)
507            {
508                pieceColor = fBlue3Color;
509                fPieces[i] = 3;
510            }
511        }
512        else
513        {
514            if (fPieces[i] != 4)
515            {
516                pieceColor = fBlue4Color;
517                fPieces[i] = 4;
518            }
519        }
520       
521        if (pieceColor)
522            for (h = 0; h < barRect.size.height; h++)
523                [fBitmap setColor: pieceColor atX: i y: h];
524    }
525   
526    free(piecePercent);
527   
528    //actually draw image
529    [fBitmap drawInRect: barRect];
530   
531    if (!fTransparentGradient)
532        fTransparentGradient = [[CTGradient progressTransparentGradient] retain];
533    [fTransparentGradient fillRect: barRect angle: -90];
534}
535
536- (NSRect) rectForMinimalStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
537{
538    if (![fDefaults boolForKey: @"SmallView"])
539        return NSZeroRect;
540   
541    NSRect result = bounds;
542    result.size = [string size];
543   
544    result.origin.x += bounds.size.width - result.size.width - PADDING_HORIZONAL;
545    result.origin.y += PADDING_ABOVE_MIN_STATUS;
546   
547    return result;
548}
549
550- (NSRect) rectForTitleWithString: (NSAttributedString *) string basedOnMinimalStatusRect: (NSRect) statusRect
551            inBounds: (NSRect) bounds
552{
553    BOOL minimal = [fDefaults boolForKey: @"SmallView"];
554   
555    NSRect result = bounds;
556    result.origin.y += PADDING_ABOVE_TITLE;
557    result.origin.x += PADDING_HORIZONAL + (minimal ? IMAGE_SIZE_MIN : IMAGE_SIZE_REG) + PADDING_BETWEEN_IMAGE_AND_TITLE;
558   
559    result.size = [string size];
560    result.size.width = MIN(result.size.width, NSMaxX(bounds) - result.origin.x - PADDING_HORIZONAL
561                            - (minimal ? PADDING_BETWEEN_TITLE_AND_MIN_STATUS + statusRect.size.width : 0));
562   
563    return result;
564}
565
566- (NSRect) rectForProgressWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
567{
568    if ([fDefaults boolForKey: @"SmallView"])
569        return NSZeroRect;
570   
571    NSRect result = bounds;
572    result.origin.y += PADDING_ABOVE_TITLE + HEIGHT_TITLE + PADDING_BETWEEN_TITLE_AND_PROGRESS;
573    result.origin.x += PADDING_HORIZONAL + 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   
578    return result;
579}
580
581- (NSRect) rectForStatusWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
582{
583    if ([fDefaults boolForKey: @"SmallView"])
584        return NSZeroRect;
585   
586    NSRect result = bounds;
587    result.origin.y += PADDING_ABOVE_TITLE + HEIGHT_TITLE + PADDING_BETWEEN_TITLE_AND_PROGRESS + HEIGHT_STATUS
588                        + PADDING_BETWEEN_PROGRESS_AND_BAR + BAR_HEIGHT + PADDING_BETWEEN_BAR_AND_STATUS;
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- (NSAttributedString *) attributedTitleWithColor: (NSColor *) color
598{
599    if (color)
600        [fTitleAttributes setObject: color forKey: NSForegroundColorAttributeName];
601   
602    NSString * title = [[self representedObject] name];
603    return [[[NSAttributedString alloc] initWithString: title attributes: fTitleAttributes] autorelease];
604}
605
606- (NSAttributedString *) attributedStatusString: (NSString *) string withColor: (NSColor *) color
607{
608    if (color)
609        [fStatusAttributes setObject: color forKey: NSForegroundColorAttributeName];
610   
611    return [[[NSAttributedString alloc] initWithString: string attributes: fStatusAttributes] autorelease];
612}
613
614@end
Note: See TracBrowser for help on using the repository browser.