source: trunk/macosx/InfoActivityViewController.m

Last change on this file was 14341, checked in by livings124, 7 years ago

Yosemite: use NSDateComponentsFormatter instead of custom time string code

  • Property svn:keywords set to Date Rev Author Id
File size: 10.8 KB
Line 
1/******************************************************************************
2 * $Id: InfoActivityViewController.m 14341 2014-10-17 05:12:00Z mikedld $
3 *
4 * Copyright (c) 2010-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 "InfoActivityViewController.h"
26#import "NSApplicationAdditions.h"
27#import "NSStringAdditions.h"
28#import "PiecesView.h"
29#import "Torrent.h"
30
31#include "transmission.h" // required by utils.h
32#include "utils.h" //tr_getRatio()
33
34#define PIECES_CONTROL_PROGRESS 0
35#define PIECES_CONTROL_AVAILABLE 1
36
37@interface InfoActivityViewController (Private)
38
39- (void) setupInfo;
40
41@end
42
43@implementation InfoActivityViewController
44
45- (id) init
46{
47    if ((self = [super initWithNibName: @"InfoActivityView" bundle: nil]))
48    {
49        [self setTitle: NSLocalizedString(@"Activity", "Inspector view -> title")];
50    }
51   
52    return self;
53}
54
55- (void) awakeFromNib
56{
57    [fTransferSectionLabel sizeToFit];
58    [fDatesSectionLabel sizeToFit];
59    [fTimeSectionLabel sizeToFit];
60   
61    NSArray * labels = @[ fStateLabel, fProgressLabel, fHaveLabel, fDownloadedLabel, fUploadedLabel, fFailedDLLabel, fRatioLabel, fErrorLabel, fDateAddedLabel, fDateCompletedLabel, fDateActivityLabel, fDownloadTimeLabel, fSeedTimeLabel ];
62   
63    CGFloat oldMaxWidth = 0.0, originX, newMaxWidth = 0.0;
64    for (NSTextField * label in labels)
65    {
66        const NSRect oldFrame = [label frame];
67        if (oldFrame.size.width > oldMaxWidth)
68        {
69            oldMaxWidth = oldFrame.size.width;
70            originX = oldFrame.origin.x;
71        }
72       
73        [label sizeToFit];
74        const CGFloat newWidth = [label bounds].size.width;
75        if (newWidth > newMaxWidth)
76            newMaxWidth = newWidth;
77    }
78   
79    for (NSTextField * label in labels)
80    {
81        NSRect frame = [label frame];
82        frame.origin.x = originX + (newMaxWidth - frame.size.width);
83        [label setFrame: frame];
84    }
85   
86    NSArray * fields = @[ fDateAddedField, fDateCompletedField, fDateActivityField, fStateField, fProgressField, fHaveField, fDownloadedTotalField, fUploadedTotalField, fFailedHashField, fRatioField, fDownloadTimeField, fSeedTimeField, fErrorScrollView ];
87   
88    const CGFloat widthIncrease = newMaxWidth - oldMaxWidth;
89    for (NSView * field in fields) {
90        NSRect frame = [field frame];
91        frame.origin.x += widthIncrease;
92        frame.size.width -= widthIncrease;
93        [field setFrame: frame];
94    }
95   
96    //set the click action of the pieces view
97    #warning after 2.8 just hook this up in the xib
98    [fPiecesView setAction:@selector(updatePiecesView:)];
99    [fPiecesView setTarget:self];
100}
101
102- (void) dealloc
103{
104    [[NSNotificationCenter defaultCenter] removeObserver: self];
105   
106    [fTorrents release];
107   
108    [super dealloc];
109}
110
111- (void) setInfoForTorrents: (NSArray *) torrents
112{
113    //don't check if it's the same in case the metadata changed
114    [fTorrents release];
115    fTorrents = [torrents retain];
116   
117    fSet = NO;
118}
119
120- (void) updateInfo
121{
122    if (!fSet)
123        [self setupInfo];
124   
125    const NSInteger numberSelected = [fTorrents count];
126    if (numberSelected == 0)
127        return;
128   
129    uint64_t have = 0, haveVerified = 0, downloadedTotal = 0, uploadedTotal = 0, failedHash = 0;
130    NSDate * lastActivity = nil;
131    for (Torrent * torrent in fTorrents)
132    {
133        have += [torrent haveTotal];
134        haveVerified += [torrent haveVerified];
135        downloadedTotal += [torrent downloadedTotal];
136        uploadedTotal += [torrent uploadedTotal];
137        failedHash += [torrent failedHash];
138       
139        NSDate * nextLastActivity;
140        if ((nextLastActivity = [torrent dateActivity]))
141            lastActivity = lastActivity ? [lastActivity laterDate: nextLastActivity] : nextLastActivity;
142    }
143   
144    if (have == 0)
145        [fHaveField setStringValue: [NSString stringForFileSize: 0]];
146    else
147    {
148        NSString * verifiedString = [NSString stringWithFormat: NSLocalizedString(@"%@ verified", "Inspector -> Activity tab -> have"),
149                                        [NSString stringForFileSize: haveVerified]];
150        if (have == haveVerified)
151            [fHaveField setStringValue: verifiedString];
152        else
153            [fHaveField setStringValue: [NSString stringWithFormat: @"%@ (%@)", [NSString stringForFileSize: have], verifiedString]];
154    }
155   
156    [fDownloadedTotalField setStringValue: [NSString stringForFileSize: downloadedTotal]];
157    [fUploadedTotalField setStringValue: [NSString stringForFileSize: uploadedTotal]];
158    [fFailedHashField setStringValue: [NSString stringForFileSize: failedHash]];
159   
160    [fDateActivityField setObjectValue: lastActivity];
161   
162    if (numberSelected == 1)
163    {
164        Torrent * torrent = [fTorrents objectAtIndex: 0];
165       
166        [fStateField setStringValue: [torrent stateString]];
167       
168        NSString * progressString = [NSString percentString: [torrent progress] longDecimals: YES];
169        if ([torrent isFolder])
170        {
171            NSString * progressSelectedString = [NSString stringWithFormat:
172                                                    NSLocalizedString(@"%@ selected", "Inspector -> Activity tab -> progress"),
173                                                    [NSString percentString: [torrent progressDone] longDecimals: YES]];
174            progressString = [progressString stringByAppendingFormat: @" (%@)", progressSelectedString];
175        }
176        [fProgressField setStringValue: progressString];
177           
178        [fRatioField setStringValue: [NSString stringForRatio: [torrent ratio]]];
179       
180        NSString * errorMessage = [torrent errorMessage];
181        if (![errorMessage isEqualToString: [fErrorMessageView string]])
182            [fErrorMessageView setString: errorMessage];
183       
184        [fDateCompletedField setObjectValue: [torrent dateCompleted]];
185       
186        //uses a relative date, so can't be set once
187        [fDateAddedField setObjectValue: [torrent dateAdded]];
188       
189        if ([NSApp isOnYosemiteOrBetter]) {
190            static NSDateComponentsFormatter *timeFormatter;
191            static dispatch_once_t onceToken;
192            dispatch_once(&onceToken, ^{
193                timeFormatter = [NSDateComponentsFormatter new];
194                timeFormatter.unitsStyle = NSDateComponentsFormatterUnitsStyleShort;
195                timeFormatter.allowedUnits = NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
196                timeFormatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorDropLeading;
197            });
198           
199            [fDownloadTimeField setStringValue: [timeFormatter stringFromTimeInterval:[torrent secondsDownloading]]];
200            [fSeedTimeField setStringValue: [timeFormatter stringFromTimeInterval:[torrent secondsSeeding]]];
201        }
202        else {
203            [fDownloadTimeField setStringValue: [NSString timeString: [torrent secondsDownloading] includesTimeRemainingPhrase:NO showSeconds: YES]];
204            [fSeedTimeField setStringValue: [NSString timeString: [torrent secondsSeeding] includesTimeRemainingPhrase:NO showSeconds: YES]];
205        }
206       
207        [fPiecesView updateView];
208    }
209    else if (numberSelected > 1)
210    {
211        [fRatioField setStringValue: [NSString stringForRatio: tr_getRatio(uploadedTotal, downloadedTotal)]];
212    }
213    else;
214}
215
216- (void) setPiecesView: (id) sender
217{
218    const BOOL availability = [sender selectedSegment] == PIECES_CONTROL_AVAILABLE;
219    [[NSUserDefaults standardUserDefaults] setBool: availability forKey: @"PiecesViewShowAvailability"];
220    [self updatePiecesView:nil];
221}
222
223
224- (void) updatePiecesView: (id) sender
225{
226    const BOOL piecesAvailableSegment = [[NSUserDefaults standardUserDefaults] boolForKey: @"PiecesViewShowAvailability"];
227   
228    [fPiecesControl setSelected: piecesAvailableSegment forSegment: PIECES_CONTROL_AVAILABLE];
229    [fPiecesControl setSelected: !piecesAvailableSegment forSegment: PIECES_CONTROL_PROGRESS];
230   
231    [fPiecesView updateView];
232}
233
234- (void) clearView
235{
236    [fPiecesView clearView];
237}
238
239@end
240
241@implementation InfoActivityViewController (Private)
242
243- (void) setupInfo
244{
245    const NSUInteger count = [fTorrents count];
246    if (count != 1)
247    {
248        if (count == 0)
249        {
250            [fHaveField setStringValue: @""];
251            [fDownloadedTotalField setStringValue: @""];
252            [fUploadedTotalField setStringValue: @""];
253            [fFailedHashField setStringValue: @""];
254            [fDateActivityField setObjectValue: @""]; //using [field setStringValue: @""] causes "December 31, 1969 7:00 PM" to be displayed, at least on 10.7.3
255            [fRatioField setStringValue: @""];
256        }
257       
258        [fStateField setStringValue: @""];
259        [fProgressField setStringValue: @""];
260       
261        [fErrorMessageView setString: @""];
262       
263        //using [field setStringValue: @""] causes "December 31, 1969 7:00 PM" to be displayed, at least on 10.7.3
264        [fDateAddedField setObjectValue: @""];
265        [fDateCompletedField setObjectValue: @""];
266       
267        [fDownloadTimeField setStringValue: @""];
268        [fSeedTimeField setStringValue: @""];
269       
270        [fPiecesControl setSelected: NO forSegment: PIECES_CONTROL_AVAILABLE];
271        [fPiecesControl setSelected: NO forSegment: PIECES_CONTROL_PROGRESS];
272        [fPiecesControl setEnabled: NO];
273        [fPiecesView setTorrent: nil];
274    }
275    else
276    {
277        Torrent * torrent = [fTorrents objectAtIndex: 0];
278       
279        const BOOL piecesAvailableSegment = [[NSUserDefaults standardUserDefaults] boolForKey: @"PiecesViewShowAvailability"];
280        [fPiecesControl setSelected: piecesAvailableSegment forSegment: PIECES_CONTROL_AVAILABLE];
281        [fPiecesControl setSelected: !piecesAvailableSegment forSegment: PIECES_CONTROL_PROGRESS];
282        [fPiecesControl setEnabled: YES];
283       
284        [fPiecesView setTorrent: torrent];
285    }
286   
287    fSet = YES;
288}
289
290@end
Note: See TracBrowser for help on using the repository browser.