diff --git a/Jamrules b/Jamrules index 002b1a0c7..e638aef91 100644 --- a/Jamrules +++ b/Jamrules @@ -8,7 +8,7 @@ if ! $(DEFINES) VERSION_MAJOR = 0 ; VERSION_MINOR = 4 ; # VERSION_STRING = $(VERSION_MAJOR).$(VERSION_MINOR) ; -VERSION_STRING = CVS-20051213 ; +VERSION_STRING = CVS-20051221 ; DEFINES += VERSION_MAJOR=$(VERSION_MAJOR) VERSION_MINOR=$(VERSION_MINOR) @@ -49,7 +49,7 @@ if $(OS) = MACOSX actions OSXInfoPlist { $(RM) $(1) - sed "s/%%VERSION%%/$(VERSION_STRING)/" < $(2) > $(1) + sed "s/%%VERSION%%/$(VERSION_STRING)/g" < $(2) > $(1) } rule OSXBundle @@ -107,4 +107,4 @@ if $(OS) = BEOS $(RM) $(1) && ( cd beos && make ) && \ mv beos/obj.$(CPU)/Transmission $(1) } -} \ No newline at end of file +} diff --git a/macosx/Controller.h b/macosx/Controller.h index 39c57b414..99b7c0079 100644 --- a/macosx/Controller.h +++ b/macosx/Controller.h @@ -31,83 +31,100 @@ @interface Controller : NSObject { - tr_handle_t * fHandle; - int fCount; - tr_stat_t * fStat; - int fResumeOnWake[TR_MAX_TORRENT_COUNT]; + tr_handle_t * fHandle; + int fCount; + tr_stat_t * fStat; + int fResumeOnWake[TR_MAX_TORRENT_COUNT]; - NSToolbar * fToolbar; + NSToolbar * fToolbar; - IBOutlet PrefsController * fPrefsController; + IBOutlet NSMenuItem * fAdvancedBarItem; + IBOutlet NSMenuItem * fPauseResumeItem; + IBOutlet NSMenuItem * fRemoveItem; + IBOutlet NSMenuItem * fRemoveTorrentItem; + IBOutlet NSMenuItem * fRemoveDataItem; + IBOutlet NSMenuItem * fRemoveBothItem; + IBOutlet NSMenuItem * fRevealItem; + IBOutlet NSMenuItem * fShowHideToolbar; - IBOutlet NSMenuItem * fAdvancedBarItem; - IBOutlet NSMenuItem * fPauseResumeItem; - IBOutlet NSMenuItem * fRemoveItem; - IBOutlet NSMenuItem * fRemoveTorrentItem; - IBOutlet NSMenuItem * fRemoveDataItem; - IBOutlet NSMenuItem * fRemoveBothItem; - IBOutlet NSMenuItem * fRevealItem; - IBOutlet NSMenuItem * fShowHideToolbar; + IBOutlet NSWindow * fWindow; + IBOutlet TorrentTableView * fTableView; + IBOutlet NSTextField * fTotalDLField; + IBOutlet NSTextField * fTotalULField; - IBOutlet NSWindow * fWindow; - IBOutlet TorrentTableView * fTableView; - IBOutlet NSTextField * fTotalDLField; - IBOutlet NSTextField * fTotalULField; - IBOutlet NSMenu * fContextMenu; + IBOutlet NSPanel * fInfoPanel; + IBOutlet NSTextField * fInfoTitle; + IBOutlet NSTextField * fInfoTracker; + IBOutlet NSTextField * fInfoAnnounce; + IBOutlet NSTextField * fInfoSize; + IBOutlet NSTextField * fInfoPieces; + IBOutlet NSTextField * fInfoPieceSize; + IBOutlet NSTextField * fInfoSeeders; + IBOutlet NSTextField * fInfoLeechers; + IBOutlet NSTextField * fInfoFolder; + IBOutlet NSTextField * fInfoDownloaded; + IBOutlet NSTextField * fInfoUploaded; - IBOutlet NSPanel * fInfoPanel; - IBOutlet NSTextField * fInfoTitle; - IBOutlet NSTextField * fInfoTracker; - IBOutlet NSTextField * fInfoAnnounce; - IBOutlet NSTextField * fInfoSize; - IBOutlet NSTextField * fInfoPieces; - IBOutlet NSTextField * fInfoPieceSize; - IBOutlet NSTextField * fInfoSeeders; - IBOutlet NSTextField * fInfoLeechers; - IBOutlet NSTextField * fInfoFolder; - IBOutlet NSTextField * fInfoDownloaded; - IBOutlet NSTextField * fInfoUploaded; - - io_connect_t fRootPort; - NSArray * fFilenames; - NSTimer * fTimer; + io_connect_t fRootPort; + NSArray * fFilenames; + NSTimer * fTimer; + + IBOutlet NSPanel * fPrefsWindow; + IBOutlet PrefsController * fPrefsController; + NSUserDefaults * fDefaults; + + BOOL fHasGrowl; } - (void) advancedChanged: (id) sender; - (void) openShowSheet: (id) sender; - (void) openSheetClosed: (NSOpenPanel *) s returnCode: (int) code - contextInfo: (void *) info; -- (void) stopTorrent: (id) sender; -- (void) stopAllTorrents: (id) sender; -- (void) stopTorrentWithIndex: (int) index; -- (void) resumeTorrent: (id) sender; -- (void) resumeAllTorrents: (id) sender; -- (void) resumeTorrentWithIndex: (int) index; -- (void) removeTorrent: (id) sender; -- (void) removeTorrentDeleteFile: (id) sender; -- (void) removeTorrentDeleteData: (id) sender; -- (void) removeTorrentDeleteBoth: (id) sender; -- (void) removeTorrentWithIndex: (int) idx - deleteTorrent: (BOOL) deleteTorrent - deleteData: (BOOL) deleteData; + contextInfo: (void *) info; + +- (void) quitSheetDidEnd: (NSWindow *)sheet returnCode:(int)returnCode + contextInfo:(void *)contextInfo; +- (void) quitProcedure; + +- (void) stopTorrent: (id) sender; +- (void) stopAllTorrents: (id) sender; +- (void) stopTorrentWithIndex: (int) index; +- (void) resumeTorrent: (id) sender; +- (void) resumeAllTorrents: (id) sender; +- (void) resumeTorrentWithIndex: (int) index; + +- (void) removeTorrent: (id) sender; +- (void) removeTorrentDeleteFile: (id) sender; +- (void) removeTorrentDeleteData: (id) sender; +- (void) removeTorrentDeleteBoth: (id) sender; +- (void) removeTorrentWithIndex: (int) idx + deleteTorrent: (BOOL) deleteTorrent + deleteData: (BOOL) deleteData; + +- (void) removeSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode + contextInfo:(NSDictionary *)dict; +- (void) confirmRemoveTorrentWithIndex: (int) idx + deleteTorrent: (BOOL) deleteTorrent + deleteData: (BOOL) deleteData; + - (void) showInfo: (id) sender; - (void) updateUI: (NSTimer *) timer; - (void) sleepCallBack: (natural_t) messageType argument: - (void *) messageArgument; - -- (NSMenu *) menuForIndex: (int) idx; + (void *) messageArgument; - (void) runCustomizationPalette: (id) sender; - (void) showHideToolbar: (id) sender; -- (void) showMainWindow: (id) sender; -- (void) linkHomepage: (id) sender; -- (void) linkForums: (id) sender; -- (void) notifyGrowl: (NSString *) file; -- (void) finderReveal: (NSString *) path; -- (void) finderTrash: (NSString *) path; -- (void) growlRegister: (id) sender; +- (void) showPreferenceWindow: (id) sender; + +- (void) showMainWindow: (id) sender; +- (void) linkHomepage: (id) sender; +- (void) linkForums: (id) sender; +- (void) notifyGrowl: (NSString *) file; +- (void) revealFromMenu: (id) sender; +- (void) finderReveal: (NSString *) path; +- (void) finderTrash: (NSString *) path; +- (void) growlRegister: (id) sender; @end diff --git a/macosx/Controller.m b/macosx/Controller.m index 0d89a3f09..9426412bf 100644 --- a/macosx/Controller.m +++ b/macosx/Controller.m @@ -27,19 +27,18 @@ #include "Utils.h" #include "TorrentTableView.h" +#import "PrefsController.h" + #define TOOLBAR_OPEN @"Toolbar Open" #define TOOLBAR_REMOVE @"Toolbar Remove" -#define TOOLBAR_PREFS @"Toolbar Preferences" #define TOOLBAR_INFO @"Toolbar Info" #define TOOLBAR_PAUSE_ALL @"Toolbar Pause All" #define TOOLBAR_RESUME_ALL @"Toolbar Resume All" -#define CONTEXT_PAUSE 1 -#define CONTEXT_REMOVE 2 -#define CONTEXT_REMOVE_TORRENT 3 -#define CONTEXT_REMOVE_DATA 4 -#define CONTEXT_REMOVE_BOTH 5 -#define CONTEXT_INFO 6 +#define WEBSITE_URL @"http://transmission.m0k.org/" +#define FORUM_URL @"http://transmission.m0k.org/forum/" + +#define GROWL_PATH @"/Library/PreferencePanes/Growl.prefPane/Contents/Resources/GrowlHelperApp.app" static void sleepCallBack( void * controller, io_service_t y, natural_t messageType, void * messageArgument ) @@ -52,103 +51,88 @@ static void sleepCallBack( void * controller, io_service_t y, - (void) awakeFromNib { + [fWindow setContentMinSize: NSMakeSize( 400, 120 )]; + fHandle = tr_init(); - [fPrefsController setHandle: fHandle]; + [fPrefsController setPrefsWindow: fHandle]; + fDefaults = [NSUserDefaults standardUserDefaults]; + + [fInfoPanel setFrameAutosaveName:@"InfoPanel"]; - [fWindow setContentMinSize: NSMakeSize( 400, 120 )]; - - /* Check or uncheck menu item in respect to current preferences */ - [fAdvancedBarItem setState: [[NSUserDefaults standardUserDefaults] + //check advanced bar menu item + [fAdvancedBarItem setState: [fDefaults boolForKey:@"UseAdvancedBar"] ? NSOnState : NSOffState]; fToolbar = [[NSToolbar alloc] initWithIdentifier: @"Transmission Toolbar"]; [fToolbar setDelegate: self]; [fToolbar setAllowsUserCustomization: YES]; [fToolbar setAutosavesConfiguration: YES]; - [fWindow setToolbar: fToolbar]; - [fWindow setDelegate: self]; + [fWindow setToolbar: fToolbar]; + [fWindow setDelegate: self]; NSTableColumn * tableColumn; - NameCell * nameCell; - ProgressCell * progressCell; + NameCell * nameCell = [[NameCell alloc] init]; + ProgressCell * progressCell = [[ProgressCell alloc] init]; - nameCell = [[NameCell alloc] init]; - progressCell = [[ProgressCell alloc] init]; tableColumn = [fTableView tableColumnWithIdentifier: @"Name"]; [tableColumn setDataCell: nameCell]; - [tableColumn setMinWidth: 10.0]; - [tableColumn setMaxWidth: 3000.0]; tableColumn = [fTableView tableColumnWithIdentifier: @"Progress"]; [tableColumn setDataCell: progressCell]; - [tableColumn setMinWidth: 134.0]; - [tableColumn setMaxWidth: 134.0]; [fTableView setAutosaveTableColumns: YES]; - [fTableView sizeToFit]; + //[fTableView sizeToFit]; [fTableView registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, NULL]]; + //Register for sleep notifications IONotificationPortRef notify; io_object_t anIterator; - /* Register for sleep notifications */ - fRootPort = IORegisterForSystemPower( self, ¬ify, sleepCallBack, - &anIterator); - if( !fRootPort ) - { - printf( "Could not IORegisterForSystemPower\n" ); - } - else + fRootPort = IORegisterForSystemPower( self, & notify, sleepCallBack, + & anIterator); + if (fRootPort) { CFRunLoopAddSource( CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource( notify ), kCFRunLoopCommonModes ); } + else + printf( "Could not IORegisterForSystemPower\n" ); - NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; + NSString * torrentPath, * downloadFolder, * paused; + NSDictionary * dic; - NSArray * history = [defaults arrayForKey: @"History"]; - if( history ) + NSEnumerator * enumerator = [[fDefaults arrayForKey: @"History"] objectEnumerator]; + while ((dic = [enumerator nextObject])) { - unsigned i; - NSDictionary * dic; - NSString * torrentPath, * downloadFolder, * paused; + torrentPath = [dic objectForKey: @"TorrentPath"]; + downloadFolder = [dic objectForKey: @"DownloadFolder"]; + paused = [dic objectForKey: @"Paused"]; + + if (!torrentPath || !downloadFolder || !paused) + continue; - for( i = 0; i < [history count]; i++ ) - { - dic = [history objectAtIndex: i]; + if (tr_torrentInit(fHandle, [torrentPath UTF8String])) + continue; - torrentPath = [dic objectForKey: @"TorrentPath"]; - downloadFolder = [dic objectForKey: @"DownloadFolder"]; - paused = [dic objectForKey: @"Paused"]; + tr_torrentSetFolder( fHandle, tr_torrentCount( fHandle ) - 1, + [downloadFolder UTF8String] ); - if( !torrentPath || !downloadFolder || !paused ) - { - continue; - } - - if( tr_torrentInit( fHandle, [torrentPath UTF8String] ) ) - { - continue; - } - - tr_torrentSetFolder( fHandle, tr_torrentCount( fHandle ) - 1, - [downloadFolder UTF8String] ); - - if( [paused isEqualToString: @"NO"] ) - { - tr_torrentStart( fHandle, tr_torrentCount( fHandle ) - 1 ); - } - } + if ([paused isEqualToString: @"NO"]) + tr_torrentStart( fHandle, tr_torrentCount( fHandle ) - 1 ); } - - /* Register with the growl system */ + + //check and register Growl if it is installed for this user or all users + NSFileManager * manager = [NSFileManager defaultManager]; + fHasGrowl = [manager fileExistsAtPath: GROWL_PATH] + || [manager fileExistsAtPath: [[NSString stringWithFormat: @"~%@", + GROWL_PATH] stringByExpandingTildeInPath]]; [self growlRegister: self]; - /* Update the interface every 500 ms */ + //update the interface every 500 ms fCount = 0; fStat = NULL; fTimer = [NSTimer scheduledTimerWithTimeInterval: 0.5 target: self @@ -175,17 +159,50 @@ static void sleepCallBack( void * controller, io_service_t y, return NO; } -- (NSApplicationTerminateReply) applicationShouldTerminate: - (NSApplication *) app +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { + if ([[fDefaults stringForKey: @"CheckQuit"] isEqualToString:@"YES"]) + { + int i; + for( i = 0; i < fCount; i++ ) + { + if( fStat[i].status & ( TR_STATUS_CHECK | + TR_STATUS_DOWNLOAD ) ) + { + NSBeginAlertSheet(@"Confirm Quit", + @"Quit", @"Cancel", nil, + fWindow, self, + @selector(quitSheetDidEnd:returnCode:contextInfo:), + NULL, NULL, @"There are active torrents. Do you really want to quit?"); + return NSTerminateLater; + } + } + } + + [self quitProcedure]; + return NSTerminateNow; +} + +- (void) quitSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode + contextInfo:(void *)contextInfo +{ + if (returnCode == NSAlertDefaultReturn) + [self quitProcedure]; + + [NSApp stopModal]; + [NSApp replyToApplicationShouldTerminate: (returnCode == NSAlertDefaultReturn)]; +} + +- (void) quitProcedure +{ + int i; NSMutableArray * history = [NSMutableArray arrayWithCapacity: TR_MAX_TORRENT_COUNT]; - int i; - - /* Stop updating the interface */ + + // Stop updating the interface [fTimer invalidate]; - /* Save history and stop running torrents */ + // Save history and stop running torrents for( i = 0; i < fCount; i++ ) { [history addObject: [NSDictionary dictionaryWithObjectsAndKeys: @@ -205,7 +222,7 @@ static void sleepCallBack( void * controller, io_service_t y, } } - /* Wait for torrents to stop (5 seconds timeout) */ + // Wait for torrents to stop (5 seconds timeout) NSDate * start = [NSDate date]; while( fCount > 0 ) { @@ -224,48 +241,73 @@ static void sleepCallBack( void * controller, io_service_t y, tr_close( fHandle ); - [[NSUserDefaults standardUserDefaults] - setObject: history forKey: @"History"]; + [fDefaults setObject: history forKey: @"History"]; +} - return NSTerminateNow; +- (void) showPreferenceWindow: (id) sender +{ + NSRect mainFrame; + NSRect prefsFrame; + NSRect screenRect; + NSPoint point; + + /* Place the window */ + mainFrame = [fWindow frame]; + prefsFrame = [fPrefsWindow frame]; + screenRect = [[NSScreen mainScreen] visibleFrame]; + point.x = mainFrame.origin.x + mainFrame.size.width / 2 - + prefsFrame.size.width / 2; + point.y = mainFrame.origin.y + mainFrame.size.height - 30; + + /* Make sure it is in the screen */ + if( point.x < screenRect.origin.x ) + { + point.x = screenRect.origin.x; + } + if( point.x + prefsFrame.size.width > + screenRect.origin.x + screenRect.size.width ) + { + point.x = screenRect.origin.x + + screenRect.size.width - prefsFrame.size.width; + } + if( point.y - prefsFrame.size.height < screenRect.origin.y ) + { + point.y = screenRect.origin.y + prefsFrame.size.height; + } + + [fPrefsWindow setFrameTopLeftPoint: point]; + [fPrefsWindow makeKeyAndOrderFront:NULL]; } - (void) folderChoiceClosed: (NSOpenPanel *) s returnCode: (int) code contextInfo: (void *) info { - if( code != NSOKButton ) + if (code == NSOKButton) + { + tr_torrentSetFolder( fHandle, tr_torrentCount( fHandle ) - 1, + [[[s filenames] objectAtIndex: 0] UTF8String] ); + tr_torrentStart( fHandle, tr_torrentCount( fHandle ) - 1 ); + } + else { tr_torrentClose( fHandle, tr_torrentCount( fHandle ) - 1 ); - [NSApp stopModal]; - return; } - - tr_torrentSetFolder( fHandle, tr_torrentCount( fHandle ) - 1, - [[[s filenames] objectAtIndex: 0] UTF8String] ); - tr_torrentStart( fHandle, tr_torrentCount( fHandle ) - 1 ); [NSApp stopModal]; } - - (void) application: (NSApplication *) sender openFiles: (NSArray *) filenames { - unsigned i; - NSUserDefaults * defaults; NSString * downloadChoice, * downloadFolder, * torrentPath; - defaults = [NSUserDefaults standardUserDefaults]; - downloadChoice = [defaults stringForKey: @"DownloadChoice"]; - downloadFolder = [defaults stringForKey: @"DownloadFolder"]; + downloadChoice = [fDefaults stringForKey: @"DownloadChoice"]; + downloadFolder = [fDefaults stringForKey: @"DownloadFolder"]; - for( i = 0; i < [filenames count]; i++ ) + NSEnumerator * enumerator = [filenames objectEnumerator]; + while ((torrentPath = [enumerator nextObject])) { - torrentPath = [filenames objectAtIndex: i]; - if( tr_torrentInit( fHandle, [torrentPath UTF8String] ) ) - { continue; - } if( [downloadChoice isEqualToString: @"Constant"] ) { @@ -283,19 +325,15 @@ static void sleepCallBack( void * controller, io_service_t y, continue; } - NSOpenPanel * panel; - NSString * message; - - panel = [NSOpenPanel openPanel]; - message = [NSString stringWithFormat: - @"Select the download folder for %@", - [torrentPath lastPathComponent]]; - - [panel setPrompt: @"Select"]; - [panel setMessage: message]; - [panel setAllowsMultipleSelection: NO]; - [panel setCanChooseFiles: NO]; - [panel setCanChooseDirectories: YES]; + NSOpenPanel * panel = [NSOpenPanel openPanel]; + + [panel setPrompt: @"Select Download Folder"]; + [panel setMessage: [NSString stringWithFormat: + @"Select the download folder for %@", + [torrentPath lastPathComponent]]]; + [panel setAllowsMultipleSelection: NO]; + [panel setCanChooseFiles: NO]; + [panel setCanChooseDirectories: YES]; [panel beginSheetForDirectory: NULL file: NULL types: NULL modalForWindow: fWindow modalDelegate: self didEndSelector: @@ -309,21 +347,14 @@ static void sleepCallBack( void * controller, io_service_t y, - (void) advancedChanged: (id) sender { - NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; - if( [fAdvancedBarItem state] == NSOnState ) - { - [fAdvancedBarItem setState: NSOffState]; - [defaults setObject:@"NO" forKey:@"UseAdvancedBar"]; - } - else - { - [fAdvancedBarItem setState: NSOnState]; - [defaults setObject:@"YES" forKey:@"UseAdvancedBar"]; - } + [fAdvancedBarItem setState: ![fAdvancedBarItem state]]; + [fDefaults setObject: [fAdvancedBarItem state] == NSOffState ? @"NO" : @"YES" + forKey:@"UseAdvancedBar"]; + [fTableView display]; } -/* called on by applescript */ +//called on by applescript - (void) open: (NSArray *) files { fFilenames = [files retain]; @@ -417,10 +448,62 @@ static void sleepCallBack( void * controller, io_service_t y, [self updateUI: NULL]; } - - (void) removeTorrentWithIndex: (int) idx deleteTorrent: (BOOL) deleteTorrent deleteData: (BOOL) deleteData +{ + if ( fStat[idx].status & ( TR_STATUS_CHECK + | TR_STATUS_DOWNLOAD) ) + { + if ([[fDefaults stringForKey: @"CheckRemove"] isEqualToString:@"YES"]) + { + NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys: + [NSString stringWithFormat: @"%d", idx], @"Index", + [NSString stringWithFormat: @"%d", deleteTorrent], @"DeleteTorrent", + [NSString stringWithFormat: @"%d", deleteData], @"DeleteData", + nil]; + [dict retain]; + + NSBeginAlertSheet(@"Confirm Remove", + @"Remove", @"Cancel", nil, + fWindow, self, + @selector(removeSheetDidEnd:returnCode:contextInfo:), + NULL, dict, @"This torrent is active. Do you really want to remove it?"); + return; + } + //stop if not stopped + else + [self stopTorrentWithIndex:idx]; + } + + [self confirmRemoveTorrentWithIndex: idx + deleteTorrent: deleteTorrent + deleteData: deleteData]; +} + +- (void) removeSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode + contextInfo:(NSDictionary *)dict +{ + [NSApp stopModal]; + if (returnCode != NSAlertDefaultReturn) + { + [dict release]; + return; + } + + int idx = [[dict objectForKey:@"Index"] intValue]; + + [self stopTorrentWithIndex:idx]; + + [self confirmRemoveTorrentWithIndex: idx + deleteTorrent: [[dict objectForKey:@"DeleteTorrent"] intValue] + deleteData: [[dict objectForKey:@"DeleteData"] intValue]]; + [dict release]; +} + +- (void) confirmRemoveTorrentWithIndex: (int) idx + deleteTorrent: (BOOL) deleteTorrent + deleteData: (BOOL) deleteData { if( deleteData ) { @@ -475,24 +558,23 @@ static void sleepCallBack( void * controller, io_service_t y, float dl, ul; int row, i; - /* Update the NSTableView */ - if( fStat ) - { - free( fStat ); - } + //Update the NSTableView + if (fStat) + free(fStat); + fCount = tr_torrentStat( fHandle, &fStat ); [fTableView updateUI: fStat]; - /* Update the global DL/UL rates */ + //Update the global DL/UL rates tr_torrentRates( fHandle, &dl, &ul ); [fTotalDLField setStringValue: [NSString stringWithFormat: @"Total DL: %.2f KB/s", dl]]; [fTotalULField setStringValue: [NSString stringWithFormat: @"Total UL: %.2f KB/s", ul]]; - /* Update DL/UL totals in the Info panel */ + //Update DL/UL totals in the Info panel row = [fTableView selectedRow]; - if( row > -1 ) + if( row >= 0 ) { [fInfoDownloaded setStringValue: stringForFileSize( fStat[row].downloaded )]; @@ -500,64 +582,18 @@ static void sleepCallBack( void * controller, io_service_t y, stringForFileSize( fStat[row].uploaded )]; } - /* check if torrents have recently ended. */ + //check if torrents have recently ended. for (i = 0; i < fCount; i++) { if( !tr_getFinished( fHandle, i ) ) - { continue; - } + [self notifyGrowl: [NSString stringWithUTF8String: fStat[i].info.name]]; tr_setFinished( fHandle, i, 0 ); } } - -- (NSMenu *) menuForIndex: (int) idx -{ - if ( idx < 0 || idx >= fCount ) - { - return nil; - } - - int status = fStat[idx].status; - - NSMenuItem *pauseItem = [fContextMenu itemWithTag: CONTEXT_PAUSE]; - NSMenuItem *removeItem = [fContextMenu itemAtIndex: 1]; - NSMenuItem *infoItem = [fContextMenu itemAtIndex: 2]; - - [pauseItem setTarget: self]; - - if ( status & TR_STATUS_CHECK || - status & TR_STATUS_DOWNLOAD || - status & TR_STATUS_SEED ) - { - /* we can stop */ - [removeItem setEnabled: NO]; - [pauseItem setTitle: @"Pause"]; - [pauseItem setAction: @selector(stopTorrent:)]; - [pauseItem setEnabled: YES]; - } else { - /* we are stopped */ - [removeItem setEnabled: YES]; - [pauseItem setTitle: @"Resume"]; - [pauseItem setAction: @selector(resumeTorrent:)]; - /* don't allow resuming if we aren't in PAUSE */ - if ( !(status & TR_STATUS_PAUSE) ) - [pauseItem setEnabled: NO]; - } - - if( [fInfoPanel isVisible] ) - { - [infoItem setTitle: @"Hide Info"]; - } else { - [infoItem setTitle: @"Show Info"]; - } - - return fContextMenu; -} - - (int) numberOfRowsInTableView: (NSTableView *) t { return fCount; @@ -663,8 +699,7 @@ static void sleepCallBack( void * controller, io_service_t y, - (NSToolbarItem *) toolbar: (NSToolbar *) t itemForItemIdentifier: (NSString *) ident willBeInsertedIntoToolbar: (BOOL) flag { - NSToolbarItem * item; - item = [[NSToolbarItem alloc] initWithItemIdentifier: ident]; + NSToolbarItem * item = [[NSToolbarItem alloc] initWithItemIdentifier: ident]; if( [ident isEqualToString: TOOLBAR_OPEN] ) { @@ -684,15 +719,6 @@ static void sleepCallBack( void * controller, io_service_t y, [item setTarget: self]; [item setAction: @selector( removeTorrent: )]; } - else if( [ident isEqualToString: TOOLBAR_PREFS] ) - { - [item setLabel: @"Preferences"]; - [item setPaletteLabel: [item label]]; - [item setToolTip: @"Show the Preferences panel"]; - [item setImage: [NSImage imageNamed: @"Preferences.png"]]; - [item setTarget: fPrefsController]; - [item setAction: @selector( show: )]; - } else if( [ident isEqualToString: TOOLBAR_INFO] ) { [item setLabel: @"Info"]; @@ -733,8 +759,8 @@ static void sleepCallBack( void * controller, io_service_t y, { return [NSArray arrayWithObjects: TOOLBAR_OPEN, TOOLBAR_REMOVE, - /* TOOLBAR_RESUME_ALL, TOOLBAR_PAUSE_ALL, */ - TOOLBAR_PREFS, TOOLBAR_INFO, + TOOLBAR_RESUME_ALL, TOOLBAR_PAUSE_ALL, + TOOLBAR_INFO, NSToolbarSeparatorItemIdentifier, NSToolbarSpaceItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, @@ -746,26 +772,13 @@ static void sleepCallBack( void * controller, io_service_t y, { return [NSArray arrayWithObjects: TOOLBAR_OPEN, TOOLBAR_REMOVE, - /* NSToolbarSeparatorItemIdentifier, - TOOLBAR_RESUME_ALL, TOOLBAR_PAUSE_ALL, */ + NSToolbarSeparatorItemIdentifier, + TOOLBAR_RESUME_ALL, TOOLBAR_PAUSE_ALL, NSToolbarFlexibleSpaceItemIdentifier, - TOOLBAR_PREFS, TOOLBAR_INFO, + TOOLBAR_INFO, NULL]; } -- (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem -{ - //check remove item - if ([toolbarItem action] == @selector(removeTorrent:)) - { - int row = [fTableView selectedRow]; - return ( row >= 0 ) && ( fStat[row].status & - ( TR_STATUS_STOPPING | TR_STATUS_PAUSE ) ); - } - - return true; -} - - (void) runCustomizationPalette: (id) sender { [fToolbar runCustomizationPalette:sender]; @@ -776,37 +789,72 @@ static void sleepCallBack( void * controller, io_service_t y, [fWindow toggleToolbarShown:sender]; } +- (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem +{ + //enable remove item + if ([toolbarItem action] == @selector(removeTorrent:)) + return [fTableView selectedRow] >= 0; + + //enable pause all and resume all items + if ([toolbarItem action] == @selector(stopAllTorrents:) + || [toolbarItem action] == @selector(resumeAllTorrents:)) + return fCount > 0; + + return YES; +} + - (BOOL)validateMenuItem:(NSMenuItem *)menuItem { + //disable menus if customize sheet is active + if ([fToolbar customizationPaletteIsRunning]) + return NO; + //enable customize toolbar item if ([menuItem action] == @selector(showHideToolbar:)) + { [menuItem setTitle: [fToolbar isVisible] ? @"Hide Toolbar" : @"Show Toolbar"]; - - if ([fToolbar customizationPaletteIsRunning]) - return false; + return YES; + } //enable show info if ([menuItem action] == @selector(showInfo:)) { [menuItem setTitle: [fInfoPanel isVisible] ? @"Hide Info" : @"Show Info"]; - return true; + return YES; } + + //enable pause all and resume all + if ([menuItem action] == @selector(stopAllTorrents:) || [menuItem action] == @selector(resumeAllTorrents:)) + return fCount > 0; int row = [fTableView selectedRow]; //enable remove items - if ([menuItem action] == @selector(removeTorrent:) || [menuItem action] == @selector(removeTorrentDeleteFile:) - || [menuItem action] == @selector(removeTorrentDeleteData:) || [menuItem action] == @selector(removeTorrentDeleteBoth:)) { - /* Can we remove it ? */ - return ( row >= 0 ) && ( fStat[row].status & - ( TR_STATUS_STOPPING | TR_STATUS_PAUSE ) ); + if ([menuItem action] == @selector(removeTorrent:) + || [menuItem action] == @selector(removeTorrentDeleteFile:) + || [menuItem action] == @selector(removeTorrentDeleteData:) + || [menuItem action] == @selector(removeTorrentDeleteBoth:)) + { + //append or remove ellipsis when needed + if (row >= 0 && fStat[row].status & ( TR_STATUS_CHECK | TR_STATUS_DOWNLOAD) + && [[fDefaults stringForKey: @"CheckRemove"] isEqualToString:@"YES"]) + { + if (![[menuItem title] hasSuffix:NS_ELLIPSIS]) + [menuItem setTitle:[[menuItem title] stringByAppendingString:NS_ELLIPSIS]]; + } + else + { + if ([[menuItem title] hasSuffix:NS_ELLIPSIS]) + [menuItem setTitle:[[menuItem title] substringToIndex:[[menuItem title] length]-[NS_ELLIPSIS length]]]; + } + return row >= 0; } //enable reveal in finder item if ([menuItem action] == @selector(revealFromMenu:)) return row >= 0; - //enable and change pause and remove item + //enable and change pause / remove item if ([menuItem action] == @selector(resumeTorrent:) || [menuItem action] == @selector(stopTorrent:)) { if (row >= 0 && fStat[row].status & TR_STATUS_PAUSE) @@ -822,7 +870,7 @@ static void sleepCallBack( void * controller, io_service_t y, return row >= 0; } - return true; + return YES; } - (void) sleepCallBack: (natural_t) messageType argument: @@ -893,40 +941,19 @@ static void sleepCallBack( void * controller, io_service_t y, - (void) showMainWindow: (id) sender { - [fWindow makeKeyAndOrderFront: NULL]; + [fWindow makeKeyAndOrderFront: nil]; } - (void) linkHomepage: (id) sender { [[NSWorkspace sharedWorkspace] openURL: [NSURL - URLWithString:@"http://transmission.m0k.org/"]]; + URLWithString: WEBSITE_URL]]; } - (void) linkForums: (id) sender { [[NSWorkspace sharedWorkspace] openURL: [NSURL - URLWithString:@"http://transmission.m0k.org/forum/"]]; -} - -- (BOOL) hasGrowl -{ - NSFileManager * manager = [NSFileManager defaultManager]; - NSString * helper = @"/Library/PreferencePanes/Growl.prefPane/" - "Contents/Resources/GrowlHelperApp.app"; - - if( [manager fileExistsAtPath: helper] ) - { - /* Growl was installed for all users */ - return YES; - } - if( [manager fileExistsAtPath: [[NSString stringWithFormat: @"~%@", - helper] stringByExpandingTildeInPath]] ) - { - /* Growl was installed for this user only */ - return YES; - } - - return NO; + URLWithString: FORUM_URL]]; } - (void) notifyGrowl: (NSString * ) file @@ -935,10 +962,8 @@ static void sleepCallBack( void * controller, io_service_t y, NSAppleScript * appleScript; NSDictionary * error; - if( ![self hasGrowl] ) - { + if( !fHasGrowl ) return; - } growlScript = [NSString stringWithFormat: @"tell application \"System Events\"\n" @@ -965,10 +990,8 @@ static void sleepCallBack( void * controller, io_service_t y, NSAppleScript * appleScript; NSDictionary * error; - if( ![self hasGrowl] ) - { + if( !fHasGrowl ) return; - } growlScript = [NSString stringWithFormat: @"tell application \"System Events\"\n" @@ -981,6 +1004,7 @@ static void sleepCallBack( void * controller, io_service_t y, " end tell\n" " end if\n" "end tell"]; + appleScript = [[NSAppleScript alloc] initWithSource: growlScript]; if( ![appleScript executeAndReturnError: &error] ) { @@ -989,19 +1013,15 @@ static void sleepCallBack( void * controller, io_service_t y, [appleScript release]; } - - (void) revealFromMenu: (id) sender { - int row; - - row = [fTableView selectedRow]; - if( row < 0 ) + int row = [fTableView selectedRow]; + if (row >= 0) { - return; + [self finderReveal: [NSString stringWithFormat: @"%@/%@", + [NSString stringWithUTF8String: fStat[row].folder], + [NSString stringWithUTF8String: fStat[row].info.name]]]; } - [self finderReveal: [NSString stringWithFormat: @"%@/%@", - [NSString stringWithUTF8String: fStat[row].folder], - [NSString stringWithUTF8String: fStat[row].info.name]]]; } - (void) finderReveal: (NSString *) path diff --git a/macosx/English.lproj/MainMenu.nib/classes.nib b/macosx/English.lproj/MainMenu.nib/classes.nib index 14b0c1066..8f5d7bd5b 100644 --- a/macosx/English.lproj/MainMenu.nib/classes.nib +++ b/macosx/English.lproj/MainMenu.nib/classes.nib @@ -18,6 +18,7 @@ showHideToolbar = id; showInfo = id; showMainWindow = id; + showPreferenceWindow = id; stopAllTorrents = id; stopTorrent = id; }; @@ -25,7 +26,6 @@ LANGUAGE = ObjC; OUTLETS = { fAdvancedBarItem = NSMenuItem; - fContextMenu = NSMenu; fInfoAnnounce = NSTextField; fInfoDownloaded = NSTextField; fInfoFolder = NSTextField; @@ -40,6 +40,7 @@ fInfoUploaded = NSTextField; fPauseResumeItem = NSMenuItem; fPrefsController = PrefsController; + fPrefsWindow = NSPanel; fRemoveBothItem = NSMenuItem; fRemoveDataItem = NSMenuItem; fRemoveItem = NSMenuItem; @@ -54,25 +55,40 @@ SUPERCLASS = NSObject; }, {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + {CLASS = NameCell; LANGUAGE = ObjC; SUPERCLASS = NSCell; }, { - ACTIONS = {cancel = id; check = id; ratio = id; save = id; show = id; }; + ACTIONS = { + folderSheetShow = id; + setDownloadLocation = id; + setLimitUploadCheck = id; + setPort = id; + setQuitMessage = id; + setRemoveMessage = id; + setUploadLimit = id; + }; CLASS = PrefsController; LANGUAGE = ObjC; OUTLETS = { + fBlankView = NSView; fFolderMatrix = NSMatrix; fFolderPopUp = NSPopUpButton; + fGeneralView = NSView; + fNetworkView = NSView; fPortField = NSTextField; - fPrefsWindow = NSWindow; + fPrefsWindow = NSPanel; + fQuitCheck = NSButton; + fRemoveCheck = NSButton; fUploadCheck = NSButton; fUploadField = NSTextField; fWindow = NSWindow; }; SUPERCLASS = NSObject; }, + {CLASS = ProgressCell; LANGUAGE = ObjC; SUPERCLASS = NSCell; }, { CLASS = TorrentTableView; LANGUAGE = ObjC; - OUTLETS = {fController = Controller; }; + OUTLETS = {fContextNoRow = NSMenu; fContextRow = NSMenu; fController = Controller; }; SUPERCLASS = NSTableView; } ); diff --git a/macosx/English.lproj/MainMenu.nib/info.nib b/macosx/English.lproj/MainMenu.nib/info.nib index 5cf994340..b18e6c982 100644 --- a/macosx/English.lproj/MainMenu.nib/info.nib +++ b/macosx/English.lproj/MainMenu.nib/info.nib @@ -3,13 +3,23 @@ IBDocumentLocation - 416 137 361 432 0 0 1152 842 + 62 66 426 365 0 0 1280 832 IBEditorPositions 29 - 79 779 371 44 0 0 1152 842 + 92 768 371 44 0 0 1280 832 456 - 134 408 144 106 0 0 1152 842 + 212 488 144 118 0 0 1152 842 + 581 + 324 628 112 68 0 0 1152 842 + 589 + 54 521 112 118 0 0 1152 842 + 783 + 428 442 385 225 0 0 1280 832 + 796 + 479 490 282 129 0 0 1280 832 + 825 + 498 523 155 107 0 0 1152 842 IBFramework Version 443.0 @@ -18,6 +28,9 @@ IBOpenObjects 29 + 783 + 796 + 21 IBSystem Version 8F46 diff --git a/macosx/English.lproj/MainMenu.nib/keyedobjects.nib b/macosx/English.lproj/MainMenu.nib/keyedobjects.nib index 9dd04a4a3..17b5885e0 100644 Binary files a/macosx/English.lproj/MainMenu.nib/keyedobjects.nib and b/macosx/English.lproj/MainMenu.nib/keyedobjects.nib differ diff --git a/macosx/Images/Network.png b/macosx/Images/Network.png new file mode 100755 index 000000000..5865914f4 Binary files /dev/null and b/macosx/Images/Network.png differ diff --git a/macosx/Info.plist.in b/macosx/Info.plist.in index a644b2e6b..1bcb9918b 100644 --- a/macosx/Info.plist.in +++ b/macosx/Info.plist.in @@ -37,6 +37,8 @@ TR## CFBundleVersion %%VERSION%% + CFBundleShortVersionString + %%VERSION%% NSMainNibFile MainMenu NSPrincipalClass diff --git a/macosx/PrefsController.h b/macosx/PrefsController.h index fbbc7427c..61870d406 100644 --- a/macosx/PrefsController.h +++ b/macosx/PrefsController.h @@ -27,23 +27,35 @@ { tr_handle_t * fHandle; + + IBOutlet NSPanel * fPrefsWindow; + NSToolbar * fToolbar; + IBOutlet NSView * fGeneralView; + IBOutlet NSView * fNetworkView; + IBOutlet NSView * fBlankView; + + IBOutlet NSMatrix * fFolderMatrix; + IBOutlet NSPopUpButton * fFolderPopUp; + IBOutlet NSTextField * fPortField; + IBOutlet NSButton * fUploadCheck; + IBOutlet NSTextField * fUploadField; + IBOutlet NSButton * fQuitCheck; + IBOutlet NSButton * fRemoveCheck; + + IBOutlet NSWindow * fWindow; - IBOutlet NSWindow * fWindow; - IBOutlet NSWindow * fPrefsWindow; - IBOutlet NSMatrix * fFolderMatrix; - IBOutlet NSPopUpButton * fFolderPopUp; - IBOutlet NSTextField * fPortField; - IBOutlet NSButton * fUploadCheck; - IBOutlet NSTextField * fUploadField; - - NSString * fDownloadFolder; + NSString * fDownloadFolder; + NSUserDefaults * fDefaults; } -- (void) setHandle: (tr_handle_t *) handle; -- (void) show: (id) sender; -- (void) ratio: (id) sender; -- (void) check: (id) sender; -- (void) cancel: (id) sender; -- (void) save: (id) sender; +- (void) setPrefsWindow: (tr_handle_t *) handle; + +- (void) setLimitUploadCheck: (id) sender; +- (void) setPort: (id) sender; +- (void) setUploadLimit: (id) sender; +- (void) setQuitMessage: (id) sender; +- (void) setRemoveMessage: (id) sender; +- (void) setDownloadLocation: (id) sender; +- (void) folderSheetShow: (id) sender; @end diff --git a/macosx/PrefsController.m b/macosx/PrefsController.m index 95473652a..24abe94dc 100644 --- a/macosx/PrefsController.m +++ b/macosx/PrefsController.m @@ -22,187 +22,271 @@ #include "PrefsController.h" +#define DEFAULT_UPLOAD @"20" +#define MIN_PORT 1 +#define MAX_PORT 65535 + +#define DOWNLOAD_FOLDER 0 +#define DOWNLOAD_TORRENT 1 +#define DOWNLOAD_ASK 2 + +#define TOOLBAR_GENERAL @"General" +#define TOOLBAR_NETWORK @"Network" + @interface PrefsController (Private) -- (void) folderSheetShow: (id) sender; +- (void) showGeneralPref: (id) sender; +- (void) showNetworkPref: (id) sender; + +- (void) setPrefView: (NSView *) view; + - (void) folderSheetClosed: (NSOpenPanel *) s returnCode: (int) code contextInfo: (void *) info; -- (void) loadSettings; -- (void) saveSettings; - (void) updatePopUp; @end @implementation PrefsController -/*********************************************************************** - * setHandle - *********************************************************************** - * - **********************************************************************/ -- (void) setHandle: (tr_handle_t *) handle ++ (void) initialize { - NSUserDefaults * defaults; NSDictionary * appDefaults; NSString * desktop, * port; - fHandle = handle; - /* Register defaults settings: - Simple bar - Always download to Desktop - Port TR_DEFAULT_PORT - - 20 KB/s upload limit */ + - Upload limit DEFAULT_UPLOAD + - Do not limit upload + - Ask before quitting + - Ask before removing */ desktop = [NSHomeDirectory() stringByAppendingString: @"/Desktop"]; - port = [NSString stringWithFormat: @"%d", TR_DEFAULT_PORT]; + port = [NSString stringWithFormat: @"%d", TR_DEFAULT_PORT]; - defaults = [NSUserDefaults standardUserDefaults]; appDefaults = [NSDictionary dictionaryWithObjectsAndKeys: - @"NO", @"UseAdvancedBar", - @"Constant", @"DownloadChoice", - desktop, @"DownloadFolder", - port, @"BindPort", - @"20", @"UploadLimit", + @"NO", @"UseAdvancedBar", + @"Constant", @"DownloadChoice", + desktop, @"DownloadFolder", + port, @"BindPort", + DEFAULT_UPLOAD, @"UploadLimit", + @"YES", @"CheckUpload", + @"YES", @"CheckQuit", + @"YES", @"CheckRemove", NULL]; - [defaults registerDefaults: appDefaults]; - - /* Apply settings */ - tr_setBindPort( fHandle, [defaults integerForKey: @"BindPort"] ); - tr_setUploadLimit( fHandle, [defaults integerForKey: @"UploadLimit"] ); + [[NSUserDefaults standardUserDefaults] registerDefaults: appDefaults]; } -/*********************************************************************** - * show - *********************************************************************** - * - **********************************************************************/ -- (void) show: (id) sender +- (void)dealloc { - NSRect mainFrame; - NSRect prefsFrame; - NSRect screenRect; - NSPoint point; - - [self loadSettings]; - - /* Place the window */ - mainFrame = [fWindow frame]; - prefsFrame = [fPrefsWindow frame]; - screenRect = [[NSScreen mainScreen] visibleFrame]; - point.x = mainFrame.origin.x + mainFrame.size.width / 2 - - prefsFrame.size.width / 2; - point.y = mainFrame.origin.y + mainFrame.size.height - 30; - - /* Make sure it is in the screen */ - if( point.x < screenRect.origin.x ) - { - point.x = screenRect.origin.x; - } - if( point.x + prefsFrame.size.width > - screenRect.origin.x + screenRect.size.width ) - { - point.x = screenRect.origin.x + - screenRect.size.width - prefsFrame.size.width; - } - if( point.y - prefsFrame.size.height < screenRect.origin.y ) - { - point.y = screenRect.origin.y + prefsFrame.size.height; - } - - [fPrefsWindow setFrameTopLeftPoint: point]; - [fPrefsWindow makeKeyAndOrderFront: NULL]; + [fDownloadFolder release]; + [super dealloc]; } -/*********************************************************************** - * ratio - *********************************************************************** - * - **********************************************************************/ -- (void) ratio: (id) sender +- (void) setPrefsWindow: (tr_handle_t *) handle { - [fFolderPopUp setEnabled: ![fFolderMatrix selectedRow]]; -} + fToolbar = [[NSToolbar alloc] initWithIdentifier: @"Preferences Toolbar"]; + [fToolbar setDelegate: self]; + [fToolbar setAllowsUserCustomization: NO]; + [fPrefsWindow setToolbar: fToolbar]; + [fToolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel]; + [fToolbar setSizeMode: NSToolbarSizeModeRegular]; + [fPrefsWindow setShowsToolbarButton: NO]; + + [fToolbar setSelectedItemIdentifier: TOOLBAR_GENERAL]; + [self setPrefView: fGeneralView]; -/*********************************************************************** - * check - *********************************************************************** - * - **********************************************************************/ -- (void) check: (id) sender -{ - if( [fUploadCheck state] == NSOnState ) + fDefaults = [NSUserDefaults standardUserDefaults]; + + //set download folder + NSString * downloadChoice = [fDefaults stringForKey: @"DownloadChoice"]; + fDownloadFolder = [fDefaults stringForKey: @"DownloadFolder"]; + [fDownloadFolder retain]; + + if( [downloadChoice isEqualToString: @"Constant"] ) { - [fUploadField setEnabled: YES]; + [fFolderMatrix selectCellAtRow: DOWNLOAD_FOLDER column: 0]; + } + else if( [downloadChoice isEqualToString: @"Torrent"] ) + { + [fFolderMatrix selectCellAtRow: DOWNLOAD_TORRENT column: 0]; } else { - [fUploadField setEnabled: NO]; - [fUploadField setStringValue: @""]; + [fFolderMatrix selectCellAtRow: DOWNLOAD_ASK column: 0]; } -} + [self updatePopUp]; + [fFolderPopUp setEnabled: [fFolderMatrix selectedRow] == 0]; -/*********************************************************************** - * cancel - *********************************************************************** - * Discards changes and closes the Preferences window - **********************************************************************/ -- (void) cancel: (id) sender -{ - [fDownloadFolder release]; - [fPrefsWindow close]; -} - -/*********************************************************************** - * save - *********************************************************************** - * Checks the user-defined options. If they are correct, saves settings - * and closes the Preferences window. Otherwise corrects them and leaves - * the window open - **********************************************************************/ -- (void) save: (id) sender -{ - int bindPort; - int uploadLimit; - - /* Bind port */ - bindPort = [fPortField intValue]; - bindPort = MAX( 1, bindPort ); - bindPort = MIN( bindPort, 65535 ); - - if( ![[fPortField stringValue] isEqualToString: - [NSString stringWithFormat: @"%d", bindPort]] ) + //set bind port + int bindPort = [fDefaults integerForKey: @"BindPort"]; + [fPortField setIntValue: bindPort]; + fHandle = handle; + tr_setBindPort( fHandle, bindPort ); + + //checks for old version upload speed of -1 + if ([fDefaults integerForKey: @"UploadLimit"] < 0) { + [fDefaults setObject: DEFAULT_UPLOAD forKey: @"UploadLimit"]; + [fDefaults setObject: @"NO" forKey: @"CheckUpload"]; + } + + //set upload limit + BOOL checkUpload = [[fDefaults stringForKey: @"CheckUpload"] isEqualToString:@"YES"]; + int uploadLimit = [fDefaults integerForKey: @"UploadLimit"]; + + [fUploadCheck setState: checkUpload ? NSOnState : NSOffState]; + [fUploadField setIntValue: uploadLimit]; + [fUploadField setEnabled: checkUpload]; + + if (!checkUpload || uploadLimit == 0) + uploadLimit = -1; + tr_setUploadLimit( fHandle, uploadLimit ); + + //set remove and quit prompts + [fQuitCheck setState:([[fDefaults stringForKey: @"CheckQuit"] + isEqualToString:@"YES"] ? NSOnState : NSOffState)]; + [fRemoveCheck setState:([[fDefaults stringForKey: @"CheckRemove"] + isEqualToString:@"YES"] ? NSOnState : NSOffState)]; +} + +- (NSToolbarItem *) toolbar: (NSToolbar *) t itemForItemIdentifier: + (NSString *) ident willBeInsertedIntoToolbar: (BOOL) flag +{ + NSToolbarItem * item; + item = [[NSToolbarItem alloc] initWithItemIdentifier: ident]; + + if ([ident isEqualToString: TOOLBAR_GENERAL]) + { + [item setLabel: TOOLBAR_GENERAL]; + [item setImage: [NSImage imageNamed: @"Preferences.png"]]; + [item setTarget: self]; + [item setAction: @selector( showGeneralPref: )]; + } + else if ([ident isEqualToString: TOOLBAR_NETWORK]) + { + [item setLabel: TOOLBAR_NETWORK]; + [item setImage: [NSImage imageNamed: @"Network.png"]]; + [item setTarget: self]; + [item setAction: @selector( showNetworkPref: )]; + } + else + { + [item release]; + return nil; + } + + return item; +} + +- (NSArray *) toolbarSelectableItemIdentifiers: (NSToolbar *)toolbar +{ + return [self toolbarDefaultItemIdentifiers: nil]; +} + +- (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *)toolbar +{ + return [self toolbarAllowedItemIdentifiers: nil]; +} + +- (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *)toolbar +{ + return [NSArray arrayWithObjects: + TOOLBAR_GENERAL, + TOOLBAR_NETWORK, + nil]; +} + +- (void) setPort: (id) sender +{ + int bindPort = [fPortField intValue]; + + //if value entered is not an int or is not in range do not change + if (![[fPortField stringValue] isEqualToString: + [NSString stringWithFormat: @"%d", bindPort]] + || bindPort < MIN_PORT + || bindPort > MAX_PORT) + { + NSBeep(); + bindPort = [fDefaults integerForKey: @"BindPort"]; [fPortField setIntValue: bindPort]; - return; } - - /* Upload limit */ - if( [fUploadCheck state] == NSOnState ) + else { - uploadLimit = [fUploadField intValue]; - uploadLimit = MAX( 0, uploadLimit ); - - if( ![[fUploadField stringValue] isEqualToString: - [NSString stringWithFormat: @"%d", uploadLimit]] ) - { - [fUploadField setIntValue: uploadLimit]; - return; - } + tr_setBindPort( fHandle, bindPort ); + [fDefaults setObject: [NSString stringWithFormat: @"%d", bindPort] + forKey: @"BindPort"]; } - - [self saveSettings]; - [self cancel: NULL]; } -@end /* @implementation PrefsController */ +- (void) setLimitUploadCheck: (id) sender +{ + BOOL checkUpload = [fUploadCheck state] == NSOnState; -@implementation PrefsController (Private) + [fDefaults setObject: checkUpload ? @"YES" : @"NO" + forKey: @"CheckUpload"]; + + [self setUploadLimit: sender]; + [fUploadField setEnabled: checkUpload]; +} + +- (void) setUploadLimit: (id) sender +{ + int uploadLimit = [fUploadField intValue]; + + //if value entered is not an int or is less than 0 do not change + if (![[fUploadField stringValue] isEqualToString: + [NSString stringWithFormat: @"%d", uploadLimit]] + || uploadLimit < 0) + { + NSBeep(); + uploadLimit = [fDefaults integerForKey: @"UploadLimit"]; + [fUploadField setIntValue: uploadLimit]; + } + else + { + [fDefaults setObject: [NSString stringWithFormat: @"%d", uploadLimit] + forKey: @"UploadLimit"]; + } + + if ([fUploadCheck state] == NSOffState || uploadLimit == 0) + uploadLimit = -1; + tr_setUploadLimit( fHandle, uploadLimit ); +} + +- (void) setQuitMessage: (id) sender +{ + [fDefaults setObject: ([fQuitCheck state] == NSOnState ? @"YES" : @"NO") + forKey: @"CheckQuit"]; +} + +- (void) setRemoveMessage: (id) sender +{ + [fDefaults setObject: ([fRemoveCheck state] == NSOnState ? @"YES" : @"NO") + forKey: @"CheckRemove"]; +} + +- (void) setDownloadLocation: (id) sender +{ + //Download folder + switch( [fFolderMatrix selectedRow] ) + { + case DOWNLOAD_FOLDER: + [fDefaults setObject: @"Constant" forKey: @"DownloadChoice"]; + break; + case DOWNLOAD_TORRENT: + [fDefaults setObject: @"Torrent" forKey: @"DownloadChoice"]; + break; + case DOWNLOAD_ASK: + [fDefaults setObject: @"Ask" forKey: @"DownloadChoice"]; + break; + } + [fFolderPopUp setEnabled: [fFolderMatrix selectedRow] == 0]; +} - (void) folderSheetShow: (id) sender { - NSOpenPanel * panel; - - panel = [NSOpenPanel openPanel]; + NSOpenPanel * panel = [NSOpenPanel openPanel]; [panel setPrompt: @"Select"]; [panel setAllowsMultipleSelection: NO]; @@ -215,146 +299,62 @@ contextInfo: NULL]; } -- (void) folderSheetClosed: (NSOpenPanel *) s returnCode: (int) code +@end // @implementation PrefsController + +@implementation PrefsController (Private) + +- (void) showGeneralPref: (id) sender +{ + [self setPrefView: fGeneralView]; +} + +- (void) showNetworkPref: (id) sender +{ + [self setPrefView: fNetworkView]; +} + +- (void) setPrefView: (NSView *) view +{ + NSRect windowRect = [fPrefsWindow frame]; + int difference = [view frame].size.height - [[fPrefsWindow contentView] frame].size.height; + + windowRect.origin.y -= difference; + windowRect.size.height += difference; + + [fPrefsWindow setTitle: [fToolbar selectedItemIdentifier]]; + [fPrefsWindow setContentView: fBlankView]; + [fPrefsWindow setFrame:windowRect display: YES animate: YES]; + [fPrefsWindow setContentView: view]; +} + +- (void) folderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info { [fFolderPopUp selectItemAtIndex: 0]; - if( code != NSOKButton ) - { + if (code != NSOKButton) return; - } [fDownloadFolder release]; - fDownloadFolder = [[s filenames] objectAtIndex: 0]; + fDownloadFolder = [[openPanel filenames] objectAtIndex: 0]; [fDownloadFolder retain]; + + [fDefaults setObject: fDownloadFolder forKey: @"DownloadFolder"]; [self updatePopUp]; } -/*********************************************************************** - * loadSettings - *********************************************************************** - * Update the interface with the current settings - **********************************************************************/ -- (void) loadSettings -{ - NSUserDefaults * defaults; - NSString * downloadChoice; - int uploadLimit; - - /* Fill with current settings */ - defaults = [NSUserDefaults standardUserDefaults]; - - /* Download folder selection */ - downloadChoice = [defaults stringForKey: @"DownloadChoice"]; - fDownloadFolder = [defaults stringForKey: @"DownloadFolder"]; - [fDownloadFolder retain]; - - if( [downloadChoice isEqualToString: @"Constant"] ) - { - [fFolderMatrix selectCellAtRow: 0 column: 0]; - } - else if( [downloadChoice isEqualToString: @"Torrent"] ) - { - [fFolderMatrix selectCellAtRow: 1 column: 0]; - } - else - { - [fFolderMatrix selectCellAtRow: 2 column: 0]; - } - [self ratio: NULL]; - [self updatePopUp]; - - [fPortField setIntValue: [defaults integerForKey: @"BindPort"]]; - - uploadLimit = [defaults integerForKey: @"UploadLimit"]; - if( uploadLimit < 0 ) - { - [fUploadCheck setState: NSOffState]; - } - else - { - [fUploadCheck setState: NSOnState]; - [fUploadField setIntValue: uploadLimit]; - } - [self check: NULL]; -} - -/*********************************************************************** - * saveSettings - *********************************************************************** - * - **********************************************************************/ -- (void) saveSettings -{ - NSUserDefaults * defaults; - int bindPort; - int uploadLimit; - - defaults = [NSUserDefaults standardUserDefaults]; - - /* Download folder */ - switch( [fFolderMatrix selectedRow] ) - { - case 0: - [defaults setObject: @"Constant" forKey: @"DownloadChoice"]; - break; - case 1: - [defaults setObject: @"Torrent" forKey: @"DownloadChoice"]; - break; - case 2: - [defaults setObject: @"Ask" forKey: @"DownloadChoice"]; - break; - } - [defaults setObject: fDownloadFolder forKey: @"DownloadFolder"]; - - /* Bind port */ - bindPort = [fPortField intValue]; - tr_setBindPort( fHandle, bindPort ); - [defaults setObject: [NSString stringWithFormat: @"%d", bindPort] - forKey: @"BindPort"]; - - /* Upload limit */ - if( [fUploadCheck state] == NSOnState ) - { - uploadLimit = [fUploadField intValue]; - } - else - { - uploadLimit = -1; - } - tr_setUploadLimit( fHandle, uploadLimit ); - [defaults setObject: [NSString stringWithFormat: @"%d", uploadLimit] - forKey: @"UploadLimit"]; -} - -/*********************************************************************** - * updatePopUp - *********************************************************************** - * Uses fDownloadFolder to update the displayed folder name and icon - **********************************************************************/ - (void) updatePopUp { NSMenuItem * menuItem; NSImage * image32, * image16; - /* Set up the pop up */ - [fFolderPopUp removeAllItems]; - [fFolderPopUp addItemWithTitle: @""]; - [[fFolderPopUp menu] addItem: [NSMenuItem separatorItem]]; - [fFolderPopUp addItemWithTitle: @"Other..."]; - - menuItem = (NSMenuItem *) [fFolderPopUp lastItem]; - [menuItem setTarget: self]; - [menuItem setAction: @selector( folderSheetShow: )]; - - /* Get the icon for the folder */ + // Get the icon for the folder image32 = [[NSWorkspace sharedWorkspace] iconForFile: fDownloadFolder]; image16 = [[NSImage alloc] initWithSize: NSMakeSize(16,16)]; - /* 32x32 -> 16x16 scaling */ + // 32x32 -> 16x16 scaling [image16 lockFocus]; [[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationHigh]; @@ -363,7 +363,7 @@ fraction: 1.0]; [image16 unlockFocus]; - /* Update the menu item */ + // Update the menu item menuItem = (NSMenuItem *) [fFolderPopUp itemAtIndex: 0]; [menuItem setTitle: [fDownloadFolder lastPathComponent]]; [menuItem setImage: image16]; diff --git a/macosx/TorrentTableView.h b/macosx/TorrentTableView.h index d9af14948..db9f83354 100644 --- a/macosx/TorrentTableView.h +++ b/macosx/TorrentTableView.h @@ -10,6 +10,9 @@ tr_stat_t * fStat; NSPoint fClickPoint; + + IBOutlet NSMenu * fContextRow; + IBOutlet NSMenu * fContextNoRow; } - (void) updateUI: (tr_stat_t *) stat; diff --git a/macosx/TorrentTableView.m b/macosx/TorrentTableView.m index e1fcf4882..859ccf35d 100644 --- a/macosx/TorrentTableView.m +++ b/macosx/TorrentTableView.m @@ -56,7 +56,6 @@ return rect; } - - (BOOL) pointInPauseRect: (NSPoint) point { return NSPointInRect( point, [self pauseRectForRow: @@ -114,15 +113,10 @@ point = [self convertPoint: [e locationInWindow] fromView: NULL]; row = [self rowAtPoint: point]; + + [self selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO]; - if( row < 0 ) - { - return NULL; - } - - [self selectRowIndexes: [NSIndexSet indexSetWithIndex: row] - byExtendingSelection: NO]; - return [fController menuForIndex: row]; + return row >= 0 ? fContextRow : fContextNoRow; } - (void) drawRect: (NSRect) r diff --git a/macosx/Transmission.xcodeproj/project.pbxproj b/macosx/Transmission.xcodeproj/project.pbxproj index 0554b71e5..f2cdc29a4 100644 --- a/macosx/Transmission.xcodeproj/project.pbxproj +++ b/macosx/Transmission.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 4D6DAAC7090CE00500F43C22 /* RevealOn.png in Resources */ = {isa = PBXBuildFile; fileRef = 4D6DAAC5090CE00500F43C22 /* RevealOn.png */; }; 4D752E930913C949008EAAD4 /* Preferences.png in Resources */ = {isa = PBXBuildFile; fileRef = 4D752E920913C949008EAAD4 /* Preferences.png */; }; 4D813EB508AA43AC00191DB4 /* Progress.png in Resources */ = {isa = PBXBuildFile; fileRef = 4D813EB408AA43AC00191DB4 /* Progress.png */; }; + 4D8CEF91095870E00063BAEA /* Network.png in Resources */ = {isa = PBXBuildFile; fileRef = 4D8CEF90095870E00063BAEA /* Network.png */; }; 4DA6FDBA0911233800450CB1 /* PauseOn.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DA6FDB80911233800450CB1 /* PauseOn.png */; }; 4DA6FDBB0911233800450CB1 /* PauseOff.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DA6FDB90911233800450CB1 /* PauseOff.png */; }; 4DA6FDC5091141AD00450CB1 /* ResumeOff.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DA6FDC3091141AD00450CB1 /* ResumeOff.png */; }; @@ -84,6 +85,7 @@ 4D6DAAC5090CE00500F43C22 /* RevealOn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = RevealOn.png; path = Images/RevealOn.png; sourceTree = ""; }; 4D752E920913C949008EAAD4 /* Preferences.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Preferences.png; path = Images/Preferences.png; sourceTree = ""; }; 4D813EB408AA43AC00191DB4 /* Progress.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Progress.png; path = Images/Progress.png; sourceTree = ""; }; + 4D8CEF90095870E00063BAEA /* Network.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Network.png; path = Images/Network.png; sourceTree = ""; }; 4DA6FDB80911233800450CB1 /* PauseOn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = PauseOn.png; path = Images/PauseOn.png; sourceTree = ""; }; 4DA6FDB90911233800450CB1 /* PauseOff.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = PauseOff.png; path = Images/PauseOff.png; sourceTree = ""; }; 4DA6FDC3091141AD00450CB1 /* ResumeOff.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ResumeOff.png; path = Images/ResumeOff.png; sourceTree = ""; }; @@ -194,6 +196,7 @@ 4DA6FDC3091141AD00450CB1 /* ResumeOff.png */, 4DA6FDC4091141AD00450CB1 /* ResumeOn.png */, 4D752E920913C949008EAAD4 /* Preferences.png */, + 4D8CEF90095870E00063BAEA /* Network.png */, 8D1107310486CEB800E47090 /* Info.plist */, 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, 29B97318FDCFA39411CA2CEA /* MainMenu.nib */, @@ -283,6 +286,7 @@ 4DA6FDC5091141AD00450CB1 /* ResumeOff.png in Resources */, 4DA6FDC6091141AD00450CB1 /* ResumeOn.png in Resources */, 4D752E930913C949008EAAD4 /* Preferences.png in Resources */, + 4D8CEF91095870E00063BAEA /* Network.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -331,9 +335,7 @@ ppc, i386, ); - FRAMEWORK_SEARCH_PATHS = ( - "$(FRAMEWORK_SEARCH_PATHS)", - ); + FRAMEWORK_SEARCH_PATHS = "$(FRAMEWORK_SEARCH_PATHS)"; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_OPTIMIZATION_LEVEL = 3; GCC_PRECOMPILE_PREFIX_HEADER = YES;