1// 2// FileRenameSheetController.m 3// Transmission 4// 5// Created by Mitchell Livingston on 1/20/13. 6// Copyright (c) 2013 The Transmission Project. All rights reserved. 7// 8 9#import "FileRenameSheetController.h" 10#import "FileListNode.h" 11#import "Torrent.h" 12 13typedef void (^CompletionBlock)(BOOL); 14 15@interface FileRenameSheetController () 16 17@property (nonatomic, strong) Torrent * torrent; 18@property (nonatomic, strong) FileListNode * node; 19@property (nonatomic, copy) CompletionBlock completionHandler; 20 21@property (nonatomic, copy) NSString * originalName; 22 23@end 24 25@implementation FileRenameSheetController 26 27#warning remove ivars in header when 64-bit only (or it compiles in 32-bit mode) 28@synthesize torrent = _torrent; 29@synthesize node = _node; 30@synthesize completionHandler = _completionHandler; 31@synthesize originalName = _originalName; 32@synthesize labelField = _labelField; 33@synthesize inputField = _inputField; 34@synthesize renameButton = _renameButton; 35@synthesize cancelButton = _cancelButton; 36 37+ (void) presentSheetForTorrent: (Torrent *) torrent modalForWindow: (NSWindow *) window completionHandler: (void (^)(BOOL didRename)) completionHandler 38{ 39 NSParameterAssert(torrent != nil); 40 NSParameterAssert(window != nil); 41 42 FileRenameSheetController * renamer = [[FileRenameSheetController alloc] initWithWindowNibName: @"FileRenameSheetController"]; 43 44 renamer.torrent = torrent; 45 renamer.completionHandler = completionHandler; 46 47 [NSApp beginSheet: [renamer window] modalForWindow: window modalDelegate: self didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:) contextInfo: (__bridge_retained void *)(renamer)]; 48} 49 50+ (void) presentSheetForFileListNode: (FileListNode *) node modalForWindow: (NSWindow *) window completionHandler: (void (^)(BOOL didRename)) completionHandler 51{ 52 NSParameterAssert(node != nil); 53 NSParameterAssert(window != nil); 54 55 FileRenameSheetController * renamer = [[FileRenameSheetController alloc] initWithWindowNibName: @"FileRenameSheetController"]; 56 57 renamer.torrent = [node torrent]; 58 renamer.node = node; 59 renamer.completionHandler = completionHandler; 60 61 [NSApp beginSheet: [renamer window] modalForWindow: window modalDelegate: self didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:) contextInfo: (__bridge_retained void *)(renamer)]; 62} 63 64+ (void) sheetDidEnd: (NSWindow *) sheet returnCode: (NSInteger) returnCode contextInfo: (void *) contextInfo 65{ 66 FileRenameSheetController * renamer = (__bridge_transfer FileRenameSheetController *)(contextInfo); 67 NSParameterAssert([renamer isKindOfClass:[FileRenameSheetController class]]); 68 69 renamer.completionHandler(returnCode == NSOKButton); 70 71 [sheet orderOut: self]; 72} 73 74 75- (void) windowDidLoad 76{ 77 [super windowDidLoad]; 78 79 self.originalName = [self.node name] ?: [self.torrent name]; 80 NSString * label = [NSString stringWithFormat: NSLocalizedString(@"Rename the file \"%@\":", "rename sheet label"), self.originalName]; 81 [self.labelField setStringValue: label]; 82 83 [self.inputField setStringValue: self.originalName]; 84 [self.renameButton setEnabled: NO]; 85 86 //resize the buttons so that they're long enough and the same width 87 const NSRect oldRenameFrame = [self.renameButton frame]; 88 const NSRect oldCancelFrame = [self.cancelButton frame]; 89 90 //get the extra width of the rename button from the English xib - the width from sizeToFit is too squished 91 [self.renameButton sizeToFit]; 92 const CGFloat extra = NSWidth(oldRenameFrame) - NSWidth([self.renameButton frame]); 93 94 [self.renameButton setTitle: NSLocalizedString(@"Rename", "rename sheet button")]; 95 [self.cancelButton setTitle: NSLocalizedString(@"Cancel", "rename sheet button")]; 96 97 [self.renameButton sizeToFit]; 98 [self.cancelButton sizeToFit]; 99 NSRect newRenameFrame = [self.renameButton frame]; 100 NSRect newCancelFrame = [self.cancelButton frame]; 101 newRenameFrame.size.width = MAX(NSWidth(newRenameFrame), NSWidth(newCancelFrame)) + extra; 102 newCancelFrame.size.width = MAX(NSWidth(newRenameFrame), NSWidth(newCancelFrame)) + extra; 103 104 const CGFloat renameWidthIncrease = NSWidth(newRenameFrame) - NSWidth(oldRenameFrame); 105 newRenameFrame.origin.x -= renameWidthIncrease; 106 [self.renameButton setFrame:newRenameFrame]; 107 108 const CGFloat cancelWidthIncrease = NSWidth(newCancelFrame) - NSWidth(oldCancelFrame); 109 newCancelFrame.origin.x -= renameWidthIncrease + cancelWidthIncrease; 110 [self.cancelButton setFrame:newCancelFrame]; 111} 112 113- (IBAction) rename: (id) sender 114{ 115 void (^completionHandler)(BOOL) = ^(BOOL didRename) { 116 if (didRename) 117 [NSApp endSheet: [self window] returnCode: NSOKButton]; 118 else 119 { 120 #warning more thorough error 121 NSBeep(); 122 } 123 }; 124 125 if (self.node) 126 [self.torrent renameFileNode: self.node withName: [self.inputField stringValue] completionHandler: completionHandler]; 127 else 128 [self.torrent renameTorrent: [self.inputField stringValue] completionHandler: completionHandler]; 129} 130 131- (IBAction) cancelRename: (id) sender 132{ 133 [NSApp endSheet: [self window] returnCode: NSCancelButton]; 134} 135 136- (void) controlTextDidChange: (NSNotification *) notification 137{ 138 [self.renameButton setEnabled: ![[self.inputField stringValue] isEqualToString: @""] && ![[self.inputField stringValue] isEqualToString: self.originalName]]; 139} 140 141@end 142