1/****************************************************************************** 2 * Copyright (c) 2010-2012 Transmission authors and contributors 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 *****************************************************************************/ 22 23#import "AddMagnetWindowController.h" 24#import "Controller.h" 25#import "ExpandedPathToIconTransformer.h" 26#import "GroupsController.h" 27#import "NSStringAdditions.h" 28#import "Torrent.h" 29 30#define POPUP_PRIORITY_HIGH 0 31#define POPUP_PRIORITY_NORMAL 1 32#define POPUP_PRIORITY_LOW 2 33 34@interface AddMagnetWindowController (Private) 35 36- (void) confirmAdd; 37 38- (void) setDestinationPath: (NSString *) destination determinationType: (TorrentDeterminationType) determinationType; 39 40- (void) setGroupsMenu; 41- (void) changeGroupValue: (id) sender; 42 43- (void) sameNameAlertDidEnd: (NSAlert *) alert returnCode: (NSInteger) returnCode contextInfo: (void *) contextInfo; 44 45@end 46 47@implementation AddMagnetWindowController 48 49- (id) initWithTorrent: (Torrent *) torrent destination: (NSString *) path controller: (Controller *) controller 50{ 51 if ((self = [super initWithWindowNibName: @"AddMagnetWindow"])) 52 { 53 fTorrent = torrent; 54 fDestination = [path stringByExpandingTildeInPath]; 55 56 fController = controller; 57 58 fGroupValue = [torrent groupValue]; 59 fGroupDeterminationType = TorrentDeterminationAutomatic; 60 } 61 return self; 62} 63 64- (void) awakeFromNib 65{ 66 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(updateGroupMenu:) 67 name: @"UpdateGroups" object: nil]; 68 69 NSString * name = [fTorrent name]; 70 [[self window] setTitle: name]; 71 [fNameField setStringValue: name]; 72 [fNameField setToolTip: name]; 73 74 [self setGroupsMenu]; 75 [fGroupPopUp selectItemWithTag: fGroupValue]; 76 77 NSInteger priorityIndex; 78 switch ([fTorrent priority]) 79 { 80 case TR_PRI_HIGH: priorityIndex = POPUP_PRIORITY_HIGH; break; 81 case TR_PRI_NORMAL: priorityIndex = POPUP_PRIORITY_NORMAL; break; 82 case TR_PRI_LOW: priorityIndex = POPUP_PRIORITY_LOW; break; 83 default: 84 NSAssert1(NO, @"Unknown priority for adding torrent: %d", [fTorrent priority]); 85 priorityIndex = POPUP_PRIORITY_NORMAL; 86 } 87 [fPriorityPopUp selectItemAtIndex: priorityIndex]; 88 89 [fStartCheck setState: [[NSUserDefaults standardUserDefaults] boolForKey: @"AutoStartDownload"] ? NSOnState : NSOffState]; 90 91 if (fDestination) 92 [self setDestinationPath: fDestination determinationType: TorrentDeterminationAutomatic]; 93 else 94 { 95 [fLocationField setStringValue: @""]; 96 [fLocationImageView setImage: nil]; 97 } 98 99 #warning when 10.7-only, switch to auto layout 100 [fMagnetLinkLabel sizeToFit]; 101 102 const CGFloat downloadToLabelOldWidth = [fDownloadToLabel frame].size.width; 103 [fDownloadToLabel sizeToFit]; 104 const CGFloat changeDestOldWidth = [fChangeDestinationButton frame].size.width; 105 [fChangeDestinationButton sizeToFit]; 106 NSRect changeDestFrame = [fChangeDestinationButton frame]; 107 changeDestFrame.origin.x -= changeDestFrame.size.width - changeDestOldWidth; 108 [fChangeDestinationButton setFrame: changeDestFrame]; 109 110 NSRect downloadToBoxFrame = [fDownloadToBox frame]; 111 const CGFloat downloadToBoxSizeDiff = ([fDownloadToLabel frame].size.width - downloadToLabelOldWidth) + (changeDestFrame.size.width - changeDestOldWidth); 112 downloadToBoxFrame.size.width -= downloadToBoxSizeDiff; 113 downloadToBoxFrame.origin.x -= downloadToLabelOldWidth - [fDownloadToLabel frame].size.width; 114 [fDownloadToBox setFrame: downloadToBoxFrame]; 115 116 NSRect groupPopUpFrame = [fGroupPopUp frame]; 117 NSRect priorityPopUpFrame = [fPriorityPopUp frame]; 118 const CGFloat popUpOffset = groupPopUpFrame.origin.x - NSMaxX([fGroupLabel frame]); 119 [fGroupLabel sizeToFit]; 120 [fPriorityLabel sizeToFit]; 121 NSRect groupLabelFrame = [fGroupLabel frame]; 122 NSRect priorityLabelFrame = [fPriorityLabel frame]; 123 //first bring them both to the left edge 124 groupLabelFrame.origin.x = MIN(groupLabelFrame.origin.x, priorityLabelFrame.origin.x); 125 priorityLabelFrame.origin.x = MIN(groupLabelFrame.origin.x, priorityLabelFrame.origin.x); 126 //then align on the right 127 const CGFloat labelWidth = MAX(groupLabelFrame.size.width, priorityLabelFrame.size.width); 128 groupLabelFrame.origin.x += labelWidth - groupLabelFrame.size.width; 129 priorityLabelFrame.origin.x += labelWidth - priorityLabelFrame.size.width; 130 groupPopUpFrame.origin.x = NSMaxX(groupLabelFrame) + popUpOffset; 131 priorityPopUpFrame.origin.x = NSMaxX(priorityLabelFrame) + popUpOffset; 132 [fGroupLabel setFrame: groupLabelFrame]; 133 [fGroupPopUp setFrame: groupPopUpFrame]; 134 [fPriorityLabel setFrame: priorityLabelFrame]; 135 [fPriorityPopUp setFrame: priorityPopUpFrame]; 136 137 const CGFloat minButtonWidth = 82.0; 138 const CGFloat oldAddButtonWidth = [fAddButton bounds].size.width; 139 const CGFloat oldCancelButtonWidth = [fCancelButton bounds].size.width; 140 [fAddButton sizeToFit]; 141 [fCancelButton sizeToFit]; 142 NSRect addButtonFrame = [fAddButton frame]; 143 NSRect cancelButtonFrame = [fCancelButton frame]; 144 CGFloat buttonWidth = MAX(addButtonFrame.size.width, cancelButtonFrame.size.width); 145 buttonWidth = MAX(buttonWidth, minButtonWidth); 146 addButtonFrame.size.width = buttonWidth; 147 cancelButtonFrame.size.width = buttonWidth; 148 const CGFloat addButtonWidthIncrease = buttonWidth - oldAddButtonWidth; 149 addButtonFrame.origin.x -= addButtonWidthIncrease; 150 cancelButtonFrame.origin.x -= addButtonWidthIncrease + (buttonWidth - oldCancelButtonWidth); 151 [fAddButton setFrame: addButtonFrame]; 152 [fCancelButton setFrame: cancelButtonFrame]; 153 154 [fStartCheck sizeToFit]; 155} 156 157- (void) windowDidLoad 158{ 159 //if there is no destination, prompt for one right away 160 if (!fDestination) 161 [self setDestination: nil]; 162} 163 164- (void) dealloc 165{ 166 [[NSNotificationCenter defaultCenter] removeObserver: self]; 167} 168 169- (Torrent *) torrent 170{ 171 return fTorrent; 172} 173 174- (void) setDestination: (id) sender 175{ 176 NSOpenPanel * panel = [NSOpenPanel openPanel]; 177 178 [panel setPrompt: NSLocalizedString(@"Select", "Open torrent -> prompt")]; 179 [panel setAllowsMultipleSelection: NO]; 180 [panel setCanChooseFiles: NO]; 181 [panel setCanChooseDirectories: YES]; 182 [panel setCanCreateDirectories: YES]; 183 184 [panel setMessage: [NSString stringWithFormat: NSLocalizedString(@"Select the download folder for \"%@\"", 185 "Add -> select destination folder"), [fTorrent name]]]; 186 187 [panel beginSheetModalForWindow: [self window] completionHandler: ^(NSInteger result) { 188 if (result == NSFileHandlingPanelOKButton) 189 [self setDestinationPath: [[panel URLs][0] path] determinationType:TorrentDeterminationUserSpecified]; 190 else 191 { 192 if (!fDestination) 193 [self performSelectorOnMainThread: @selector(cancelAdd:) withObject: nil waitUntilDone: NO]; 194 } 195 }]; 196} 197 198- (void) add: (id) sender 199{ 200 if ([[fDestination lastPathComponent] isEqualToString: [fTorrent name]] 201 && [[NSUserDefaults standardUserDefaults] boolForKey: @"WarningFolderDataSameName"]) 202 { 203 NSAlert * alert = [[NSAlert alloc] init]; 204 [alert setMessageText: NSLocalizedString(@"The destination directory and root data directory have the same name.", 205 "Add torrent -> same name -> title")]; 206 [alert setInformativeText: NSLocalizedString(@"If you are attempting to use already existing data," 207 " the root data directory should be inside the destination directory.", "Add torrent -> same name -> message")]; 208 [alert setAlertStyle: NSWarningAlertStyle]; 209 [alert addButtonWithTitle: NSLocalizedString(@"Cancel", "Add torrent -> same name -> button")]; 210 [alert addButtonWithTitle: NSLocalizedString(@"Add", "Add torrent -> same name -> button")]; 211 [alert setShowsSuppressionButton: YES]; 212 213 [alert beginSheetModalForWindow: [self window] modalDelegate: self 214 didEndSelector: @selector(sameNameAlertDidEnd:returnCode:contextInfo:) contextInfo: nil]; 215 } 216 else 217 [self confirmAdd]; 218} 219 220- (void) cancelAdd: (id) sender 221{ 222 [[self window] performClose: sender]; 223} 224 225//only called on cancel 226- (BOOL) windowShouldClose: (id) window 227{ 228 [fController askOpenMagnetConfirmed: self add: NO]; 229 return YES; 230} 231 232- (void) changePriority: (id) sender 233{ 234 tr_priority_t priority; 235 switch ([sender indexOfSelectedItem]) 236 { 237 case POPUP_PRIORITY_HIGH: priority = TR_PRI_HIGH; break; 238 case POPUP_PRIORITY_NORMAL: priority = TR_PRI_NORMAL; break; 239 case POPUP_PRIORITY_LOW: priority = TR_PRI_LOW; break; 240 default: 241 NSAssert1(NO, @"Unknown priority tag for adding torrent: %ld", [sender tag]); 242 priority = TR_PRI_NORMAL; 243 } 244 [fTorrent setPriority: priority]; 245} 246 247- (void) updateGroupMenu: (NSNotification *) notification 248{ 249 [self setGroupsMenu]; 250 if (![fGroupPopUp selectItemWithTag: fGroupValue]) 251 { 252 fGroupValue = -1; 253 fGroupDeterminationType = TorrentDeterminationAutomatic; 254 [fGroupPopUp selectItemWithTag: fGroupValue]; 255 } 256} 257 258@end 259 260@implementation AddMagnetWindowController (Private) 261 262- (void) confirmAdd 263{ 264 [fTorrent setGroupValue: fGroupValue determinationType: fGroupDeterminationType]; 265 266 if ([fStartCheck state] == NSOnState) 267 [fTorrent startTransfer]; 268 269 [self close]; 270 [fController askOpenMagnetConfirmed: self add: YES]; 271} 272 273- (void) setDestinationPath: (NSString *) destination determinationType: (TorrentDeterminationType) determinationType 274{ 275 destination = [destination stringByExpandingTildeInPath]; 276 if (!fDestination || ![fDestination isEqualToString: destination]) 277 { 278 fDestination = destination; 279 280 [fTorrent changeDownloadFolderBeforeUsing: fDestination determinationType: determinationType]; 281 } 282 283 [fLocationField setStringValue: [fDestination stringByAbbreviatingWithTildeInPath]]; 284 [fLocationField setToolTip: fDestination]; 285 286 ExpandedPathToIconTransformer * iconTransformer = [[ExpandedPathToIconTransformer alloc] init]; 287 [fLocationImageView setImage: [iconTransformer transformedValue: fDestination]]; 288} 289 290- (void) setGroupsMenu 291{ 292 NSMenu * groupMenu = [[GroupsController groups] groupMenuWithTarget: self action: @selector(changeGroupValue:) isSmall: NO]; 293 [fGroupPopUp setMenu: groupMenu]; 294} 295 296- (void) changeGroupValue: (id) sender 297{ 298 NSInteger previousGroup = fGroupValue; 299 fGroupValue = [sender tag]; 300 fGroupDeterminationType = TorrentDeterminationUserSpecified; 301 302 if ([[GroupsController groups] usesCustomDownloadLocationForIndex: fGroupValue]) 303 [self setDestinationPath: [[GroupsController groups] customDownloadLocationForIndex: fGroupValue] determinationType: TorrentDeterminationAutomatic]; 304 else if ([fDestination isEqualToString: [[GroupsController groups] customDownloadLocationForIndex: previousGroup]]) 305 [self setDestinationPath: [[NSUserDefaults standardUserDefaults] stringForKey: @"DownloadFolder"] determinationType: TorrentDeterminationAutomatic]; 306 else; 307} 308 309- (void) sameNameAlertDidEnd: (NSAlert *) alert returnCode: (NSInteger) returnCode contextInfo: (void *) contextInfo 310{ 311 if ([[alert suppressionButton] state] == NSOnState) 312 [[NSUserDefaults standardUserDefaults] setBool: NO forKey: @"WarningFolderDataSameName"]; 313 314 315 if (returnCode == NSAlertSecondButtonReturn) 316 [self performSelectorOnMainThread: @selector(confirmAdd) withObject: nil waitUntilDone: NO]; 317} 318 319@end 320