source: trunk/macosx/PrefsController.m @ 956

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

Status on ports in prefs window. Thanks to cluthi on the forums for this.

  • Property svn:keywords set to Date Rev Author Id
File size: 31.8 KB
Line 
1/******************************************************************************
2 * $Id: PrefsController.m 956 2006-09-28 21:14:49Z livings124 $
3 *
4 * Copyright (c) 2005-2006 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 "PrefsController.h"
26#import "StringAdditions.h"
27#import "UKKQueue.h"
28
29#define MIN_PORT    1
30#define MAX_PORT    65535
31
32#define DOWNLOAD_FOLDER     0
33#define DOWNLOAD_TORRENT    2
34#define DOWNLOAD_ASK        3
35
36#define UPDATE_DAILY    0
37#define UPDATE_WEEKLY   1
38#define UPDATE_NEVER    2
39
40#define TOOLBAR_GENERAL     @"General"
41#define TOOLBAR_TRANSFERS   @"Transfers"
42#define TOOLBAR_BANDWIDTH   @"Bandwidth"
43#define TOOLBAR_NETWORK     @"Network"
44
45@interface PrefsController (Private)
46
47- (void) showGeneralPref: (id) sender;
48- (void) showTransfersPref: (id) sender;
49- (void) showBandwidthPref: (id) sender;
50- (void) showNetworkPref: (id) sender;
51
52- (void) setPrefView: (NSView *) view;
53
54- (void) folderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info;
55- (void) updatePopUp;
56
57- (void) importFolderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info;
58- (void) updateImportPopUp;
59
60@end
61
62@implementation PrefsController
63
64- (id) initWithWindowNibName: (NSString *) name handle: (tr_handle_t *) handle
65{
66    if ((self = [self initWithWindowNibName: name]))
67    {
68        fDefaults = [NSUserDefaults standardUserDefaults];
69        fHandle = handle;
70       
71        [[self window] update]; //make sure nib is loaded right away
72    }
73    return self;
74}
75
76- (void) dealloc
77{
78    [fNatStatusTimer invalidate];
79
80    [fDownloadFolder release];
81    [fImportFolder release];
82    [super dealloc];
83}
84
85- (void) awakeFromNib
86{
87    fToolbar = [[NSToolbar alloc] initWithIdentifier: @"Preferences Toolbar"];
88    [fToolbar setDelegate: self];
89    [fToolbar setAllowsUserCustomization: NO];
90    [[self window] setToolbar: fToolbar];
91    [fToolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
92    [fToolbar setSizeMode: NSToolbarSizeModeRegular];
93
94    [fToolbar setSelectedItemIdentifier: TOOLBAR_GENERAL];
95    [self showGeneralPref: nil];
96   
97    //set download folder
98    NSString * downloadChoice = [fDefaults stringForKey: @"DownloadChoice"];
99    fDownloadFolder = [[[fDefaults stringForKey: @"DownloadFolder"] stringByExpandingTildeInPath] retain];
100    if ([downloadChoice isEqualToString: @"Constant"])
101        [fFolderPopUp selectItemAtIndex: DOWNLOAD_FOLDER];
102    else if ([downloadChoice isEqualToString: @"Torrent"])
103        [fFolderPopUp selectItemAtIndex: DOWNLOAD_TORRENT];
104    else
105        [fFolderPopUp selectItemAtIndex: DOWNLOAD_ASK];
106    [self updatePopUp];
107   
108    //set auto import
109    fImportFolder = [[[fDefaults stringForKey: @"AutoImportDirectory"] stringByExpandingTildeInPath] retain];
110    [self updateImportPopUp];
111 
112    BOOL autoImport = [fDefaults boolForKey: @"AutoImport"];
113    [fAutoImportCheck setState: autoImport];
114    [fImportFolderPopUp setEnabled: autoImport];
115   
116    if (autoImport)
117        [[UKKQueue sharedFileWatcher] addPath: fImportFolder];
118   
119    //set auto size
120    [fAutoSizeCheck setState: [fDefaults boolForKey: @"AutoSize"]];
121   
122    //set bind port
123    int bindPort = [fDefaults integerForKey: @"BindPort"];
124    [fPortField setIntValue: bindPort];
125    tr_setBindPort(fHandle, bindPort);
126    [self updatePortStatus];
127   
128    //set NAT
129    BOOL natShouldEnable = [fDefaults boolForKey: @"NatTraversal"];
130    if (natShouldEnable)
131        tr_natTraversalEnable(fHandle);
132    [fNatCheck setState: natShouldEnable];
133   
134    fNatStatus = -1;
135    [self updateNatStatus];
136    fNatStatusTimer = [NSTimer scheduledTimerWithTimeInterval: 5.0 target: self
137                        selector: @selector(updateNatStatus) userInfo: nil repeats: YES];
138   
139    //checks for old version upload speed of -1
140    if ([fDefaults integerForKey: @"UploadLimit"] < 0)
141    {
142        [fDefaults setInteger: 20 forKey: @"UploadLimit"];
143        [fDefaults setBool: NO forKey: @"CheckUpload"];
144    }
145   
146    //set upload limit
147    BOOL checkUpload = [fDefaults boolForKey: @"CheckUpload"];
148    int uploadLimit = [fDefaults integerForKey: @"UploadLimit"];
149   
150    [fUploadCheck setState: checkUpload];
151    [fUploadField setIntValue: uploadLimit];
152    [fUploadField setEnabled: checkUpload];
153
154        //set download limit
155    BOOL checkDownload = [fDefaults boolForKey: @"CheckDownload"];
156    int downloadLimit = [fDefaults integerForKey: @"DownloadLimit"];
157   
158    [fDownloadCheck setState: checkDownload];
159    [fDownloadField setIntValue: downloadLimit];
160    [fDownloadField setEnabled: checkDownload];
161   
162    //set speed limit
163    int speedLimitUploadLimit = [fDefaults integerForKey: @"SpeedLimitUploadLimit"];
164    [fSpeedLimitUploadField setIntValue: speedLimitUploadLimit];
165   
166    int speedLimitDownloadLimit = [fDefaults integerForKey: @"SpeedLimitDownloadLimit"];
167    [fSpeedLimitDownloadField setIntValue: speedLimitDownloadLimit];
168   
169    //actually set bandwidth limits
170    if ([fDefaults boolForKey: @"SpeedLimit"])
171    {
172        tr_setUploadLimit(fHandle, speedLimitUploadLimit);
173        tr_setDownloadLimit(fHandle, speedLimitDownloadLimit);
174    }
175    else
176    {
177        tr_setUploadLimit(fHandle, checkUpload ? uploadLimit : -1);
178        tr_setDownloadLimit(fHandle, checkDownload ? downloadLimit : -1);
179    }
180   
181    //set auto speed limit
182    BOOL speedLimitAuto = [fDefaults boolForKey: @"SpeedLimitAuto"];
183    [fSpeedLimitAutoCheck setState: speedLimitAuto];
184   
185    int speedLimitAutoOnHour = [fDefaults integerForKey: @"SpeedLimitAutoOnHour"];
186    [fSpeedLimitAutoOnField setStringValue: [NSString stringWithFormat: @"%02d", speedLimitAutoOnHour]];
187    [fSpeedLimitAutoOnField setEnabled: speedLimitAuto];
188   
189    int speedLimitAutoOffHour = [fDefaults integerForKey: @"SpeedLimitAutoOffHour"];
190    [fSpeedLimitAutoOffField setStringValue: [NSString stringWithFormat: @"%02d", speedLimitAutoOffHour]];
191    [fSpeedLimitAutoOffField setEnabled: speedLimitAuto];
192   
193    //set ratio limit
194    BOOL ratioCheck = [fDefaults boolForKey: @"RatioCheck"];
195    [fRatioCheck setState: ratioCheck];
196    [fRatioField setEnabled: ratioCheck];
197    [fRatioField setFloatValue: [fDefaults floatForKey: @"RatioLimit"]];
198   
199    //set remove and quit prompts
200    BOOL isQuitCheck = [fDefaults boolForKey: @"CheckQuit"],
201        isRemoveCheck = [fDefaults boolForKey: @"CheckRemove"];
202   
203    [fQuitCheck setState: isQuitCheck];
204    [fRemoveCheck setState: isRemoveCheck];
205   
206    [fQuitDownloadingCheck setState: [fDefaults boolForKey: @"CheckQuitDownloading"]];
207    [fQuitDownloadingCheck setEnabled: isQuitCheck];
208    [fRemoveDownloadingCheck setState: [fDefaults boolForKey: @"CheckRemoveDownloading"]];
209    [fRemoveDownloadingCheck setEnabled: isRemoveCheck];
210
211    //set dock badging
212    [fBadgeDownloadRateCheck setState: [fDefaults boolForKey: @"BadgeDownloadRate"]];
213    [fBadgeUploadRateCheck setState: [fDefaults boolForKey: @"BadgeUploadRate"]];
214   
215    //set play sound
216    NSMutableArray * sounds = [NSMutableArray array];
217    NSEnumerator * soundEnumerator,
218                * soundDirectoriesEnumerator = [[NSArray arrayWithObjects: @"System/Library/Sounds",
219                        [NSHomeDirectory() stringByAppendingPathComponent: @"Library/Sounds"], nil] objectEnumerator];
220    NSString * soundPath, * sound;
221   
222    //get list of all sounds and sort alphabetically
223    while ((soundPath = [soundDirectoriesEnumerator nextObject]))
224        if (soundEnumerator = [[NSFileManager defaultManager] enumeratorAtPath: soundPath])
225            while ((sound = [soundEnumerator nextObject]))
226            {
227                sound = [sound stringByDeletingPathExtension];
228                if ([NSSound soundNamed: sound])
229                    [sounds addObject: sound];
230            }
231   
232    [sounds sortUsingSelector: @selector(caseInsensitiveCompare:)];
233   
234    //set download sound
235    [fDownloadSoundPopUp removeAllItems];
236    [fDownloadSoundPopUp addItemsWithTitles: sounds];
237   
238    BOOL playDownloadSound = [fDefaults boolForKey: @"PlayDownloadSound"];
239    [fPlayDownloadSoundCheck setState: playDownloadSound];
240    [fDownloadSoundPopUp setEnabled: playDownloadSound];
241   
242    int downloadSoundIndex = [fDownloadSoundPopUp indexOfItemWithTitle: [fDefaults stringForKey: @"DownloadSound"]];
243    if (downloadSoundIndex >= 0)
244        [fDownloadSoundPopUp selectItemAtIndex: downloadSoundIndex];
245    else
246        [fDefaults setObject: [fDownloadSoundPopUp titleOfSelectedItem] forKey: @"DownloadSound"];
247   
248    //set seeding sound
249    [fSeedingSoundPopUp removeAllItems];
250    [fSeedingSoundPopUp addItemsWithTitles: sounds];
251   
252    BOOL playSeedingSound = [fDefaults boolForKey: @"PlaySeedingSound"];
253    [fPlaySeedingSoundCheck setState: playSeedingSound];
254    [fSeedingSoundPopUp setEnabled: playSeedingSound];
255   
256    int seedingSoundIndex = [fDownloadSoundPopUp indexOfItemWithTitle: [fDefaults stringForKey: @"SeedingSound"]];
257    if (seedingSoundIndex >= 0)
258        [fSeedingSoundPopUp selectItemAtIndex: seedingSoundIndex];
259    else
260        [fDefaults setObject: [fSeedingSoundPopUp titleOfSelectedItem] forKey: @"SeedingSound"];
261   
262    //set start settings
263    BOOL useQueue = [fDefaults boolForKey: @"Queue"];
264    [fQueueCheck setState: useQueue];
265    [fQueueNumberField setEnabled: useQueue];
266    [fQueueNumberField setIntValue: [fDefaults integerForKey: @"QueueDownloadNumber"]];
267   
268    [fStartAtOpenCheck setState: [fDefaults boolForKey: @"AutoStartDownload"]];
269   
270    //set private torrents
271    BOOL copyTorrents = [fDefaults boolForKey: @"SavePrivateTorrent"];
272    [fCopyTorrentCheck setState: copyTorrents];
273   
274    [fDeleteOriginalTorrentCheck setEnabled: copyTorrents];
275    [fDeleteOriginalTorrentCheck setState: [fDefaults boolForKey: @"DeleteOriginalTorrent"]];
276
277    //set update check
278    NSString * updateCheck = [fDefaults stringForKey: @"UpdateCheck"];
279    if ([updateCheck isEqualToString: @"Weekly"])
280        [fUpdatePopUp selectItemAtIndex: UPDATE_WEEKLY];
281    else if ([updateCheck isEqualToString: @"Never"])
282        [fUpdatePopUp selectItemAtIndex: UPDATE_NEVER];
283    else
284        [fUpdatePopUp selectItemAtIndex: UPDATE_DAILY];
285}
286
287- (NSToolbarItem *) toolbar: (NSToolbar *) t itemForItemIdentifier:
288    (NSString *) ident willBeInsertedIntoToolbar: (BOOL) flag
289{
290    NSToolbarItem * item;
291    item = [[NSToolbarItem alloc] initWithItemIdentifier: ident];
292
293    if ([ident isEqualToString: TOOLBAR_GENERAL])
294    {
295        [item setLabel: TOOLBAR_GENERAL];
296        [item setImage: [NSImage imageNamed: @"Preferences.png"]];
297        [item setTarget: self];
298        [item setAction: @selector(showGeneralPref:)];
299    }
300    else if ([ident isEqualToString: TOOLBAR_TRANSFERS])
301    {
302        [item setLabel: TOOLBAR_TRANSFERS];
303        [item setImage: [NSImage imageNamed: @"Transfers.png"]];
304        [item setTarget: self];
305        [item setAction: @selector(showTransfersPref:)];
306    }
307    else if ([ident isEqualToString: TOOLBAR_BANDWIDTH])
308    {
309        [item setLabel: TOOLBAR_BANDWIDTH];
310        [item setImage: [NSImage imageNamed: @"Bandwidth.png"]];
311        [item setTarget: self];
312        [item setAction: @selector(showBandwidthPref:)];
313    }
314    else if ([ident isEqualToString: TOOLBAR_NETWORK])
315    {
316        [item setLabel: TOOLBAR_NETWORK];
317        [item setImage: [NSImage imageNamed: @"Network.png"]];
318        [item setTarget: self];
319        [item setAction: @selector(showNetworkPref:)];
320    }
321    else
322    {
323        [item release];
324        return nil;
325    }
326
327    return item;
328}
329
330- (NSArray *) toolbarSelectableItemIdentifiers: (NSToolbar *) toolbar
331{
332    return [self toolbarDefaultItemIdentifiers: toolbar];
333}
334
335- (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
336{
337    return [self toolbarAllowedItemIdentifiers: toolbar];
338}
339
340- (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar
341{
342    return [NSArray arrayWithObjects:
343            TOOLBAR_GENERAL, TOOLBAR_TRANSFERS,
344            TOOLBAR_BANDWIDTH, TOOLBAR_NETWORK, nil];
345}
346
347- (void) setPort: (id) sender
348{
349    int bindPort = [sender intValue];
350    if (![[NSString stringWithInt: bindPort] isEqualToString: [sender stringValue]]
351            || bindPort < MIN_PORT || bindPort > MAX_PORT)
352    {
353        NSBeep();
354        bindPort = [fDefaults integerForKey: @"BindPort"];
355        [sender setIntValue: bindPort];
356    }
357    else
358    {
359        tr_setBindPort(fHandle, bindPort);
360        [fDefaults setInteger: bindPort forKey: @"BindPort"];
361       
362        [self updateNatStatus];
363        [self updatePortStatus];
364    }
365}
366
367- (void) updatePortStatus
368{
369    long sytemVersion;
370    [fPortStatusField setStringValue: @""];
371    [fPortStatusImage setImage: nil];
372   
373    Gestalt('sysv', & sytemVersion);
374    if (sytemVersion >= 0x1040)
375    {
376        //NSXML features are unfortunately only available since Mac OS X v10.4
377        PortChecker * checker = [[PortChecker alloc] initWithDelegate: self];
378
379        [fPortStatusField setStringValue: [@"Checking port status" stringByAppendingEllipsis]];
380        [fPortStatusProgress startAnimation: self];
381       
382        [checker probePort: [fDefaults integerForKey: @"BindPort"]];
383    }
384}
385
386- (void) portCheckerDidFinishProbing: (PortChecker *) portChecker
387{
388    [fPortStatusProgress stopAnimation: self];
389    switch ([portChecker status])
390    {
391        case PORT_STATUS_OPEN:
392            [fPortStatusField setStringValue: @"Port is open"];
393            [fPortStatusImage setImage: [NSImage imageNamed: @"GreenDot.tiff"]];
394            break;
395        case PORT_STATUS_STEALTH:
396            [fPortStatusField setStringValue: @"Port is stealth"];
397            [fPortStatusImage setImage: [NSImage imageNamed: @"RedDot.tiff"]];
398            break;
399        case PORT_STATUS_CLOSED:
400            [fPortStatusField setStringValue: @"Port is closed"];
401            [fPortStatusImage setImage: [NSImage imageNamed: @"RedDot.tiff"]];
402            break;
403        case PORT_STATUS_ERROR:
404            [fPortStatusField setStringValue: @"Unable to check port status"];
405            [fPortStatusImage setImage: [NSImage imageNamed: @"YellowDot.tiff"]];
406            break;
407    }
408    [portChecker release];
409}
410
411- (void) setNat: (id) sender
412{
413    BOOL enable = [sender state] == NSOnState;
414    enable ? tr_natTraversalEnable(fHandle) : tr_natTraversalDisable(fHandle);
415    [fDefaults setBool: enable forKey: @"NatTraversal"];
416   
417    [self updateNatStatus];
418}
419
420- (void) updateNatStatus
421{
422    int status = tr_natTraversalStatus(fHandle);
423    if (fNatStatus == status)
424        return;
425    fNatStatus = status;
426   
427    if (status == 2)
428    {
429        [fNatStatusField setStringValue: @"Ports successfully mapped"];
430        [fNatStatusImage setImage: [NSImage imageNamed: @"Check.png"]];
431    }
432    else if (status == 3 || status == 4)
433    {
434        [fNatStatusField setStringValue: @"Error mapping ports"];
435        [fNatStatusImage setImage: [NSImage imageNamed: @"Error.tiff"]];
436    }
437    else
438    {
439        [fNatStatusField setStringValue: @""];
440        [fNatStatusImage setImage: nil];
441    }
442}
443
444- (void) setLimit: (id) sender
445{
446    NSString * key;
447    NSButton * check;
448    NSString * type;
449    if (sender == fUploadField)
450    {
451        key = @"UploadLimit";
452        check = fUploadCheck;
453        type = @"Upload";
454    }
455    else
456    {
457        key = @"DownloadLimit";
458        check = fDownloadCheck;
459        type = @"Download";
460    }
461
462    int limit = [sender intValue];
463    if (![[sender stringValue] isEqualToString: [NSString stringWithFormat: @"%d", limit]] || limit < 0)
464    {
465        NSBeep();
466        limit = [fDefaults integerForKey: key];
467        [sender setIntValue: limit];
468    }
469    else
470    {
471        if (![fDefaults boolForKey: @"SpeedLimit"])
472        {
473            int realLimit = [check state] ? limit : -1;
474            if (sender == fUploadField)
475                tr_setUploadLimit(fHandle, realLimit);
476            else
477                tr_setDownloadLimit(fHandle, realLimit);
478        }
479       
480        [fDefaults setInteger: limit forKey: key];
481    }
482   
483    NSDictionary * dict = [[NSDictionary alloc] initWithObjectsAndKeys:
484                                    [NSNumber numberWithBool: [check state]], @"Enable",
485                                    [NSNumber numberWithInt: limit], @"Limit",
486                                    type, @"Type", nil];
487    [[NSNotificationCenter defaultCenter] postNotificationName: @"LimitGlobalChange" object: dict];
488}
489
490- (void) setLimitCheck: (id) sender
491{
492    NSString * key;
493    NSTextField * field;
494    if (sender == fUploadCheck)
495    {
496        key = @"CheckUpload";
497        field = fUploadField;
498    }
499    else
500    {
501        key = @"CheckDownload";
502        field = fDownloadField;
503    }
504   
505    BOOL check = [sender state] == NSOnState;
506    [self setLimit: field];
507    [field setEnabled: check];
508   
509    [fDefaults setBool: check forKey: key];
510}
511
512- (void) setLimitEnabled: (BOOL) enable type: (NSString *) type
513{
514    NSButton * check = [type isEqualToString: @"Upload"] ? fUploadCheck : fDownloadCheck;
515    [check setState: enable ? NSOnState : NSOffState];
516    [self setLimitCheck: check];
517}
518
519- (void) setQuickLimit: (int) limit type: (NSString *) type
520{
521    NSButton * check;
522    if ([type isEqualToString: @"Upload"])
523    {
524        [fUploadField setIntValue: limit];
525        check = fUploadCheck;
526    }
527    else
528    {
529        [fDownloadField setIntValue: limit];
530        check = fDownloadCheck;
531    }
532    [check setState: NSOnState];
533    [self setLimitCheck: check];
534}
535
536- (void) enableSpeedLimit: (BOOL) enable
537{
538    if ([fDefaults boolForKey: @"SpeedLimit"] != enable)
539    {
540        [fDefaults setBool: enable forKey: @"SpeedLimit"];
541       
542        if (enable)
543        {
544            tr_setUploadLimit(fHandle, [fDefaults integerForKey: @"SpeedLimitUploadLimit"]);
545            tr_setDownloadLimit(fHandle, [fDefaults integerForKey: @"SpeedLimitDownloadLimit"]);
546        }
547        else
548        {
549            tr_setUploadLimit(fHandle, [fUploadCheck state] ? [fDefaults integerForKey: @"UploadLimit"] : -1);
550            tr_setDownloadLimit(fHandle, [fDownloadCheck state] ? [fDefaults integerForKey: @"DownloadLimit"] : -1);
551        }
552    }
553}
554
555- (void) setSpeedLimit: (id) sender
556{
557    NSString * key = sender == fSpeedLimitUploadField ? @"SpeedLimitUploadLimit" : @"SpeedLimitDownloadLimit";
558
559    int limit = [sender intValue];
560    if (![[sender stringValue] isEqualToString: [NSString stringWithFormat: @"%d", limit]] || limit < 0)
561    {
562        NSBeep();
563        limit = [fDefaults integerForKey: key];
564        [sender setIntValue: limit];
565    }
566    else
567    {
568        if ([fDefaults boolForKey: @"SpeedLimit"])
569        {
570            if (sender == fSpeedLimitUploadField)
571                tr_setUploadLimit(fHandle, limit);
572            else
573                tr_setDownloadLimit(fHandle, limit);
574        }
575       
576        [fDefaults setInteger: limit forKey: key];
577    }
578}
579
580- (void) setAutoSpeedLimitCheck: (id) sender
581{
582    BOOL check = [sender state] == NSOnState;
583   
584    [fDefaults setBool: check forKey: @"SpeedLimitAuto"];
585
586    [self setAutoSpeedLimitHour: fSpeedLimitAutoOnField];
587    [fSpeedLimitAutoOnField setEnabled: check];
588   
589    [self setAutoSpeedLimitHour: fSpeedLimitAutoOffField];
590    [fSpeedLimitAutoOffField setEnabled: check];
591}
592
593- (void) setAutoSpeedLimitHour: (id) sender
594{
595    NSString * key = (sender == fSpeedLimitAutoOnField) ? @"SpeedLimitAutoOnHour" : @"SpeedLimitAutoOffHour";
596
597    int hour = [sender intValue];
598   
599    //allow numbers under ten in the format 0x
600    if (!([[sender stringValue] isEqualToString: [NSString stringWithFormat: @"%d", hour]]
601        || [[sender stringValue] isEqualToString: [NSString stringWithFormat: @"%02d", hour]]) || hour < 0 || hour > 23
602        || [fSpeedLimitAutoOnField intValue] == [fSpeedLimitAutoOffField intValue])
603    {
604        NSBeep();
605        hour = [fDefaults integerForKey: key];
606        [sender setStringValue: [NSString stringWithFormat: @"%02d", hour]];
607    }
608    else
609        [fDefaults setInteger: hour forKey: key];
610   
611    [sender setStringValue: [NSString stringWithFormat: @"%02d", hour]]; //ensure number has 2 digits
612   
613    [[NSNotificationCenter defaultCenter] postNotificationName: @"AutoSpeedLimitChange" object: self];
614}
615
616- (void) setRatio: (id) sender
617{
618    float ratioLimit = [sender floatValue];
619    if (![[sender stringValue] isEqualToString: [NSString stringWithFormat: @"%.2f", ratioLimit]]
620            || ratioLimit < 0)
621    {
622        NSBeep();
623        ratioLimit = [fDefaults floatForKey: @"RatioLimit"];
624        [sender setFloatValue: ratioLimit];
625    }
626    else
627        [fDefaults setFloat: ratioLimit forKey: @"RatioLimit"];
628   
629    NSDictionary * dict = [[NSDictionary alloc] initWithObjectsAndKeys:
630                                [NSNumber numberWithBool: [fRatioCheck state]], @"Enable",
631                                [NSNumber numberWithFloat: ratioLimit], @"Ratio", nil];
632    [[NSNotificationCenter defaultCenter] postNotificationName: @"RatioGlobalChange" object: dict];
633}
634
635- (void) setRatioCheck: (id) sender
636{
637    BOOL check = [sender state] == NSOnState;
638    [self setRatio: fRatioField];
639    [fRatioField setEnabled: check];
640   
641    [fDefaults setBool: check forKey: @"RatioCheck"];
642}
643
644- (void) setRatioEnabled: (BOOL) enable
645{
646    int state = enable ? NSOnState : NSOffState;
647   
648    [fRatioCheck setState: state];
649    [self setRatioCheck: fRatioCheck];
650}
651
652- (void) setQuickRatio: (float) ratioLimit
653{
654    [fRatioField setFloatValue: ratioLimit];
655   
656    [fRatioCheck setState: NSOnState];
657    [self setRatioCheck: fRatioCheck];
658}
659
660- (void) setShowMessage: (id) sender
661{
662    BOOL state = [sender state];
663
664    if (sender == fQuitCheck)
665    {
666        [fDefaults setBool: state forKey: @"CheckQuit"];
667        [fQuitDownloadingCheck setEnabled: state];
668    }
669    else if (sender == fRemoveCheck)
670    {
671        [fDefaults setBool: state forKey: @"CheckRemove"];
672        [fRemoveDownloadingCheck setEnabled: state];
673    }
674    if (sender == fQuitDownloadingCheck)
675        [fDefaults setBool: state forKey: @"CheckQuitDownloading"];
676    else if (sender == fRemoveDownloadingCheck)
677        [fDefaults setBool: state forKey: @"CheckRemoveDownloading"];
678    else;
679}
680
681- (void) setBadge: (id) sender
682{   
683    if (sender == fBadgeDownloadRateCheck)
684        [fDefaults setBool: [sender state] forKey: @"BadgeDownloadRate"];
685    else if (sender == fBadgeUploadRateCheck)
686        [fDefaults setBool: [sender state] forKey: @"BadgeUploadRate"];
687    else;
688   
689    [[NSNotificationCenter defaultCenter] postNotificationName: @"DockBadgeChange" object: self];
690}
691
692- (void) setPlaySound: (id) sender
693{
694    BOOL state = [sender state];
695
696    if (sender == fPlayDownloadSoundCheck)
697    {
698        [fDownloadSoundPopUp setEnabled: state];
699        [fDefaults setBool: state forKey: @"PlayDownloadSound"];
700    }
701    else if (sender == fPlaySeedingSoundCheck)
702    {
703        [fSeedingSoundPopUp setEnabled: state];
704        [fDefaults setBool: state forKey: @"PlaySeedingSound"];
705    }
706    else;
707}
708
709- (void) setSound: (id) sender
710{
711    //play sound when selecting
712    NSString * soundName = [sender titleOfSelectedItem];
713    NSSound * sound;
714    if ((sound = [NSSound soundNamed: soundName]))
715        [sound play];
716
717    if (sender == fDownloadSoundPopUp)
718        [fDefaults setObject: soundName forKey: @"DownloadSound"];
719    else if (sender == fSeedingSoundPopUp)
720        [fDefaults setObject: soundName forKey: @"SeedingSound"];
721    else;
722}
723
724- (void) setUpdate: (id) sender
725{
726    int index = [fUpdatePopUp indexOfSelectedItem];
727    NSTimeInterval seconds;
728    if (index == UPDATE_DAILY)
729    {
730        [fDefaults setObject: @"Daily" forKey: @"UpdateCheck"];
731        seconds = 86400;
732    }
733    else if (index == UPDATE_WEEKLY)
734    {
735        [fDefaults setObject: @"Weekly" forKey: @"UpdateCheck"];
736        seconds = 604800;
737    }
738    else
739    {
740        [fDefaults setObject: @"Never" forKey: @"UpdateCheck"];
741        seconds = 0;
742    }
743
744    [fDefaults setInteger: seconds forKey: @"SUScheduledCheckInterval"];
745    [fUpdater scheduleCheckWithInterval: seconds];
746}
747
748- (void) setStartAtOpen: (id) sender
749{
750    [fDefaults setBool: [sender state] == NSOnState forKey: @"AutoStartDownload"];
751}
752
753- (void) setUseQueue: (id) sender
754{
755    BOOL useQueue = [sender state] == NSOnState;
756   
757    [fDefaults setBool: useQueue forKey: @"Queue"];
758    [self setQueueNumber: fQueueNumberField];
759    [fQueueNumberField setEnabled: useQueue];
760}
761
762- (void) setQueueNumber: (id) sender
763{
764    int queueNumber = [sender intValue];
765    if (![[sender stringValue] isEqualToString: [NSString stringWithInt: queueNumber]] || queueNumber < 1)
766    {
767        NSBeep();
768        queueNumber = [fDefaults integerForKey: @"QueueDownloadNumber"];
769        [sender setIntValue: queueNumber];
770    }
771    else
772        [fDefaults setInteger: queueNumber forKey: @"QueueDownloadNumber"];
773   
774    [[NSNotificationCenter defaultCenter] postNotificationName: @"GlobalStartSettingChange" object: self];
775}
776
777- (void) setMoveTorrent: (id) sender
778{
779    int state = [sender state];
780    if (sender == fCopyTorrentCheck)
781    {
782        [fDefaults setBool: state forKey: @"SavePrivateTorrent"];
783       
784        [fDeleteOriginalTorrentCheck setEnabled: state];
785        if (state == NSOffState)
786        {
787            [fDeleteOriginalTorrentCheck setState: NSOffState];
788            [fDefaults setBool: NO forKey: @"DeleteOriginalTorrent"];
789        }
790    }
791    else
792        [fDefaults setBool: state forKey: @"DeleteOriginalTorrent"];
793}
794
795- (void) setDownloadLocation: (id) sender
796{
797    //Download folder
798    switch ([fFolderPopUp indexOfSelectedItem])
799    {
800        case DOWNLOAD_FOLDER:
801            [fDefaults setObject: @"Constant" forKey: @"DownloadChoice"];
802            break;
803        case DOWNLOAD_TORRENT:
804            [fDefaults setObject: @"Torrent" forKey: @"DownloadChoice"];
805            break;
806        case DOWNLOAD_ASK:
807            [fDefaults setObject: @"Ask" forKey: @"DownloadChoice"];
808            break;
809    }
810}
811
812- (void) checkUpdate
813{
814    [fUpdater checkForUpdates: nil];
815}
816
817- (void) folderSheetShow: (id) sender
818{
819    NSOpenPanel * panel = [NSOpenPanel openPanel];
820
821    [panel setPrompt: @"Select"];
822    [panel setAllowsMultipleSelection: NO];
823    [panel setCanChooseFiles: NO];
824    [panel setCanChooseDirectories: YES];
825    [panel setCanCreateDirectories: YES];
826
827    [panel beginSheetForDirectory: nil file: nil types: nil
828        modalForWindow: [self window] modalDelegate: self didEndSelector:
829        @selector(folderSheetClosed:returnCode:contextInfo:) contextInfo: nil];
830}
831
832- (void) setAutoImport: (id) sender
833{
834    int state = [fAutoImportCheck state];
835    [fDefaults setBool: state forKey: @"AutoImport"];
836    [fImportFolderPopUp setEnabled: state];
837   
838    if (state == NSOnState)
839        [[UKKQueue sharedFileWatcher] addPath: fImportFolder];
840    else
841        [[UKKQueue sharedFileWatcher] removePathFromQueue: fImportFolder];
842   
843    [[NSNotificationCenter defaultCenter] postNotificationName: @"AutoImportSettingChange" object: self];
844}
845
846- (void) importFolderSheetShow: (id) sender
847{
848    NSOpenPanel * panel = [NSOpenPanel openPanel];
849
850    [panel setPrompt: @"Select"];
851    [panel setAllowsMultipleSelection: NO];
852    [panel setCanChooseFiles: NO];
853    [panel setCanChooseDirectories: YES];
854    [panel setCanCreateDirectories: YES];
855
856    [panel beginSheetForDirectory: nil file: nil types: nil
857        modalForWindow: [self window] modalDelegate: self didEndSelector:
858        @selector(importFolderSheetClosed:returnCode:contextInfo:) contextInfo: nil];
859}
860
861- (void) setAutoSize: (id) sender
862{
863    [fDefaults setBool: [sender state] forKey: @"AutoSize"];
864   
865    [[NSNotificationCenter defaultCenter] postNotificationName: @"AutoSizeSettingChange" object: self];
866}
867
868- (void) helpForNetwork: (id) sender
869{
870    [[NSHelpManager sharedHelpManager] openHelpAnchor: @"PortForwarding"
871        inBook: [[NSBundle mainBundle] objectForInfoDictionaryKey: @"CFBundleHelpBookName"]];
872}
873
874@end
875
876@implementation PrefsController (Private)
877
878- (void) showGeneralPref: (id) sender
879{
880    [self setPrefView: fGeneralView];
881}
882
883- (void) showTransfersPref: (id) sender
884{
885    [self setPrefView: fTransfersView];
886}
887
888- (void) showBandwidthPref: (id) sender
889{
890    [self setPrefView: fBandwidthView];
891}
892
893- (void) showNetworkPref: (id) sender
894{
895    [self setPrefView: fNetworkView];
896}
897
898- (void) setPrefView: (NSView *) view
899{
900    NSWindow * window = [self window];
901   
902    if ([window contentView] == view)
903        return;
904   
905    NSRect windowRect = [window frame];
906    int difference = [view frame].size.height - [[window contentView] frame].size.height;
907    windowRect.origin.y -= difference;
908    windowRect.size.height += difference;
909
910    [window setTitle: [fToolbar selectedItemIdentifier]];
911   
912    [view setHidden: YES];
913    [window setContentView: view];
914    [window setFrame: windowRect display: YES animate: YES];
915    [view setHidden: NO];
916}
917
918- (void) folderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info
919{
920    if (code == NSOKButton)
921    {
922        [fDownloadFolder release];
923        fDownloadFolder = [[[openPanel filenames] objectAtIndex: 0] retain];
924       
925        [fFolderPopUp selectItemAtIndex: DOWNLOAD_FOLDER];
926        [fDefaults setObject: fDownloadFolder forKey: @"DownloadFolder"];
927        [fDefaults setObject: @"Constant" forKey: @"DownloadChoice"];
928       
929        [self updatePopUp];
930    }
931    else
932    {
933        //reset if cancelled
934        NSString * downloadChoice = [fDefaults stringForKey: @"DownloadChoice"];
935        if ([downloadChoice isEqualToString: @"Constant"])
936            [fFolderPopUp selectItemAtIndex: DOWNLOAD_FOLDER];
937        else if ([downloadChoice isEqualToString: @"Torrent"])
938            [fFolderPopUp selectItemAtIndex: DOWNLOAD_TORRENT];
939        else
940            [fFolderPopUp selectItemAtIndex: DOWNLOAD_ASK];
941    }
942}
943
944- (void) updatePopUp
945{
946    //get and resize the icon
947    NSImage * icon = [[NSWorkspace sharedWorkspace] iconForFile: fDownloadFolder];
948    [icon setScalesWhenResized: YES];
949    [icon setSize: NSMakeSize(16.0, 16.0)];
950
951    //update menu item
952    NSMenuItem * menuItem = (NSMenuItem *) [fFolderPopUp itemAtIndex: 0];
953    [menuItem setTitle: [fDownloadFolder lastPathComponent]];
954    [menuItem setImage: icon];
955}
956
957- (void) importFolderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info
958{
959    if (code == NSOKButton)
960    {
961        UKKQueue * sharedQueue = [UKKQueue sharedFileWatcher];
962        [sharedQueue removePathFromQueue: fImportFolder];
963       
964        [fImportFolder release];
965        fImportFolder = [[[openPanel filenames] objectAtIndex: 0] retain];
966       
967        [fDefaults setObject: fImportFolder forKey: @"AutoImportDirectory"];
968       
969        [self updateImportPopUp];
970       
971        [sharedQueue addPath: fImportFolder];
972       
973        [[NSNotificationCenter defaultCenter] postNotificationName: @"AutoImportSettingChange" object: self];
974    }
975    [fImportFolderPopUp selectItemAtIndex: 0];
976}
977
978- (void) updateImportPopUp
979{
980    //get and resize the icon
981    NSImage * icon = [[NSWorkspace sharedWorkspace] iconForFile: fImportFolder];
982    [icon setScalesWhenResized: YES];
983    [icon setSize: NSMakeSize(16.0, 16.0)];
984
985    //update menu item
986    NSMenuItem * menuItem = (NSMenuItem *) [fImportFolderPopUp itemAtIndex: 0];
987    [menuItem setTitle: [fImportFolder lastPathComponent]];
988    [menuItem setImage: icon];
989}
990
991@end
Note: See TracBrowser for help on using the repository browser.