1/****************************************************************************** 2 * $Id: FileNameCell.m 13251 2012-03-13 02:52:11Z livings124 $ 3 * 4 * Copyright (c) 2007-2012 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 "FileNameCell.h" 26#import "FileOutlineView.h" 27#import "Torrent.h" 28#import "FileListNode.h" 29#import "NSStringAdditions.h" 30 31#import "transmission.h" // required by utils.h 32#import "utils.h" 33 34#define PADDING_HORIZONAL 2.0 35#define IMAGE_FOLDER_SIZE 16.0 36#define IMAGE_ICON_SIZE 32.0 37#define PADDING_BETWEEN_IMAGE_AND_TITLE 4.0 38#define PADDING_ABOVE_TITLE_FILE 2.0 39#define PADDING_BELOW_STATUS_FILE 2.0 40#define PADDING_BETWEEN_NAME_AND_FOLDER_STATUS 4.0 41 42@interface FileNameCell (Private) 43 44- (NSRect) rectForTitleWithString: (NSAttributedString *) string inBounds: (NSRect) bounds; 45- (NSRect) rectForStatusWithString: (NSAttributedString *) string withTitleRect: (NSRect) titleRect inBounds: (NSRect) bounds; 46 47- (NSAttributedString *) attributedTitle; 48- (NSAttributedString *) attributedStatus; 49 50@end 51 52@implementation FileNameCell 53 54- (id) init 55{ 56 if ((self = [super init])) 57 { 58 NSMutableParagraphStyle * paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; 59 [paragraphStyle setLineBreakMode: NSLineBreakByTruncatingMiddle]; 60 61 fTitleAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys: 62 [NSFont messageFontOfSize: 12.0], NSFontAttributeName, 63 paragraphStyle, NSParagraphStyleAttributeName, nil]; 64 65 NSMutableParagraphStyle * statusParagraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; 66 [statusParagraphStyle setLineBreakMode: NSLineBreakByTruncatingTail]; 67 68 fStatusAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys: 69 [NSFont messageFontOfSize: 9.0], NSFontAttributeName, 70 statusParagraphStyle, NSParagraphStyleAttributeName, nil]; 71 72 [paragraphStyle release]; 73 [statusParagraphStyle release]; 74 } 75 return self; 76} 77 78- (void) dealloc 79{ 80 [fTitleAttributes release]; 81 [fStatusAttributes release]; 82 83 [super dealloc]; 84} 85 86- (id) copyWithZone: (NSZone *) zone 87{ 88 FileNameCell * copy = [super copyWithZone: zone]; 89 90 copy->fTitleAttributes = [fTitleAttributes retain]; 91 copy->fStatusAttributes = [fStatusAttributes retain]; 92 93 return copy; 94} 95 96- (NSImage *) image 97{ 98 FileListNode * node = (FileListNode *)[self objectValue]; 99 return [node icon]; 100} 101 102- (NSRect) imageRectForBounds: (NSRect) bounds 103{ 104 NSRect result = bounds; 105 106 result.origin.x += PADDING_HORIZONAL; 107 108 const CGFloat IMAGE_SIZE = [(FileListNode *)[self objectValue] isFolder] ? IMAGE_FOLDER_SIZE : IMAGE_ICON_SIZE; 109 result.origin.y += (result.size.height - IMAGE_SIZE) * 0.5; 110 result.size = NSMakeSize(IMAGE_SIZE, IMAGE_SIZE); 111 112 return result; 113} 114 115- (void) drawWithFrame: (NSRect) cellFrame inView: (NSView *) controlView 116{ 117 //icon 118 [[self image] drawInRect: [self imageRectForBounds: cellFrame] fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0 respectFlipped: YES hints: nil]; 119 120 NSColor * titleColor, * statusColor; 121 if ([self backgroundStyle] == NSBackgroundStyleDark) 122 titleColor = statusColor = [NSColor whiteColor]; 123 else if ([[(FileListNode *)[self objectValue] torrent] checkForFiles: [(FileListNode *)[self objectValue] indexes]] == NSOffState) 124 titleColor = statusColor = [NSColor disabledControlTextColor]; 125 else 126 { 127 titleColor = [NSColor controlTextColor]; 128 statusColor = [NSColor darkGrayColor]; 129 } 130 131 [fTitleAttributes setObject: titleColor forKey: NSForegroundColorAttributeName]; 132 [fStatusAttributes setObject: statusColor forKey: NSForegroundColorAttributeName]; 133 134 //title 135 NSAttributedString * titleString = [self attributedTitle]; 136 NSRect titleRect = [self rectForTitleWithString: titleString inBounds: cellFrame]; 137 [titleString drawInRect: titleRect]; 138 139 //status 140 NSAttributedString * statusString = [self attributedStatus]; 141 NSRect statusRect = [self rectForStatusWithString: statusString withTitleRect: titleRect inBounds: cellFrame]; 142 [statusString drawInRect: statusRect]; 143} 144 145@end 146 147@implementation FileNameCell (Private) 148 149- (NSRect) rectForTitleWithString: (NSAttributedString *) string inBounds: (NSRect) bounds 150{ 151 const NSSize titleSize = [string size]; 152 153 NSRect result; 154 if (![(FileListNode *)[self objectValue] isFolder]) 155 { 156 result.origin.x = NSMinX(bounds) + PADDING_HORIZONAL + IMAGE_ICON_SIZE + PADDING_BETWEEN_IMAGE_AND_TITLE; 157 result.origin.y = NSMinY(bounds) + PADDING_ABOVE_TITLE_FILE; 158 result.size.width = NSMaxX(bounds) - NSMinX(result) - PADDING_HORIZONAL; 159 } 160 else 161 { 162 result.origin.x = NSMinX(bounds) + PADDING_HORIZONAL + IMAGE_FOLDER_SIZE + PADDING_BETWEEN_IMAGE_AND_TITLE; 163 result.origin.y = NSMidY(bounds) - titleSize.height * 0.5; 164 result.size.width = MIN(titleSize.width, NSMaxX(bounds) - NSMinX(result) - PADDING_HORIZONAL); 165 } 166 result.size.height = titleSize.height; 167 168 return result; 169} 170 171- (NSRect) rectForStatusWithString: (NSAttributedString *) string withTitleRect: (NSRect) titleRect inBounds: (NSRect) bounds; 172{ 173 const NSSize statusSize = [string size]; 174 175 NSRect result; 176 if (![(FileListNode *)[self objectValue] isFolder]) 177 { 178 result.origin.x = NSMinX(titleRect); 179 result.origin.y = NSMaxY(bounds) - PADDING_BELOW_STATUS_FILE - statusSize.height; 180 result.size.width = NSWidth(titleRect); 181 } 182 else 183 { 184 result.origin.x = NSMaxX(titleRect) + PADDING_BETWEEN_NAME_AND_FOLDER_STATUS; 185 result.origin.y = NSMaxY(titleRect) - statusSize.height - 1.0; 186 result.size.width = NSMaxX(bounds) - NSMaxX(titleRect) - PADDING_HORIZONAL; 187 } 188 result.size.height = statusSize.height; 189 190 return result; 191} 192 193- (NSAttributedString *) attributedTitle 194{ 195 NSString * title = [(FileListNode *)[self objectValue] name]; 196 return [[[NSAttributedString alloc] initWithString: title attributes: fTitleAttributes] autorelease]; 197} 198 199- (NSAttributedString *) attributedStatus 200{ 201 FileListNode * node = (FileListNode *)[self objectValue]; 202 Torrent * torrent = [node torrent]; 203 204 const CGFloat progress = [torrent fileProgress: node]; 205 NSString * percentString = [NSString percentString: progress longDecimals: YES]; 206 207 NSString * status = [NSString stringWithFormat: NSLocalizedString(@"%@ of %@", 208 "Inspector -> Files tab -> file status string"), percentString, [NSString stringForFileSize: [node size]]]; 209 210 return [[[NSAttributedString alloc] initWithString: status attributes: fStatusAttributes] autorelease]; 211} 212 213@end 214