1/******************************************************************************
2 * $Id: StatusBarController.m 13434 2012-08-13 00:52:04Z livings124 $
3 * 
4 * Copyright (c) 2011-2012 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#import "StatusBarController.h"
26#import "NSStringAdditions.h"
27
28#import "transmission.h"
29
30#define STATUS_RATIO_TOTAL      @"RatioTotal"
31#define STATUS_RATIO_SESSION    @"RatioSession"
32#define STATUS_TRANSFER_TOTAL   @"TransferTotal"
33#define STATUS_TRANSFER_SESSION @"TransferSession"
34
35typedef enum
36{
37    STATUS_RATIO_TOTAL_TAG = 0,
38    STATUS_RATIO_SESSION_TAG = 1,
39    STATUS_TRANSFER_TOTAL_TAG = 2,
40    STATUS_TRANSFER_SESSION_TAG = 3
41} statusTag;
42
43@interface StatusBarController (Private)
44
45- (void) resizeStatusButton;
46
47@end
48
49@implementation StatusBarController
50
51- (id) initWithLib: (tr_session *) lib
52{
53    if ((self = [super initWithNibName: @"StatusBar" bundle: nil]))
54    {
55        fLib = lib;
56        
57        fPreviousDownloadRate = -1.0;
58        fPreviousUploadRate = -1.0;
59    }
60    
61    return self;
62}
63
64- (void) awakeFromNib
65{
66    //localize menu items
67    [[[fStatusButton menu] itemWithTag: STATUS_RATIO_TOTAL_TAG] setTitle: NSLocalizedString(@"Total Ratio",
68        "Status Bar -> status menu")];
69    [[[fStatusButton menu] itemWithTag: STATUS_RATIO_SESSION_TAG] setTitle: NSLocalizedString(@"Session Ratio",
70        "Status Bar -> status menu")];
71    [[[fStatusButton menu] itemWithTag: STATUS_TRANSFER_TOTAL_TAG] setTitle: NSLocalizedString(@"Total Transfer",
72        "Status Bar -> status menu")];
73    [[[fStatusButton menu] itemWithTag: STATUS_TRANSFER_SESSION_TAG] setTitle: NSLocalizedString(@"Session Transfer",
74        "Status Bar -> status menu")];
75    
76    [[fStatusButton cell] setBackgroundStyle: NSBackgroundStyleRaised];
77    [[fTotalDLField cell] setBackgroundStyle: NSBackgroundStyleRaised];
78    [[fTotalULField cell] setBackgroundStyle: NSBackgroundStyleRaised];
79    [[fTotalDLImageView cell] setBackgroundStyle: NSBackgroundStyleRaised];
80    [[fTotalULImageView cell] setBackgroundStyle: NSBackgroundStyleRaised];
81    
82    [self updateSpeedFieldsToolTips];
83    
84    //update when speed limits are changed
85    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(updateSpeedFieldsToolTips)
86        name: @"SpeedLimitUpdate" object: nil];
87    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(resizeStatusButton)
88        name: NSWindowDidResizeNotification object: [[self view] window]];
89}
90
91- (void) dealloc
92{
93    [[NSNotificationCenter defaultCenter] removeObserver: self];
94    
95    [super dealloc];
96}
97
98- (void) updateWithDownload: (CGFloat) dlRate upload: (CGFloat) ulRate
99{
100    //set rates
101    if (dlRate != fPreviousDownloadRate)
102    {
103        [fTotalDLField setStringValue: [NSString stringForSpeed: dlRate]];
104        fPreviousDownloadRate = dlRate;
105    }
106    
107    if (ulRate != fPreviousUploadRate)
108    {
109        [fTotalULField setStringValue: [NSString stringForSpeed: ulRate]];
110        fPreviousUploadRate = ulRate;
111    }
112    
113    //set status button text
114    NSString * statusLabel = [[NSUserDefaults standardUserDefaults] stringForKey: @"StatusLabel"], * statusString;
115    BOOL total;
116    if ((total = [statusLabel isEqualToString: STATUS_RATIO_TOTAL]) || [statusLabel isEqualToString: STATUS_RATIO_SESSION])
117    {
118        tr_session_stats stats;
119        if (total)
120            tr_sessionGetCumulativeStats(fLib, &stats);
121        else
122            tr_sessionGetStats(fLib, &stats);
123        
124        statusString = [NSLocalizedString(@"Ratio", "status bar -> status label") stringByAppendingFormat: @": %@",
125                        [NSString stringForRatio: stats.ratio]];
126    }
127    else //STATUS_TRANSFER_TOTAL or STATUS_TRANSFER_SESSION
128    {
129        total = [statusLabel isEqualToString: STATUS_TRANSFER_TOTAL];
130        
131        tr_session_stats stats;
132        if (total)
133            tr_sessionGetCumulativeStats(fLib, &stats);
134        else
135            tr_sessionGetStats(fLib, &stats);
136        
137        statusString = [NSString stringWithFormat: @"%@: %@  %@: %@",
138                NSLocalizedString(@"DL", "status bar -> status label"), [NSString stringForFileSize: stats.downloadedBytes],
139                NSLocalizedString(@"UL", "status bar -> status label"), [NSString stringForFileSize: stats.uploadedBytes]];
140    }
141    
142    
143    if (![[fStatusButton title] isEqualToString: statusString])
144    {
145        [fStatusButton setTitle: statusString];
146        [self resizeStatusButton];
147    }
148}
149
150- (void) setStatusLabel: (id) sender
151{
152    NSString * statusLabel;
153    switch ([sender tag])
154    {
155        case STATUS_RATIO_TOTAL_TAG:
156            statusLabel = STATUS_RATIO_TOTAL;
157            break;
158        case STATUS_RATIO_SESSION_TAG:
159            statusLabel = STATUS_RATIO_SESSION;
160            break;
161        case STATUS_TRANSFER_TOTAL_TAG:
162            statusLabel = STATUS_TRANSFER_TOTAL;
163            break;
164        case STATUS_TRANSFER_SESSION_TAG:
165            statusLabel = STATUS_TRANSFER_SESSION;
166            break;
167        default:
168            NSAssert1(NO, @"Unknown status label tag received: %ld", [sender tag]);
169            return;
170    }
171    
172    [[NSUserDefaults standardUserDefaults] setObject: statusLabel forKey: @"StatusLabel"];
173    
174    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
175}
176
177- (void) updateSpeedFieldsToolTips
178{
179    NSString * uploadText, * downloadText;
180    
181    if ([[NSUserDefaults standardUserDefaults] boolForKey: @"SpeedLimit"])
182    {
183        NSString * speedString = [NSString stringWithFormat: @"%@ (%@)", NSLocalizedString(@"%d KB/s", "Status Bar -> speed tooltip"),
184                                    NSLocalizedString(@"Speed Limit", "Status Bar -> speed tooltip")];
185        
186        uploadText = [NSString stringWithFormat: speedString,
187                        [[NSUserDefaults standardUserDefaults] integerForKey: @"SpeedLimitUploadLimit"]];
188        downloadText = [NSString stringWithFormat: speedString,
189                        [[NSUserDefaults standardUserDefaults] integerForKey: @"SpeedLimitDownloadLimit"]];
190    }
191    else
192    {
193        if ([[NSUserDefaults standardUserDefaults] boolForKey: @"CheckUpload"])
194            uploadText = [NSString stringWithFormat: NSLocalizedString(@"%d KB/s", "Status Bar -> speed tooltip"),
195                            [[NSUserDefaults standardUserDefaults] integerForKey: @"UploadLimit"]];
196        else
197            uploadText = NSLocalizedString(@"unlimited", "Status Bar -> speed tooltip");
198        
199        if ([[NSUserDefaults standardUserDefaults] boolForKey: @"CheckDownload"])
200            downloadText = [NSString stringWithFormat: NSLocalizedString(@"%d KB/s", "Status Bar -> speed tooltip"),
201                            [[NSUserDefaults standardUserDefaults] integerForKey: @"DownloadLimit"]];
202        else
203            downloadText = NSLocalizedString(@"unlimited", "Status Bar -> speed tooltip");
204    }
205    
206    uploadText = [NSLocalizedString(@"Global upload limit", "Status Bar -> speed tooltip")
207                    stringByAppendingFormat: @": %@", uploadText];
208    downloadText = [NSLocalizedString(@"Global download limit", "Status Bar -> speed tooltip")
209                    stringByAppendingFormat: @": %@", downloadText];
210    
211    [fTotalULField setToolTip: uploadText];
212    [fTotalDLField setToolTip: downloadText];
213}
214
215- (BOOL) validateMenuItem: (NSMenuItem *) menuItem
216{
217    const SEL action = [menuItem action];
218    
219    //enable sort options
220    if (action == @selector(setStatusLabel:))
221    {
222        NSString * statusLabel;
223        switch ([menuItem tag])
224        {
225            case STATUS_RATIO_TOTAL_TAG:
226                statusLabel = STATUS_RATIO_TOTAL;
227                break;
228            case STATUS_RATIO_SESSION_TAG:
229                statusLabel = STATUS_RATIO_SESSION;
230                break;
231            case STATUS_TRANSFER_TOTAL_TAG:
232                statusLabel = STATUS_TRANSFER_TOTAL;
233                break;
234            case STATUS_TRANSFER_SESSION_TAG:
235                statusLabel = STATUS_TRANSFER_SESSION;
236                break;
237            default:
238                NSAssert1(NO, @"Unknown status label tag received: %ld", [menuItem tag]);
239        }
240        
241        [menuItem setState: [statusLabel isEqualToString: [[NSUserDefaults standardUserDefaults] stringForKey: @"StatusLabel"]]
242                            ? NSOnState : NSOffState];
243        return YES;
244    }
245    
246    return YES;
247}
248
249@end
250
251@implementation StatusBarController (Private)
252
253- (void) resizeStatusButton
254{
255    [fStatusButton sizeToFit];
256    
257    //width ends up being too long
258    NSRect statusFrame = [fStatusButton frame];
259    statusFrame.size.width -= 25.0;
260    
261    const CGFloat difference = NSMaxX(statusFrame) + 5.0 - NSMinX([fTotalDLImageView frame]);
262    if (difference > 0.0)
263        statusFrame.size.width -= difference;
264    
265    [fStatusButton setFrame: statusFrame];
266}
267
268@end
269