source: trunk/macosx/PrefsController.m @ 6027

Last change on this file since 6027 was 6027, checked in by livings124, 14 years ago

sort ip addresses in the rpc access table; other cleanup with this table code

  • Property svn:keywords set to Date Rev Author Id
File size: 33.3 KB
Line 
1/******************************************************************************
2 * $Id: PrefsController.m 6027 2008-06-04 06:40:50Z livings124 $
3 *
4 * Copyright (c) 2005-2008 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 "BlocklistDownloader.h"
27#import "NSApplicationAdditions.h"
28#import "NSStringAdditions.h"
29#import "UKKQueue.h"
30
31#define DOWNLOAD_FOLDER     0
32#define DOWNLOAD_TORRENT    2
33
34#define RPC_ACCESS_ALLOW    0
35#define RPC_ACCESS_DENY    1
36
37#define RPC_IP_ADD_TAG      0
38#define RPC_IP_REMOVE_TAG   1
39
40#define UPDATE_SECONDS 86400
41
42#define TOOLBAR_GENERAL     @"TOOLBAR_GENERAL"
43#define TOOLBAR_TRANSFERS   @"TOOLBAR_TRANSFERS"
44#define TOOLBAR_BANDWIDTH   @"TOOLBAR_BANDWIDTH"
45#define TOOLBAR_PEERS       @"TOOLBAR_PEERS"
46#define TOOLBAR_NETWORK     @"TOOLBAR_NETWORK"
47#define TOOLBAR_REMOTE      @"TOOLBAR_REMOTE"
48
49@interface PrefsController (Private)
50
51- (void) setPrefView: (id) sender;
52
53- (void) folderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info;
54- (void) incompleteFolderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info;
55- (void) importFolderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info;
56
57@end
58
59@implementation PrefsController
60
61- (id) initWithHandle: (tr_handle *) handle
62{
63    if ((self = [super initWithWindowNibName: @"PrefsWindow"]))
64    {
65        fDefaults = [NSUserDefaults standardUserDefaults];
66        fHandle = handle;
67       
68        //checks for old version speeds of -1
69        if ([fDefaults integerForKey: @"UploadLimit"] < 0)
70        {
71            [fDefaults setInteger: 20 forKey: @"UploadLimit"];
72            [fDefaults setBool: NO forKey: @"CheckUpload"];
73        }
74        if ([fDefaults integerForKey: @"DownloadLimit"] < 0)
75        {
76            [fDefaults setInteger: 20 forKey: @"DownloadLimit"];
77            [fDefaults setBool: NO forKey: @"CheckDownload"];
78        }
79       
80        //check for old version download location (before 1.1)
81        NSString * choice;
82        if ((choice = [fDefaults stringForKey: @"DownloadChoice"]))
83        {
84            [fDefaults setBool: [choice isEqualToString: @"Constant"] forKey: @"DownloadLocationConstant"];
85            [fDefaults setBool: YES forKey: @"DownloadAsk"];
86           
87            [fDefaults removeObjectForKey: @"DownloadChoice"];
88        }
89       
90        //set check for update to right value
91        [self setCheckForUpdate: nil];
92       
93        //set auto import
94        NSString * autoPath;
95        if ([fDefaults boolForKey: @"AutoImport"] && (autoPath = [fDefaults stringForKey: @"AutoImportDirectory"]))
96            [[UKKQueue sharedFileWatcher] addPath: [autoPath stringByExpandingTildeInPath]];
97       
98        //set encryption
99        [self setEncryptionMode: nil];
100       
101        //actually set bandwidth limits
102        [self applySpeedSettings: nil];
103       
104        //update rpc access list
105        fRPCAccessArray = [[fDefaults arrayForKey: @"RPCAccessList"] mutableCopy];
106        if (!fRPCAccessArray)
107            fRPCAccessArray = [[NSMutableArray arrayWithObject: [NSDictionary dictionaryWithObjectsAndKeys: @"127.0.0.1", @"IP",
108                                [NSNumber numberWithBool: YES], @"Allow", nil]] retain];
109        [self updateRPCAccessList];
110    }
111   
112    return self;
113}
114
115- (tr_handle *) handle
116{
117    return fHandle;
118}
119
120- (void) dealloc
121{
122    if (fPortStatusTimer)
123        [fPortStatusTimer invalidate];
124    if (fPortChecker)
125    {
126        [fPortChecker cancelProbe];
127        [fPortChecker release];
128    }
129   
130    [fRPCAccessArray release];
131   
132    [super dealloc];
133}
134
135- (void) awakeFromNib
136{
137    fHasLoaded = YES;
138   
139    NSToolbar * toolbar = [[NSToolbar alloc] initWithIdentifier: @"Preferences Toolbar"];
140    [toolbar setDelegate: self];
141    [toolbar setAllowsUserCustomization: NO];
142    [toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
143    [toolbar setSizeMode: NSToolbarSizeModeRegular];
144    [toolbar setSelectedItemIdentifier: TOOLBAR_GENERAL];
145    [[self window] setToolbar: toolbar];
146    [toolbar release];
147   
148    [self setPrefView: nil];
149   
150    if (![NSApp isOnLeopardOrBetter])
151    {
152        [fRPCAddRemoveControl sizeToFit];
153        [fRPCAddRemoveControl setLabel: @"+" forSegment: RPC_IP_ADD_TAG];
154        [fRPCAddRemoveControl setLabel: @"-" forSegment: RPC_IP_REMOVE_TAG];
155    }
156   
157    //set download folder
158    [fFolderPopUp selectItemAtIndex: [fDefaults boolForKey: @"DownloadLocationConstant"] ? DOWNLOAD_FOLDER : DOWNLOAD_TORRENT];
159   
160    //set stop ratio
161    [self updateRatioStopField];
162   
163    //set limits
164    [self updateLimitFields];
165   
166    //set speed limit
167    [fSpeedLimitUploadField setIntValue: [fDefaults integerForKey: @"SpeedLimitUploadLimit"]];
168    [fSpeedLimitDownloadField setIntValue: [fDefaults integerForKey: @"SpeedLimitDownloadLimit"]];
169   
170    //set port
171    [fPortField setIntValue: [fDefaults integerForKey: @"BindPort"]];
172    fNatStatus = -1;
173   
174    [self updatePortStatus];
175    fPortStatusTimer = [NSTimer scheduledTimerWithTimeInterval: 5.0 target: self
176                        selector: @selector(updatePortStatus) userInfo: nil repeats: YES];
177   
178    //set peer connections
179    [fPeersGlobalField setIntValue: [fDefaults integerForKey: @"PeersTotal"]];
180    [fPeersTorrentField setIntValue: [fDefaults integerForKey: @"PeersTorrent"]];
181   
182    //set queue values
183    [fQueueDownloadField setIntValue: [fDefaults integerForKey: @"QueueDownloadNumber"]];
184    [fQueueSeedField setIntValue: [fDefaults integerForKey: @"QueueSeedNumber"]];
185    [fStalledField setIntValue: [fDefaults integerForKey: @"StalledMinutes"]];
186   
187    //set blocklist
188    [self updateBlocklistFields];
189   
190    //set rpc port
191    [fRPCPortField setIntValue: [fDefaults integerForKey: @"RPCPort"]];
192}
193
194- (void) setUpdater: (SUUpdater *) updater
195{
196    fUpdater = updater;
197}
198
199- (NSToolbarItem *) toolbar: (NSToolbar *) toolbar itemForItemIdentifier: (NSString *) ident willBeInsertedIntoToolbar: (BOOL) flag
200{
201    NSToolbarItem * item = [[NSToolbarItem alloc] initWithItemIdentifier: ident];
202
203    if ([ident isEqualToString: TOOLBAR_GENERAL])
204    {
205        [item setLabel: NSLocalizedString(@"General", "Preferences -> toolbar item title")];
206        [item setImage: [NSImage imageNamed: [NSApp isOnLeopardOrBetter] ? NSImageNamePreferencesGeneral : @"Preferences.png"]];
207        [item setTarget: self];
208        [item setAction: @selector(setPrefView:)];
209        [item setAutovalidates: NO];
210    }
211    else if ([ident isEqualToString: TOOLBAR_TRANSFERS])
212    {
213        [item setLabel: NSLocalizedString(@"Transfers", "Preferences -> toolbar item title")];
214        [item setImage: [NSImage imageNamed: @"Transfers.png"]];
215        [item setTarget: self];
216        [item setAction: @selector(setPrefView:)];
217        [item setAutovalidates: NO];
218    }
219    else if ([ident isEqualToString: TOOLBAR_BANDWIDTH])
220    {
221        [item setLabel: NSLocalizedString(@"Bandwidth", "Preferences -> toolbar item title")];
222        [item setImage: [NSImage imageNamed: @"Bandwidth.png"]];
223        [item setTarget: self];
224        [item setAction: @selector(setPrefView:)];
225        [item setAutovalidates: NO];
226    }
227    else if ([ident isEqualToString: TOOLBAR_PEERS])
228    {
229        [item setLabel: NSLocalizedString(@"Peers", "Preferences -> toolbar item title")];
230        [item setImage: [NSImage imageNamed: [NSApp isOnLeopardOrBetter] ? NSImageNameUserGroup : @"Peers.png"]];
231        [item setTarget: self];
232        [item setAction: @selector(setPrefView:)];
233        [item setAutovalidates: NO];
234    }
235    else if ([ident isEqualToString: TOOLBAR_NETWORK])
236    {
237        [item setLabel: NSLocalizedString(@"Network", "Preferences -> toolbar item title")];
238        [item setImage: [NSImage imageNamed: [NSApp isOnLeopardOrBetter] ? NSImageNameNetwork : @"Network.png"]];
239        [item setTarget: self];
240        [item setAction: @selector(setPrefView:)];
241        [item setAutovalidates: NO];
242    }
243    else if ([ident isEqualToString: TOOLBAR_REMOTE])
244    {
245        [item setLabel: NSLocalizedString(@"Remote", "Preferences -> toolbar item title")];
246        [item setImage: [NSImage imageNamed: [NSApp isOnLeopardOrBetter] ? NSImageNameNetwork : @"Network.png"]];
247        [item setTarget: self];
248        [item setAction: @selector(setPrefView:)];
249        [item setAutovalidates: NO];
250    }
251    else
252    {
253        [item release];
254        return nil;
255    }
256
257    return [item autorelease];
258}
259
260- (NSArray *) toolbarSelectableItemIdentifiers: (NSToolbar *) toolbar
261{
262    return [self toolbarDefaultItemIdentifiers: toolbar];
263}
264
265- (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
266{
267    return [self toolbarAllowedItemIdentifiers: toolbar];
268}
269
270- (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar
271{
272    return [NSArray arrayWithObjects: TOOLBAR_GENERAL, TOOLBAR_TRANSFERS, TOOLBAR_BANDWIDTH,
273                                        TOOLBAR_PEERS, TOOLBAR_NETWORK, TOOLBAR_REMOTE, nil];
274}
275
276//used by ipc
277- (void) updatePortField
278{
279    [fPortField setIntValue: [fDefaults integerForKey: @"BindPort"]];
280}
281
282- (void) setPort: (id) sender
283{
284    int port = [sender intValue];
285    [fDefaults setInteger: port forKey: @"BindPort"];
286    tr_sessionSetPeerPort(fHandle, port);
287   
288    fPeerPort = -1;
289    [self updatePortStatus];
290}
291
292- (void) setNat: (id) sender
293{
294    tr_sessionSetPortForwardingEnabled(fHandle, [fDefaults boolForKey: @"NatTraversal"]);
295   
296    fNatStatus = -1;
297    [self updatePortStatus];
298}
299
300- (void) updatePortStatus
301{
302    const tr_port_forwarding fwd = tr_sessionGetPortForwarding(fHandle);
303    const int port = tr_sessionGetPeerPort(fHandle);
304
305    if (fNatStatus != fwd || fPeerPort != port )
306    {
307        fNatStatus = fwd;
308        fPeerPort = port;
309       
310        [fPortStatusField setStringValue: [NSLocalizedString(@"Checking port status", "Preferences -> Network -> port status")
311            stringByAppendingEllipsis]];
312        [fPortStatusImage setImage: nil];
313        [fPortStatusProgress startAnimation: self];
314       
315        if (fPortChecker)
316        {
317            [fPortChecker cancelProbe];
318            [fPortChecker release];
319        }
320        fPortChecker = [[PortChecker alloc] initForPort: fPeerPort withDelegate: self];
321    }
322}
323
324- (void) portCheckerDidFinishProbing: (PortChecker *) portChecker
325{
326    [fPortStatusProgress stopAnimation: self];
327    switch ([fPortChecker status])
328    {
329        case PORT_STATUS_OPEN:
330            [fPortStatusField setStringValue: NSLocalizedString(@"Port is open", "Preferences -> Network -> port status")];
331            [fPortStatusImage setImage: [NSImage imageNamed: @"GreenDot.png"]];
332            break;
333        case PORT_STATUS_CLOSED:
334            [fPortStatusField setStringValue: NSLocalizedString(@"Port is closed", "Preferences -> Network -> port status")];
335            [fPortStatusImage setImage: [NSImage imageNamed: @"RedDot.png"]];
336            break;
337        case PORT_STATUS_STEALTH:
338            [fPortStatusField setStringValue: NSLocalizedString(@"Port is stealth", "Preferences -> Network -> port status")];
339            [fPortStatusImage setImage: [NSImage imageNamed: @"RedDot.png"]];
340            break;
341        case PORT_STATUS_ERROR:
342            [fPortStatusField setStringValue: NSLocalizedString(@"Unable to check port status",
343                                                "Preferences -> Network -> port status")];
344            [fPortStatusImage setImage: [NSImage imageNamed: @"YellowDot.png"]];
345            break;
346    }
347    [fPortChecker release];
348    fPortChecker = nil;
349}
350
351- (NSArray *) sounds
352{
353    NSMutableArray * sounds = [NSMutableArray array];
354   
355    NSMutableArray * directories = [NSMutableArray arrayWithObjects: @"/System/Library/Sounds", @"/Library/Sounds", nil];
356    if ([NSApp isOnLeopardOrBetter])
357        [directories addObject: [NSHomeDirectory() stringByAppendingPathComponent: @"Library/Sounds"]];
358   
359    BOOL isDirectory;
360    NSString * directory;
361    NSEnumerator * enumerator = [directories objectEnumerator];
362    while ((directory = [enumerator nextObject]))
363        if ([[NSFileManager defaultManager] fileExistsAtPath: directory isDirectory: &isDirectory] && isDirectory)
364        {
365            NSString * sound;
366            NSEnumerator * soundEnumerator = [[[NSFileManager defaultManager] directoryContentsAtPath: directory] objectEnumerator];
367            while ((sound = [soundEnumerator nextObject]))
368            {
369                sound = [sound stringByDeletingPathExtension];
370                if ([NSSound soundNamed: sound])
371                    [sounds addObject: sound];
372            }
373        }
374   
375    return sounds;
376}
377
378- (void) setSound: (id) sender
379{
380    //play sound when selecting
381    NSSound * sound;
382    if ((sound = [NSSound soundNamed: [sender titleOfSelectedItem]]))
383        [sound play];
384}
385
386- (void) setPeersGlobal: (id) sender
387{
388    int count = [sender intValue];
389    [fDefaults setInteger: count forKey: @"PeersTotal"];
390    tr_sessionSetPeerLimit(fHandle, count);
391}
392
393- (void) setPeersTorrent: (id) sender
394{
395    int count = [sender intValue];
396    [fDefaults setInteger: count forKey: @"PeersTorrent"];
397}
398
399- (void) setPEX: (id) sender
400{
401    tr_sessionSetPexEnabled(fHandle, [fDefaults boolForKey: @"PEXGlobal"]);
402}
403
404- (void) setEncryptionMode: (id) sender
405{
406    tr_sessionSetEncryption(fHandle, [fDefaults boolForKey: @"EncryptionPrefer"] ?
407        ([fDefaults boolForKey: @"EncryptionRequire"] ? TR_ENCRYPTION_REQUIRED : TR_ENCRYPTION_PREFERRED) : TR_PLAINTEXT_PREFERRED);
408}
409
410- (void) setBlocklistEnabled: (id) sender
411{
412    BOOL enable = [sender state] == NSOnState;
413    [fDefaults setBool: enable forKey: @"Blocklist"];
414    tr_blocklistSetEnabled(fHandle, enable);
415}
416
417- (void) updateBlocklist: (id) sender
418{
419    [BlocklistDownloader downloadWithPrefsController: self];
420}
421
422- (void) updateBlocklistFields
423{
424    BOOL exists = tr_blocklistExists(fHandle);
425   
426    if (exists)
427    {
428        NSNumberFormatter * numberFormatter = [[NSNumberFormatter alloc] init];
429        [numberFormatter setNumberStyle: NSNumberFormatterDecimalStyle];
430        [numberFormatter setMaximumFractionDigits: 0];
431        NSString * countString = [numberFormatter stringFromNumber: [NSNumber numberWithInt: tr_blocklistGetRuleCount(fHandle)]];
432        [numberFormatter release];
433       
434        [fBlocklistMessageField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%@ IP address rules in list",
435            "Prefs -> blocklist -> message"), countString]];
436    }
437    else
438        [fBlocklistMessageField setStringValue: NSLocalizedString(@"A blocklist must first be downloaded",
439            "Prefs -> blocklist -> message")];
440   
441    [fBlocklistEnableCheck setEnabled: exists];
442    [fBlocklistEnableCheck setState: exists && [fDefaults boolForKey: @"Blocklist"]];
443}
444
445- (void) applySpeedSettings: (id) sender
446{
447    if ([fDefaults boolForKey: @"SpeedLimit"])
448    {
449        tr_sessionSetSpeedLimitEnabled(fHandle, TR_UP, 1);
450        tr_sessionSetSpeedLimit(fHandle, TR_UP, [fDefaults integerForKey: @"SpeedLimitUploadLimit"]);
451       
452        tr_sessionSetSpeedLimitEnabled(fHandle, TR_DOWN, 1);
453        tr_sessionSetSpeedLimit(fHandle, TR_DOWN, [fDefaults integerForKey: @"SpeedLimitDownloadLimit"]);
454    }
455    else
456    {
457        tr_sessionSetSpeedLimitEnabled(fHandle, TR_UP, [fDefaults boolForKey: @"CheckUpload"]);
458        tr_sessionSetSpeedLimit(fHandle, TR_UP, [fDefaults integerForKey: @"UploadLimit"]);
459       
460        tr_sessionSetSpeedLimitEnabled(fHandle, TR_DOWN, [fDefaults boolForKey: @"CheckDownload"]);
461        tr_sessionSetSpeedLimit(fHandle, TR_DOWN, [fDefaults integerForKey: @"DownloadLimit"]);
462    }
463}
464
465- (void) applyRatioSetting: (id) sender
466{
467    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
468}
469
470- (void) updateRatioStopField
471{
472    if (!fHasLoaded)
473        return;
474   
475    [fRatioStopField setFloatValue: [fDefaults floatForKey: @"RatioLimit"]];
476   
477    [self applyRatioSetting: nil];
478}
479
480- (void) setRatioStop: (id) sender
481{
482    [fDefaults setFloat: [sender floatValue] forKey: @"RatioLimit"];
483    [self applyRatioSetting: nil];
484}
485
486- (void) updateLimitFields
487{
488    if (!fHasLoaded)
489        return;
490   
491    [fUploadField setIntValue: [fDefaults integerForKey: @"UploadLimit"]];
492    [fDownloadField setIntValue: [fDefaults integerForKey: @"DownloadLimit"]];
493}
494
495- (void) setGlobalLimit: (id) sender
496{
497    [fDefaults setInteger: [sender intValue] forKey: sender == fUploadField ? @"UploadLimit" : @"DownloadLimit"];
498    [self applySpeedSettings: self];
499}
500
501- (void) setSpeedLimit: (id) sender
502{
503    [fDefaults setInteger: [sender intValue] forKey: sender == fSpeedLimitUploadField
504                                                        ? @"SpeedLimitUploadLimit" : @"SpeedLimitDownloadLimit"];
505    [self applySpeedSettings: self];
506}
507
508- (void) setAutoSpeedLimit: (id) sender
509{
510    [[NSNotificationCenter defaultCenter] postNotificationName: @"AutoSpeedLimitChange" object: self];
511}
512
513- (BOOL) control: (NSControl *) control textShouldBeginEditing: (NSText *) fieldEditor
514{
515    [fInitialString release];
516    fInitialString = [[control stringValue] retain];
517   
518    return YES;
519}
520
521- (BOOL) control: (NSControl *) control didFailToFormatString: (NSString *) string errorDescription: (NSString *) error
522{
523    NSBeep();
524    if (fInitialString)
525    {
526        [control setStringValue: fInitialString];
527        [fInitialString release];
528        fInitialString = nil;
529    }
530    return NO;
531}
532
533- (void) setBadge: (id) sender
534{
535    [[NSNotificationCenter defaultCenter] postNotificationName: @"DockBadgeChange" object: self];
536}
537
538- (void) resetWarnings: (id) sender
539{
540    [fDefaults setBool: YES forKey: @"WarningDuplicate"];
541    [fDefaults setBool: YES forKey: @"WarningRemainingSpace"];
542    [fDefaults setBool: YES forKey: @"WarningFolderDataSameName"];
543    [fDefaults setBool: YES forKey: @"WarningResetStats"];
544    [fDefaults setBool: YES forKey: @"WarningCreatorBlankAddress"];
545    [fDefaults setBool: YES forKey: @"WarningRemoveBuiltInTracker"];
546}
547
548- (void) setCheckForUpdate: (id) sender
549{
550    NSTimeInterval seconds = [fDefaults boolForKey: @"CheckForUpdates"] ? UPDATE_SECONDS : 0;
551    [fDefaults setInteger: seconds forKey: @"SUScheduledCheckInterval"];
552    if (fUpdater)
553        [fUpdater scheduleCheckWithInterval: seconds];
554}
555
556- (void) setQueue: (id) sender
557{
558    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateQueue" object: self];
559}
560
561- (void) setQueueNumber: (id) sender
562{
563    [fDefaults setInteger: [sender intValue] forKey: sender == fQueueDownloadField ? @"QueueDownloadNumber" : @"QueueSeedNumber"];
564    [self setQueue: nil];
565}
566
567- (void) setStalled: (id) sender
568{
569    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateQueue" object: self];
570}
571
572- (void) setStalledMinutes: (id) sender
573{
574    [fDefaults setInteger: [sender intValue] forKey: @"StalledMinutes"];
575    [self setStalled: nil];
576}
577
578- (void) setDownloadLocation: (id) sender
579{
580    [fDefaults setBool: [fFolderPopUp indexOfSelectedItem] == DOWNLOAD_FOLDER forKey: @"DownloadLocationConstant"];
581}
582
583- (void) folderSheetShow: (id) sender
584{
585    NSOpenPanel * panel = [NSOpenPanel openPanel];
586
587    [panel setPrompt: NSLocalizedString(@"Select", "Preferences -> Open panel prompt")];
588    [panel setAllowsMultipleSelection: NO];
589    [panel setCanChooseFiles: NO];
590    [panel setCanChooseDirectories: YES];
591    [panel setCanCreateDirectories: YES];
592
593    [panel beginSheetForDirectory: nil file: nil types: nil
594        modalForWindow: [self window] modalDelegate: self didEndSelector:
595        @selector(folderSheetClosed:returnCode:contextInfo:) contextInfo: nil];
596}
597
598- (void) incompleteFolderSheetShow: (id) sender
599{
600    NSOpenPanel * panel = [NSOpenPanel openPanel];
601
602    [panel setPrompt: NSLocalizedString(@"Select", "Preferences -> Open panel prompt")];
603    [panel setAllowsMultipleSelection: NO];
604    [panel setCanChooseFiles: NO];
605    [panel setCanChooseDirectories: YES];
606    [panel setCanCreateDirectories: YES];
607
608    [panel beginSheetForDirectory: nil file: nil types: nil
609        modalForWindow: [self window] modalDelegate: self didEndSelector:
610        @selector(incompleteFolderSheetClosed:returnCode:contextInfo:) contextInfo: nil];
611}
612
613- (void) setAutoImport: (id) sender
614{
615    NSString * path;
616    if ((path = [fDefaults stringForKey: @"AutoImportDirectory"]))
617    {
618        path = [path stringByExpandingTildeInPath];
619        if ([fDefaults boolForKey: @"AutoImport"])
620            [[UKKQueue sharedFileWatcher] addPath: path];
621        else
622            [[UKKQueue sharedFileWatcher] removePathFromQueue: path];
623       
624        [[NSNotificationCenter defaultCenter] postNotificationName: @"AutoImportSettingChange" object: self];
625    }
626    else
627        [self importFolderSheetShow: nil];
628}
629
630- (void) importFolderSheetShow: (id) sender
631{
632    NSOpenPanel * panel = [NSOpenPanel openPanel];
633
634    [panel setPrompt: NSLocalizedString(@"Select", "Preferences -> Open panel prompt")];
635    [panel setAllowsMultipleSelection: NO];
636    [panel setCanChooseFiles: NO];
637    [panel setCanChooseDirectories: YES];
638    [panel setCanCreateDirectories: YES];
639
640    [panel beginSheetForDirectory: nil file: nil types: nil
641        modalForWindow: [self window] modalDelegate: self didEndSelector:
642        @selector(importFolderSheetClosed:returnCode:contextInfo:) contextInfo: nil];
643}
644
645- (void) setAutoSize: (id) sender
646{
647    [[NSNotificationCenter defaultCenter] postNotificationName: @"AutoSizeSettingChange" object: self];
648}
649
650- (void) setRPCEnabled: (id) sender
651{
652    tr_sessionSetRPCEnabled(fHandle, [fDefaults boolForKey: @"RPC"]);
653}
654
655- (void) setRPCPort: (id) sender
656{
657    int port = [sender intValue];
658    [fDefaults setInteger: port forKey: @"RPCPort"];
659    tr_sessionSetRPCPort(fHandle, port);
660}
661
662- (void) updateRPCAccessList
663{
664    NSMutableArray * components = [NSMutableArray arrayWithCapacity: [fRPCAccessArray count]];
665   
666    NSEnumerator * enumerator = [fRPCAccessArray objectEnumerator];
667    NSDictionary * dict;
668    while ((dict = [enumerator nextObject]))
669        [components addObject: [NSString stringWithFormat: @"%c%@", [[dict objectForKey: @"Allow"] boolValue] ? '+' : '-',
670                                [dict objectForKey: @"IP"]]];
671   
672    NSString * string = [components componentsJoinedByString: @","];
673   
674    #warning check for an error!
675    tr_sessionSetRPCACL(fHandle, [string UTF8String], NULL);
676}
677
678- (void) addRemoveRPCIP: (id) sender
679{
680    //don't allow add/remove when currently adding - it leads to weird results
681    if ([fRPCAccessTable editedRow] != -1)
682        return;
683   
684    if ([[sender cell] tagForSegment: [sender selectedSegment]] == RPC_IP_REMOVE_TAG)
685    {
686        [fRPCAccessArray removeObjectsAtIndexes: [fRPCAccessTable selectedRowIndexes]];
687        [fRPCAccessTable deselectAll: self];
688        [fRPCAccessTable reloadData];
689       
690        [fDefaults setObject: fRPCAccessArray forKey: @"RPCAccessList"];
691        [self updateRPCAccessList];
692    }
693    else
694    {
695        [fRPCAccessArray addObject: [NSDictionary dictionaryWithObjectsAndKeys: @"", @"IP",
696                                        [NSNumber numberWithBool: YES], @"Allow", nil]];
697        [fRPCAccessTable reloadData];
698       
699        int row = [fRPCAccessArray count] - 1;
700        [fRPCAccessTable selectRow: row byExtendingSelection: NO];
701        [fRPCAccessTable editColumn: 0 row: row withEvent: nil select: YES];
702    }
703}
704
705- (NSInteger) numberOfRowsInTableView: (NSTableView *) tableView
706{
707    return [fRPCAccessArray count];
708}
709
710- (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row
711{
712    NSDictionary * dict = [fRPCAccessArray objectAtIndex: row];
713   
714    NSString * ident = [tableColumn identifier];
715    if ([ident isEqualToString: @"Permission"])
716    {
717        int allow = [[dict objectForKey: @"Allow"] boolValue] ? RPC_ACCESS_ALLOW : RPC_ACCESS_DENY;
718        return [NSNumber numberWithInt: allow];
719    }
720    else
721        return [dict objectForKey: @"IP"];
722}
723
724- (void) tableView: (NSTableView *) tableView setObjectValue: (id) object forTableColumn: (NSTableColumn *) tableColumn
725    row: (NSInteger) row
726{
727    NSDictionary * oldDict = [fRPCAccessArray objectAtIndex: row];
728   
729    NSString * ident = [tableColumn identifier];
730    if ([ident isEqualToString: @"Permission"])
731    {
732        NSNumber * allow = [NSNumber numberWithBool: [object intValue] == RPC_ACCESS_ALLOW];
733        NSDictionary * newDict = [NSDictionary dictionaryWithObjectsAndKeys: [oldDict objectForKey: @"IP"], @"IP", allow, @"Allow", nil];
734        [fRPCAccessArray replaceObjectAtIndex: row withObject: newDict];
735    }
736    else
737    {
738        NSArray * components = [object componentsSeparatedByString: @"."];
739        NSMutableArray * newComponents = [NSMutableArray arrayWithCapacity: 4];
740       
741        //verify ip
742        if ([components count] == 4)
743        {
744            NSEnumerator * enumerator = [components objectEnumerator];
745            NSString * component;
746            while ((component = [enumerator nextObject]))
747            {
748                if ([component isEqualToString: @"*"])
749                    [newComponents addObject: component];
750                else
751                    [newComponents addObject: [[NSNumber numberWithInt: [component intValue]] stringValue]];
752            }
753        }
754       
755        NSString * newIP = [newComponents componentsJoinedByString: @"."];
756        //revert if ip is not valid
757        #warning fix
758        if ([newComponents count] != 4)
759        {
760            NSBeep();
761           
762            if ([[oldDict objectForKey: @"IP"] isEqualToString: @""])
763            {
764                [fRPCAccessArray removeObjectAtIndex: row];
765                [fRPCAccessTable deselectAll: self];
766                [fRPCAccessTable reloadData];
767            }
768           
769            return;
770        }
771       
772        NSDictionary * newDict = [NSDictionary dictionaryWithObjectsAndKeys: newIP, @"IP",
773                                    [oldDict objectForKey: @"Allow"], @"Allow", nil];
774        [fRPCAccessArray replaceObjectAtIndex: row withObject: newDict];
775       
776        NSSortDescriptor * descriptor = [[[NSSortDescriptor alloc] initWithKey: @"IP" ascending: YES selector: @selector(compareIP:)]
777                                            autorelease];
778        [fRPCAccessArray sortUsingDescriptors: [NSArray arrayWithObject: descriptor]];
779        [fRPCAccessTable deselectAll: self];
780        [fRPCAccessTable reloadData];
781    }
782   
783    [fDefaults setObject: fRPCAccessArray forKey: @"RPCAccessList"];
784    [self updateRPCAccessList];
785}
786
787- (void) tableViewSelectionDidChange: (NSNotification *) notification
788{
789    [fRPCAddRemoveControl setEnabled: [fRPCAccessTable numberOfSelectedRows] > 0 forSegment: RPC_IP_REMOVE_TAG];
790}
791
792- (void) helpForPeers: (id) sender
793{
794    [[NSHelpManager sharedHelpManager] openHelpAnchor: @"PeersPrefs"
795        inBook: [[NSBundle mainBundle] objectForInfoDictionaryKey: @"CFBundleHelpBookName"]];
796}
797
798- (void) helpForNetwork: (id) sender
799{
800    [[NSHelpManager sharedHelpManager] openHelpAnchor: @"NetworkPrefs"
801        inBook: [[NSBundle mainBundle] objectForInfoDictionaryKey: @"CFBundleHelpBookName"]];
802}
803
804- (void) rpcUpdatePrefs
805{
806    //encryption
807    tr_encryption_mode encryptionMode = tr_sessionGetEncryption(fHandle);
808    [fDefaults setBool: encryptionMode != TR_PLAINTEXT_PREFERRED forKey: @"EncryptionPrefer"];
809    [fDefaults setBool: encryptionMode == TR_ENCRYPTION_PREFERRED forKey: @"EncryptionPrefer"];
810   
811    //download directory
812    #warning missing!
813   
814    //peers
815    uint16_t peersTotal = tr_sessionGetPeerLimit(fHandle);
816    [fDefaults setInteger: peersTotal forKey: @"PeersTotal"];
817   
818    //pex
819    BOOL pex = tr_sessionIsPexEnabled(fHandle);
820    [fDefaults setBool: pex forKey: @"PEXGlobal"];
821   
822    //port
823    int port = tr_sessionGetPeerPort(fHandle);
824    [fDefaults setInteger: port forKey: @"BindPort"];
825   
826    BOOL nat = tr_sessionIsPortForwardingEnabled(fHandle);
827    [fDefaults setBool: nat forKey: @"NatTraversal"];
828   
829    fPeerPort = -1;
830    fNatStatus = -1;
831    [self updatePortStatus];
832   
833    //speed limit - down
834    BOOL downLimitEnabled = tr_sessionIsSpeedLimitEnabled(fHandle, TR_DOWN);
835    [fDefaults setBool: downLimitEnabled forKey: @"CheckDownload"];
836   
837    int downLimit = tr_sessionGetSpeedLimit(fHandle, TR_DOWN);
838    [fDefaults setInteger: downLimit forKey: @"DownloadLimit"];
839   
840    //speed limit - up
841    BOOL upLimitEnabled = tr_sessionIsSpeedLimitEnabled(fHandle, TR_UP);
842    [fDefaults setBool: upLimitEnabled forKey: @"CheckUpload"];
843   
844    int upLimit = tr_sessionGetSpeedLimit(fHandle, TR_UP);
845    [fDefaults setInteger: upLimit forKey: @"UploadLimit"];
846   
847    //update gui if loaded
848    if (fHasLoaded)
849    {
850        //encryption handled by bindings
851       
852        [fPeersGlobalField setIntValue: peersTotal];
853       
854        //pex handled by bindings
855       
856        [fPortField setIntValue: port];
857        //port forwarding (nat) handled by bindings
858       
859        //limit check handled by bindings
860        [fDownloadField setIntValue: downLimit];
861       
862        //limit check handled by bindings
863        [fUploadField setIntValue: upLimit];
864    }
865}
866
867@end
868
869@implementation PrefsController (Private)
870
871- (void) setPrefView: (id) sender
872{
873    NSView * view = fGeneralView;
874    if (sender)
875    {
876        NSString * identifier = [sender itemIdentifier];
877        if ([identifier isEqualToString: TOOLBAR_TRANSFERS])
878            view = fTransfersView;
879        else if ([identifier isEqualToString: TOOLBAR_BANDWIDTH])
880            view = fBandwidthView;
881        else if ([identifier isEqualToString: TOOLBAR_PEERS])
882            view = fPeersView;
883        else if ([identifier isEqualToString: TOOLBAR_NETWORK])
884            view = fNetworkView;
885        else if ([identifier isEqualToString: TOOLBAR_REMOTE])
886            view = fRemoteView;
887        else; //general view already selected
888    }
889   
890    NSWindow * window = [self window];
891    if ([window contentView] == view)
892        return;
893   
894    NSRect windowRect = [window frame];
895    float difference = ([view frame].size.height - [[window contentView] frame].size.height) * [window userSpaceScaleFactor];
896    windowRect.origin.y -= difference;
897    windowRect.size.height += difference;
898   
899    [view setHidden: YES];
900    [window setContentView: view];
901    [window setFrame: windowRect display: YES animate: YES];
902    [view setHidden: NO];
903   
904    //set title label
905    if (sender)
906        [window setTitle: [sender label]];
907    else
908    {
909        NSToolbar * toolbar = [window toolbar];
910        NSString * itemIdentifier = [toolbar selectedItemIdentifier];
911        NSEnumerator * enumerator = [[toolbar items] objectEnumerator];
912        NSToolbarItem * item;
913        while ((item = [enumerator nextObject]))
914            if ([[item itemIdentifier] isEqualToString: itemIdentifier])
915            {
916                [window setTitle: [item label]];
917                break;
918            }
919    }
920   
921    //for network view make sure progress indicator hides itself (get around a Tiger bug)
922    if (![NSApp isOnLeopardOrBetter] && view == fNetworkView && [fPortStatusImage image])
923        [fPortStatusProgress setDisplayedWhenStopped: NO];
924}
925
926- (void) folderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info
927{
928    if (code == NSOKButton)
929    {
930        [fFolderPopUp selectItemAtIndex: DOWNLOAD_FOLDER];
931        [fDefaults setObject: [[openPanel filenames] objectAtIndex: 0] forKey: @"DownloadFolder"];
932        [fDefaults setObject: @"Constant" forKey: @"DownloadChoice"];
933    }
934    else
935    {
936        //reset if cancelled
937        [fFolderPopUp selectItemAtIndex: [fDefaults boolForKey: @"DownloadLocationConstant"] ? DOWNLOAD_FOLDER : DOWNLOAD_TORRENT];
938    }
939}
940
941- (void) incompleteFolderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info
942{
943    if (code == NSOKButton)
944        [fDefaults setObject: [[openPanel filenames] objectAtIndex: 0] forKey: @"IncompleteDownloadFolder"];
945    [fIncompleteFolderPopUp selectItemAtIndex: 0];
946}
947
948- (void) importFolderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info
949{
950    NSString * path = [fDefaults stringForKey: @"AutoImportDirectory"];
951    if (code == NSOKButton)
952    {
953        UKKQueue * sharedQueue = [UKKQueue sharedFileWatcher];
954        if (path)
955            [sharedQueue removePathFromQueue: [path stringByExpandingTildeInPath]];
956       
957        path = [[openPanel filenames] objectAtIndex: 0];
958        [fDefaults setObject: path forKey: @"AutoImportDirectory"];
959        [sharedQueue addPath: [path stringByExpandingTildeInPath]];
960       
961        [[NSNotificationCenter defaultCenter] postNotificationName: @"AutoImportSettingChange" object: self];
962    }
963    else if (!path)
964        [fDefaults setBool: NO forKey: @"AutoImport"];
965   
966    [fImportFolderPopUp selectItemAtIndex: 0];
967}
968
969@end
Note: See TracBrowser for help on using the repository browser.