Changeset 272


Ignore:
Timestamp:
Jun 6, 2006, 6:05:57 PM (15 years ago)
Author:
livings124
Message:

First commit on my own 8-)

Sorting by progress, sorting no longer causes crashes.
New look for the table.
Info is now inspector: can set individual and multiple ratio limits, shows listing of files, more info in general, resizes when changing tabs, can change tabs with cmd-left and cmd-right.
Menu items moved to "Transfers" menu.
Sliding status bar in its own view.
Prefs moved into their own nib.
Toolbar items for pause and resume selected (many wanted this, but it needs better icons)
New icons for Transfers and General.
A lot of tweaking of main window to fix alignment etc.
Sparkle used for updated (still needs to be added to website to work).

And a lot more tweaking and changes that I'm too lazy to list.

...now let's hope I commit this right

Location:
trunk
Files:
87 added
30 edited

Legend:

Unmodified
Added
Removed
  • trunk/Transmission.xcodeproj/project.pbxproj

    r264 r272  
    8080                A200B9B60A22893D007BBB1E /* InfoWindow.nib in Resources */ = {isa = PBXBuildFile; fileRef = A200B9620A227FD0007BBB1E /* InfoWindow.nib */; };
    8181                A21610FC0A050B1700E8E4C1 /* MenuButton.m in Sources */ = {isa = PBXBuildFile; fileRef = A21610FB0A050B1700E8E4C1 /* MenuButton.m */; };
     82                A2173E1C0A33C1B300B0D8AB /* ActionButtonPressed.tiff in Resources */ = {isa = PBXBuildFile; fileRef = A2173E1B0A33C1B300B0D8AB /* ActionButtonPressed.tiff */; };
     83                A21DFF100A292B2B007C5F76 /* Transfers.png in Resources */ = {isa = PBXBuildFile; fileRef = A21DFF0F0A292B2B007C5F76 /* Transfers.png */; };
     84                A2495B6D0A2F697C0098B31F /* ResumeSelected.tiff in Resources */ = {isa = PBXBuildFile; fileRef = A2495B6B0A2F697C0098B31F /* ResumeSelected.tiff */; };
     85                A2495B6E0A2F697D0098B31F /* PauseSelected.tiff in Resources */ = {isa = PBXBuildFile; fileRef = A2495B6C0A2F697C0098B31F /* PauseSelected.tiff */; };
     86                A2519D490A2FADFC00479D0C /* SmoothAquaView.m in Sources */ = {isa = PBXBuildFile; fileRef = A2519D470A2FADFC00479D0C /* SmoothAquaView.m */; };
     87                A2519D4A0A2FADFC00479D0C /* SmoothAquaView.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = A2519D480A2FADFC00479D0C /* SmoothAquaView.h */; };
    8288                A26D450B0A0503AC00A10BB3 /* peermessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D1838A309DEC0430047D688 /* peermessages.h */; };
    8389                A27A53570A06A76400E1F16F /* StatusSep.png in Resources */ = {isa = PBXBuildFile; fileRef = A27A53560A06A76400E1F16F /* StatusSep.png */; };
    8490                A27A53660A06AEDB00E1F16F /* StatusBorder.tiff in Resources */ = {isa = PBXBuildFile; fileRef = A27A53650A06AEDB00E1F16F /* StatusBorder.tiff */; };
    85                 A2A84AD00A04FCD000C898D4 /* ActionButton.tiff in Resources */ = {isa = PBXBuildFile; fileRef = A2A84ACF0A04FCD000C898D4 /* ActionButton.tiff */; };
     91                A289EB0C0A33C56D00B082A3 /* ButtonBorder.tiff in Resources */ = {isa = PBXBuildFile; fileRef = A289EB0B0A33C56D00B082A3 /* ButtonBorder.tiff */; };
     92                A28DBADC0A33C1D800F4B4A7 /* ActionButton.tiff in Resources */ = {isa = PBXBuildFile; fileRef = A28DBADB0A33C1D800F4B4A7 /* ActionButton.tiff */; };
     93                A2912C540A2956E80097A0CA /* PrefsWindow.nib in Resources */ = {isa = PBXBuildFile; fileRef = A2912C520A2956E80097A0CA /* PrefsWindow.nib */; };
    8694                A2BD40070A09BBEA008CCE96 /* bencode.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D1838B709DEC0430047D688 /* bencode.h */; };
    8795                A2C655650A04FEDC00E9FD82 /* BottomBorder.tiff in Resources */ = {isa = PBXBuildFile; fileRef = A2C655640A04FEDC00E9FD82 /* BottomBorder.tiff */; };
     96                A2D5CCFD0A2661590089A8C2 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A2D5CCFC0A2661590089A8C2 /* Sparkle.framework */; };
     97                A2D5CD100A2661610089A8C2 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = A2D5CCFC0A2661590089A8C2 /* Sparkle.framework */; };
     98                A2F8951F0A2D4BA500ED2127 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = A2F8951E0A2D4BA500ED2127 /* Credits.rtf */; };
    8899/* End PBXBuildFile section */
    89100
     
    104115                };
    105116/* End PBXContainerItemProxy section */
     117
     118/* Begin PBXCopyFilesBuildPhase section */
     119                A2D5CCDD0A265F790089A8C2 /* CopyFiles */ = {
     120                        isa = PBXCopyFilesBuildPhase;
     121                        buildActionMask = 2147483647;
     122                        dstPath = "";
     123                        dstSubfolderSpec = 10;
     124                        files = (
     125                        );
     126                        runOnlyForDeploymentPostprocessing = 0;
     127                };
     128                A2D5CCF80A2660660089A8C2 /* CopyFiles */ = {
     129                        isa = PBXCopyFilesBuildPhase;
     130                        buildActionMask = 2147483647;
     131                        dstPath = "";
     132                        dstSubfolderSpec = 10;
     133                        files = (
     134                        );
     135                        runOnlyForDeploymentPostprocessing = 0;
     136                };
     137                A2D5CD110A2661660089A8C2 /* CopyFiles */ = {
     138                        isa = PBXCopyFilesBuildPhase;
     139                        buildActionMask = 2147483647;
     140                        dstPath = "";
     141                        dstSubfolderSpec = 7;
     142                        files = (
     143                        );
     144                        runOnlyForDeploymentPostprocessing = 0;
     145                };
     146                A2D5CD130A26616F0089A8C2 /* CopyFiles */ = {
     147                        isa = PBXCopyFilesBuildPhase;
     148                        buildActionMask = 2147483647;
     149                        dstPath = "";
     150                        dstSubfolderSpec = 10;
     151                        files = (
     152                                A2D5CD100A2661610089A8C2 /* Sparkle.framework in CopyFiles */,
     153                                A2519D4A0A2FADFC00479D0C /* SmoothAquaView.h in CopyFiles */,
     154                        );
     155                        runOnlyForDeploymentPostprocessing = 0;
     156                };
     157/* End PBXCopyFilesBuildPhase section */
    106158
    107159/* Begin PBXFileReference section */
     
    194246                A21610FA0A050B1700E8E4C1 /* MenuButton.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = MenuButton.h; path = macosx/MenuButton.h; sourceTree = "<group>"; };
    195247                A21610FB0A050B1700E8E4C1 /* MenuButton.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = MenuButton.m; path = macosx/MenuButton.m; sourceTree = "<group>"; };
     248                A2173E1B0A33C1B300B0D8AB /* ActionButtonPressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = ActionButtonPressed.tiff; path = macosx/Images/ActionButtonPressed.tiff; sourceTree = "<group>"; };
     249                A21DFF0F0A292B2B007C5F76 /* Transfers.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Transfers.png; path = macosx/Images/Transfers.png; sourceTree = "<group>"; };
     250                A2495B6B0A2F697C0098B31F /* ResumeSelected.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = ResumeSelected.tiff; path = macosx/Images/ResumeSelected.tiff; sourceTree = "<group>"; };
     251                A2495B6C0A2F697C0098B31F /* PauseSelected.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = PauseSelected.tiff; path = macosx/Images/PauseSelected.tiff; sourceTree = "<group>"; };
     252                A2519D470A2FADFC00479D0C /* SmoothAquaView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = SmoothAquaView.m; path = macosx/SmoothAquaView.m; sourceTree = "<group>"; };
     253                A2519D480A2FADFC00479D0C /* SmoothAquaView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SmoothAquaView.h; path = macosx/SmoothAquaView.h; sourceTree = "<group>"; };
    196254                A27A53420A06A62500E1F16F /* StatusSep.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = StatusSep.png; path = macosx/Images/StatusSep.png; sourceTree = "<group>"; };
    197255                A27A53560A06A76400E1F16F /* StatusSep.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = StatusSep.png; path = macosx/Images/StatusSep.png; sourceTree = "<group>"; };
    198256                A27A53640A06AED200E1F16F /* StatusBorder.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = StatusBorder.tiff; path = macosx/Images/StatusBorder.tiff; sourceTree = "<group>"; };
    199257                A27A53650A06AEDB00E1F16F /* StatusBorder.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = StatusBorder.tiff; path = macosx/Images/StatusBorder.tiff; sourceTree = "<group>"; };
    200                 A2A84ACF0A04FCD000C898D4 /* ActionButton.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = ActionButton.tiff; path = macosx/Images/ActionButton.tiff; sourceTree = "<group>"; };
     258                A289EB0B0A33C56D00B082A3 /* ButtonBorder.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = ButtonBorder.tiff; path = macosx/Images/ButtonBorder.tiff; sourceTree = "<group>"; };
     259                A28DBADB0A33C1D800F4B4A7 /* ActionButton.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = ActionButton.tiff; path = macosx/Images/ActionButton.tiff; sourceTree = "<group>"; };
     260                A2912C530A2956E80097A0CA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = macosx/English.lproj/PrefsWindow.nib; sourceTree = "<group>"; };
    201261                A2A84AD20A04FCDC00C898D4 /* BottomBorder.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = BottomBorder.tiff; path = macosx/Images/BottomBorder.tiff; sourceTree = "<group>"; };
    202262                A2C655640A04FEDC00E9FD82 /* BottomBorder.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = BottomBorder.tiff; path = macosx/Images/BottomBorder.tiff; sourceTree = "<group>"; };
     263                A2D5CCFC0A2661590089A8C2 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Sparkle.framework; sourceTree = "<group>"; };
     264                A2F8951E0A2D4BA500ED2127 /* Credits.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = Credits.rtf; path = macosx/Credits.rtf; sourceTree = "<group>"; };
    203265/* End PBXFileReference section */
    204266
     
    228290                                4D1838DD09DEC0E80047D688 /* libtransmission.a in Frameworks */,
    229291                                4D4B7F6109E055660053C1EB /* libcrypto.0.9.dylib in Frameworks */,
     292                                A2D5CCFD0A2661590089A8C2 /* Sparkle.framework in Frameworks */,
    230293                        );
    231294                        runOnlyForDeploymentPostprocessing = 0;
     
    257320                                A21610FA0A050B1700E8E4C1 /* MenuButton.h */,
    258321                                A21610FB0A050B1700E8E4C1 /* MenuButton.m */,
     322                                A2519D470A2FADFC00479D0C /* SmoothAquaView.m */,
     323                                A2519D480A2FADFC00479D0C /* SmoothAquaView.h */,
    259324                        );
    260325                        name = Sources;
     
    278343                                4DDBB70A09E16B3200284745 /* GUI */,
    279344                                4DDBB71509E16B3F00284745 /* Libraries */,
     345                                A250C8590A27511C000F3E9F /* Linked Frameworks */,
    280346                                19C28FACFE9D520D11CA2CBB /* Products */,
    281347                        );
     
    286352                        isa = PBXGroup;
    287353                        children = (
     354                                A2F8951E0A2D4BA500ED2127 /* Credits.rtf */,
     355                                A2495B6B0A2F697C0098B31F /* ResumeSelected.tiff */,
     356                                A2495B6C0A2F697C0098B31F /* PauseSelected.tiff */,
     357                                A21DFF0F0A292B2B007C5F76 /* Transfers.png */,
    288358                                A27A53640A06AED200E1F16F /* StatusBorder.tiff */,
    289359                                A27A53420A06A62500E1F16F /* StatusSep.png */,
     
    313383                                A200B9620A227FD0007BBB1E /* InfoWindow.nib */,
    314384                                A2C655640A04FEDC00E9FD82 /* BottomBorder.tiff */,
    315                                 A2A84ACF0A04FCD000C898D4 /* ActionButton.tiff */,
    316                                 A2A84ACF0A04FCD000C898D4 /* ActionButton.tiff */,
     385                                A289EB0B0A33C56D00B082A3 /* ButtonBorder.tiff */,
     386                                A28DBADB0A33C1D800F4B4A7 /* ActionButton.tiff */,
     387                                A2173E1B0A33C1B300B0D8AB /* ActionButtonPressed.tiff */,
    317388                                A27A53560A06A76400E1F16F /* StatusSep.png */,
    318389                                A27A53650A06AEDB00E1F16F /* StatusBorder.tiff */,
     390                                A2912C520A2956E80097A0CA /* PrefsWindow.nib */,
    319391                        );
    320392                        name = Resources;
     
    401473                        sourceTree = "<group>";
    402474                };
     475                A250C8590A27511C000F3E9F /* Linked Frameworks */ = {
     476                        isa = PBXGroup;
     477                        children = (
     478                                A2D5CCFC0A2661590089A8C2 /* Sparkle.framework */,
     479                        );
     480                        name = "Linked Frameworks";
     481                        sourceTree = "<group>";
     482                };
    403483/* End PBXGroup section */
    404484
     
    441521                                4D18389409DEC0030047D688 /* Sources */,
    442522                                4D18389509DEC0030047D688 /* Frameworks */,
     523                                A2D5CCDD0A265F790089A8C2 /* CopyFiles */,
     524                                A2D5CCF80A2660660089A8C2 /* CopyFiles */,
     525                                A2D5CD110A2661660089A8C2 /* CopyFiles */,
    443526                        );
    444527                        buildRules = (
     
    475558                                8D11072C0486CEB800E47090 /* Sources */,
    476559                                8D11072E0486CEB800E47090 /* Frameworks */,
     560                                A2D5CD130A26616F0089A8C2 /* CopyFiles */,
    477561                        );
    478562                        buildRules = (
     
    531615                                4DDFDD22099A5D8E00189D81 /* DownloadBadge.png in Resources */,
    532616                                4DDFDD23099A5D8E00189D81 /* UploadBadge.png in Resources */,
    533                                 A2A84AD00A04FCD000C898D4 /* ActionButton.tiff in Resources */,
    534617                                A2C655650A04FEDC00E9FD82 /* BottomBorder.tiff in Resources */,
    535618                                A27A53570A06A76400E1F16F /* StatusSep.png in Resources */,
    536619                                A27A53660A06AEDB00E1F16F /* StatusBorder.tiff in Resources */,
     620                                A21DFF100A292B2B007C5F76 /* Transfers.png in Resources */,
     621                                A2912C540A2956E80097A0CA /* PrefsWindow.nib in Resources */,
     622                                A2F8951F0A2D4BA500ED2127 /* Credits.rtf in Resources */,
     623                                A2495B6D0A2F697C0098B31F /* ResumeSelected.tiff in Resources */,
     624                                A2495B6E0A2F697D0098B31F /* PauseSelected.tiff in Resources */,
     625                                A2173E1C0A33C1B300B0D8AB /* ActionButtonPressed.tiff in Resources */,
     626                                A28DBADC0A33C1D800F4B4A7 /* ActionButton.tiff in Resources */,
     627                                A289EB0C0A33C56D00B082A3 /* ButtonBorder.tiff in Resources */,
    537628                        );
    538629                        runOnlyForDeploymentPostprocessing = 0;
     
    585676                                A21610FC0A050B1700E8E4C1 /* MenuButton.m in Sources */,
    586677                                A200B9200A22798F007BBB1E /* InfoWindowController.m in Sources */,
     678                                A2519D490A2FADFC00479D0C /* SmoothAquaView.m in Sources */,
    587679                        );
    588680                        runOnlyForDeploymentPostprocessing = 0;
     
    628720                        sourceTree = "<group>";
    629721                };
     722                A2912C520A2956E80097A0CA /* PrefsWindow.nib */ = {
     723                        isa = PBXVariantGroup;
     724                        children = (
     725                                A2912C530A2956E80097A0CA /* English */,
     726                        );
     727                        name = PrefsWindow.nib;
     728                        sourceTree = "<group>";
     729                };
    630730/* End PBXVariantGroup section */
    631731
     
    634734                        isa = XCBuildConfiguration;
    635735                        buildSettings = {
     736                                FRAMEWORK_SEARCH_PATHS = (
     737                                        "$(inherited)",
     738                                        "$(FRAMEWORK_SEARCH_PATHS_QUOTED_1)",
     739                                );
     740                                FRAMEWORK_SEARCH_PATHS_QUOTED_1 = "\"$(SRCROOT)\"";
    636741                                OTHER_CFLAGS = (
    637742                                        "-D_FILE_OFFSET_BITS=64",
     
    667772                        buildSettings = {
    668773                                CONFIGURATION_BUILD_DIR = "$(SRCROOT)/macosx";
     774                                FRAMEWORK_SEARCH_PATHS = (
     775                                        "$(inherited)",
     776                                        "$(FRAMEWORK_SEARCH_PATHS_QUOTED_1)",
     777                                );
     778                                FRAMEWORK_SEARCH_PATHS_QUOTED_1 = "\"$(SRCROOT)\"";
    669779                                GCC_PRECOMPILE_PREFIX_HEADER = YES;
    670780                                GCC_PREFIX_HEADER = macosx/Transmission_Prefix.pch;
     
    684794                                        i386,
    685795                                );
     796                                DEBUG_INFORMATION_FORMAT = dwarf;
    686797                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
    687798                                GCC_OPTIMIZATION_LEVEL = 3;
  • trunk/macosx/Badger.h

    r261 r272  
    4040
    4141- (void) updateBadgeWithCompleted: (int) completed
    42                     uploadRate: (NSString *) uploadRate
    43                     downloadRate: (NSString *) downloadRate;
     42                    uploadRate: (int) uploadRate
     43                    downloadRate: (int) downloadRate;
    4444- (void) clearBadge;
    4545
  • trunk/macosx/Badger.m

    r261 r272  
    2525#import "Badger.h"
    2626#import "StringAdditions.h"
    27 #import "Utils.h"
    2827
    2928@interface Badger (Private)
     
    7574
    7675- (void) updateBadgeWithCompleted: (int) completed
    77                     uploadRate: (NSString *) uploadRate
    78                     downloadRate: (NSString *) downloadRate
     76                    uploadRate: (int) uploadRate
     77                    downloadRate: (int) downloadRate
    7978{
    8079    NSImage * dockIcon = nil;
     
    119118
    120119    //set upload and download rate badges
    121     BOOL speedShown = uploadRate || downloadRate;
     120    NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
     121    NSString * uploadRateString = uploadRate >= 0.1 && [defaults boolForKey: @"BadgeUploadRate"]
     122                                    ? [NSString stringForSpeedAbbrev: uploadRate] : nil,
     123            * downloadRateString = downloadRate >= 0.1 && [defaults boolForKey: @"BadgeDownloadRate"]
     124                                    ? [NSString stringForSpeedAbbrev: downloadRate] : nil;
     125   
     126    BOOL speedShown = uploadRateString || downloadRateString;
    122127    if (speedShown)
    123128    {
     
    137142        [dockIcon lockFocus];
    138143       
    139         if (uploadRate)
     144        if (uploadRateString)
    140145        {
    141146            //place badge
     
    144149           
    145150            //place badge text
    146             [self badgeString: uploadRate forRect: stringRect];
     151            [self badgeString: uploadRateString forRect: stringRect];
    147152        }
    148153       
    149         if (downloadRate)
     154        if (downloadRateString)
    150155        {
    151156            //download rate above upload rate
    152             if (uploadRate)
     157            if (uploadRateString)
    153158            {
    154159                float spaceBetween = badgeRect.size.height + 2.0;
     
    162167           
    163168            //place badge text
    164             [self badgeString: downloadRate forRect: stringRect];
     169            [self badgeString: downloadRateString forRect: stringRect];
    165170        }
    166171       
  • trunk/macosx/Controller.h

    r261 r272  
    3131#import "InfoWindowController.h"
    3232#import "Badger.h"
     33#import "SmoothAquaView.h"
    3334
    3435@class TorrentTableView;
     
    4041    NSMutableArray              * fTorrents;
    4142   
     43    PrefsController             * fPrefsController;
     44    NSUserDefaults              * fDefaults;
    4245    InfoWindowController        * fInfoController;
    43 
    44     NSToolbar                   * fToolbar;
    45 
    46     IBOutlet NSMenuItem         * fAdvancedBarItem;
    47     IBOutlet NSMenuItem         * fPauseResumeItem;
    48     IBOutlet NSMenuItem         * fRemoveItem;
    49     IBOutlet NSMenuItem         * fRemoveTorrentItem;
    50     IBOutlet NSMenuItem         * fRemoveDataItem;
    51     IBOutlet NSMenuItem         * fRemoveBothItem;
    52     IBOutlet NSMenuItem         * fRevealItem;
    53     IBOutlet NSMenuItem         * fShowHideToolbar;
    5446
    5547    IBOutlet NSWindow           * fWindow;
    5648    IBOutlet NSScrollView       * fScrollView;
    5749    IBOutlet TorrentTableView   * fTableView;
     50    NSToolbar                   * fToolbar;
     51   
     52    IBOutlet NSMenuItem         * fAdvancedBarItem;
     53    IBOutlet NSButton           * fActionButton;
     54   
     55    IBOutlet SmoothAquaView     * fStatusBar;
     56    BOOL                        fStatusBarVisible;
    5857    IBOutlet NSTextField        * fTotalDLField;
    5958    IBOutlet NSTextField        * fTotalULField;
    6059    IBOutlet NSTextField        * fTotalTorrentsField;
    61     IBOutlet NSBox              * fStats;
    62     BOOL                        fStatusBar;
    63    
    64     IBOutlet NSButton           * fActionButton;
    6560   
    6661    NSString                    * fSortType;
    67     IBOutlet NSMenuItem         * fNameSortItem,
    68                                 * fStateSortItem,
    69                                 * fDateSortItem;
    70     NSMenuItem                  * fCurrentSortItem;
     62    IBOutlet NSMenuItem         * fNameSortItem, * fStateSortItem,
     63                                * fProgressSortItem, * fDateSortItem;
     64                               
     65    IBOutlet NSMenuItem         * fNextInfoTabItem, * fPrevInfoTabItem;
     66   
     67    IBOutlet NSMenu             * fUploadMenu, * fDownloadMenu;
     68    IBOutlet NSMenuItem         * fUploadLimitItem, * fUploadNoLimitItem,
     69                                * fDownloadLimitItem, * fDownloadNoLimitItem,
     70                                * fRatioSetItem, * fRatioNotSetItem;
    7171
    7272    io_connect_t                fRootPort;
    7373    NSTimer                     * fTimer;
    74     NSTimer                     * fUpdateTimer;
    75    
    76     IBOutlet NSPanel            * fPrefsWindow;
    77     IBOutlet PrefsController    * fPrefsController;
    78     NSUserDefaults              * fDefaults;
    7974   
    8075    BOOL                        fHasGrowl;
    81     Badger                      * fBadger; 
    82     BOOL                        fCheckIsAutomatic;
     76    Badger                      * fBadger;
     77    BOOL                        fUpdateInProgress;
    8378}
    8479
     
    10196- (void) stopTorrentWithIndex:      (NSIndexSet *) indexSet;
    10297
    103 - (void) removeTorrent:             (id) sender;
    104 - (void) removeTorrentDeleteFile:   (id) sender;
    105 - (void) removeTorrentDeleteData:   (id) sender;
    106 - (void) removeTorrentDeleteBoth:   (id) sender;
    107 - (void) removeTorrentWithIndex:    (NSIndexSet *) indexSet
    108                 deleteTorrent:      (BOOL) deleteTorrent
    109                 deleteData:         (BOOL) deleteData;
     98- (void) removeTorrent:                 (id) sender;
     99- (void) removeTorrentDeleteTorrent:    (id) sender;
     100- (void) removeTorrentDeleteData:       (id) sender;
     101- (void) removeTorrentDeleteBoth:       (id) sender;
     102- (void) removeTorrentWithIndex:        (NSIndexSet *) indexSet
     103                deleteTorrent:          (BOOL) deleteTorrent
     104                deleteData:             (BOOL) deleteData;
    110105               
    111106- (void) removeSheetDidEnd: (NSWindow *) sheet returnCode: (int) returnCode
     
    115110            deleteData: (BOOL) deleteData;
    116111
    117 - (void) revealTorrent: (id) sender;
    118                      
    119 - (void) showInfo:        (id) sender;
    120 - (void) updateInfo;
    121 - (void) updateInfoStats;
     112- (void) revealFile: (id) sender;
    122113
    123 - (void) updateUI:        (NSTimer *) timer;
     114- (void) showPreferenceWindow: (id) sender;
     115
     116- (void) showInfo: (id) sender;
     117- (void) setInfoTab: (id) sender;
     118
     119- (void) updateUI: (NSTimer *) timer;
    124120- (void) updateTorrentHistory;
    125121
     
    127123- (void) setSort: (id) sender;
    128124
    129 - (void) sleepCallBack:   (natural_t) messageType argument:
     125- (void) setLimitGlobalEnabled: (id) sender;
     126- (void) setQuickLimitGlobal: (id) sender;
     127- (void) limitGlobalChange: (NSNotification *) notification;
     128
     129- (void) setRatioGlobalEnabled: (id) sender;
     130- (void) setQuickRatioGlobal: (id) sender;
     131- (void) ratioGlobalChange: (NSNotification *) notification;
     132- (void) ratioSingleChange: (NSNotification *) notification;
     133
     134- (void) sleepCallBack: (natural_t) messageType argument:
    130135                        (void *) messageArgument;
    131136
    132137- (void) toggleStatusBar: (id) sender;
    133 
    134 - (void) showPreferenceWindow: (id) sender;
     138- (void) showStatusBar: (BOOL) show animate: (BOOL) animate;
    135139
    136140- (void) showMainWindow:    (id) sender;
     
    140144- (void) growlRegister:     (id) sender;
    141145
    142 - (void) checkForUpdate:      (id) sender;
    143 - (void) checkForUpdateTimer: (NSTimer *) timer;
    144 - (void) checkForUpdateAuto:  (BOOL) automatic;
     146- (void) checkUpdate:       (id) sender;
     147- (void) prepareForUpdate:  (NSNotification *) notification;
    145148
    146149@end
  • trunk/macosx/Controller.m

    r261 r272  
    2828#import "Torrent.h"
    2929#import "TorrentCell.h"
     30#import "TorrentTableView.h"
    3031#import "StringAdditions.h"
    3132#import "Utils.h"
    32 #import "TorrentTableView.h"
    33 
    34 #import "PrefsController.h"
    35 
    36 #define TOOLBAR_OPEN        @"Toolbar Open"
    37 #define TOOLBAR_REMOVE      @"Toolbar Remove"
    38 #define TOOLBAR_INFO        @"Toolbar Info"
    39 #define TOOLBAR_PAUSE_ALL   @"Toolbar Pause All"
    40 #define TOOLBAR_RESUME_ALL  @"Toolbar Resume All"
     33
     34#import <Sparkle/Sparkle.h>
     35
     36#define TOOLBAR_OPEN            @"Toolbar Open"
     37#define TOOLBAR_REMOVE          @"Toolbar Remove"
     38#define TOOLBAR_INFO            @"Toolbar Info"
     39#define TOOLBAR_PAUSE_ALL       @"Toolbar Pause All"
     40#define TOOLBAR_RESUME_ALL      @"Toolbar Resume All"
     41#define TOOLBAR_PAUSE_SELECTED  @"Toolbar Pause Selected"
     42#define TOOLBAR_RESUME_SELECTED @"Toolbar Resume Selected"
    4143
    4244#define WEBSITE_URL         @"http://transmission.m0k.org/"
     
    6264        fLib = tr_init();
    6365        fTorrents = [[NSMutableArray alloc] initWithCapacity: 10];
     66        fDefaults = [NSUserDefaults standardUserDefaults];
     67        fInfoController = [[InfoWindowController alloc] initWithWindowNibName: @"InfoWindow"];
     68        fPrefsController = [[PrefsController alloc] initWithWindowNibName: @"PrefsWindow"];
    6469    }
    6570    return self;
     
    6873- (void) dealloc
    6974{
     75    [[NSNotificationCenter defaultCenter] removeObserver: self];
     76
    7077    [fTorrents release];
    71    
     78    [fToolbar release];
    7279    [fInfoController release];
     80    [fBadger release];
     81    [fSortType release];
    7382   
    7483    tr_close( fLib );
     
    7988{
    8089    [fPrefsController setPrefsWindow: fLib];
    81     fDefaults = [NSUserDefaults standardUserDefaults];
    82 
    83     fInfoController = [[InfoWindowController alloc] initWithWindowNibName: @"InfoWindow"];
    8490   
    8591    [fAdvancedBarItem setState: [fDefaults
     
    9399    [fWindow setDelegate: self];
    94100   
    95     fStatusBar = YES;
    96     if (![fDefaults boolForKey: @"StatusBar"])
    97         [self toggleStatusBar: nil];
    98    
    99     [fActionButton setToolTip: @"Shortcuts for performing special actions."];
     101    //window min height
     102    NSSize contentMinSize = [fWindow contentMinSize];
     103    contentMinSize.height = [[fWindow contentView] frame].size.height - [fScrollView frame].size.height
     104                                + [fTableView rowHeight] + [fTableView intercellSpacing].height;
     105    [fWindow setContentMinSize: contentMinSize];
     106   
     107    //set info keyboard shortcuts
     108    unichar ch = NSRightArrowFunctionKey;
     109    [fNextInfoTabItem setKeyEquivalent: [NSString stringWithCharacters: & ch length: 1]];
     110    ch = NSLeftArrowFunctionKey;
     111    [fPrevInfoTabItem setKeyEquivalent: [NSString stringWithCharacters: & ch length: 1]];
     112   
     113    //set up status bar
     114    NSRect statusBarFrame = [fStatusBar frame];
     115    statusBarFrame.size.width = [fWindow frame].size.width;
     116    [fStatusBar setFrame: statusBarFrame];
     117   
     118    NSView * contentView = [fWindow contentView];
     119    [contentView addSubview: fStatusBar];
     120    [fStatusBar setFrameOrigin: NSMakePoint(0, [fScrollView frame].origin.y
     121                                                + [fScrollView frame].size.height)];
     122    [self showStatusBar: [fDefaults boolForKey: @"StatusBar"] animate: NO];
     123   
     124    [fActionButton setToolTip: @"Shortcuts for changing global settings."];
    100125
    101126    [fTableView setTorrents: fTorrents];
     
    109134    IONotificationPortRef notify;
    110135    io_object_t anIterator;
    111     if (fRootPort= IORegisterForSystemPower(self, & notify,
     136    if (fRootPort = IORegisterForSystemPower(self, & notify,
    112137                                sleepCallBack, & anIterator))
    113138    {
     
    133158   
    134159    //set sort
    135     fSortType = [fDefaults stringForKey: @"Sort"];
     160    fSortType = [[fDefaults stringForKey: @"Sort"] retain];
     161   
     162    NSMenuItem * currentSortItem;
    136163    if ([fSortType isEqualToString: @"Name"])
    137         fCurrentSortItem = fNameSortItem;
     164        currentSortItem = fNameSortItem;
    138165    else if ([fSortType isEqualToString: @"State"])
    139         fCurrentSortItem = fStateSortItem;
     166        currentSortItem = fStateSortItem;
     167    else if ([fSortType isEqualToString: @"Progress"])
     168        currentSortItem = fProgressSortItem;
    140169    else
    141         fCurrentSortItem = fDateSortItem;
    142     [fCurrentSortItem setState: NSOnState];
     170        currentSortItem = fDateSortItem;
     171    [currentSortItem setState: NSOnState];
    143172
    144173    //check and register Growl if it is installed for this user or all users
     
    151180    //initialize badging
    152181    fBadger = [[Badger alloc] init];
     182   
     183    //set upload limit action button
     184    [fUploadLimitItem setTitle: [NSString stringWithFormat: @"Limit (%d KB/s)",
     185                    [fDefaults integerForKey: @"UploadLimit"]]];
     186    if ([fDefaults boolForKey: @"CheckUpload"])
     187        [fUploadLimitItem setState: NSOnState];
     188    else
     189        [fUploadNoLimitItem setState: NSOnState];
     190
     191        //set download limit action menu
     192    [fDownloadLimitItem setTitle: [NSString stringWithFormat: @"Limit (%d KB/s)",
     193                    [fDefaults integerForKey: @"DownloadLimit"]]];
     194    if ([fDefaults boolForKey: @"CheckDownload"])
     195        [fDownloadLimitItem setState: NSOnState];
     196    else
     197        [fDownloadNoLimitItem setState: NSOnState];
     198   
     199    //set ratio action menu
     200    [fRatioSetItem setTitle: [NSString stringWithFormat: @"Stop at Ratio (%.2f)",
     201                                [fDefaults floatForKey: @"RatioLimit"]]];
     202    if ([fDefaults boolForKey: @"RatioCheck"])
     203        [fRatioSetItem setState: NSOnState];
     204    else
     205        [fRatioNotSetItem setState: NSOnState];
     206   
     207    //observe notifications
     208    NSNotificationCenter * nc = [NSNotificationCenter defaultCenter];
     209   
     210    [nc addObserver: self selector: @selector(prepareForUpdate:)
     211                    name: SUUpdaterWillRestartNotification object: nil];
     212    fUpdateInProgress = NO;
     213   
     214    [nc addObserver: self selector: @selector(ratioSingleChange:)
     215                    name: @"TorrentRatioChanged" object: nil];
     216   
     217    [nc addObserver: self selector: @selector(limitGlobalChange:)
     218                    name: @"LimitGlobalChange" object: nil];
     219   
     220    [nc addObserver: self selector: @selector(ratioGlobalChange:)
     221                    name: @"RatioGlobalChange" object: nil];
    153222
    154223    //timer to update the interface
     
    161230    [[NSRunLoop currentRunLoop] addTimer: fTimer
    162231        forMode: NSEventTrackingRunLoopMode];
    163 
    164     //timer to check for updates
    165     [self checkForUpdateTimer: nil];
    166     fUpdateTimer = [NSTimer scheduledTimerWithTimeInterval: 60.0
    167         target: self selector: @selector( checkForUpdateTimer: )
    168         userInfo: nil repeats: YES];
    169232   
    170233    [self sortTorrents];
     
    172235    //show windows
    173236    [fWindow makeKeyAndOrderFront: nil];
     237
     238    [fInfoController updateInfoForTorrents: [self torrentsAtIndexes:
     239                                    [fTableView selectedRowIndexes]]];
    174240    if ([fDefaults boolForKey: @"InfoVisible"])
    175241        [self showInfo: nil];
    176242}
    177243
    178 - (void) windowDidBecomeKey: (NSNotification *) n
    179 {
    180     /* Reset the number of recently completed downloads */
    181     fCompleted = 0;
    182 }
    183 
    184244- (BOOL) applicationShouldHandleReopen: (NSApplication *) app
    185245    hasVisibleWindows: (BOOL) flag
    186246{
    187     [self showMainWindow: nil];
     247    if (![fWindow isVisible] && ![[fPrefsController window] isVisible])
     248        [self showMainWindow: nil];
    188249    return NO;
    189250}
     
    191252- (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication *) sender
    192253{
    193     int active = 0;
    194     Torrent * torrent;
    195     NSEnumerator * enumerator = [fTorrents objectEnumerator];
    196     while( ( torrent = [enumerator nextObject] ) )
    197         if( [torrent isActive] )
    198             active++;
    199 
    200     if (active > 0 && [fDefaults boolForKey: @"CheckQuit"])
    201     {
    202         NSString * message = active == 1
    203             ? @"There is an active torrent. Do you really want to quit?"
    204             : [NSString stringWithFormat:
    205                 @"There are %d active torrents. Do you really want to quit?",
    206                 active];
    207 
    208         NSBeginAlertSheet(@"Confirm Quit",
    209                             @"Quit", @"Cancel", nil,
    210                             fWindow, self,
    211                             @selector(quitSheetDidEnd:returnCode:contextInfo:),
    212                             nil, nil, message);
    213         return NSTerminateLater;
     254    if (!fUpdateInProgress && [fDefaults boolForKey: @"CheckQuit"])
     255    {
     256        int active = 0;
     257        Torrent * torrent;
     258        NSEnumerator * enumerator = [fTorrents objectEnumerator];
     259        while ((torrent = [enumerator nextObject]))
     260            if ([torrent isActive])
     261                active++;
     262
     263        if (active > 0)
     264        {
     265            NSString * message = active == 1
     266                ? @"There is an active torrent. Do you really want to quit?"
     267                : [NSString stringWithFormat:
     268                    @"There are %d active torrents. Do you really want to quit?",
     269                    active];
     270
     271            NSBeginAlertSheet(@"Confirm Quit",
     272                                @"Quit", @"Cancel", nil,
     273                                fWindow, self,
     274                                @selector(quitSheetDidEnd:returnCode:contextInfo:),
     275                                nil, nil, message);
     276            return NSTerminateLater;
     277        }
    214278    }
    215279
     
    229293    // Stop updating the interface
    230294    [fTimer invalidate];
    231     [fUpdateTimer invalidate];
    232 
     295   
     296    //save history
     297    [self updateTorrentHistory];
     298   
     299    //remember window states
     300    [fDefaults setBool: [[fInfoController window] isVisible] forKey: @"InfoVisible"];
     301    [fWindow close];
     302    [self showStatusBar: NO animate: NO];
     303   
    233304    //clear badge
    234305    [fBadger clearBadge];
    235     [fBadger release];
    236    
    237     //remember info window state
    238     [fDefaults setBool: [[fInfoController window] isVisible] forKey: @"InfoVisible"];
    239 
    240     //save history
    241     [self updateTorrentHistory];
    242 
    243     // Stop running torrents
     306
     307    //end quickly if updated version will open
     308    if (fUpdateInProgress)
     309        return;
     310
     311    //stop running torrents and wait for them to stop (5 seconds timeout)
    244312    [fTorrents makeObjectsPerformSelector: @selector(stop)];
    245 
    246     // Wait for torrents to stop (5 seconds timeout)
     313   
    247314    NSDate * start = [NSDate date];
    248315    Torrent * torrent;
     
    260327}
    261328
    262 - (void) showPreferenceWindow: (id) sender
    263 {
    264     if (![fPrefsWindow isVisible])
    265         [fPrefsWindow center];
    266 
    267     [fPrefsWindow makeKeyAndOrderFront: nil];
    268 }
    269 
    270329- (void) folderChoiceClosed: (NSOpenPanel *) s returnCode: (int) code
    271330    contextInfo: (Torrent *) torrent
     
    273332    if (code == NSOKButton)
    274333    {
    275         [torrent setFolder: [[s filenames] objectAtIndex: 0]];
     334        [torrent setDownloadFolder: [[s filenames] objectAtIndex: 0]];
    276335        if ([fDefaults boolForKey: @"AutoStartDownload"])
    277336            [torrent start];
     
    289348    BOOL autoStart = [fDefaults boolForKey: @"AutoStartDownload"];
    290349   
    291     NSString * downloadChoice = [fDefaults stringForKey: @"DownloadChoice"];
    292     NSString * torrentPath;
     350    NSString * downloadChoice = [fDefaults stringForKey: @"DownloadChoice"],
     351            * torrentPath;
    293352    Torrent * torrent;
    294353    NSEnumerator * enumerator = [filenames objectEnumerator];
     
    311370            [panel setCanChooseDirectories: YES];
    312371
    313             [panel setMessage: [NSString stringWithFormat:
    314                                 @"Select the download folder for %@",
    315                                 [torrentPath lastPathComponent]]];
     372            [panel setMessage: [@"Select the download folder for "
     373                    stringByAppendingString: [torrentPath lastPathComponent]]];
    316374
    317375            [panel beginSheetForDirectory: nil file: nil types: nil
     
    328386                                : [torrentPath stringByDeletingLastPathComponent];
    329387
    330             [torrent setFolder: folder];
     388            [torrent setDownloadFolder: folder];
    331389            if (autoStart)
    332390                [torrent start];
     
    356414- (void) torrentNumberChanged
    357415{
    358     int count = [fTorrents count];
    359     [fTotalTorrentsField setStringValue: [NSString stringWithFormat:
    360                 @"%d Torrent%s", count, count == 1 ? "" : "s"]];
     416    if (fStatusBarVisible)
     417    {
     418        int count = [fTorrents count];
     419        [fTotalTorrentsField setStringValue: [NSString stringWithFormat:
     420                    @"%d Torrent%s", count, count == 1 ? "" : "s"]];
     421    }
    361422}
    362423
     
    426487   
    427488    [self updateUI: nil];
    428     [self sortTorrents];
     489    if ([fSortType isEqualToString: @"State"])
     490        [self sortTorrents];
    429491    [self updateTorrentHistory];
    430492}
     
    452514   
    453515    [self updateUI: nil];
    454     [self sortTorrents];
     516    if ([fSortType isEqualToString: @"State"])
     517        [self sortTorrents];
    455518    [self updateTorrentHistory];
    456519}
     
    471534    if( active > 0 && [fDefaults boolForKey: @"CheckRemove"] )
    472535    {
    473         NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys:
     536        NSDictionary * dict = [[NSDictionary alloc] initWithObjectsAndKeys:
    474537            torrents, @"Torrents",
    475538            [NSNumber numberWithBool: deleteTorrent], @"DeleteTorrent",
    476539            [NSNumber numberWithBool: deleteData], @"DeleteData",
    477540            nil];
    478         [dict retain];
    479541
    480542        NSString * title, * message;
     
    483545        if (selected == 1)
    484546        {
    485             title = [NSString stringWithFormat: @"Comfirm Removal of %@",
     547            title = [NSString stringWithFormat: @"Comfirm Removal of \"%@\"",
    486548                        [[fTorrents objectAtIndex: [fTableView selectedRow]] name]];
    487549            message = @"This torrent is active. Do you really want to remove it?";
     
    489551        else
    490552        {
    491             title = [NSString stringWithFormat: @"Comfirm Removal of %d Torrents", active];
     553            title = [NSString stringWithFormat: @"Comfirm Removal of %d Torrents", selected];
    492554            if (selected == active)
    493555                message = [NSString stringWithFormat:
     
    552614   
    553615    [self torrentNumberChanged];
    554 
    555616    [fTableView deselectAll: nil];
    556617    [self updateUI: nil];
     
    563624}
    564625
    565 - (void) removeTorrentDeleteFile: (id) sender
     626- (void) removeTorrentDeleteTorrent: (id) sender
    566627{
    567628    [self removeTorrentWithIndex: [fTableView selectedRowIndexes] deleteTorrent: YES deleteData: NO];
     
    578639}
    579640
    580 - (void) revealTorrent: (id) sender
     641- (void) revealFile: (id) sender
    581642{
    582643    Torrent * torrent;
     
    589650        [torrent reveal];
    590651    }
     652}
     653
     654- (void) showPreferenceWindow: (id) sender
     655{
     656    NSWindow * window = [fPrefsController window];
     657    if (![window isVisible])
     658        [window center];
     659
     660    [window makeKeyAndOrderFront: nil];
     661}
     662
     663- (void) showInfo: (id) sender
     664{
     665    if ([[fInfoController window] isVisible])
     666        [[fInfoController window] performClose: nil];
     667    else
     668    {
     669        [fInfoController updateInfoStats];
     670        [[fInfoController window] orderFront: nil];
     671    }
     672}
     673
     674- (void) setInfoTab: (id) sender
     675{
     676    if (sender == fNextInfoTabItem)
     677        [fInfoController setNextTab];
     678    else
     679        [fInfoController setPreviousTab];
    591680}
    592681
     
    605694            if( ![fWindow isKeyWindow] )
    606695                fCompleted++;
    607                
    608             [self sortTorrents];
     696           
     697            if ([fSortType isEqualToString: @"State"])
     698                [self sortTorrents];
    609699        }
    610700    }
    611    
    612     [fTableView reloadData];
     701
     702    if ([fSortType isEqualToString: @"Progress"])
     703        [self sortTorrents];
     704    else
     705        [fTableView reloadData];
    613706   
    614707    //Update the global DL/UL rates
    615     float dl, ul;
    616     tr_torrentRates( fLib, &dl, &ul );
    617     NSString * downloadRate = [NSString stringForSpeed: dl];
    618     NSString * uploadRate = [NSString stringForSpeed: ul];
    619     [fTotalDLField setStringValue: downloadRate];
    620     [fTotalULField setStringValue: uploadRate];
    621 
    622     [self updateInfoStats];
     708    float downloadRate, uploadRate;
     709    tr_torrentRates(fLib, & downloadRate, & uploadRate);
     710    if (fStatusBarVisible)
     711    {
     712        [fTotalDLField setStringValue: [NSString stringForSpeed: downloadRate]];
     713        [fTotalULField setStringValue: [NSString stringForSpeed: uploadRate]];
     714    }
     715
     716    if ([[fInfoController window] isVisible])
     717        [fInfoController updateInfoStats];
    623718
    624719    //badge dock
    625720    [fBadger updateBadgeWithCompleted: fCompleted
    626         uploadRate: ul >= 0.1 && [fDefaults boolForKey: @"BadgeUploadRate"]
    627           ? [NSString stringForSpeedAbbrev: ul] : nil
    628         downloadRate: dl >= 0.1 && [fDefaults boolForKey: @"BadgeDownloadRate"]
    629           ? [NSString stringForSpeedAbbrev: dl] : nil];
     721        uploadRate: uploadRate downloadRate: downloadRate];
    630722}
    631723
     
    641733
    642734    [fDefaults setObject: history forKey: @"History"];
    643 }
    644 
    645 - (void) showInfo: (id) sender
    646 {
    647     if ([[fInfoController window] isVisible])
    648         [[fInfoController window] performClose: nil];
    649     else
    650     {
    651         [fInfoController updateInfoForTorrents: [self torrentsAtIndexes:
    652                                             [fTableView selectedRowIndexes]]];
    653         [[fInfoController window] orderFront: nil];
    654     }
    655 }
    656 
    657 - (void) updateInfo
    658 {
    659     if ([[fInfoController window] isVisible])
    660         [fInfoController updateInfoForTorrents: [self torrentsAtIndexes:
    661                                             [fTableView selectedRowIndexes]]];
    662 }
    663 
    664 - (void) updateInfoStats
    665 {
    666     if ([[fInfoController window] isVisible])
    667         [fInfoController updateInfoStatsForTorrents: [self torrentsAtIndexes:
    668                                             [fTableView selectedRowIndexes]]];
    669735}
    670736
     
    681747                    * dateDescriptor = [[[NSSortDescriptor alloc] initWithKey:
    682748                                            @"date" ascending: YES] autorelease];
    683 
    684749    NSArray * descriptors;
    685750    if ([fSortType isEqualToString: @"Name"])
     
    691756        descriptors = [[NSArray alloc] initWithObjects: stateDescriptor, nameDescriptor, dateDescriptor, nil];
    692757    }
     758    else if ([fSortType isEqualToString: @"Progress"])
     759    {
     760        NSSortDescriptor * progressDescriptor = [[[NSSortDescriptor alloc] initWithKey:
     761                                                @"progressSortKey" ascending: YES] autorelease];
     762        descriptors = [[NSArray alloc] initWithObjects: progressDescriptor, nameDescriptor, dateDescriptor, nil];
     763    }
    693764    else
    694765        descriptors = [[NSArray alloc] initWithObjects: dateDescriptor, nameDescriptor, nil];
    695766
    696767    [fTorrents sortUsingDescriptors: descriptors];
     768   
    697769    [descriptors release];
    698770   
     
    702774    if (selectedTorrents)
    703775    {
    704         [fTableView deselectAll: nil];
    705        
    706776        Torrent * torrent;
    707777        NSEnumerator * enumerator = [selectedTorrents objectEnumerator];
     778        NSMutableIndexSet * indexSet = [[NSMutableIndexSet alloc] init];
    708779        while ((torrent = [enumerator nextObject]))
    709             [fTableView selectRow: [fTorrents indexOfObject: torrent] byExtendingSelection: YES];
     780            [indexSet addIndex: [fTorrents indexOfObject: torrent]];
     781       
     782        [fTableView selectRowIndexes: indexSet byExtendingSelection: NO];
     783        [indexSet release];
    710784    }
    711785}
     
    713787- (void) setSort: (id) sender
    714788{
    715     [fCurrentSortItem setState: NSOffState];
    716     fCurrentSortItem = sender;
     789    NSMenuItem * prevSortItem;
     790    if ([fSortType isEqualToString: @"Name"])
     791        prevSortItem = fNameSortItem;
     792    else if ([fSortType isEqualToString: @"State"])
     793        prevSortItem = fStateSortItem;
     794    else if ([fSortType isEqualToString: @"Progress"])
     795        prevSortItem = fProgressSortItem;
     796    else
     797        prevSortItem = fDateSortItem;
     798   
     799    if (sender == prevSortItem)
     800        return;
     801   
     802    [prevSortItem setState: NSOffState];
    717803    [sender setState: NSOnState];
    718804
     805    [fSortType release];
    719806    if (sender == fNameSortItem)
    720         fSortType = @"Name";
     807        fSortType = [[NSString alloc] initWithString: @"Name"];
    721808    else if (sender == fStateSortItem)
    722         fSortType = @"State";
     809        fSortType = [[NSString alloc] initWithString: @"State"];
     810    else if (sender == fProgressSortItem)
     811        fSortType = [[NSString alloc] initWithString: @"Progress"];
    723812    else
    724         fSortType = @"Date";
     813        fSortType = [[NSString alloc] initWithString: @"Date"];
    725814       
    726815    [fDefaults setObject: fSortType forKey: @"Sort"];
     
    729818}
    730819
     820- (void) setLimitGlobalEnabled: (id) sender
     821{
     822    [fPrefsController setLimitEnabled: (sender == fUploadLimitItem || sender == fDownloadLimitItem)
     823                        type: (sender == fUploadLimitItem || sender == fUploadNoLimitItem)
     824                            ? @"Upload" : @"Download"];
     825}
     826
     827- (void) setQuickLimitGlobal: (id) sender
     828{
     829    NSString * title = [sender title];
     830    [fPrefsController setQuickLimit: [[title substringToIndex: [title length]
     831                                                    - [@" KB/s" length]] intValue]
     832                    type: [sender menu] == fUploadMenu ? @"Upload" : @"Download"];
     833}
     834
     835- (void) limitGlobalChange: (NSNotification *) notification
     836{
     837    NSDictionary * dict = [notification object];
     838   
     839    BOOL enable = [[dict objectForKey: @"Enable"] boolValue];
     840    int limit = [[dict objectForKey: @"Limit"] intValue];
     841   
     842    NSMenuItem * limitItem, * noLimitItem;
     843    if ([[dict objectForKey: @"Type"] isEqualToString: @"Upload"])
     844    {
     845        limitItem = fUploadLimitItem;
     846        noLimitItem = fUploadNoLimitItem;
     847    }
     848    else
     849    {
     850        limitItem = fDownloadLimitItem;
     851        noLimitItem = fDownloadNoLimitItem;
     852    }
     853    [limitItem setState: enable ? NSOnState : NSOffState];
     854    [noLimitItem setState: !enable ? NSOnState : NSOffState];
     855   
     856    [limitItem setTitle: [NSString stringWithFormat: @"Limit (%d KB/s)",
     857                            [[dict objectForKey: @"Limit"] intValue]]];
     858
     859    [dict release];
     860}
     861
     862- (void) setRatioGlobalEnabled: (id) sender
     863{
     864    [fPrefsController setRatioEnabled: sender == fRatioSetItem];
     865}
     866
     867- (void) setQuickRatioGlobal: (id) sender
     868{
     869    [fPrefsController setQuickRatio: [[sender title] floatValue]];
     870}
     871
     872- (void) ratioGlobalChange: (NSNotification *) notification
     873{
     874    NSDictionary * dict = [notification object];
     875   
     876    BOOL enable = [[dict objectForKey: @"Enable"] boolValue];
     877    [fRatioSetItem setState: enable ? NSOnState : NSOffState];
     878    [fRatioNotSetItem setState: !enable ? NSOnState : NSOffState];
     879   
     880    [fRatioSetItem setTitle: [NSString stringWithFormat: @"Stop at Ratio (%.2f)",
     881                            [[dict objectForKey: @"Ratio"] floatValue]]];
     882
     883    [dict release];
     884}
     885
     886- (void) ratioSingleChange: (NSNotification *) notification
     887{
     888    if ([fSortType isEqualToString: @"State"])
     889        [self sortTorrents];
     890   
     891    //update info for changed ratio setting
     892    NSArray * torrents = [self torrentsAtIndexes: [fTableView selectedRowIndexes]];
     893    if ([torrents containsObject: [notification object]])
     894        [fInfoController updateInfoForTorrents: torrents];
     895}
     896
    731897- (int) numberOfRowsInTableView: (NSTableView *) t
    732898{
     
    735901
    736902- (void) tableView: (NSTableView *) t willDisplayCell: (id) cell
    737     forTableColumn: (NSTableColumn *) tableColumn row: (int) rowIndex
    738 {
    739     [cell setTorrent: [fTorrents objectAtIndex: rowIndex]];
    740 
    741     if( [fWindow isKeyWindow] && [fTableView isRowSelected: rowIndex] )
    742         [cell setTextColor: [NSColor whiteColor]];
    743     else
    744         [cell setTextColor: [NSColor blackColor]];
     903    forTableColumn: (NSTableColumn *) tableColumn row: (int) row
     904{
     905    [cell setTorrent: [fTorrents objectAtIndex: row]];
    745906}
    746907
     
    760921{
    761922    NSPasteboard * pasteboard = [info draggingPasteboard];
    762 
    763923    if (![[pasteboard types] containsObject: NSFilenamesPboardType]
    764924            || [[[pasteboard propertyListForType: NSFilenamesPboardType]
     
    767927        return NSDragOperationNone;
    768928
    769     [fTableView setDropRow: [fTableView numberOfRows]
    770         dropOperation: NSTableViewDropAbove];
     929    [fTableView setDropRow: [fTableView numberOfRows] dropOperation: NSTableViewDropAbove];
    771930    return NSDragOperationGeneric;
    772931}
    773932
    774 - (void) tableViewSelectionDidChange: (NSNotification *) n
    775 {
    776     [self updateInfo];
     933- (void) tableViewSelectionDidChange: (NSNotification *) notification
     934{
     935    [fInfoController updateInfoForTorrents: [self torrentsAtIndexes:
     936                                    [fTableView selectedRowIndexes]]];
     937}
     938
     939- (void) toggleStatusBar: (id) sender
     940{
     941    [self showStatusBar: !fStatusBarVisible animate: YES];
     942    [fDefaults setBool: fStatusBarVisible forKey: @"StatusBar"];
     943}
     944
     945- (void) showStatusBar: (BOOL) show animate: (BOOL) animate
     946{
     947    if (show == fStatusBarVisible)
     948        return;
     949
     950    NSRect frame = [fWindow frame];
     951    float heightChange = [fStatusBar frame].size.height;
     952    if (!show)
     953        heightChange *= -1;
     954
     955    frame.size.height += heightChange;
     956    frame.origin.y -= heightChange;
     957       
     958    fStatusBarVisible = !fStatusBarVisible;
     959   
     960    //reloads stats
     961    [self torrentNumberChanged];
     962    [self updateUI: nil];
     963   
     964    //set views to not autoresize
     965    unsigned int statsMask = [fStatusBar autoresizingMask];
     966    unsigned int scrollMask = [fScrollView autoresizingMask];
     967    [fStatusBar setAutoresizingMask: 0];
     968    [fScrollView setAutoresizingMask: 0];
     969   
     970    [fWindow setFrame: frame display: YES animate: animate];
     971   
     972    //re-enable autoresize
     973    [fStatusBar setAutoresizingMask: statsMask];
     974    [fScrollView setAutoresizingMask: scrollMask];
     975   
     976    //change min size
     977    NSSize minSize = [fWindow contentMinSize];
     978    minSize.height += heightChange;
     979    [fWindow setContentMinSize: minSize];
    777980}
    778981
     
    785988    {
    786989        [item setLabel: @"Open"];
    787         [item setPaletteLabel: [item label]];
     990        [item setPaletteLabel: @"Open Torrent Files"];
    788991        [item setToolTip: @"Open torrent files"];
    789992        [item setImage: [NSImage imageNamed: @"Open.png"]];
    790993        [item setTarget: self];
    791994        [item setAction: @selector( openShowSheet: )];
     995        [item setAutovalidates: NO];
    792996    }
    793997    else if( [ident isEqualToString: TOOLBAR_REMOVE] )
    794998    {
    795999        [item setLabel: @"Remove"];
    796         [item setPaletteLabel: [item label]];
     1000        [item setPaletteLabel: @"Remove Selected"];
    7971001        [item setToolTip: @"Remove selected torrents"];
    7981002        [item setImage: [NSImage imageNamed: @"Remove.png"]];
     
    8021006    else if( [ident isEqualToString: TOOLBAR_INFO] )
    8031007    {
    804         [item setLabel: @"Info"];
    805         [item setPaletteLabel: [item label]];
    806         [item setToolTip: @"Display torrent info"];
     1008        [item setLabel: @"Inspector"];
     1009        [item setPaletteLabel: @"Show/Hide Inspector"];
     1010        [item setToolTip: @"Displays torrent inspector"];
    8071011        [item setImage: [NSImage imageNamed: @"Info.png"]];
    8081012        [item setTarget: self];
    8091013        [item setAction: @selector( showInfo: )];
     1014        [item setAutovalidates: NO];
     1015    }
     1016    else if( [ident isEqualToString: TOOLBAR_PAUSE_ALL] )
     1017    {
     1018        [item setLabel: @"Pause All"];
     1019        [item setPaletteLabel: [item label]];
     1020        [item setToolTip: @"Pause all torrents"];
     1021        [item setImage: [NSImage imageNamed: @"PauseAll.png"]];
     1022        [item setTarget: self];
     1023        [item setAction: @selector( stopAllTorrents: )];
    8101024    }
    8111025    else if( [ident isEqualToString: TOOLBAR_RESUME_ALL] )
     
    8181032        [item setAction: @selector( resumeAllTorrents: )];
    8191033    }
    820     else if( [ident isEqualToString: TOOLBAR_PAUSE_ALL] )
    821     {
    822         [item setLabel: @"Pause All"];
    823         [item setPaletteLabel: [item label]];
    824         [item setToolTip: @"Pause all torrents"];
    825         [item setImage: [NSImage imageNamed: @"PauseAll.png"]];
     1034    else if( [ident isEqualToString: TOOLBAR_PAUSE_SELECTED] )
     1035    {
     1036        [item setLabel: @"Pause"];
     1037        [item setPaletteLabel: @"Pause Selected"];
     1038        [item setToolTip: @"Pause selected torrents"];
     1039        [item setImage: [NSImage imageNamed: @"PauseSelected.tiff"]];
    8261040        [item setTarget: self];
    827         [item setAction: @selector( stopAllTorrents: )];
     1041        [item setAction: @selector( stopTorrent: )];
     1042    }
     1043    else if( [ident isEqualToString: TOOLBAR_RESUME_SELECTED] )
     1044    {
     1045        [item setLabel: @"Resume"];
     1046        [item setPaletteLabel: @"Resume Selected"];
     1047        [item setToolTip: @"Resume selected torrents"];
     1048        [item setImage: [NSImage imageNamed: @"ResumeSelected.tiff"]];
     1049        [item setTarget: self];
     1050        [item setAction: @selector( resumeTorrent: )];
    8281051    }
    8291052    else
     
    8401063    return [NSArray arrayWithObjects:
    8411064            TOOLBAR_OPEN, TOOLBAR_REMOVE,
     1065            TOOLBAR_PAUSE_SELECTED, TOOLBAR_RESUME_SELECTED,
    8421066            TOOLBAR_PAUSE_ALL, TOOLBAR_RESUME_ALL,
    8431067            TOOLBAR_INFO,
     
    8581082}
    8591083
    860 - (void) toggleStatusBar: (id) sender
    861 {
    862     fStatusBar = !fStatusBar;
    863 
    864     NSSize frameSize = [fScrollView frame].size;
    865     [fStats setHidden: !fStatusBar];
    866    
    867     if (fStatusBar)
    868         frameSize.height -= 18;
    869     else
    870         frameSize.height += 18;
    871 
    872     [fScrollView setFrameSize: frameSize];
    873     [fWindow display];
    874    
    875     [fDefaults setBool: fStatusBar forKey: @"StatusBar"];
    876 }
    877 
    8781084- (BOOL) validateToolbarItem: (NSToolbarItem *) toolbarItem
    8791085{
     
    8841090        return [fTableView numberOfSelectedRows] > 0;
    8851091
    886     Torrent * torrent;
    887     NSEnumerator * enumerator;
    888 
    889     //enable resume all item
    890     if (action == @selector(resumeAllTorrents:))
    891     {
    892         enumerator = [fTorrents objectEnumerator];
    893         while( ( torrent = [enumerator nextObject] ) )
    894             if( [torrent isPaused] )
    895                 return YES;
    896         return NO;
    897     }
    898 
    8991092    //enable pause all item
    9001093    if (action == @selector(stopAllTorrents:))
    9011094    {
    902         enumerator = [fTorrents objectEnumerator];
     1095        Torrent * torrent;
     1096        NSEnumerator * enumerator = [fTorrents objectEnumerator];
    9031097        while( ( torrent = [enumerator nextObject] ) )
    9041098            if( [torrent isActive] )
    9051099                return YES;
    9061100        return NO;
    907     }
    908 
    909     return YES;
    910 }
    911 
    912 - (BOOL) validateMenuItem: (NSMenuItem *) menuItem
    913 {
    914     SEL action = [menuItem action];
    915 
    916     //only enable some menus if window is useable
    917     BOOL canUseWindow = [fWindow isKeyWindow] && ![fToolbar customizationPaletteIsRunning];
    918 
    919     //enable show info
    920     if (action == @selector(showInfo:))
    921     {
    922         [menuItem setTitle: [[fInfoController window] isVisible] ? @"Hide Info" : @"Show Info"];
    923         return YES;
    924     }
    925    
    926     //enable toggle toolbar
    927     if (action == @selector(toggleStatusBar:))
    928     {
    929         [menuItem setTitle: fStatusBar ? @"Hide Status Bar" : @"Show Status Bar"];
    930         return canUseWindow;
    9311101    }
    9321102
     
    9421112    }
    9431113
     1114    //enable pause item
     1115    if( action == @selector(stopTorrent:) )
     1116    {
     1117        Torrent * torrent;
     1118        NSIndexSet * indexSet = [fTableView selectedRowIndexes];
     1119        unsigned int i;
     1120       
     1121        for (i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
     1122        {
     1123            torrent = [fTorrents objectAtIndex: i];
     1124            if ([torrent isActive])
     1125                return YES;
     1126        }
     1127        return NO;
     1128    }
     1129   
     1130    //enable resume item
     1131    if( action == @selector(resumeTorrent:) )
     1132    {
     1133        Torrent * torrent;
     1134        NSIndexSet * indexSet = [fTableView selectedRowIndexes];
     1135        unsigned int i;
     1136       
     1137        for (i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
     1138        {
     1139            torrent = [fTorrents objectAtIndex: i];
     1140            if ([torrent isPaused])
     1141                return YES;
     1142        }
     1143        return NO;
     1144    }
     1145
     1146    return YES;
     1147}
     1148
     1149- (BOOL) validateMenuItem: (NSMenuItem *) menuItem
     1150{
     1151    SEL action = [menuItem action];
     1152
     1153    //only enable some menus if window is useable
     1154    BOOL canUseWindow = [fWindow isKeyWindow] && ![fToolbar customizationPaletteIsRunning];
     1155
     1156    //enable show info
     1157    if (action == @selector(showInfo:))
     1158    {
     1159        NSString * title = [[fInfoController window] isVisible] ? @"Hide Inspector" : @"Show Inspector";
     1160        if (![[menuItem title] isEqualToString: title])
     1161                [menuItem setTitle: title];
     1162
     1163        return YES;
     1164    }
     1165   
     1166    if (action == @selector(setInfoTab:))
     1167        return [[fInfoController window] isVisible];
     1168   
     1169    //enable toggle status bar
     1170    if (action == @selector(toggleStatusBar:))
     1171    {
     1172        NSString * title = fStatusBarVisible ? @"Hide Status Bar" : @"Show Status Bar";
     1173        if (![[menuItem title] isEqualToString: title])
     1174                [menuItem setTitle: title];
     1175
     1176        return canUseWindow;
     1177    }
     1178
     1179    //enable resume all item
     1180    if (action == @selector(resumeAllTorrents:))
     1181    {
     1182        Torrent * torrent;
     1183        NSEnumerator * enumerator = [fTorrents objectEnumerator];
     1184        while( ( torrent = [enumerator nextObject] ) )
     1185            if( [torrent isPaused] )
     1186                return YES;
     1187        return NO;
     1188    }
     1189
    9441190    //enable pause all item
    9451191    if (action == @selector(stopAllTorrents:))
     
    9531199    }
    9541200
    955     if (action == @selector(revealTorrent:))
     1201    if (action == @selector(revealFile:))
    9561202    {
    9571203        return canUseWindow && [fTableView numberOfSelectedRows] > 0;
     
    9601206    //enable remove items
    9611207    if (action == @selector(removeTorrent:)
    962         || action == @selector(removeTorrentDeleteFile:)
     1208        || action == @selector(removeTorrentDeleteTorrent:)
    9631209        || action == @selector(removeTorrentDeleteData:)
    9641210        || action == @selector(removeTorrentDeleteBoth:))
     
    9891235        {
    9901236            if ([title hasSuffix: NS_ELLIPSIS])
    991                 [menuItem setTitle:[title substringToIndex:
     1237                [menuItem setTitle: [title substringToIndex:
    9921238                            [title rangeOfString: NS_ELLIPSIS].location]];
    9931239        }
     
    10341280   
    10351281    //enable resume item
    1036     if (action == @selector(setSort:))
     1282    if (action == @selector(setSort:) || (action == @selector(advancedChanged:)))
    10371283        return canUseWindow;
    10381284
     
    10741320            active = NO;
    10751321            enumerator = [fTorrents objectEnumerator];
    1076             while( !active && ( torrent = [enumerator nextObject] ) )
    1077                 if( [torrent isActive] )
     1322            while ((torrent = [enumerator nextObject]))
     1323                if ([torrent isActive])
     1324                {
    10781325                    active = YES;
     1326                    break;
     1327                }
    10791328
    10801329            if (active)
     
    10941343    defaultFrame: (NSRect) defaultFrame
    10951344{
    1096     NSRect rectWin = [fWindow frame];
    1097     float newHeight = rectWin.size.height - [fScrollView frame].size.height
    1098             + [fTorrents count] * ([fTableView rowHeight] + [fTableView intercellSpacing].height);
     1345    NSRect windowRect = [fWindow frame];
     1346    int count = [fTorrents count];
     1347    float newHeight = windowRect.size.height - [fScrollView frame].size.height
     1348            + count * ([fTableView rowHeight] + [fTableView intercellSpacing].height) + 30.0;
    10991349
    11001350    float minHeight = [fWindow minSize].height;
     
    11021352        newHeight = minHeight;
    11031353
    1104     rectWin.origin.y -= (newHeight - rectWin.size.height);
    1105     rectWin.size.height = newHeight;
    1106 
    1107     return rectWin;
     1354    windowRect.origin.y -= (newHeight - windowRect.size.height);
     1355    windowRect.size.height = newHeight;
     1356
     1357    return windowRect;
    11081358}
    11091359
     
    11111361{
    11121362    [fWindow makeKeyAndOrderFront: nil];
     1363}
     1364
     1365- (void) windowDidBecomeKey: (NSNotification *) notification
     1366{
     1367    fCompleted = 0;
    11131368}
    11141369
     
    11821437}
    11831438
    1184 - (void) checkForUpdate: (id) sender
    1185 {
    1186     [self checkForUpdateAuto: NO];
    1187 }
    1188 
    1189 - (void) checkForUpdateTimer: (NSTimer *) timer
    1190 {
    1191     NSString * check = [fDefaults stringForKey: @"VersionCheck"];
    1192 
    1193     NSTimeInterval interval;
    1194     if( [check isEqualToString: @"Daily"] )
    1195         interval = 24 * 3600;
    1196     else if( [check isEqualToString: @"Weekly"] )
    1197         interval = 7 * 24 * 3600;
    1198     else
    1199         return;
    1200 
    1201     NSDate * lastDate = [fDefaults objectForKey: @"VersionCheckLast"];
    1202     if( lastDate )
    1203     {
    1204         NSTimeInterval actualInterval = [[NSDate date]
    1205                             timeIntervalSinceDate: lastDate];
    1206         if( actualInterval > 0 && actualInterval < interval )
    1207             return;
    1208     }
    1209 
    1210     [self checkForUpdateAuto: YES];
    1211     [fDefaults setObject: [NSDate date] forKey: @"VersionCheckLast"];
    1212 }
    1213 
    1214 - (void) checkForUpdateAuto: (BOOL) automatic
    1215 {
    1216     fCheckIsAutomatic = automatic;
    1217     [[NSURL URLWithString: VERSION_PLIST_URL]
    1218             loadResourceDataNotifyingClient: self usingCache: NO];
    1219 }
    1220 
    1221 - (void) URLResourceDidFinishLoading: (NSURL *) sender
    1222 {
    1223     //check if plist was actually found and contains a version
    1224     NSDictionary * dict = [NSPropertyListSerialization
    1225                             propertyListFromData: [sender resourceDataUsingCache: NO]
    1226                             mutabilityOption: NSPropertyListImmutable
    1227                             format: nil errorDescription: nil];
    1228     NSString * webVersion;
    1229     if (!dict || !(webVersion = [dict objectForKey: @"Version"]))
    1230     {
    1231         if (!fCheckIsAutomatic)
    1232         {
    1233             NSAlert * dialog = [[NSAlert alloc] init];
    1234             [dialog addButtonWithTitle: @"OK"];
    1235             [dialog setMessageText: @"Error checking for updates."];
    1236             [dialog setInformativeText:
    1237                     @"Transmission was not able to check the latest version available."];
    1238             [dialog setAlertStyle: NSInformationalAlertStyle];
    1239 
    1240             [dialog runModal];
    1241             [dialog release];
    1242         }
    1243         return;
    1244     }
    1245 
    1246     NSString * currentVersion = [[[NSBundle mainBundle] infoDictionary]
    1247                                 objectForKey: (NSString *)kCFBundleVersionKey];
    1248 
    1249     NSEnumerator * webEnum = [[webVersion componentsSeparatedByString: @"."] objectEnumerator],
    1250             * currentEnum = [[currentVersion componentsSeparatedByString: @"."] objectEnumerator];
    1251     NSString * webSub, * currentSub;
    1252 
    1253     BOOL webGreater = NO;
    1254     NSComparisonResult result;
    1255     while ((webSub = [webEnum nextObject]))
    1256     {
    1257         if (!(currentSub = [currentEnum nextObject]))
    1258         {
    1259             webGreater = YES;
    1260             break;
    1261         }
    1262 
    1263         result = [currentSub compare: webSub options: NSNumericSearch];
    1264         if (result != NSOrderedSame)
    1265         {
    1266             if (result == NSOrderedAscending)
    1267                 webGreater = YES;
    1268             break;
    1269         }
    1270     }
    1271 
    1272     if (webGreater)
    1273     {
    1274         NSAlert * dialog = [[NSAlert alloc] init];
    1275         [dialog addButtonWithTitle: @"Go to Website"];
    1276         [dialog addButtonWithTitle:@"Cancel"];
    1277         [dialog setMessageText: @"New version is available!"];
    1278         [dialog setInformativeText: [NSString stringWithFormat:
    1279             @"A newer version (%@) is available for download from the Transmission website.", webVersion]];
    1280         [dialog setAlertStyle: NSInformationalAlertStyle];
    1281 
    1282         if ([dialog runModal] == NSAlertFirstButtonReturn)
    1283             [self linkHomepage: nil];
    1284 
    1285         [dialog release];
    1286     }
    1287     else if (!fCheckIsAutomatic)
    1288     {
    1289         NSAlert * dialog = [[NSAlert alloc] init];
    1290         [dialog addButtonWithTitle: @"OK"];
    1291         [dialog setMessageText: @"No new versions are available."];
    1292         [dialog setInformativeText: [NSString stringWithFormat:
    1293             @"You are running the most current version of Transmission (%@).", currentVersion]];
    1294         [dialog setAlertStyle: NSInformationalAlertStyle];
    1295 
    1296         [dialog runModal];
    1297         [dialog release];
    1298     }
    1299     else;
     1439- (void) checkUpdate: (id) sender
     1440{
     1441    [fPrefsController checkUpdate];
     1442}
     1443
     1444- (void) prepareForUpdate: (NSNotification *) notification
     1445{
     1446    fUpdateInProgress = YES;
    13001447}
    13011448
  • trunk/macosx/Defaults.plist

    r261 r272  
    3939        <key>RatioLimit</key>
    4040        <integer>2</integer>
     41        <key>SUScheduledCheckInterval</key>
     42        <integer>86400</integer>
    4143        <key>ShowInspector</key>
    4244        <false/>
     
    4547        <key>StatusBar</key>
    4648        <true/>
     49        <key>UpdateCheck</key>
     50        <string>Daily</string>
    4751        <key>UploadLimit</key>
    4852        <integer>20</integer>
    4953        <key>UseAdvancedBar</key>
    5054        <false/>
    51         <key>VersionCheck</key>
    52         <string>Weekly</string>
    5355</dict>
    5456</plist>
  • trunk/macosx/English.lproj/InfoPlist.strings

    r261 r272  
    22
    33CFBundleName = "Transmission";
    4 NSHumanReadableCopyright = "Copyright 2005 Eric Petit";
     4NSHumanReadableCopyright = "Copyright 2005-2006 Eric Petit";
  • trunk/macosx/English.lproj/InfoWindow.nib/classes.nib

    r261 r272  
    33        {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
    44        {
     5            ACTIONS = {revealFile = id; setRatioCheck = id; setRatioLimit = id; };
    56            CLASS = InfoWindowController;
    67            LANGUAGE = ObjC;
    78            OUTLETS = {
    8                 fAnnounce = NSTextField;
    9                 fDownloaded = NSTextField;
    10                 fHash = NSTextField;
     9                fAnnounceField = NSTextField;
     10                fConnectedPeersField = NSTextField;
     11                fDataLocationField = NSTextField;
     12                fDateStartedField = NSTextField;
     13                fDownloadRateField = NSTextField;
     14                fDownloadedField = NSTextField;
     15                fDownloadingFromField = NSTextField;
     16                fFileTable = NSTableView;
     17                fHashField = NSTextField;
    1118                fImageView = NSImageView;
    12                 fLeechers = NSTextField;
    13                 fName = NSTextField;
    14                 fPieceSize = NSTextField;
    15                 fPieces = NSTextField;
    16                 fSeeders = NSTextField;
    17                 fSize = NSTextField;
    18                 fTracker = NSTextField;
    19                 fUploaded = NSTextField;
     19                fLeechersField = NSTextField;
     20                fNameField = NSTextField;
     21                fPercentField = NSTextField;
     22                fPieceSizeField = NSTextField;
     23                fPiecesField = NSTextField;
     24                fRatioField = NSTextField;
     25                fRatioLimitField = NSTextField;
     26                fRatioMatrix = NSMatrix;
     27                fSeedersField = NSTextField;
     28                fSizeField = NSTextField;
     29                fStateField = NSTextField;
     30                fTabView = NSTabView;
     31                fTorrentLocationField = NSTextField;
     32                fTrackerField = NSTextField;
     33                fUploadRateField = NSTextField;
     34                fUploadedField = NSTextField;
     35                fUploadingToField = NSTextField;
    2036            };
    2137            SUPERCLASS = NSWindowController;
    22         }
     38        },
     39        {CLASS = NSSegmentedControl; LANGUAGE = ObjC; SUPERCLASS = NSControl; }
    2340    );
    2441    IBVersion = 1;
  • trunk/macosx/English.lproj/InfoWindow.nib/info.nib

    r261 r272  
    1111                <integer>5</integer>
    1212        </array>
     13        <key>IBLockedTabItems</key>
     14        <array>
     15                <integer>332</integer>
     16        </array>
    1317        <key>IBOpenObjects</key>
    1418        <array>
  • trunk/macosx/English.lproj/MainMenu.nib/classes.nib

    r261 r272  
    44            ACTIONS = {
    55                advancedChanged = id;
    6                 checkForUpdate = id;
     6                checkUpdate = id;
    77                growlRegister = id;
    88                linkForums = id;
     
    1212                removeTorrentDeleteBoth = id;
    1313                removeTorrentDeleteData = id;
    14                 removeTorrentDeleteFile = id;
     14                removeTorrentDeleteTorrent = id;
    1515                resumeAllTorrents = id;
    1616                resumeTorrent = id;
    17                 revealTorrent = id;
     17                revealFile = id;
     18                setInfoTab = id;
     19                setLimitGlobalEnabled = id;
     20                setQuickLimitGlobal = id;
     21                setQuickRatioGlobal = id;
     22                setRatioGlobalEnabled = id;
    1823                setSort = id;
    1924                showInfo = id;
     
    3035                fAdvancedBarItem = NSMenuItem;
    3136                fDateSortItem = NSMenuItem;
     37                fDownloadLimitItem = NSMenuItem;
     38                fDownloadMenu = NSMenu;
     39                fDownloadNoLimitItem = NSMenuItem;
    3240                fNameSortItem = NSMenuItem;
    33                 fPauseResumeItem = NSMenuItem;
    34                 fPrefsController = PrefsController;
    35                 fPrefsWindow = NSPanel;
    36                 fRemoveBothItem = NSMenuItem;
    37                 fRemoveDataItem = NSMenuItem;
    38                 fRemoveItem = NSMenuItem;
    39                 fRemoveTorrentItem = NSMenuItem;
    40                 fRevealItem = NSMenuItem;
     41                fNextInfoTabItem = NSMenuItem;
     42                fPrevInfoTabItem = NSMenuItem;
     43                fProgressSortItem = NSMenuItem;
     44                fRatioNotSetItem = NSMenuItem;
     45                fRatioSetItem = NSMenuItem;
    4146                fScrollView = NSScrollView;
    42                 fShowHideToolbar = NSMenuItem;
    4347                fStateSortItem = NSMenuItem;
    44                 fStats = NSBox;
     48                fStatusBar = SmoothAquaView;
    4549                fTableView = TorrentTableView;
    4650                fTotalDLField = NSTextField;
    4751                fTotalTorrentsField = NSTextField;
    4852                fTotalULField = NSTextField;
     53                fUploadLimitItem = NSMenuItem;
     54                fUploadMenu = NSMenu;
     55                fUploadNoLimitItem = NSMenuItem;
    4956                fWindow = NSWindow;
    5057            };
    5158            SUPERCLASS = NSObject;
    5259        },
    53         {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
     60        {
     61            ACTIONS = {revealFile = id; setNextTab = id; setPreviousTab = id; };
     62            CLASS = FirstResponder;
     63            LANGUAGE = ObjC;
     64            SUPERCLASS = NSObject;
     65        },
    5466        {CLASS = MenuButton; LANGUAGE = ObjC; SUPERCLASS = NSButton; },
    5567        {CLASS = NSSegmentedControl; LANGUAGE = ObjC; SUPERCLASS = NSControl; },
     
    98110                fTransfersView = NSView;
    99111                fUpdatePopUp = NSPopUpButton;
     112                fUpdater = SUUpdater;
    100113                fUploadCheck = NSButton;
    101114                fUploadField = NSTextField;
     
    109122        {CLASS = ProgressCell; LANGUAGE = ObjC; SUPERCLASS = NSCell; },
    110123        {
     124            ACTIONS = {checkForUpdates = id; };
     125            CLASS = SUUpdater;
     126            LANGUAGE = ObjC;
     127            SUPERCLASS = NSObject;
     128        },
     129        {CLASS = SmoothAquaView; LANGUAGE = ObjC; SUPERCLASS = NSView; },
     130        {
    111131            CLASS = TorrentTableView;
    112132            LANGUAGE = ObjC;
  • trunk/macosx/English.lproj/MainMenu.nib/info.nib

    r261 r272  
    44<dict>
    55        <key>IBDocumentLocation</key>
    6         <string>51 70 426 365 0 0 1152 842 </string>
     6        <string>28 75 422 283 0 0 1152 842 </string>
    77        <key>IBEditorPositions</key>
    88        <dict>
    99                <key>1041</key>
    1010                <string>344 478 208 99 0 0 1152 842 </string>
    11                 <key>1343</key>
    12                 <string>344 526 463 104 0 0 1152 842 </string>
     11                <key>1480</key>
     12                <string>400 366 420 60 0 0 1152 842 </string>
    1313                <key>29</key>
    14                 <string>154 771 371 44 0 0 1152 842 </string>
     14                <string>154 771 451 44 0 0 1152 842 </string>
    1515                <key>456</key>
    1616                <string>212 488 144 137 0 0 1152 842 </string>
     
    1919                <key>589</key>
    2020                <string>54 521 103 68 0 0 1152 842 </string>
    21                 <key>783</key>
    22                 <string>347 472 457 212 0 0 1152 842 </string>
    23                 <key>796</key>
    24                 <string>347 461 457 234 0 0 1152 842 </string>
    25                 <key>825</key>
    26                 <string>348 524 463 107 0 0 1152 842 </string>
    2721        </dict>
    2822        <key>IBFramework Version</key>
     
    3024        <key>IBOldestOS</key>
    3125        <integer>3</integer>
     26        <key>IBOpenObjects</key>
     27        <array>
     28                <integer>21</integer>
     29                <integer>1480</integer>
     30        </array>
    3231        <key>IBSystem Version</key>
    3332        <string>8I127</string>
  • trunk/macosx/InfoWindowController.h

    r261 r272  
    2828@interface InfoWindowController : NSWindowController
    2929{
    30     IBOutlet NSImageView        * fImageView;
    31     IBOutlet NSTextField        * fName;
    32     IBOutlet NSTextField        * fSize;
    33     IBOutlet NSTextField        * fTracker;
    34     IBOutlet NSTextField        * fAnnounce;
    35     IBOutlet NSTextField        * fPieceSize;
    36     IBOutlet NSTextField        * fPieces;
    37     IBOutlet NSTextField        * fHash;
    38     IBOutlet NSTextField        * fSeeders;
    39     IBOutlet NSTextField        * fLeechers;
    40     IBOutlet NSTextField        * fDownloaded;
    41     IBOutlet NSTextField        * fUploaded;
     30    NSMutableArray * fTorrents, * fFiles;
     31    NSImage * fAppIcon;
    4232   
    43     NSImage                     * fAppIcon;
     33    IBOutlet NSTabView * fTabView;
     34
     35    IBOutlet NSImageView * fImageView;
     36    IBOutlet NSTextField * fNameField, * fSizeField, * fTrackerField,
     37                        * fAnnounceField, * fPieceSizeField, * fPiecesField,
     38                        * fHashField,
     39                        * fTorrentLocationField, * fDataLocationField,
     40                        * fDateStartedField,
     41                        * fStateField, * fPercentField,
     42                        * fDownloadRateField, * fUploadRateField,
     43                        * fDownloadedField, * fUploadedField, * fRatioField,
     44                        * fSeedersField, * fLeechersField,
     45                        * fConnectedPeersField, * fDownloadingFromField, * fUploadingToField;
     46
     47    IBOutlet NSTableView * fFileTable;
     48   
     49    IBOutlet NSMatrix * fRatioMatrix;
     50    IBOutlet NSTextField * fRatioLimitField;
    4451}
    4552
    4653- (void) updateInfoForTorrents: (NSArray *) torrents;
    47 - (void) updateInfoStatsForTorrents: (NSArray *) torrents;
     54- (void) updateInfoStats;
     55
     56- (void) setNextTab;
     57- (void) setPreviousTab;
     58- (void) revealFile: (id) sender;
     59
     60- (void) setRatioCheck: (id) sender;
     61- (void) setRatioLimit: (id) sender;
    4862
    4963@end
  • trunk/macosx/InfoWindowController.m

    r261 r272  
    2626#import "StringAdditions.h"
    2727
     28#define RATIO_NO_CHECK_TAG 0
     29#define RATIO_GLOBAL_TAG 1
     30#define RATIO_CHECK_TAG 2
     31
     32#define TAB_INFO_IDENT @"Info"
     33#define TAB_STATUS_IDENT @"Status"
     34#define TAB_OPTIONS_IDENT @"Options"
     35#define TAB_FILES_IDENT @"Files"
     36
     37#define TAB_INFO_HEIGHT 191.0
     38#define TAB_STATUS_HEIGHT 241.0
     39#define TAB_OPTIONS_HEIGHT 82.0
     40#define TAB_FILES_HEIGHT 250.0
     41
    2842@implementation InfoWindowController
    2943
     
    3145{
    3246    fAppIcon = [[NSApp applicationIconImage] copy];
     47   
     48    fFiles = [[NSMutableArray alloc] initWithCapacity: 6];
     49    [fFileTable setDoubleAction: @selector(revealFile:)];
     50   
     51    //window location and size
     52    NSWindow * window = [self window];
     53    [window setFrameAutosaveName: @"InspectorWindowFrame"];
     54    [window setFrameUsingName: @"InspectorWindowFrame" force: YES];
     55   
     56    NSRect frame = [window frame];
     57    float difference = TAB_INFO_HEIGHT - [[[fTabView selectedTabViewItem]
     58                                                    view] frame].size.height;
     59    frame.origin.y -= difference;
     60    frame.size.height += difference;
     61    [window setFrame: frame display: YES];
    3362}
    3463
    3564- (void) dealloc
    3665{
     66    if (fTorrents)
     67        [fTorrents release];
     68    [fFiles release];
     69
    3770    [fAppIcon release];
    3871    [super dealloc];
     
    4174- (void) updateInfoForTorrents: (NSArray *) torrents
    4275{
    43     int numberSelected = [torrents count];
     76    if (fTorrents)
     77        [fTorrents release];
     78    fTorrents = [torrents retain];
     79
     80    int numberSelected = [fTorrents count];
    4481    if (numberSelected != 1)
    4582    {
    46         [fImageView setImage: fAppIcon];
    47 
    48         [fTracker setStringValue: @""];
    49         [fAnnounce setStringValue: @""];
    50         [fPieceSize setStringValue: @""];
    51         [fPieces setStringValue: @""];
    52         [fHash setStringValue: @""];
    53        
    54         [fSeeders setStringValue: @""];
    55         [fLeechers setStringValue: @""];
    56        
    5783        if (numberSelected > 0)
    5884        {
    59             [fName setStringValue: [[NSString stringWithInt: numberSelected]
    60                                     stringByAppendingString: @" Torrents Selected"]];
     85            [fNameField setStringValue: [NSString stringWithFormat:
     86                            @"%d Torrents Selected", numberSelected]];
    6187       
    6288            uint64_t size = 0;
     
    6692                size += [torrent size];
    6793           
    68             [fSize setStringValue: [[NSString
    69                 stringForFileSize: size] stringByAppendingString: @" Total"]];
     94            [fSizeField setStringValue: [[NSString stringForFileSize: size]
     95                                stringByAppendingString: @" Total"]];
    7096        }
    7197        else
    7298        {
    73             [fName setStringValue: @"No Torrents Selected"];
    74 
    75             [fSize setStringValue: @""];
    76             [fDownloaded setStringValue: @""];
    77             [fUploaded setStringValue: @""];
    78         }
     99            [fNameField setStringValue: @"No Torrents Selected"];
     100            [fSizeField setStringValue: @""];
     101           
     102            [fDownloadRateField setStringValue: @""];
     103            [fUploadRateField setStringValue: @""];
     104           
     105            [fDownloadedField setStringValue: @""];
     106            [fUploadedField setStringValue: @""];
     107        }
     108       
     109        [fImageView setImage: fAppIcon];
     110       
     111        [fNameField setToolTip: nil];
     112
     113        [fTrackerField setStringValue: @""];
     114        [fTrackerField setToolTip: nil];
     115        [fAnnounceField setStringValue: @""];
     116        [fAnnounceField setToolTip: nil];
     117        [fPieceSizeField setStringValue: @""];
     118        [fPiecesField setStringValue: @""];
     119        [fHashField setStringValue: @""];
     120       
     121        [fTorrentLocationField setStringValue: @""];
     122        [fTorrentLocationField setToolTip: nil];
     123        [fDataLocationField setStringValue: @""];
     124        [fDataLocationField setToolTip: nil];
     125        [fDateStartedField setStringValue: @""];
     126       
     127        [fStateField setStringValue: @""];
     128        [fPercentField setStringValue: @""];
     129        [fRatioField setStringValue: @""];
     130       
     131        [fSeedersField setStringValue: @""];
     132        [fLeechersField setStringValue: @""];
     133        [fConnectedPeersField setStringValue: @""];
     134        [fDownloadingFromField setStringValue: @""];
     135        [fUploadingToField setStringValue: @""];
    79136    }
    80137    else
    81138    {   
    82         Torrent * torrent = [torrents objectAtIndex: 0];
    83        
    84         [fImageView setImage: [torrent iconNonFlipped]];
    85        
    86         [fName setStringValue: [torrent name]];
    87         [fSize setStringValue: [NSString stringForFileSize: [torrent size]]];
    88         [fTracker setStringValue: [torrent tracker]];
    89         [fAnnounce setStringValue: [torrent announce]];
    90         [fPieceSize setStringValue: [NSString stringForFileSize: [torrent pieceSize]]];
    91         [fPieces setIntValue: [torrent pieceCount]];
    92         [fHash setStringValue: [torrent hash]];
    93     }
    94 
    95     [self updateInfoStatsForTorrents: torrents];
    96 }
    97 
    98 - (void) updateInfoStatsForTorrents: (NSArray *) torrents
    99 {
    100     int numberSelected = [torrents count];
     139        Torrent * torrent = [fTorrents objectAtIndex: 0];
     140       
     141        [fImageView setImage: [torrent icon]];
     142       
     143        NSString * name = [torrent name];
     144        [fNameField setStringValue: name];
     145        [fNameField setToolTip: name];
     146        [fSizeField setStringValue: [NSString stringForFileSize: [torrent size]]];
     147       
     148        NSString * tracker = [torrent tracker], * announce = [torrent announce];
     149        [fTrackerField setStringValue: tracker];
     150        [fTrackerField setToolTip: tracker];
     151        [fAnnounceField setStringValue: announce];
     152        [fAnnounceField setToolTip: announce];
     153        [fPieceSizeField setStringValue: [NSString stringForFileSize: [torrent pieceSize]]];
     154        [fPiecesField setIntValue: [torrent pieceCount]];
     155        [fHashField setStringValue: [torrent hashString]];
     156       
     157        [fTorrentLocationField setStringValue: [[torrent torrentLocation]
     158                                        stringByAbbreviatingWithTildeInPath]];
     159        [fTorrentLocationField setToolTip: [torrent torrentLocation]];
     160        [fDataLocationField setStringValue: [[torrent dataLocation]
     161                                        stringByAbbreviatingWithTildeInPath]];
     162        [fDataLocationField setToolTip: [torrent dataLocation]];
     163        [fDateStartedField setObjectValue: [torrent date]];
     164    }
     165    [self updateInfoStats];
     166
     167    //set file table
     168    [fFiles removeAllObjects];
     169   
     170    Torrent * torrent;
     171    NSEnumerator * enumerator = [fTorrents objectEnumerator];
     172    while ((torrent = [enumerator nextObject]))
     173        [fFiles addObjectsFromArray: [torrent fileList]];
     174   
     175    [fFileTable deselectAll: nil];
     176    [fFileTable reloadData];
     177   
     178    //set ratio settings
    101179    if (numberSelected > 0)
    102180    {
     181        NSEnumerator * enumerator = [fTorrents objectEnumerator];
     182        Torrent * torrent = [enumerator nextObject]; //first torrent
     183        const int INVALID = -99;
     184        int ratioSetting = [torrent stopRatioSetting];
     185        float ratioLimit = [torrent ratioLimit];
     186       
     187        while ((ratioSetting != INVALID || ratioLimit != INVALID)
     188                && (torrent = [enumerator nextObject]))
     189        {
     190            if (ratioSetting != INVALID && ratioSetting != [torrent stopRatioSetting])
     191                ratioSetting = INVALID;
     192           
     193            if (ratioLimit != INVALID && ratioLimit != [torrent ratioLimit])
     194                ratioLimit = INVALID;
     195        }
     196       
     197        [fRatioMatrix setEnabled: YES];
     198       
     199        if (ratioSetting == RATIO_CHECK)
     200        {
     201            [fRatioMatrix selectCellWithTag: RATIO_CHECK_TAG];
     202            [fRatioLimitField setEnabled: YES];
     203        }
     204        else
     205        {
     206            if (ratioSetting == RATIO_NO_CHECK)
     207                [fRatioMatrix selectCellWithTag: RATIO_NO_CHECK_TAG];
     208            else if (ratioSetting == RATIO_GLOBAL)
     209                [fRatioMatrix selectCellWithTag: RATIO_GLOBAL_TAG];
     210            else
     211                [fRatioMatrix deselectAllCells];
     212           
     213            [fRatioLimitField setEnabled: NO];
     214        }
     215       
     216        if (ratioLimit != INVALID)
     217            [fRatioLimitField setFloatValue: ratioLimit];
     218        else
     219            [fRatioLimitField setStringValue: @""];
     220    }
     221    else
     222    {
     223        [fRatioMatrix deselectAllCells];
     224        [fRatioMatrix setEnabled: NO];
     225       
     226        [fRatioLimitField setEnabled: NO];
     227        [fRatioLimitField setStringValue: @""];
     228    }
     229}
     230
     231- (void) updateInfoStats
     232{
     233    int numberSelected = [fTorrents count];
     234    if (numberSelected > 0)
     235    {
     236        float downloadRate = 0, uploadRate = 0;
     237        uint64_t downloaded = 0, uploaded = 0;
    103238        Torrent * torrent;
    104         if (numberSelected == 1)
    105         {   
    106             torrent = [torrents objectAtIndex: 0];
    107            
    108             int seeders = [torrent seeders], leechers = [torrent leechers];
    109             [fSeeders setStringValue: seeders < 0 ?
    110                 @"?" : [NSString stringWithInt: seeders]];
    111             [fLeechers setStringValue: leechers < 0 ?
    112                 @"?" : [NSString stringWithInt: leechers]];
    113         }
    114    
    115         uint64_t downloaded = 0, uploaded = 0;
    116         NSEnumerator * enumerator = [torrents objectEnumerator];
     239        NSEnumerator * enumerator = [fTorrents objectEnumerator];
    117240        while ((torrent = [enumerator nextObject]))
    118241        {
     242            downloadRate += [torrent downloadRate];
     243            uploadRate += [torrent uploadRate];
     244           
    119245            downloaded += [torrent downloaded];
    120246            uploaded += [torrent uploaded];
    121247        }
    122248       
    123         [fDownloaded setStringValue: [NSString stringForFileSize: downloaded]];
    124         [fUploaded setStringValue: [NSString stringForFileSize: uploaded]];
     249        [fDownloadRateField setStringValue: [NSString stringForSpeed: downloadRate]];
     250        [fUploadRateField setStringValue: [NSString stringForSpeed: uploadRate]];
     251       
     252        [fDownloadedField setStringValue: [NSString stringForFileSize: downloaded]];
     253        [fUploadedField setStringValue: [NSString stringForFileSize: uploaded]];
     254   
     255        if (numberSelected == 1)
     256        {
     257            torrent = [fTorrents objectAtIndex: 0];
     258           
     259            [fStateField setStringValue: [torrent state]];
     260            [fPercentField setStringValue: [NSString stringWithFormat:
     261                                            @"%.2f%%", 100 * [torrent progress]]];
     262
     263            int seeders = [torrent seeders], leechers = [torrent leechers];
     264            [fSeedersField setStringValue: seeders < 0 ?
     265                @"N/A" : [NSString stringWithInt: seeders]];
     266            [fLeechersField setStringValue: leechers < 0 ?
     267                @"N/A" : [NSString stringWithInt: leechers]];
     268           
     269            BOOL active = [torrent isActive];
     270           
     271            [fConnectedPeersField setStringValue: active ? [NSString
     272                    stringWithInt: [torrent totalPeers]] : @"N/A"];
     273            [fDownloadingFromField setStringValue: active ? [NSString
     274                    stringWithInt: [torrent peersUploading]] : @"N/A"];
     275            [fUploadingToField setStringValue: active ? [NSString
     276                    stringWithInt: [torrent peersDownloading]] : @"N/A"];
     277           
     278            [fRatioField setStringValue: [NSString stringForRatioWithDownload:
     279                                                        downloaded upload: uploaded]];
     280        }
     281    }
     282}
     283
     284- (BOOL) validateMenuItem: (NSMenuItem *) menuItem
     285{
     286    SEL action = [menuItem action];
     287   
     288    if (action == @selector(revealFile:))
     289        return [fFileTable numberOfSelectedRows] > 0 &&
     290            [[[fTabView selectedTabViewItem] identifier] isEqualToString: TAB_FILES_IDENT];
     291       
     292    return YES;
     293}
     294
     295- (void) tabView: (NSTabView *) tabView didSelectTabViewItem: (NSTabViewItem *) tabViewItem
     296{
     297    NSWindow * window = [self window];
     298    NSRect frame = [window frame];
     299
     300    float height;
     301    NSString * identifier = [tabViewItem identifier];
     302    if ([identifier isEqualToString: TAB_INFO_IDENT])
     303        height = TAB_INFO_HEIGHT;
     304    else if ([identifier isEqualToString: TAB_STATUS_IDENT])
     305        height = TAB_STATUS_HEIGHT;
     306    else if ([identifier isEqualToString: TAB_OPTIONS_IDENT])
     307        height = TAB_OPTIONS_HEIGHT;
     308    else
     309        height = TAB_FILES_HEIGHT;
     310   
     311    NSView * view = [tabViewItem view];
     312    float difference = height - [view frame].size.height;
     313    frame.origin.y -= difference;
     314    frame.size.height += difference;
     315   
     316    [view setHidden: YES];
     317    [window setFrame: frame display: YES animate: YES];
     318    [view setHidden: NO];
     319}
     320
     321- (void) setNextTab
     322{
     323    if ([fTabView indexOfTabViewItem: [fTabView selectedTabViewItem]]
     324                                    == [fTabView numberOfTabViewItems] - 1)
     325        [fTabView selectFirstTabViewItem: nil];
     326    else
     327        [fTabView selectNextTabViewItem: nil];
     328}
     329
     330- (void) setPreviousTab
     331{
     332    if ([fTabView indexOfTabViewItem: [fTabView selectedTabViewItem]] == 0)
     333        [fTabView selectLastTabViewItem: nil];
     334    else
     335        [fTabView selectPreviousTabViewItem: nil];
     336}
     337
     338- (int) numberOfRowsInTableView: (NSTableView *) tableView
     339{
     340    return [fFiles count];
     341}
     342
     343- (id) tableView: (NSTableView *) tableView objectValueForTableColumn:
     344                    (NSTableColumn *) column row: (int) row
     345{
     346    NSString * file = [fFiles objectAtIndex: row];
     347    if ([[column identifier] isEqualToString: @"Icon"])
     348        return [[NSWorkspace sharedWorkspace] iconForFileType: [file pathExtension]];
     349    else
     350        return [file lastPathComponent];
     351}
     352
     353//only called on >= 10.4
     354- (NSString *) tableView: (NSTableView *) tableView toolTipForCell: (NSCell *) cell
     355        rect: (NSRectPointer) rect tableColumn: (NSTableColumn *) column
     356        row: (int) row mouseLocation: (NSPoint) mouseLocation
     357{
     358    return [fFiles objectAtIndex: row];
     359}
     360
     361- (void) revealFile: (id) sender
     362{
     363    if ([fFileTable numberOfSelectedRows] > 0)
     364        [[NSWorkspace sharedWorkspace] selectFile: [fFiles objectAtIndex: [fFileTable selectedRow]]
     365            inFileViewerRootedAtPath: nil];
     366}
     367
     368- (void) setRatioCheck: (id) sender
     369{
     370    NSButtonCell * selected = [fRatioMatrix selectedCell];
     371    int ratioSetting;
     372    if (selected == [fRatioMatrix cellWithTag: RATIO_CHECK_TAG])
     373        ratioSetting = RATIO_CHECK;
     374    else if (selected == [fRatioMatrix cellWithTag: RATIO_NO_CHECK_TAG])
     375        ratioSetting = RATIO_NO_CHECK;
     376    else
     377        ratioSetting = RATIO_GLOBAL;
     378
     379    Torrent * torrent;
     380    NSEnumerator * enumerator = [fTorrents objectEnumerator];
     381    while ((torrent = [enumerator nextObject]))
     382        [torrent setStopRatioSetting: ratioSetting];
     383   
     384    [self setRatioLimit: fRatioLimitField];
     385    [fRatioLimitField setEnabled: selected == [fRatioMatrix cellWithTag: RATIO_CHECK_TAG]];
     386}
     387
     388- (void) setRatioLimit: (id) sender
     389{
     390    Torrent * torrent;
     391    NSEnumerator * enumerator = [fTorrents objectEnumerator];
     392
     393    float ratioLimit = [sender floatValue];
     394    if (![[sender stringValue] isEqualToString:
     395            [NSString stringWithFormat: @"%.2f", ratioLimit]]
     396            || ratioLimit < 0)
     397    {
     398        NSBeep();
     399        float ratioLimit = [[enumerator nextObject] ratioLimit]; //use first torrent
     400        while ((torrent = [enumerator nextObject]))
     401            if (ratioLimit != [torrent ratioLimit])
     402            {
     403                [sender setStringValue: @""];
     404                return;
     405            }
     406       
     407        [sender setFloatValue: ratioLimit];
     408    }
     409    else
     410    {
     411        while ((torrent = [enumerator nextObject]))
     412            [torrent setRatioLimit: ratioLimit];
    125413    }
    126414}
  • trunk/macosx/MenuButton.m

    r261 r272  
    2929- (void) mouseDown: (NSEvent *) event
    3030{
    31    [self setState: NSOnState];
    32    [self highlight: YES];
    33    
    34    NSPoint location = NSMakePoint(3, -2);
    35    
    36    NSEvent * theEvent= [NSEvent mouseEventWithType: [event type]
     31    NSImage * image = [self image];
     32    [self setImage: [self alternateImage]];
     33
     34    NSPoint location = NSMakePoint(3, -2);
     35
     36    NSEvent * theEvent= [NSEvent mouseEventWithType: [event type]
    3737                        location: location
    3838                        modifierFlags: [event modifierFlags]
     
    4444                        pressure: [event pressure]];
    4545
    46    [NSMenu popUpContextMenu: [self menu] withEvent: theEvent forView: self];
    47    
    48    [self setState: NSOffState];
    49    [self highlight: NO];
     46    [NSMenu popUpContextMenu: [self menu] withEvent: theEvent forView: self];
     47
     48    [self setImage: image];
    5049}
    5150
  • trunk/macosx/PrefsController.h

    r261 r272  
    2525#import <Cocoa/Cocoa.h>
    2626#import <transmission.h>
     27#import <Sparkle/Sparkle.h>
    2728
    28 @interface PrefsController : NSObject
    29 
     29@interface PrefsController : NSWindowController
    3030{
    3131    tr_handle_t * fHandle;
    3232   
    33     IBOutlet NSPanel        * fPrefsWindow;
    3433    NSToolbar               * fToolbar;
    35     IBOutlet NSView         * fGeneralView, * fTransfersView,
    36                             * fNetworkView, * fBlankView;
     34    IBOutlet NSView         * fGeneralView, * fTransfersView, * fNetworkView;
    3735   
    3836    IBOutlet NSPopUpButton  * fFolderPopUp;
     
    4240    IBOutlet NSPopUpButton  * fUpdatePopUp;
    4341
    44     IBOutlet NSTextField    * fPortField;
    45     IBOutlet NSButton       * fUploadCheck;
    46     IBOutlet NSTextField    * fUploadField;
    47     IBOutlet NSButton       * fDownloadCheck;
    48     IBOutlet NSTextField    * fDownloadField;
     42    IBOutlet NSTextField    * fPortField, * fUploadField, * fDownloadField;
     43    IBOutlet NSButton       * fUploadCheck, * fDownloadCheck;
     44   
    4945    IBOutlet NSButton       * fRatioCheck;
    5046    IBOutlet NSTextField    * fRatioField;
    5147   
    52     IBOutlet NSMenu         * fUploadMenu, * fDownloadMenu;
    53     IBOutlet NSMenuItem     * fUploadLimitItem, * fUploadNoLimitItem,
    54                             * fDownloadLimitItem, * fDownloadNoLimitItem,
    55                             * fRatioSetItem, * fRatioNotSetItem;
    56    
    57     IBOutlet NSWindow       * fWindow;
     48    IBOutlet SUUpdater      * fUpdater;
    5849
    5950    NSString                * fDownloadFolder;
     
    6657- (void) setBadge:              (id) sender;
    6758- (void) setUpdate:             (id) sender;
     59- (void) checkUpdate;
    6860- (void) setAutoStart:          (id) sender;
    6961- (void) setDownloadLocation:   (id) sender;
     
    7163
    7264- (void) setPort:               (id) sender;
     65
     66- (void) setLimit:              (id) sender;
    7367- (void) setLimitCheck:         (id) sender;
    74 - (void) setLimit:              (id) sender;
    75 - (void) setLimitMenu:          (id) sender;
    76 - (void) setQuickSpeed:         (id) sender;
     68- (void) setLimitEnabled:       (BOOL) enable type: (NSString *) type;
     69- (void) setQuickLimit:         (int) limit type: (NSString *) type;
    7770
    7871- (void) setRatio:              (id) sender;
    7972- (void) setRatioCheck:                 (id) sender;
    80 - (void) setRatioMenu:          (id) sender;
    81 - (void) setQuickRatio:         (id) sender;
     73- (void) setRatioEnabled:       (BOOL) enable;
     74- (void) setQuickRatio:         (float) ratioLimit;
    8275
    8376@end
  • trunk/macosx/PrefsController.m

    r261 r272  
    2727#import "Utils.h"
    2828
     29#define MIN_PORT            1
     30#define MAX_PORT            65535
     31
    2932#define DOWNLOAD_FOLDER     0
    3033#define DOWNLOAD_TORRENT    2
     
    3639
    3740#define TOOLBAR_GENERAL     @"General"
    38 #define TOOLBAR_TRANSFERS    @"Transfers"
     41#define TOOLBAR_TRANSFERS   @"Transfers"
    3942#define TOOLBAR_NETWORK     @"Network"
    4043
     
    7477    [fToolbar setDelegate: self];
    7578    [fToolbar setAllowsUserCustomization: NO];
    76     [fPrefsWindow setToolbar: fToolbar];
     79    [[self window] setToolbar: fToolbar];
    7780    [fToolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
    7881    [fToolbar setSizeMode: NSToolbarSizeModeRegular];
     
    8992    [fDownloadFolder retain];
    9093
    91     if( [downloadChoice isEqualToString: @"Constant"] )
    92     {
     94    if ([downloadChoice isEqualToString: @"Constant"])
    9395        [fFolderPopUp selectItemAtIndex: DOWNLOAD_FOLDER];
    94     }
    95     else if( [downloadChoice isEqualToString: @"Torrent"] )
    96     {
     96    else if ([downloadChoice isEqualToString: @"Torrent"])
    9797        [fFolderPopUp selectItemAtIndex: DOWNLOAD_TORRENT];
    98     }
    99     else
    100     {
     98    else
    10199        [fFolderPopUp selectItemAtIndex: DOWNLOAD_ASK];
    102     }
    103100    [self updatePopUp];
    104101
     
    124121    [fUploadField setEnabled: checkUpload];
    125122   
    126     [fUploadLimitItem setTitle:
    127                 [NSString stringWithFormat: @"Limit (%d KB/s)", uploadLimit]];
    128     if (checkUpload)
    129         [fUploadLimitItem setState: NSOnState];
    130     else
    131         [fUploadNoLimitItem setState: NSOnState];
    132    
    133123    tr_setUploadLimit( fHandle, checkUpload ? uploadLimit : -1 );
    134124
     
    141131    [fDownloadField setEnabled: checkDownload];
    142132   
    143     [fDownloadLimitItem setTitle:
    144                 [NSString stringWithFormat: @"Limit (%d KB/s)", downloadLimit]];
    145     if (checkDownload)
    146         [fDownloadLimitItem setState: NSOnState];
    147     else
    148         [fDownloadNoLimitItem setState: NSOnState];
    149    
    150133    tr_setDownloadLimit( fHandle, checkDownload ? downloadLimit : -1 );
    151134   
    152135    //set ratio limit
    153136    BOOL ratioCheck = [fDefaults boolForKey: @"RatioCheck"];
    154     float ratioLimit = [fDefaults floatForKey: @"RatioLimit"];
    155 
    156137    [fRatioCheck setState: ratioCheck ? NSOnState : NSOffState];
    157138    [fRatioField setEnabled: ratioCheck];
    158     [fRatioField setFloatValue: ratioLimit];
    159    
    160     [fRatioSetItem setTitle: [NSString stringWithFormat: @"Stop at Ratio (%.1f)", ratioLimit]];
    161     if (ratioCheck)
    162         [fRatioSetItem setState: NSOnState];
    163     else
    164         [fRatioNotSetItem setState: NSOnState];
     139    [fRatioField setFloatValue: [fDefaults floatForKey: @"RatioLimit"]];
    165140   
    166141    //set remove and quit prompts
     
    177152    [fAutoStartCheck setState: [fDefaults boolForKey: @"AutoStartDownload"]];
    178153
    179     /* Check for update */
    180     NSString * versionCheck  = [fDefaults stringForKey: @"VersionCheck"];
    181     if( [versionCheck isEqualToString: @"Daily"] )
     154    //set update check
     155    NSString * updateCheck = [fDefaults stringForKey: @"UpdateCheck"];
     156    if ([updateCheck isEqualToString: @"Weekly"])
     157        [fUpdatePopUp selectItemAtIndex: UPDATE_WEEKLY];
     158    else if ([updateCheck isEqualToString: @"Never"])
     159        [fUpdatePopUp selectItemAtIndex: UPDATE_NEVER];
     160    else
    182161        [fUpdatePopUp selectItemAtIndex: UPDATE_DAILY];
    183     else if( [versionCheck isEqualToString: @"Weekly"] )
    184         [fUpdatePopUp selectItemAtIndex: UPDATE_WEEKLY];
    185     else if( [versionCheck isEqualToString: @"Never"] )
    186         [fUpdatePopUp selectItemAtIndex: UPDATE_NEVER];
    187     else
    188     {
    189         [fDefaults setObject: @"Weekly" forKey: @"VersionCheck"];
    190         [fUpdatePopUp selectItemAtIndex: UPDATE_WEEKLY];
    191     }
    192162}
    193163
     
    247217- (void) setPort: (id) sender
    248218{
    249     int bindPort = [fPortField intValue];
    250    
    251     tr_setBindPort( fHandle, bindPort );
    252     [fDefaults setInteger: bindPort forKey: @"BindPort"];
     219    int bindPort = [sender intValue];
     220    if (![[NSString stringWithInt: bindPort] isEqualToString: [sender stringValue]]
     221            || bindPort < MIN_PORT || bindPort > MAX_PORT)
     222    {
     223        NSBeep();
     224        bindPort = [fDefaults integerForKey: @"BindPort"];
     225        [sender setIntValue: bindPort];
     226    }
     227    else
     228    {
     229        tr_setBindPort( fHandle, bindPort );
     230        [fDefaults setInteger: bindPort forKey: @"BindPort"];
     231    }
    253232}
    254233
     
    256235{
    257236    NSString * key;
    258     NSMenuItem * menuItem;
     237    NSButton * check;
     238    NSString * type;
    259239    if (sender == fUploadField)
    260240    {
    261241        key = @"UploadLimit";
    262         menuItem = fUploadLimitItem;
     242        check = fUploadCheck;
     243        type = @"Upload";
    263244    }
    264245    else
    265246    {
    266247        key = @"DownloadLimit";
    267         menuItem = fDownloadLimitItem;
     248        check = fDownloadCheck;
     249        type = @"Download";
    268250    }
    269251
    270252    int limit = [sender intValue];
    271     [fDefaults setInteger: limit forKey: key];
    272    
    273     [menuItem setTitle: [NSString stringWithFormat: @"Limit (%d KB/s)", limit]];
    274 
    275     if( sender == fUploadField )
    276         tr_setUploadLimit( fHandle,
    277             ( [fUploadCheck state] == NSOffState ) ? -1 : limit );
    278     else
    279         tr_setDownloadLimit( fHandle,
    280             ( [fDownloadCheck state] == NSOffState ) ? -1 : limit );
     253    if (![[sender stringValue] isEqualToString:
     254            [NSString stringWithFormat: @"%d", limit]]
     255            || limit < 0)
     256    {
     257        NSBeep();
     258        limit = [fDefaults integerForKey: key];
     259        [sender setIntValue: limit];
     260    }
     261    else
     262    {
     263        if( sender == fUploadField )
     264            tr_setUploadLimit( fHandle,
     265                ( [fUploadCheck state] == NSOffState ) ? -1 : limit );
     266        else
     267            tr_setDownloadLimit( fHandle,
     268                ( [fDownloadCheck state] == NSOffState ) ? -1 : limit );
     269       
     270        [fDefaults setInteger: limit forKey: key];
     271    }
     272   
     273    NSDictionary * dict = [[NSDictionary alloc] initWithObjectsAndKeys:
     274                                    [NSNumber numberWithBool: [check state]], @"Enable",
     275                                    [NSNumber numberWithInt: limit], @"Limit",
     276                                    type, @"Type", nil];
     277    [[NSNotificationCenter defaultCenter] postNotificationName:
     278                            @"LimitGlobalChange" object: dict];
    281279}
    282280
     
    285283    NSString * key;
    286284    NSTextField * field;
    287     NSMenuItem * limitItem, * noLimitItem;
    288     if( sender == fUploadCheck )
     285    if (sender == fUploadCheck)
    289286    {
    290287        key = @"CheckUpload";
    291288        field = fUploadField;
    292         limitItem = fUploadLimitItem;
    293         noLimitItem = fUploadNoLimitItem;
    294289    }
    295290    else
     
    297292        key = @"CheckDownload";
    298293        field = fDownloadField;
    299         limitItem = fDownloadLimitItem;
    300         noLimitItem = fDownloadNoLimitItem;
    301     }
    302 
     294    }
     295   
    303296    BOOL check = [sender state] == NSOnState;
    304     [limitItem setState: check ? NSOnState : NSOffState];
    305     [noLimitItem setState: !check ? NSOnState : NSOffState];
     297    [self setLimit: field];
     298    [field setEnabled: check];
    306299   
    307300    [fDefaults setBool: check forKey: key];
    308    
    309     [field setIntValue: [field intValue]]; //set to valid value
    310     [self setLimit: field];
    311    
    312     [field setEnabled: check];
    313 }
    314 
    315 - (void) setLimitMenu: (id) sender
    316 {
    317     NSButton * check = (sender == fUploadLimitItem || sender == fUploadNoLimitItem)
     301}
     302
     303- (void) setLimitEnabled: (BOOL) enable type: (NSString *) type
     304{
     305    NSButton * check = [type isEqualToString: @"Upload"]
    318306                        ? fUploadCheck : fDownloadCheck;
    319     int state = (sender == fUploadLimitItem || sender == fDownloadLimitItem)
    320                     ? NSOnState : NSOffState;
    321                
    322     [check setState: state];
     307    [check setState: enable ? NSOnState : NSOffState];
    323308    [self setLimitCheck: check];
    324309}
    325310
    326 - (void) setQuickSpeed: (id) sender
    327 {
    328     NSString * title = [sender title];
    329     int limit = [[title substringToIndex: [title length] - [@" KB/s" length]] intValue];
    330    
    331     if ([sender menu] == fUploadMenu)
     311- (void) setQuickLimit: (int) limit type: (NSString *) type
     312{
     313    NSButton * check;
     314    if ([type isEqualToString: @"Upload"])
    332315    {
    333316        [fUploadField setIntValue: limit];
    334         [self setLimitMenu: fUploadLimitItem];
     317        check = fUploadCheck;
    335318    }
    336319    else
    337320    {
    338321        [fDownloadField setIntValue: limit];
    339         [self setLimitMenu: fDownloadLimitItem];
    340     }
     322        check = fDownloadCheck;
     323    }
     324    [check setState: NSOnState];
     325    [self setLimitCheck: check];
    341326}
    342327
    343328- (void) setRatio: (id) sender
    344329{
    345     float ratio = [sender floatValue];
    346     [fDefaults setFloat: ratio forKey: @"RatioLimit"];
    347    
    348     [fRatioSetItem setTitle: [NSString stringWithFormat: @"Stop at Ratio (%.1f)", ratio]];
     330    float ratioLimit = [sender floatValue];
     331    if (![[sender stringValue] isEqualToString:
     332            [NSString stringWithFormat: @"%.2f", ratioLimit]]
     333            || ratioLimit < 0)
     334    {
     335        NSBeep();
     336        ratioLimit = [fDefaults floatForKey: @"RatioLimit"];
     337        [sender setFloatValue: ratioLimit];
     338    }
     339    else
     340        [fDefaults setFloat: ratioLimit forKey: @"RatioLimit"];
     341   
     342    NSDictionary * dict = [[NSDictionary alloc] initWithObjectsAndKeys:
     343                                    [NSNumber numberWithBool: [fRatioCheck state]], @"Enable",
     344                                    [NSNumber numberWithFloat: ratioLimit], @"Ratio", nil];
     345    [[NSNotificationCenter defaultCenter] postNotificationName:
     346                                @"RatioGlobalChange" object: dict];
    349347}
    350348
     
    352350{
    353351    BOOL check = [sender state] == NSOnState;
     352    [self setRatio: fRatioField];
     353    [fRatioField setEnabled: check];
    354354   
    355355    [fDefaults setBool: check forKey: @"RatioCheck"];
    356    
    357     [fRatioField setFloatValue: [fRatioField floatValue]]; //set to valid value
    358     [self setRatio: fRatioField];
    359    
    360     [fRatioField setEnabled: check];
    361    
    362     [fRatioSetItem setState: check ? NSOnState : NSOffState];
    363     [fRatioNotSetItem setState: !check ? NSOnState : NSOffState];
    364 }
    365 
    366 - (void) setRatioMenu: (id) sender
    367 {
    368     int state = sender == fRatioSetItem ? NSOnState : NSOffState;
    369                
     356}
     357
     358- (void) setRatioEnabled: (BOOL) enable
     359{
     360    int state = enable ? NSOnState : NSOffState;
     361   
    370362    [fRatioCheck setState: state];
    371363    [self setRatioCheck: fRatioCheck];
    372364}
    373365
    374 - (void) setQuickRatio: (id) sender
    375 {
    376     float limit = [[sender title] floatValue];
    377 
    378     [fRatioField setFloatValue: limit];
    379     [self setRatioMenu: fRatioSetItem];
     366- (void) setQuickRatio: (float) ratioLimit
     367{
     368    [fRatioField setFloatValue: ratioLimit];
     369   
     370    [fRatioCheck setState: NSOnState];
     371    [self setRatioCheck: fRatioCheck];
    380372}
    381373
     
    400392- (void) setUpdate: (id) sender
    401393{
    402     switch( [fUpdatePopUp indexOfSelectedItem] )
    403     {
    404         case UPDATE_DAILY:
    405             [fDefaults setObject: @"Daily" forKey: @"VersionCheck"];
    406             break;
    407         case UPDATE_WEEKLY:
    408             [fDefaults setObject: @"Weekly" forKey: @"VersionCheck"];
    409             break;
    410         case UPDATE_NEVER:
    411             [fDefaults setObject: @"Never" forKey: @"VersionCheck"];
    412             break;
    413     }
     394    NSString * schedule;
     395    int index = [fUpdatePopUp indexOfSelectedItem];
     396    NSTimeInterval seconds;
     397    if (index == UPDATE_DAILY)
     398    {
     399        [fDefaults setObject: @"Daily" forKey: @"UpdateCheck"];
     400        seconds = 86400;
     401    }
     402    else if (index == UPDATE_WEEKLY)
     403    {
     404        [fDefaults setObject: @"Weekly" forKey: @"UpdateCheck"];
     405        seconds = 604800;
     406    }
     407    else
     408    {
     409        [fDefaults setObject: @"Never" forKey: @"UpdateCheck"];
     410        seconds = 0;
     411    }
     412
     413    [fDefaults setInteger: seconds forKey: @"SUScheduledCheckInterval"];
     414    [fUpdater scheduleCheckWithInterval: seconds];
    414415}
    415416
     
    436437}
    437438
     439- (void) checkUpdate
     440{
     441    [fUpdater checkForUpdates: nil];
     442}
     443
    438444- (void) folderSheetShow: (id) sender
    439445{
     
    446452
    447453    [panel beginSheetForDirectory: NULL file: NULL types: NULL
    448         modalForWindow: fPrefsWindow modalDelegate: self didEndSelector:
     454        modalForWindow: [self window] modalDelegate: self didEndSelector:
    449455        @selector( folderSheetClosed:returnCode:contextInfo: )
    450456        contextInfo: NULL];
    451457}
    452458
    453 @end // @implementation PrefsController
     459@end
    454460
    455461@implementation PrefsController (Private)
     
    472478- (void) setPrefView: (NSView *) view
    473479{
    474     NSRect windowRect = [fPrefsWindow frame];
    475     int difference = [view frame].size.height - [[fPrefsWindow contentView] frame].size.height;
    476 
     480    NSWindow * window = [self window];
     481   
     482    NSRect windowRect = [window frame];
     483    int difference = [view frame].size.height - [[window contentView] frame].size.height;
    477484    windowRect.origin.y -= difference;
    478485    windowRect.size.height += difference;
    479    
    480     [fPrefsWindow setTitle: [fToolbar selectedItemIdentifier]];
    481     [fPrefsWindow setContentView: fBlankView];
    482     [fPrefsWindow setFrame: windowRect display: YES animate: YES];
    483     [fPrefsWindow setContentView: view];
     486
     487    [window setTitle: [fToolbar selectedItemIdentifier]];
     488   
     489    [window setContentView: view];
     490    [view setHidden: YES];
     491    [window setFrame: windowRect display: YES animate: YES];
     492    [view setHidden: NO];
    484493}
    485494
     
    520529- (void) updatePopUp
    521530{
    522     NSMenuItem     * menuItem;
    523     NSImage        * image32, * image16;
    524 
    525531    // Get the icon for the folder
    526     image32 = [[NSWorkspace sharedWorkspace] iconForFile:
     532    NSImage * image32 = [[NSWorkspace sharedWorkspace] iconForFile:
    527533                fDownloadFolder];
    528     image16 = [[NSImage alloc] initWithSize: NSMakeSize(16,16)];
     534    NSImage * image16 = [[NSImage alloc] initWithSize: NSMakeSize(16,16)];
    529535
    530536    // 32x32 -> 16x16 scaling
     
    538544
    539545    // Update the menu item
    540     menuItem = (NSMenuItem *) [fFolderPopUp itemAtIndex: 0];
     546    NSMenuItem * menuItem = (NSMenuItem *) [fFolderPopUp itemAtIndex: 0];
    541547    [menuItem setTitle: [fDownloadFolder lastPathComponent]];
    542548    [menuItem setImage: image16];
     
    545551}
    546552
    547 @end /* @implementation PrefsController (Private) */
     553@end
  • trunk/macosx/StringAdditions.h

    r261 r272  
    2828
    2929+ (NSString *) stringWithInt: (int) value;
     30
    3031+ (NSString *) stringForFileSize: (uint64_t) size;
    3132+ (NSString *) stringForSpeed: (float) speed;
    3233+ (NSString *) stringForSpeedAbbrev: (float) speed;
    33 + (NSString *) stringForRatio: (uint64_t) down upload: (uint64_t) up;
    34 - (NSString *) stringFittingInWidth: (float) width
    35                                         withAttributes: (NSDictionary *) attributes;
     34+ (NSString *) stringForRatioWithDownload: (uint64_t) down upload: (uint64_t) up;
     35
     36- (NSAttributedString *) attributedStringFittingInWidth: (float) width
     37                                attributes: (NSDictionary *) attributes;
    3638
    3739@end
  • trunk/macosx/StringAdditions.m

    r261 r272  
    9191}
    9292
    93 + (NSString *) stringForRatio: (uint64_t) down upload: (uint64_t) up
     93+ (NSString *) stringForRatioWithDownload: (uint64_t) down upload: (uint64_t) up
    9494{
    95     if( !down && !up )
    96         return @"N/A";
    97     if( !down )
    98         return [NSString stringWithUTF8String: "\xE2\x88\x9E"];
     95    if (down == 0)
     96        return up == 0 ? @"N/A" : [NSString stringWithUTF8String: "\xE2\x88\x9E"];
    9997
    10098    float ratio = (float) up / (float) down;
     
    107105}
    108106
    109 - (NSString *) stringFittingInWidth: (float) width
    110                     withAttributes: (NSDictionary *) attributes
     107- (NSAttributedString *) attributedStringFittingInWidth: (float) width
     108                                attributes: (NSDictionary *) attributes
    111109{
    112110    int i;
     
    115113    /* The whole string fits */
    116114    if( realWidth <= width )
    117         return self;
    118        
     115        return [[[NSAttributedString alloc] initWithString: self attributes: attributes] autorelease];
     116   
     117    float ellipsisWidth = [NS_ELLIPSIS sizeWithAttributes: attributes].width;
     118   
    119119    /* Width is too small */
    120     if ( [NS_ELLIPSIS sizeWithAttributes: attributes].width > width )
    121         return @"";
     120    if ( ellipsisWidth > width )
     121        return [[[NSAttributedString alloc] initWithString: @"" attributes: attributes] autorelease];
    122122
    123123    /* Don't worry about ellipsis until the end */
    124     width -= [NS_ELLIPSIS sizeWithAttributes: attributes].width;
     124    width -= ellipsisWidth;
    125125
    126126    /* Approximate how many characters we'll need to drop... */
     
    151151    else;
    152152
    153     return [newString stringByAppendingString: NS_ELLIPSIS];
     153    return [[[NSAttributedString alloc] initWithString: [newString stringByAppendingString: NS_ELLIPSIS]
     154                                        attributes: attributes] autorelease];
    154155}
    155156
  • trunk/macosx/Torrent.h

    r261 r272  
    2626#import <transmission.h>
    2727
     28#define RATIO_CHECK 1
     29#define RATIO_GLOBAL -1
     30#define RATIO_NO_CHECK 0
     31
    2832@interface Torrent : NSObject
    2933{
     
    3741    NSUserDefaults  * fDefaults;
    3842
    39     NSImage         * fIcon;
    40     NSImage         * fIconNonFlipped;
    41     NSMutableString * fStatusString;
    42     NSMutableString * fInfoString;
    43     NSMutableString * fDownloadString;
    44     NSMutableString * fUploadString;
     43    NSImage         * fIcon, * fIconFlipped;
     44    NSMutableString * fNameString, * fProgressString, * fStatusString;
    4545   
    4646    int     fStopRatioSetting;
     
    5252- (NSDictionary *) history;
    5353                   
    54 - (void)       setFolder: (NSString *) path;
    55 - (NSString *) getFolder;
     54- (void)       setDownloadFolder: (NSString *) path;
     55- (NSString *) downloadFolder;
    5656- (void)       getAvailability: (int8_t *) tab size: (int) size;
    5757
     
    6262- (void)       wakeUp;
    6363
    64 - (float)      ratio;
    65 - (int)        stopRatioSetting;
    66 - (void)       setStopRatioSetting: (int) setting;
    67 - (float)      ratioLimit;
    68 - (void)       setRatioLimit: (float) limit;
     64- (float)       ratio;
     65- (int)         stopRatioSetting;
     66- (void)        setStopRatioSetting: (int) setting;
     67- (float)       ratioLimit;
     68- (void)        setRatioLimit: (float) limit;
    6969
    70 - (NSNumber *) stateSortKey;
    71 
    72 - (void)       reveal;
    73 - (void)       trashTorrent;
    74 - (void)       trashData;
     70- (void)        reveal;
     71- (void)        trashTorrent;
     72- (void)        trashData;
    7573
    7674- (NSImage *)  icon;
    77 - (NSImage *)  iconNonFlipped;
    78 - (NSString *) path;
     75- (NSImage *)  iconFlipped;
     76
    7977- (NSString *) name;
    8078- (uint64_t)   size;
     
    8381- (int)        pieceSize;
    8482- (int)        pieceCount;
    85 - (NSString *) hash;
     83- (NSString *) hashString;
     84- (NSString *) torrentLocation;
     85- (NSString *) dataLocation;
    8686
    87 - (float)      progress;
    88 - (BOOL)       isActive;
    89 - (BOOL)       isSeeding;
    90 - (BOOL)       isPaused;
    91 - (BOOL)       justFinished;
    92 - (NSString *) statusString;
    93 - (NSString *) infoString;
    94 - (NSString *) downloadString;
    95 - (NSString *) uploadString;
    96 - (int)        seeders;
    97 - (int)        leechers;
    98 - (uint64_t)   downloaded;
    99 - (uint64_t)   uploaded;
    100 - (NSDate *)   date;
     87- (NSString *) state;
     88
     89- (float)   progress;
     90- (BOOL)    isActive;
     91- (BOOL)    isSeeding;
     92- (BOOL)    isPaused;
     93- (BOOL)    justFinished;
     94
     95- (NSString *)  progressString;
     96- (NSString *)  statusString;
     97
     98- (int) seeders;
     99- (int) leechers;
     100- (int) totalPeers;
     101- (int) peersUploading;
     102- (int) peersDownloading;
     103
     104- (float)       downloadRate;
     105- (float)       uploadRate;
     106- (uint64_t)    downloaded;
     107- (uint64_t)    uploaded;
     108
     109- (NSArray *) fileList;
     110
     111- (NSDate *) date;
     112- (NSNumber *) stateSortKey;
     113- (NSNumber *) progressSortKey;
    101114
    102115@end
  • trunk/macosx/Torrent.m

    r261 r272  
    5858            downloadFolder = [[fDefaults stringForKey: @"DownloadFolder"]
    5959                                stringByExpandingTildeInPath];
    60         [self setFolder: downloadFolder];
     60        [self setDownloadFolder: downloadFolder];
    6161
    6262        NSString * paused;
     
    6464            [self start];
    6565    }
    66    
    6766    return self;
    6867}
     
    7170{
    7271    return [NSDictionary dictionaryWithObjectsAndKeys:
    73             [self path], @"TorrentPath",
    74             [self getFolder], @"DownloadFolder",
     72            [self torrentLocation], @"TorrentPath",
     73            [self downloadFolder], @"DownloadFolder",
    7574            [self isActive] ? @"NO" : @"YES", @"Paused",
    7675            [self date], @"Date",
     
    8786        [fDate release];
    8887        [fIcon release];
    89         [fIconNonFlipped release];
     88        [fIconFlipped release];
     89        [fProgressString release];
    9090        [fStatusString release];
    91         [fInfoString release];
    92         [fDownloadString release];
    93         [fUploadString release];
    9491    }
    9592    [super dealloc];
    9693}
    9794
    98 - (void) setFolder: (NSString *) path
     95- (void) setDownloadFolder: (NSString *) path
    9996{
    10097    tr_torrentSetFolder( fHandle, [path UTF8String] );
    10198}
    10299
    103 - (NSString *) getFolder
     100- (NSString *) downloadFolder
    104101{
    105102    return [NSString stringWithUTF8String: tr_torrentGetFolder( fHandle )];
     
    116113   
    117114    if ([self isSeeding])
    118         if ((fStopRatioSetting == 1 && [self ratio] >= fRatioLimit)
    119             || (fStopRatioSetting == -1 && [fDefaults boolForKey: @"RatioCheck"]
     115        if ((fStopRatioSetting == RATIO_CHECK && [self ratio] >= fRatioLimit)
     116            || (fStopRatioSetting == RATIO_GLOBAL && [fDefaults boolForKey: @"RatioCheck"]
    120117                && [self ratio] >= [fDefaults floatForKey: @"RatioLimit"]))
    121118        {
    122119            [self stop];
    123             [self setStopRatioSetting: 0];
     120            [self setStopRatioSetting: RATIO_NO_CHECK];
    124121           
    125122            fStat = tr_torrentStat( fHandle );
     123           
     124            [[NSNotificationCenter defaultCenter] postNotificationName:
     125                @"TorrentRatioChanged" object: self];
    126126        }
    127 
    128     [fStatusString setString: @""];
    129     [fInfoString setString: @""];
     127   
     128    [fProgressString setString: @""];
     129    if ([self progress] < 1.0)
     130        [fProgressString appendFormat: @"%@ of %@ completed (%.2f%%)", [NSString stringForFileSize:
     131                [self downloaded]], [NSString stringForFileSize: [self size]], 100 * [self progress]];
     132    else
     133        [fProgressString appendFormat: @"%@, uploaded %@ (ratio: %@)", [NSString stringForFileSize:
     134                [self size]], [NSString stringForFileSize: [self uploaded]],
     135                [NSString stringForRatioWithDownload: [self downloaded] upload: [self uploaded]]];
    130136
    131137    switch( fStat->status )
    132138    {
    133139        case TR_STATUS_PAUSE:
    134             [fStatusString appendFormat: @"Paused (%.2f %%)",
    135                 100 * fStat->progress];
     140            [fStatusString setString: @"Paused"];
    136141            break;
    137142
    138143        case TR_STATUS_CHECK:
     144            [fStatusString setString: [@"Checking existing files" stringByAppendingString: NS_ELLIPSIS]];
     145            break;
     146
     147        case TR_STATUS_DOWNLOAD:
     148            [fStatusString setString: @""];
    139149            [fStatusString appendFormat:
    140                 @"Checking existing files (%.2f %%)",
    141                 100 * fStat->progress];
    142             break;
    143 
    144         case TR_STATUS_DOWNLOAD:
    145             if( fStat->eta < 0 )
    146             {
    147                 [fStatusString appendFormat:
    148                     @"Finishing in --:--:-- (%.2f %%)",
    149                     100 * fStat->progress];
    150             }
     150                @"Downloading from %d of %d peer%s",
     151                [self peersUploading], [self totalPeers],
     152                ([self totalPeers] == 1) ? "" : "s"];
     153           
     154            int eta = fStat->eta;
     155            if (eta < 0)
     156                [fProgressString appendString: @" - remaining time unknown"];
    151157            else
    152158            {
    153                 [fStatusString appendFormat:
    154                     @"Finishing in %02d:%02d:%02d (%.2f %%)",
    155                     fStat->eta / 3600, ( fStat->eta / 60 ) % 60,
    156                     fStat->eta % 60, 100 * fStat->progress];
     159                if (eta < 60)
     160                    [fProgressString appendFormat: @" - %d sec remaining", eta];
     161                else if (eta < 3600)
     162                    [fProgressString appendFormat: @" - %d min %02d sec remaining",
     163                                                    eta / 60, eta % 60];
     164                else
     165                    [fProgressString appendFormat: @" - %d hr %02d min remaining",
     166                                                    eta / 3600, (eta / 60) % 60];
    157167            }
    158             [fInfoString appendFormat:
    159                 @"Downloading from %d of %d peer%s",
    160                 fStat->peersUploading, fStat->peersTotal,
    161                 ( fStat->peersTotal == 1 ) ? "" : "s"];
    162168            break;
    163169
    164170        case TR_STATUS_SEED:
     171            [fStatusString setString: @""];
    165172            [fStatusString appendFormat:
    166                 @"Seeding, uploading to %d of %d peer%s",
    167                 fStat->peersDownloading, fStat->peersTotal,
    168                 ( fStat->peersTotal == 1 ) ? "" : "s"];
     173                @"Seeding to %d of %d peer%s",
     174                [self peersDownloading], [self totalPeers],
     175                ([self totalPeers] == 1) ? "" : "s"];
    169176            break;
    170177
    171178        case TR_STATUS_STOPPING:
    172             [fStatusString setString: [@"Stopping"
    173                 stringByAppendingString: NS_ELLIPSIS]];
    174             break;
    175     }
    176 
     179            [fStatusString setString: [@"Stopping" stringByAppendingString: NS_ELLIPSIS]];
     180            break;
     181    }
     182   
    177183    if( fStat->error & TR_ETRACKER )
    178184    {
    179         [fInfoString setString: [@"Error: " stringByAppendingString:
     185        [fStatusString setString: [@"Error: " stringByAppendingString:
    180186            [NSString stringWithUTF8String: fStat->trackerError]]];
    181187    }
    182188
    183     if( fStat->progress == 1.0 )
    184     {
    185         [fDownloadString setString: [@"Ratio: " stringByAppendingString:
    186             [NSString stringForRatio: fStat->downloaded
    187             upload: fStat->uploaded]]];
    188     }
    189     else
    190     {
    191         [fDownloadString setString: [@"DL: " stringByAppendingString:
    192             [NSString stringForSpeed: fStat->rateDownload]]];
    193     }
    194     [fUploadString setString: [@"UL: " stringByAppendingString:
    195         [NSString stringForSpeed: fStat->rateUpload]]];
     189    if ([self isActive])
     190    {
     191        if ([self progress] < 1.0)
     192            [fStatusString appendFormat: @" - DL: %@, ", [NSString stringForSpeed: [self downloadRate]]];
     193        [fStatusString appendString: [@"UL: " stringByAppendingString:
     194                                                [NSString stringForSpeed: [self uploadRate]]]];
     195    }
    196196}
    197197
     
    230230- (float) ratio
    231231{
    232     uint64_t downloaded = [self downloaded];
    233     return downloaded > 0 ? [self uploaded] / downloaded : -1;
    234 }
    235 
    236 /*  1: Check ratio
    237     0: Don't check ratio
    238    -1: Use defaults */
     232    float downloaded = [self downloaded];
     233    return downloaded > 0 ? (float)[self uploaded] / downloaded : -1;
     234}
     235
    239236- (int) stopRatioSetting
    240237{
     
    260257- (void) reveal
    261258{
    262     [[NSWorkspace sharedWorkspace] selectFile: [[self getFolder]
    263         stringByAppendingPathComponent: [self name]]
     259    [[NSWorkspace sharedWorkspace] selectFile: [self dataLocation]
    264260        inFileViewerRootedAtPath: nil];
    265261}
     
    267263- (void) trashTorrent
    268264{
    269     [self trashPath: [self path]];
     265    [self trashPath: [self torrentLocation]];
    270266}
    271267
    272268- (void) trashData
    273269{
    274     [self trashPath: [[self getFolder]
    275         stringByAppendingPathComponent: [self name]]];
     270    [self trashPath: [self dataLocation]];
    276271}
    277272
     
    281276}
    282277
    283 - (NSImage *) iconNonFlipped
    284 {
    285     return fIconNonFlipped;
    286 }
    287 
    288 - (NSString *) path
    289 {
    290     return [NSString stringWithUTF8String: fInfo->torrent];
     278- (NSImage *) iconFlipped
     279{
     280    return fIconFlipped;
    291281}
    292282
     
    322312}
    323313
    324 - (NSString *) hash
     314- (NSString *) hashString
    325315{
    326316    NSMutableString * string = [NSMutableString
     
    334324}
    335325
     326- (NSString *) torrentLocation
     327{
     328    return [NSString stringWithUTF8String: fInfo->torrent];;
     329}
     330
     331- (NSString *) dataLocation
     332{
     333    return [[self downloadFolder] stringByAppendingPathComponent: [self name]];
     334}
     335
     336- (NSString *) state
     337{
     338    switch( fStat->status )
     339    {
     340        case TR_STATUS_PAUSE:
     341            return @"Paused";
     342            break;
     343
     344        case TR_STATUS_CHECK:
     345            return [@"Checking existing files" stringByAppendingString: NS_ELLIPSIS];
     346            break;
     347
     348        case TR_STATUS_DOWNLOAD:
     349            return @"Downloading";
     350            break;
     351
     352        case TR_STATUS_SEED:
     353            return @"Seeding";
     354            break;
     355
     356        case TR_STATUS_STOPPING:
     357            return [@"Stopping" stringByAppendingString: NS_ELLIPSIS];
     358            break;
     359       
     360        default:
     361            return @"N/A";
     362    }
     363}
     364
    336365- (float) progress
    337366{
     
    359388}
    360389
     390- (NSString *) progressString
     391{
     392    return fProgressString;
     393}
     394
    361395- (NSString *) statusString
    362396{
     
    364398}
    365399
    366 - (NSString *) infoString
    367 {
    368     return fInfoString;
    369 }
    370 
    371 - (NSString *) downloadString
    372 {
    373     return fDownloadString;
    374 }
    375 
    376 - (NSString *) uploadString
    377 {
    378     return fUploadString;
    379 }
    380 
    381400- (int) seeders
    382401{
     
    389408}
    390409
     410- (int) totalPeers
     411{
     412    return fStat->peersTotal;
     413}
     414
     415//peers uploading to you
     416- (int) peersUploading
     417{
     418    return fStat->peersUploading;
     419}
     420
     421//peers downloading from you
     422- (int) peersDownloading
     423{
     424    return fStat->peersDownloading;
     425}
     426
     427- (float) downloadRate
     428{
     429    return fStat->rateDownload;
     430}
     431
     432- (float) uploadRate
     433{
     434    return fStat->rateUpload;
     435}
     436
    391437- (uint64_t) downloaded
    392438{
     
    397443{
    398444    return fStat->uploaded;
     445}
     446
     447- (NSArray *) fileList
     448{
     449    int count = fInfo->fileCount, i;
     450    NSMutableArray * files = [NSMutableArray arrayWithCapacity: count];
     451    for (i = 0; i < count; i++)
     452        [files addObject: [[self downloadFolder] stringByAppendingPathComponent:
     453            [NSString stringWithUTF8String: fInfo->files[i].name]]];
     454    return files;
    399455}
    400456
     
    414470}
    415471
     472- (NSNumber *) progressSortKey
     473{
     474    return [NSNumber numberWithFloat: [self progress]];
     475}
     476
    416477@end
    417478
     
    445506        NSFileTypeForHFSTypeCode('fldr') : [[self name] pathExtension];
    446507    fIcon = [[NSWorkspace sharedWorkspace] iconForFileType: fileType];
    447     [fIcon setFlipped: YES];
    448508    [fIcon retain];
    449     fIconNonFlipped = [[NSWorkspace sharedWorkspace] iconForFileType: fileType];
    450     [fIconNonFlipped retain];
    451 
    452     fStatusString   = [[NSMutableString alloc] initWithCapacity: 50];
    453     fInfoString     = [[NSMutableString alloc] initWithCapacity: 50];
    454     fDownloadString = [[NSMutableString alloc] initWithCapacity: 10];
    455     fUploadString   = [[NSMutableString alloc] initWithCapacity: 10];
     509   
     510    fIconFlipped = [fIcon copy];
     511    [fIconFlipped setFlipped: YES];
     512
     513    fProgressString = [[NSMutableString alloc] initWithCapacity: 50];
     514    fStatusString = [[NSMutableString alloc] initWithCapacity: 75];
    456515
    457516    [self update];
  • trunk/macosx/TorrentCell.h

    r261 r272  
    3131@interface TorrentCell : NSCell
    3232{
    33     Torrent          * fTorrent;
    34     NSColor          * fTextColor;
    35 
    36     NSBitmapImageRep * fBitmap;
    37     int                fWidth;
    38     int8_t           * fPieces;
     33    Torrent * fTorrent;
    3934}
    4035- (void) setTorrent:   (Torrent *) torrent;
    41 - (void) setTextColor: (NSColor *) color;
    4236@end
    4337
  • trunk/macosx/TorrentCell.m

    r261 r272  
    9797}
    9898
    99 - (void) setTextColor: (NSColor *) color
    100 {
    101     fTextColor = color;
    102 }
    103 
    104 /***********************************************************************
    105  * init
    106  ***********************************************************************
    107  * Prepares the NSBitmapImageReps we are going to need in order to
    108  * draw.
    109  **********************************************************************/
    110 - (id) init
    111 {
    112     self = [super init];
    113 
    114     return self;
    115 }
    116 
    117 /***********************************************************************
    118  * buildSimpleBar
    119  **********************************************************************/
    120 - (void) buildSimpleBar
     99- (void) buildSimpleBar: (int) width bitmap: (NSBitmapImageRep *) bitmap
    121100{
    122101    int        h, w, end, pixelsPerRow;
     
    124103    uint32_t * colors;
    125104
    126     pixelsPerRow = [fBitmap bytesPerRow] / 4;
    127 
    128     p   = (uint32_t *) [fBitmap bitmapData] + 1;
    129     end = lrintf( floor( [fTorrent progress] * ( fWidth - 2 ) ) );
     105    pixelsPerRow = [bitmap bytesPerRow] / 4;
     106
     107    p   = (uint32_t *) [bitmap bitmapData] + 1;
     108    end = lrintf( floor( [fTorrent progress] * ( width - 2 ) ) );
    130109
    131110    if( [fTorrent isSeeding] )
     
    142121            p[w] = htonl( colors[h] );
    143122        }
    144         for( w = end; w < fWidth - 2; w++ )
     123        for( w = end; w < width - 2; w++ )
    145124        {
    146125            p[w] = htonl( kBack[h] );
     
    150129}
    151130
    152 /***********************************************************************
    153  * buildAdvancedBar
    154  **********************************************************************/
    155 - (void) buildAdvancedBar
     131- (void) buildAdvancedBar: (int) width bitmap: (NSBitmapImageRep *) bitmap
    156132{
    157133    int      h, w, end, pixelsPerRow;
    158134    uint32_t * p, * colors;
    159     uint8_t  * bitmapData  = [fBitmap bitmapData];
    160     int        bytesPerRow = [fBitmap bytesPerRow];
    161 
    162     fPieces = malloc( fWidth );
    163     [fTorrent getAvailability: fPieces size: fWidth];
     135    uint8_t  * bitmapData  = [bitmap bitmapData];
     136    int        bytesPerRow = [bitmap bytesPerRow];
     137
     138    int8_t * pieces = malloc( width );
     139    [fTorrent getAvailability: pieces size: width];
    164140
    165141    if( [fTorrent isSeeding] )
    166142    {
    167143        /* All green, same as the simple bar */
    168         [self buildSimpleBar];
     144        [self buildSimpleBar: width bitmap: bitmap];
    169145        return;
    170146    }
    171147
    172     pixelsPerRow = [fBitmap bytesPerRow] / 4;
     148    pixelsPerRow = bytesPerRow / 4;
    173149
    174150    /* First two lines: dark blue to show progression */
    175     end  = lrintf( floor( [fTorrent progress] * ( fWidth - 2 ) ) );
     151    end  = lrintf( floor( [fTorrent progress] * ( width - 2 ) ) );
    176152    for( h = 0; h < 2; h++ )
    177153    {
     
    181157            p[w] = htonl( kBlue4[h] );
    182158        }
    183         for( w = end; w < fWidth - 2; w++ )
     159        for( w = end; w < width - 2; w++ )
    184160        {
    185161            p[w] = htonl( kBack[h] );
     
    189165    /* Lines 2 to 14: blue or grey depending on whether
    190166       we have the piece or not */
    191     for( w = 0; w < fWidth - 2; w++ )
     167    for( w = 0; w < width - 2; w++ )
    192168    {
    193169        /* Point to pixel ( 2 + w, 2 ). We will then draw
     
    195171        p  = (uint32_t *) ( bitmapData + 2 * bytesPerRow ) + 1 + w;
    196172
    197         if( fPieces[w] < 0 )
     173        if( pieces[w] < 0 )
    198174        {
    199175            colors = kGray;
    200176        }
    201         else if( fPieces[w] < 1 )
     177        else if( pieces[w] < 1 )
    202178        {
    203179            colors = kRed;
    204180        }
    205         else if( fPieces[w] < 2 )
     181        else if( pieces[w] < 2 )
    206182        {
    207183            colors = kBlue1;
    208184        }
    209         else if( fPieces[w] < 3 )
     185        else if( pieces[w] < 3 )
    210186        {
    211187            colors = kBlue2;
     
    223199    }
    224200
    225     free( fPieces );
    226 }
    227 
    228 - (void) buildBar
     201    free( pieces );
     202}
     203
     204- (void) buildBarWithWidth: (int) width bitmap: (NSBitmapImageRep *) bitmap
    229205{
    230206    int h;
     
    232208
    233209    /* Left and right borders */
    234     p = (uint32_t *) [fBitmap bitmapData];
     210    p = (uint32_t *) [bitmap bitmapData];
    235211    for( h = 0; h < BAR_HEIGHT; h++ )
    236212    {
    237213        p[0]          = htonl( kBorder[h] );
    238         p[fWidth - 1] = htonl( kBorder[h] );
    239         p += [fBitmap bytesPerRow] / 4;
     214        p[width - 1] = htonl( kBorder[h] );
     215        p += [bitmap bytesPerRow] / 4;
    240216    }
    241217
    242218    /* ...and redraw the progress bar on the top of it */
    243     if( [[NSUserDefaults standardUserDefaults]
    244             boolForKey:@"UseAdvancedBar"])
    245     {
    246         [self buildAdvancedBar];
    247     }
     219    if ([[NSUserDefaults standardUserDefaults] boolForKey: @"UseAdvancedBar"])
     220        [self buildAdvancedBar: width bitmap: bitmap];
    248221    else
    249     {
    250         [self buildSimpleBar];
    251     }
    252 }
    253 
    254 /***********************************************************************
    255  * drawWithFrame
    256  ***********************************************************************
    257  * We have the strings, we have the bitmap. Let's just draw them where
    258  * they belong.
    259  **********************************************************************/
     222        [self buildSimpleBar: width bitmap: bitmap];
     223}
     224
    260225- (void) drawWithFrame: (NSRect) cellFrame inView: (NSView *) view
    261226{
    262     if( ![view lockFocusIfCanDraw] )
    263     {
    264         return;
    265     }
    266 
    267     NSMutableDictionary * attributes;
    268     attributes = [NSMutableDictionary dictionaryWithCapacity: 2];
    269     [attributes setObject: fTextColor
    270         forKey: NSForegroundColorAttributeName];
     227    BOOL highlighted = [self isHighlighted] && [[view window] isKeyWindow];
     228    NSDictionary * nameAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
     229                    highlighted ? [NSColor whiteColor] : [NSColor blackColor],
     230                    NSForegroundColorAttributeName,
     231                    [NSFont messageFontOfSize: 12], NSFontAttributeName, nil];
     232    NSDictionary * statusAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
     233                    highlighted ? [NSColor whiteColor] : [NSColor darkGrayColor],
     234                    NSForegroundColorAttributeName,
     235                    [NSFont messageFontOfSize: 9], NSFontAttributeName, nil];
    271236
    272237    NSPoint pen = cellFrame.origin;
    273 
    274     /* Draw the icon */
    275     pen.x += 5; pen.y += 10;
    276     NSImage * icon = [fTorrent icon];
     238    float padding = 3.0, linePadding = 2.0;
     239
     240    //icon
     241    NSImage * icon = [fTorrent iconFlipped];
     242    NSSize iconSize = [icon size];
     243   
     244    pen.x += padding;
     245    pen.y += (cellFrame.size.height - iconSize.height) * 0.5;
     246   
    277247    [icon drawAtPoint: pen fromRect:
    278         NSMakeRect( 0, 0, [icon size].width, [icon size].height )
     248        NSMakeRect( 0, 0, iconSize.width, iconSize.height )
    279249        operation: NSCompositeSourceOver fraction: 1.0];
    280250
    281     NSString * string;
    282     fWidth  = NSWidth( cellFrame ) - [icon size].width - 15;
    283 
    284     /* Draw file or folder name */
    285     pen.x += [icon size].width + 5; pen.y -= 7;
    286     [attributes setObject: [NSFont messageFontOfSize: 11]
    287         forKey: NSFontAttributeName];
    288     NSString * sizeString = [NSString stringWithFormat: @" (%@)",
    289         [NSString stringForFileSize: [fTorrent size]]];
    290     string = [[[fTorrent name] stringFittingInWidth: fWidth - 50 -
    291         [sizeString sizeWithAttributes: attributes].width
    292         withAttributes: attributes] stringByAppendingString: sizeString];
    293     [string drawAtPoint: pen withAttributes: attributes];
    294 
    295     /* Draw the progress bar */
    296     pen.y += 17;
    297     fBitmap = [[NSBitmapImageRep alloc]
    298         initWithBitmapDataPlanes: nil pixelsWide: fWidth
     251    float extraNameShift = 1.0,
     252        mainWidth = cellFrame.size.width - iconSize.width - 3.0 * padding - extraNameShift;
     253
     254    //name string
     255    pen.x += iconSize.width + padding + extraNameShift;
     256    pen.y = cellFrame.origin.y + padding;
     257    NSAttributedString * nameString = [[fTorrent name] attributedStringFittingInWidth: mainWidth
     258                                attributes: nameAttributes];
     259    [nameString drawAtPoint: pen];
     260   
     261    //progress string
     262    pen.y += [nameString size].height + linePadding - 1.0;
     263   
     264    NSAttributedString * progressString = [[fTorrent progressString]
     265        attributedStringFittingInWidth: mainWidth attributes: statusAttributes];
     266    [progressString drawAtPoint: pen];
     267
     268    //progress bar
     269    pen.x -= extraNameShift;
     270    pen.y += [progressString size].height + linePadding;
     271   
     272    float barWidth = mainWidth + extraNameShift - 39.5 - padding;
     273   
     274    NSBitmapImageRep * bitmap = [[NSBitmapImageRep alloc]
     275        initWithBitmapDataPlanes: nil pixelsWide: barWidth
    299276        pixelsHigh: BAR_HEIGHT bitsPerSample: 8 samplesPerPixel: 4
    300277        hasAlpha: YES isPlanar: NO colorSpaceName:
    301278        NSCalibratedRGBColorSpace bytesPerRow: 0 bitsPerPixel: 0];
    302     NSImage * img = [[NSImage alloc] initWithSize: [fBitmap size]];
    303     [img addRepresentation: fBitmap];
     279    NSImage * img = [[NSImage alloc] initWithSize: [bitmap size]];
     280    [img addRepresentation: bitmap];
    304281    [img setFlipped: YES];
    305     [self buildBar];
     282   
     283    [self buildBarWithWidth: barWidth bitmap: bitmap];
     284   
    306285    [img drawAtPoint: pen fromRect: NSMakeRect( 0, 0,
    307286            [img size].width, [img size].height )
    308287        operation: NSCompositeSourceOver fraction: 1.0];
    309288    [img release];
    310     [fBitmap release];
    311 
    312     /* Status strings */
    313     [attributes setObject: [NSFont messageFontOfSize: 9]
    314             forKey: NSFontAttributeName];
    315     pen.y += BAR_HEIGHT + 2;
    316     [[fTorrent statusString] drawAtPoint: pen withAttributes: attributes];
    317     pen.y += 13;
    318     string = [[fTorrent infoString] stringFittingInWidth:
    319         ( fWidth - 80 ) withAttributes: attributes];
    320     [string drawAtPoint: pen withAttributes: attributes];
    321 
    322     /* Rates */
    323     pen.x += fWidth - 70; pen.y -= 13;
    324     [[fTorrent downloadString] drawAtPoint: pen withAttributes: attributes];
    325     pen.y += 13;
    326     [[fTorrent uploadString] drawAtPoint: pen withAttributes: attributes];
    327 
    328     [view unlockFocus];
     289    [bitmap release];
     290
     291    //status strings
     292    pen.x += extraNameShift;
     293    pen.y += BAR_HEIGHT + linePadding;
     294    NSAttributedString * statusString = [[fTorrent statusString]
     295        attributedStringFittingInWidth: mainWidth attributes: statusAttributes];
     296    [statusString drawAtPoint: pen];
     297   
     298    [nameAttributes release];
     299    [statusAttributes release];
    329300}
    330301
  • trunk/macosx/TorrentTableView.h

    r261 r272  
    3636    NSPoint               fClickPoint;
    3737   
    38     IBOutlet NSMenu     * fContextRow;
    39     IBOutlet NSMenu     * fContextNoRow;
     38    IBOutlet NSMenu     * fContextRow, * fContextNoRow;
    4039}
    4140- (void) setTorrents: (NSArray *) torrents;
  • trunk/macosx/TorrentTableView.m

    r261 r272  
    2828#import "Utils.h"
    2929
     30#define BUTTON_WIDTH 14.0
     31#define BUTTON_TO_TOP 32.5
     32#define AREA_CENTER 23.0
     33#define DISTANCE_FROM_CENTER 2.5
     34
    3035@implementation TorrentTableView
    3136
     
    3742- (NSRect) pauseRectForRow: (int) row
    3843{
    39     int col;
    40     NSRect cellRect, rect;
    41 
    42     col      = [self columnWithIdentifier: @"Torrent"];
    43     cellRect = [self frameOfCellAtColumn: col row: row];
    44     rect     = NSMakeRect( cellRect.origin.x + cellRect.size.width - 39,
    45                            cellRect.origin.y + 3, 14, 14 );
    46 
    47     return rect;
     44    NSRect cellRect = [self frameOfCellAtColumn:
     45                [self columnWithIdentifier: @"Torrent"] row: row];
     46               
     47    return NSMakeRect(cellRect.origin.x + cellRect.size.width
     48                        - AREA_CENTER - DISTANCE_FROM_CENTER - BUTTON_WIDTH,
     49                        cellRect.origin.y + BUTTON_TO_TOP, BUTTON_WIDTH, BUTTON_WIDTH);
    4850}
    4951
    5052- (NSRect) revealRectForRow: (int) row
    5153{
    52     int col;
    53     NSRect cellRect, rect;
    54 
    55     col      = [self columnWithIdentifier: @"Torrent"];
    56     cellRect = [self frameOfCellAtColumn: col row: row];
    57     rect     = NSMakeRect( cellRect.origin.x + cellRect.size.width - 20,
    58                            cellRect.origin.y + 3, 14, 14 );
    59 
    60     return rect;
     54    NSRect cellRect = [self frameOfCellAtColumn:
     55                [self columnWithIdentifier: @"Torrent"] row: row];
     56   
     57    return NSMakeRect(cellRect.origin.x + cellRect.size.width
     58                        - AREA_CENTER + DISTANCE_FROM_CENTER,
     59                        cellRect.origin.y + BUTTON_TO_TOP, BUTTON_WIDTH, BUTTON_WIDTH);
    6160}
    6261
     
    185184            [image setFlipped: YES];
    186185            [image drawAtPoint: rect.origin fromRect:
    187                 NSMakeRect( 0, 0, 14, 14 ) operation:
     186                NSMakeRect(0, 0, BUTTON_WIDTH, BUTTON_WIDTH) operation:
    188187                NSCompositeSourceOver fraction: 1.0];
    189188        }
     
    195194        [image setFlipped: YES];
    196195        [image drawAtPoint: rect.origin fromRect:
    197             NSMakeRect( 0, 0, 14, 14 ) operation:
     196            NSMakeRect(0, 0, BUTTON_WIDTH, BUTTON_WIDTH) operation:
    198197            NSCompositeSourceOver fraction: 1.0];
    199198    }
Note: See TracChangeset for help on using the changeset viewer.