source: trunk/macosx/CreatorWindowController.m @ 13396

Last change on this file since 13396 was 13396, checked in by livings124, 9 years ago

#4956 Crash when creating a torrent on 10.7

  • Property Id set to /Users/mitchell/Desktop/Transmission/macosx/ActionMenuRatioToDisplayRatioTransformer.h
  • Property svn:keywords set to Date Rev Author Id
File size: 26.0 KB
Line 
1/******************************************************************************
2 * $Id: CreatorWindowController.m 13396 2012-07-23 11:31:48Z 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 "CreatorWindowController.h"
26#import "Controller.h"
27#import "NSApplicationAdditions.h"
28#import "NSStringAdditions.h"
29
30#import "transmission.h" // required by utils.h
31#import "utils.h" // tr_urlIsValidTracker()
32
33#define TRACKER_ADD_TAG 0
34#define TRACKER_REMOVE_TAG 1
35
36@interface CreatorWindowController (Private)
37
38+ (NSURL *) chooseFile;
39
40- (void) updateLocationField;
41- (void) createBlankAddressAlertDidEnd: (NSAlert *) alert returnCode: (NSInteger) returnCode contextInfo: (void *) contextInfo;
42- (void) createReal;
43- (void) checkProgress;
44- (void) failureSheetClosed: (NSAlert *) alert returnCode: (NSInteger) code contextInfo: (void *) info;
45
46@end
47
48@implementation CreatorWindowController
49
50+ (CreatorWindowController *) createTorrentFile: (tr_session *) handle
51{
52    //get file/folder for torrent
53    NSURL * path;
54    if (!(path = [CreatorWindowController chooseFile]))
55        return nil;
56   
57    CreatorWindowController * creator = [[self alloc] initWithHandle: handle path: path];
58    [creator showWindow: nil];
59    return creator;
60}
61
62+ (CreatorWindowController *) createTorrentFile: (tr_session *) handle forFile: (NSURL *) file
63{
64    CreatorWindowController * creator = [[self alloc] initWithHandle: handle path: file];
65    [creator showWindow: nil];
66    return creator;
67}
68
69- (id) initWithHandle: (tr_session *) handle path: (NSURL *) path
70{
71    if ((self = [super initWithWindowNibName: @"Creator"]))
72    {
73        fStarted = NO;
74       
75        fPath = [path retain];
76        fInfo = tr_metaInfoBuilderCreate([[fPath path] UTF8String]);
77       
78        if (fInfo->fileCount == 0)
79        {
80            NSAlert * alert = [[NSAlert alloc] init];
81            [alert addButtonWithTitle: NSLocalizedString(@"OK", "Create torrent -> no files -> button")];
82            [alert setMessageText: NSLocalizedString(@"This folder contains no files.",
83                                                    "Create torrent -> no files -> title")];
84            [alert setInformativeText: NSLocalizedString(@"There must be at least one file in a folder to create a torrent file.",
85                                                        "Create torrent -> no files -> warning")];
86            [alert setAlertStyle: NSWarningAlertStyle];
87           
88            [alert runModal];
89            [alert release];
90           
91            [self release];
92            return nil;
93        }
94        if (fInfo->totalSize == 0)
95        {
96            NSAlert * alert = [[NSAlert alloc] init];
97            [alert addButtonWithTitle: NSLocalizedString(@"OK", "Create torrent -> zero size -> button")];
98            [alert setMessageText: NSLocalizedString(@"The total file size is zero bytes.",
99                                                    "Create torrent -> zero size -> title")];
100            [alert setInformativeText: NSLocalizedString(@"A torrent file cannot be created for files with no size.",
101                                                        "Create torrent -> zero size -> warning")];
102            [alert setAlertStyle: NSWarningAlertStyle];
103           
104            [alert runModal];
105            [alert release];
106           
107            [self release];
108            return nil;
109        }
110       
111        fDefaults = [NSUserDefaults standardUserDefaults];
112       
113        //get list of trackers
114        if (!(fTrackers = [[fDefaults arrayForKey: @"CreatorTrackers"] mutableCopy]))
115        {
116            fTrackers = [[NSMutableArray alloc] init];
117           
118            //check for single tracker from versions before 1.3
119            NSString * tracker;
120            if ((tracker = [fDefaults stringForKey: @"CreatorTracker"]))
121            {
122                [fDefaults removeObjectForKey: @"CreatorTracker"];
123                if (![tracker isEqualToString: @""])
124                {
125                    [fTrackers addObject: tracker];
126                    [fDefaults setObject: fTrackers forKey: @"CreatorTrackers"];
127                }
128            }
129        }
130       
131        //remove potentially invalid addresses
132        for (NSInteger i = [fTrackers count]-1; i >= 0; i--)
133        {
134            if (!tr_urlIsValidTracker([[fTrackers objectAtIndex: i] UTF8String]))
135                [fTrackers removeObjectAtIndex: i];
136        }
137    }
138    return self;
139}
140
141- (void) awakeFromNib
142{
143    if ([NSApp isOnLionOrBetter])
144        [[self window] setRestorationClass: [self class]];
145   
146    NSString * name = [fPath lastPathComponent];
147   
148    [[self window] setTitle: name];
149   
150    [fNameField setStringValue: name];
151    [fNameField setToolTip: [fPath path]];
152   
153    const BOOL multifile = !fInfo->isSingleFile;
154   
155    NSImage * icon = [[NSWorkspace sharedWorkspace] iconForFileType: multifile
156                        ? NSFileTypeForHFSTypeCode(kGenericFolderIcon) : [fPath pathExtension]];
157    [icon setSize: [fIconView frame].size];
158    [fIconView setImage: icon];
159   
160    NSString * statusString = [NSString stringForFileSize: fInfo->totalSize];
161    if (multifile)
162    {
163        NSString * fileString;
164        NSInteger count = fInfo->fileCount;
165        if (count != 1)
166            fileString = [NSString stringWithFormat: NSLocalizedString(@"%@ files", "Create torrent -> info"),
167                            [NSString formattedUInteger: count]];
168        else
169            fileString = NSLocalizedString(@"1 file", "Create torrent -> info");
170        statusString = [NSString stringWithFormat: @"%@, %@", fileString, statusString];
171    }
172    [fStatusField setStringValue: statusString];
173   
174    if (fInfo->pieceCount == 1)
175        [fPiecesField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"1 piece, %@", "Create torrent -> info"),
176                                                            [NSString stringForFileSize: fInfo->pieceSize]]];
177    else
178        [fPiecesField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%d pieces, %@ each", "Create torrent -> info"),
179                                                            fInfo->pieceCount, [NSString stringForFileSize: fInfo->pieceSize]]];
180   
181    fLocation = [[[fDefaults URLForKey: @"CreatorLocationURL"] URLByAppendingPathComponent: [name stringByAppendingPathExtension: @"torrent"]] retain];
182    if (!fLocation)
183    {
184        //for 2.5 and earlier
185        #warning we still store "CreatorLocation" in Defaults.plist, and not "CreatorLocationURL"
186        NSString * location = [fDefaults stringForKey: @"CreatorLocation"];
187        fLocation = [[NSURL alloc] initFileURLWithPath: [[location stringByExpandingTildeInPath] stringByAppendingPathComponent: [name stringByAppendingPathExtension: @"torrent"]]];
188    }
189    [self updateLocationField];
190   
191    //set previously saved values
192    if ([fDefaults objectForKey: @"CreatorPrivate"])
193        [fPrivateCheck setState: [fDefaults boolForKey: @"CreatorPrivate"] ? NSOnState : NSOffState];
194   
195    [fOpenCheck setState: [fDefaults boolForKey: @"CreatorOpen"] ? NSOnState : NSOffState];
196}
197
198- (void) dealloc
199{
200    [fPath release];
201    [fLocation release];
202   
203    [fTrackers release];
204   
205    if (fInfo)
206        tr_metaInfoBuilderFree(fInfo);
207   
208    [fTimer invalidate];
209   
210    [super dealloc];
211}
212
213+ (void) restoreWindowWithIdentifier: (NSString *) identifier state: (NSCoder *) state completionHandler: (void (^)(NSWindow *, NSError *)) completionHandler
214{
215    NSURL * path = [state decodeObjectForKey: @"TRCreatorPath"];
216    if (!path || ![path checkResourceIsReachableAndReturnError: nil])
217    {
218        completionHandler(nil, [NSError errorWithDomain: NSURLErrorDomain code: NSURLErrorCannotOpenFile userInfo: nil]);
219        return;
220    }
221   
222    NSWindow * window = [[self createTorrentFile: [(Controller *)[NSApp delegate] sessionHandle] forFile: path] window];
223    completionHandler(window, nil);
224}
225
226- (void) window: (NSWindow *) window willEncodeRestorableState: (NSCoder *) state
227{
228    [state encodeObject: fPath forKey: @"TRCreatorPath"];
229    [state encodeObject: fLocation forKey: @"TRCreatorLocation"];
230    [state encodeObject: fTrackers forKey: @"TRCreatorTrackers"];
231    [state encodeInteger: [fOpenCheck state] forKey: @"TRCreatorOpenCheck"];
232    [state encodeInteger: [fPrivateCheck state] forKey: @"TRCreatorPrivateCheck"];
233    [state encodeObject: [fCommentView string] forKey: @"TRCreatorPrivateComment"];
234}
235
236- (void) window: (NSWindow *) window didDecodeRestorableState: (NSCoder *) coder
237{
238    [fLocation release];
239    fLocation = [[coder decodeObjectForKey: @"TRCreatorLocation"] retain];
240    [self updateLocationField];
241   
242    [fTrackers release];
243    fTrackers = [[coder decodeObjectForKey: @"TRCreatorTrackers"] retain];
244    [fTrackerTable reloadData];
245   
246    [fOpenCheck setState: [coder decodeIntegerForKey: @"TRCreatorOpenCheck"]];
247    [fPrivateCheck setState: [coder decodeIntegerForKey: @"TRCreatorPrivateCheck"]];
248    [fCommentView setString: [coder decodeObjectForKey: @"TRCreatorPrivateComment"]];
249}
250
251- (IBAction) setLocation: (id) sender
252{
253    NSSavePanel * panel = [NSSavePanel savePanel];
254
255    [panel setPrompt: NSLocalizedString(@"Select", "Create torrent -> location sheet -> button")];
256    [panel setMessage: NSLocalizedString(@"Select the name and location for the torrent file.",
257                                        "Create torrent -> location sheet -> message")];
258   
259    [panel setAllowedFileTypes: [NSArray arrayWithObjects: @"org.bittorrent.torrent", @"torrent", nil]];
260    [panel setCanSelectHiddenExtension: YES];
261   
262    [panel setDirectoryURL: [fLocation URLByDeletingLastPathComponent]];
263    [panel setNameFieldStringValue: [fLocation lastPathComponent]];
264   
265    [panel beginSheetModalForWindow: [self window] completionHandler: ^(NSInteger result) {
266        if (result == NSFileHandlingPanelOKButton)
267        {
268            [fLocation release];
269            fLocation = [[panel URL] retain];
270            [self updateLocationField];
271        }
272    }];
273}
274
275- (IBAction) create: (id) sender
276{
277    //make sure the trackers are no longer being verified
278    if ([fTrackerTable editedRow] != -1)
279        [[self window] endEditingFor: fTrackerTable];
280   
281    const BOOL isPrivate = [fPrivateCheck state] == NSOnState;
282    if ([fTrackers count] == 0
283        && [fDefaults boolForKey: isPrivate ? @"WarningCreatorPrivateBlankAddress" : @"WarningCreatorBlankAddress"])
284    {
285        NSAlert * alert = [[NSAlert alloc] init];
286        [alert setMessageText: NSLocalizedString(@"There are no tracker addresses.", "Create torrent -> blank address -> title")];
287       
288        NSString * infoString = isPrivate
289                    ? NSLocalizedString(@"A transfer marked as private with no tracker addresses will be unable to connect to peers."
290                        " The torrent file will only be useful if you plan to upload the file to a tracker website"
291                        " that will add the addresses for you.", "Create torrent -> blank address -> message")
292                    : NSLocalizedString(@"The transfer will not contact trackers for peers, and will have to rely solely on"
293                        " non-tracker peer discovery methods such as PEX and DHT to download and seed.",
294                        "Create torrent -> blank address -> message");
295       
296        [alert setInformativeText: infoString];
297        [alert addButtonWithTitle: NSLocalizedString(@"Create", "Create torrent -> blank address -> button")];
298        [alert addButtonWithTitle: NSLocalizedString(@"Cancel", "Create torrent -> blank address -> button")];
299        [alert setShowsSuppressionButton: YES];
300
301        [alert beginSheetModalForWindow: [self window] modalDelegate: self
302            didEndSelector: @selector(createBlankAddressAlertDidEnd:returnCode:contextInfo:) contextInfo: nil];
303    }
304    else
305        [self createReal];
306}
307
308- (IBAction) cancelCreateWindow: (id) sender
309{
310    [[self window] close];
311}
312
313- (void) windowWillClose: (NSNotification *) notification
314{
315    [self autorelease];
316}
317
318- (IBAction) cancelCreateProgress: (id) sender
319{
320    fInfo->abortFlag = 1;
321    [fTimer fire];
322}
323
324- (NSInteger) numberOfRowsInTableView: (NSTableView *) tableView
325{
326    return [fTrackers count];
327}
328
329- (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row
330{
331    return [fTrackers objectAtIndex: row];
332}
333
334- (IBAction) addRemoveTracker: (id) sender
335{
336    //don't allow add/remove when currently adding - it leads to weird results
337    if ([fTrackerTable editedRow] != -1)
338        return;
339   
340    if ([[sender cell] tagForSegment: [sender selectedSegment]] == TRACKER_REMOVE_TAG)
341    {
342        [fTrackers removeObjectsAtIndexes: [fTrackerTable selectedRowIndexes]];
343       
344        [fTrackerTable deselectAll: self];
345        [fTrackerTable reloadData];
346    }
347    else
348    {
349        [fTrackers addObject: @""];
350        [fTrackerTable reloadData];
351       
352        const NSInteger row = [fTrackers count] - 1;
353        [fTrackerTable selectRowIndexes: [NSIndexSet indexSetWithIndex: row] byExtendingSelection: NO];
354        [fTrackerTable editColumn: 0 row: row withEvent: nil select: YES];
355    }
356}
357
358- (void) tableView: (NSTableView *) tableView setObjectValue: (id) object forTableColumn: (NSTableColumn *) tableColumn
359    row: (NSInteger) row
360{
361    NSString * tracker = (NSString *)object;
362   
363    tracker = [tracker stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
364   
365    if ([tracker rangeOfString: @"://"].location == NSNotFound)
366        tracker = [@"http://" stringByAppendingString: tracker];
367   
368    if (!tr_urlIsValidTracker([tracker UTF8String]))
369    {
370        NSBeep();
371        [fTrackers removeObjectAtIndex: row];
372    }
373    else
374        [fTrackers replaceObjectAtIndex: row withObject: tracker];
375   
376    [fTrackerTable deselectAll: self];
377    [fTrackerTable reloadData];
378}
379
380- (void) tableViewSelectionDidChange: (NSNotification *) notification
381{
382    [fTrackerAddRemoveControl setEnabled: [fTrackerTable numberOfSelectedRows] > 0 forSegment: TRACKER_REMOVE_TAG];
383}
384
385- (void) copy: (id) sender
386{
387    NSArray * addresses = [fTrackers objectsAtIndexes: [fTrackerTable selectedRowIndexes]];
388    NSString * text = [addresses componentsJoinedByString: @"\n"];
389   
390    NSPasteboard * pb = [NSPasteboard generalPasteboard];
391    [pb clearContents];
392    [pb writeObjects: [NSArray arrayWithObject: text]];
393}
394
395- (BOOL) validateMenuItem: (NSMenuItem *) menuItem
396{
397    const SEL action = [menuItem action];
398   
399    if (action == @selector(copy:))
400        return [[self window] firstResponder] == fTrackerTable && [fTrackerTable numberOfSelectedRows] > 0;
401   
402    if (action == @selector(paste:))
403        return [[self window] firstResponder] == fTrackerTable
404            && [[NSPasteboard generalPasteboard] canReadObjectForClasses: [NSArray arrayWithObject: [NSString class]] options: nil];
405   
406    return YES;
407}
408
409- (void) paste: (id) sender
410{
411    NSMutableArray * tempTrackers = [NSMutableArray array];
412   
413    NSArray * items = [[NSPasteboard generalPasteboard] readObjectsForClasses: [NSArray arrayWithObject: [NSString class]] options: nil];
414    NSAssert(items != nil, @"no string items to paste; should not be able to call this method");
415   
416    for (NSString * pbItem in items)
417    {
418        for (NSString * tracker in [pbItem componentsSeparatedByString: @"\n"])
419            [tempTrackers addObject: tracker];
420    }
421   
422    BOOL added = NO;
423   
424    for (NSString * tracker in tempTrackers)
425    {
426        tracker = [tracker stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
427       
428        if ([tracker rangeOfString: @"://"].location == NSNotFound)
429            tracker = [@"http://" stringByAppendingString: tracker];
430       
431        if (tr_urlIsValidTracker([tracker UTF8String]))
432        {
433            [fTrackers addObject: tracker];
434            added = YES;
435        }
436    }
437   
438    if (added)
439    {
440        [fTrackerTable deselectAll: self];
441        [fTrackerTable reloadData];
442    }
443    else
444        NSBeep();
445}
446
447@end
448
449@implementation CreatorWindowController (Private)
450
451- (void) updateLocationField
452{
453    NSString * pathString = [fLocation path];
454    [fLocationField setStringValue: [pathString stringByAbbreviatingWithTildeInPath]];
455    [fLocationField setToolTip: pathString];
456}
457
458+ (NSURL *) chooseFile
459{
460    NSOpenPanel * panel = [NSOpenPanel openPanel];
461   
462    [panel setTitle: NSLocalizedString(@"Create Torrent File", "Create torrent -> select file")];
463    [panel setPrompt: NSLocalizedString(@"Select", "Create torrent -> select file")];
464    [panel setAllowsMultipleSelection: NO];
465    [panel setCanChooseFiles: YES];
466    [panel setCanChooseDirectories: YES];
467    [panel setCanCreateDirectories: NO];
468
469    [panel setMessage: NSLocalizedString(@"Select a file or folder for the torrent file.", "Create torrent -> select file")];
470   
471    BOOL success = [panel runModal] == NSOKButton;
472    return success ? [[panel URLs] objectAtIndex: 0] : nil;
473}
474
475- (void) createBlankAddressAlertDidEnd: (NSAlert *) alert returnCode: (NSInteger) returnCode contextInfo: (void *) contextInfo
476{
477    if ([[alert suppressionButton] state] == NSOnState)
478    {
479        [[NSUserDefaults standardUserDefaults] setBool: NO forKey: @"WarningCreatorBlankAddress"]; //set regardless of private/public
480        if ([fPrivateCheck state] == NSOnState)
481            [[NSUserDefaults standardUserDefaults] setBool: NO forKey: @"WarningCreatorPrivateBlankAddress"];
482    }
483   
484    [alert release];
485   
486    if (returnCode == NSAlertFirstButtonReturn)
487        [self performSelectorOnMainThread: @selector(createReal) withObject: nil waitUntilDone: NO];
488}
489
490- (void) createReal
491{
492    //check if the location currently exists
493    if (![[fLocation URLByDeletingLastPathComponent] checkResourceIsReachableAndReturnError: NULL])
494    {
495        NSAlert * alert = [[[NSAlert alloc] init] autorelease];
496        [alert addButtonWithTitle: NSLocalizedString(@"OK", "Create torrent -> directory doesn't exist warning -> button")];
497        [alert setMessageText: NSLocalizedString(@"The chosen torrent file location does not exist.",
498                                                "Create torrent -> directory doesn't exist warning -> title")];
499        [alert setInformativeText: [NSString stringWithFormat:
500                NSLocalizedString(@"The directory \"%@\" does not currently exist. "
501                    "Create this directory or choose a different one to create the torrent file.",
502                    "Create torrent -> directory doesn't exist warning -> warning"),
503                    [[fLocation URLByDeletingLastPathComponent] path]]];
504        [alert setAlertStyle: NSWarningAlertStyle];
505       
506        [alert beginSheetModalForWindow: [self window] modalDelegate: self didEndSelector: nil contextInfo: nil];
507        return;
508    }
509   
510    //check if a file with the same name and location already exists
511    if ([fLocation checkResourceIsReachableAndReturnError: NULL])
512    {
513        NSArray * pathComponents = [fLocation pathComponents];
514        NSInteger count = [pathComponents count];
515       
516        NSAlert * alert = [[[NSAlert alloc] init] autorelease];
517        [alert addButtonWithTitle: NSLocalizedString(@"OK", "Create torrent -> file already exists warning -> button")];
518        [alert setMessageText: NSLocalizedString(@"A torrent file with this name and directory cannot be created.",
519                                                "Create torrent -> file already exists warning -> title")];
520        [alert setInformativeText: [NSString stringWithFormat:
521                NSLocalizedString(@"A file with the name \"%@\" already exists in the directory \"%@\". "
522                    "Choose a new name or directory to create the torrent file.",
523                    "Create torrent -> file already exists warning -> warning"),
524                    [pathComponents objectAtIndex: count-1], [pathComponents objectAtIndex: count-2]]];
525        [alert setAlertStyle: NSWarningAlertStyle];
526       
527        [alert beginSheetModalForWindow: [self window] modalDelegate: self didEndSelector: nil contextInfo: nil];
528        return;
529    }
530   
531    //parse non-empty tracker strings
532    tr_tracker_info * trackerInfo = tr_new0(tr_tracker_info, [fTrackers count]);
533   
534    for (NSUInteger i = 0; i < [fTrackers count]; i++)
535    {
536        trackerInfo[i].announce = (char *)[[fTrackers objectAtIndex: i] UTF8String];
537        trackerInfo[i].tier = i;
538    }
539   
540    //store values
541    [fDefaults setObject: fTrackers forKey: @"CreatorTrackers"];
542    [fDefaults setBool: [fPrivateCheck state] == NSOnState forKey: @"CreatorPrivate"];
543    [fDefaults setBool: [fOpenCheck state] == NSOnState forKey: @"CreatorOpen"];
544    fOpenWhenCreated = [fOpenCheck state] == NSOnState; //need this since the check box might not exist, and value in prefs might have changed from another creator window
545    [fDefaults setURL: [fLocation URLByDeletingLastPathComponent] forKey: @"CreatorLocationURL"];
546   
547    if ([NSApp isOnLionOrBetter])
548        [[self window] setRestorable: NO];
549   
550    [[NSNotificationCenter defaultCenter] postNotificationName: @"BeginCreateTorrentFile" object: fLocation userInfo: nil];
551    tr_makeMetaInfo(fInfo, [[fLocation path] UTF8String], trackerInfo, [fTrackers count], [[fCommentView string] UTF8String], [fPrivateCheck state] == NSOnState);
552    tr_free(trackerInfo);
553   
554    fTimer = [NSTimer scheduledTimerWithTimeInterval: 0.1 target: self selector: @selector(checkProgress)
555                userInfo: nil repeats: YES];
556}
557
558- (void) checkProgress
559{
560    if (fInfo->isDone)
561    {
562        [fTimer invalidate];
563        fTimer = nil;
564       
565        NSAlert * alert;
566        switch (fInfo->result)
567        {
568            case TR_MAKEMETA_OK:
569                if (fOpenWhenCreated)
570                {
571                    NSDictionary * dict = [[NSDictionary alloc] initWithObjectsAndKeys: [fLocation path], @"File",
572                                            [[fPath URLByDeletingLastPathComponent] path], @"Path", nil];
573                    [[NSNotificationCenter defaultCenter] postNotificationName: @"OpenCreatedTorrentFile" object: self userInfo: dict];
574                }
575               
576                [[self window] close];
577                break;
578           
579            case TR_MAKEMETA_CANCELLED:
580                [[self window] close];
581                break;
582           
583            default:
584                alert = [[[NSAlert alloc] init] autorelease];
585                [alert addButtonWithTitle: NSLocalizedString(@"OK", "Create torrent -> failed -> button")];
586                [alert setMessageText: [NSString stringWithFormat: NSLocalizedString(@"Creation of \"%@\" failed.",
587                                                "Create torrent -> failed -> title"), [fLocation lastPathComponent]]];
588                [alert setAlertStyle: NSWarningAlertStyle];
589               
590                if (fInfo->result == TR_MAKEMETA_IO_READ)
591                    [alert setInformativeText: [NSString stringWithFormat: NSLocalizedString(@"Could not read \"%s\": %s.",
592                        "Create torrent -> failed -> warning"), fInfo->errfile, strerror(fInfo->my_errno)]];
593                else if (fInfo->result == TR_MAKEMETA_IO_WRITE)
594                    [alert setInformativeText: [NSString stringWithFormat: NSLocalizedString(@"Could not write \"%s\": %s.",
595                        "Create torrent -> failed -> warning"), fInfo->errfile, strerror(fInfo->my_errno)]];
596                else //invalid url should have been caught before creating
597                    [alert setInformativeText: [NSString stringWithFormat: @"%@ (%d)",
598                        NSLocalizedString(@"An unknown error has occurred.", "Create torrent -> failed -> warning"), fInfo->result]];
599               
600                [alert beginSheetModalForWindow: [self window] modalDelegate: self
601                    didEndSelector: @selector(failureSheetClosed:returnCode:contextInfo:) contextInfo: nil];
602        }
603    }
604    else
605    {
606        [fProgressIndicator setDoubleValue: (double)fInfo->pieceIndex / fInfo->pieceCount];
607       
608        if (!fStarted)
609        {
610            fStarted = YES;
611           
612            [fProgressView setHidden: YES];
613           
614            NSWindow * window = [self window];
615            [window setFrameAutosaveName: @""];
616           
617            NSRect windowRect = [window frame];
618            CGFloat difference = [fProgressView frame].size.height - [[window contentView] frame].size.height;
619            windowRect.origin.y -= difference;
620            windowRect.size.height += difference;
621           
622            //don't allow vertical resizing
623            CGFloat height = windowRect.size.height;
624            [window setMinSize: NSMakeSize([window minSize].width, height)];
625            [window setMaxSize: NSMakeSize([window maxSize].width, height)];
626           
627            [window setContentView: fProgressView];
628            [window setFrame: windowRect display: YES animate: YES];
629            [fProgressView setHidden: NO];
630           
631            [[window standardWindowButton: NSWindowCloseButton] setEnabled: NO];
632        }
633    }
634}
635
636- (void) failureSheetClosed: (NSAlert *) alert returnCode: (NSInteger) code contextInfo: (void *) info
637{
638    [[alert window] orderOut: nil];
639    [[self window] close];
640}
641
642@end
Note: See TracBrowser for help on using the repository browser.