1/****************************************************************************** 2 * $Id: StatsWindowController.m 13526 2012-09-24 02:43:44Z livings124 $ 3 * 4 * Copyright (c) 2007-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 "StatsWindowController.h" 26#import "Controller.h" 27#import "NSApplicationAdditions.h" 28#import "NSStringAdditions.h" 29 30#define UPDATE_SECONDS 1.0 31 32@interface StatsWindowController (Private) 33 34- (void) updateStats; 35 36- (void) performResetStats; 37- (void) resetSheetClosed: (NSAlert *) alert returnCode: (NSInteger) code contextInfo: (void *) info; 38 39@end 40 41@implementation StatsWindowController 42 43StatsWindowController * fStatsWindowInstance = nil; 44tr_session * fLib = NULL; 45+ (StatsWindowController *) statsWindow 46{ 47 if (!fStatsWindowInstance) 48 { 49 if ((fStatsWindowInstance = [[self alloc] init])) 50 { 51 fLib = [(Controller *)[NSApp delegate] sessionHandle]; 52 } 53 } 54 return fStatsWindowInstance; 55} 56 57- (id) init 58{ 59 return [super initWithWindowNibName: @"StatsWindow"]; 60} 61 62- (void) awakeFromNib 63{ 64 [self updateStats]; 65 66 fTimer = [[NSTimer scheduledTimerWithTimeInterval: UPDATE_SECONDS target: self selector: @selector(updateStats) userInfo: nil repeats: YES] retain]; 67 [[NSRunLoop currentRunLoop] addTimer: fTimer forMode: NSModalPanelRunLoopMode]; 68 [[NSRunLoop currentRunLoop] addTimer: fTimer forMode: NSEventTrackingRunLoopMode]; 69 70 if ([NSApp isOnLionOrBetter]) 71 [[self window] setRestorationClass: [self class]]; 72 73 [[self window] setTitle: NSLocalizedString(@"Statistics", "Stats window -> title")]; 74 75 //set label text 76 [fUploadedLabelField setStringValue: [NSLocalizedString(@"Uploaded", "Stats window -> label") stringByAppendingString: @":"]]; 77 [fDownloadedLabelField setStringValue: [NSLocalizedString(@"Downloaded", "Stats window -> label") stringByAppendingString: @":"]]; 78 [fRatioLabelField setStringValue: [NSLocalizedString(@"Ratio", "Stats window -> label") stringByAppendingString: @":"]]; 79 [fTimeLabelField setStringValue: [NSLocalizedString(@"Running Time", "Stats window -> label") stringByAppendingString: @":"]]; 80 [fNumOpenedLabelField setStringValue: [NSLocalizedString(@"Program Started", "Stats window -> label") stringByAppendingString: @":"]]; 81 82 //size of all labels 83 const CGFloat oldWidth = [fUploadedLabelField frame].size.width; 84 85 NSArray * labels = @[fUploadedLabelField, fDownloadedLabelField, fRatioLabelField, fTimeLabelField, fNumOpenedLabelField]; 86 87 CGFloat maxWidth = CGFLOAT_MIN; 88 for (NSTextField * label in labels) 89 { 90 [label sizeToFit]; 91 92 const CGFloat width = [label frame].size.width; 93 maxWidth = MAX(maxWidth, width); 94 } 95 96 for (NSTextField * label in labels) 97 { 98 NSRect frame = [label frame]; 99 frame.size.width = maxWidth; 100 [label setFrame: frame]; 101 } 102 103 //resize window for new label width - fields are set in nib to adjust correctly 104 NSRect windowRect = [[self window] frame]; 105 windowRect.size.width += maxWidth - oldWidth; 106 [[self window] setFrame: windowRect display: YES]; 107 108 //resize reset button 109 const CGFloat oldButtonWidth = [fResetButton frame].size.width; 110 111 [fResetButton setTitle: NSLocalizedString(@"Reset", "Stats window -> reset button")]; 112 [fResetButton sizeToFit]; 113 114 NSRect buttonFrame = [fResetButton frame]; 115 buttonFrame.size.width += 10.0; 116 buttonFrame.origin.x -= buttonFrame.size.width - oldButtonWidth; 117 [fResetButton setFrame: buttonFrame]; 118} 119 120- (void) windowWillClose: (id) sender 121{ 122 [fTimer invalidate]; 123 [fTimer release]; 124 fTimer = nil; 125 126 [fStatsWindowInstance autorelease]; 127 fStatsWindowInstance = nil; 128} 129 130+ (void) restoreWindowWithIdentifier: (NSString *) identifier state: (NSCoder *) state completionHandler: (void (^)(NSWindow *, NSError *)) completionHandler 131{ 132 NSAssert1([identifier isEqualToString: @"StatsWindow"], @"Trying to restore unexpected identifier %@", identifier); 133 134 completionHandler([[StatsWindowController statsWindow] window], nil); 135} 136 137- (void) resetStats: (id) sender 138{ 139 if (![[NSUserDefaults standardUserDefaults] boolForKey: @"WarningResetStats"]) 140 { 141 [self performResetStats]; 142 return; 143 } 144 145 NSAlert * alert = [[NSAlert alloc] init]; 146 [alert setMessageText: NSLocalizedString(@"Are you sure you want to reset usage statistics?", "Stats reset -> title")]; 147 [alert setInformativeText: NSLocalizedString(@"This will clear the global statistics displayed by Transmission." 148 " Individual transfer statistics will not be affected.", "Stats reset -> message")]; 149 [alert setAlertStyle: NSWarningAlertStyle]; 150 [alert addButtonWithTitle: NSLocalizedString(@"Reset", "Stats reset -> button")]; 151 [alert addButtonWithTitle: NSLocalizedString(@"Cancel", "Stats reset -> button")]; 152 [alert setShowsSuppressionButton: YES]; 153 154 [alert beginSheetModalForWindow: [self window] modalDelegate: self 155 didEndSelector: @selector(resetSheetClosed:returnCode:contextInfo:) contextInfo: nil]; 156} 157 158- (NSString *) windowFrameAutosaveName 159{ 160 return @"StatsWindow"; 161} 162 163@end 164 165@implementation StatsWindowController (Private) 166 167- (void) updateStats 168{ 169 tr_session_stats statsAll, statsSession; 170 tr_sessionGetCumulativeStats(fLib, &statsAll); 171 tr_sessionGetStats(fLib, &statsSession); 172 173 NSByteCountFormatter * byteFormatter = nil; 174 if ([NSApp isOnMountainLionOrBetter]) 175 { 176 byteFormatter = [[NSByteCountFormatterMtLion alloc] init]; 177 [byteFormatter setAllowedUnits: NSByteCountFormatterUseBytes]; 178 } 179 180 [fUploadedField setStringValue: [NSString stringForFileSize: statsSession.uploadedBytes]]; 181 [fUploadedField setToolTip: [NSApp isOnMountainLionOrBetter] ? [byteFormatter stringFromByteCount: statsSession.uploadedBytes] : [NSString stringWithFormat: NSLocalizedString(@"%@ bytes", "stats -> bytes"), [NSString formattedUInteger: statsSession.uploadedBytes]]]; 182 [fUploadedAllField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%@ total", "stats total"), [NSString stringForFileSize: statsAll.uploadedBytes]]]; 183 [fUploadedAllField setToolTip: [NSApp isOnMountainLionOrBetter] ? [byteFormatter stringFromByteCount: statsAll.uploadedBytes] : [NSString stringWithFormat: NSLocalizedString(@"%@ bytes", "stats -> bytes"), [NSString formattedUInteger: statsAll.uploadedBytes]]]; 184 185 [fDownloadedField setStringValue: [NSString stringForFileSize: statsSession.downloadedBytes]]; 186 [fDownloadedField setToolTip: [NSApp isOnMountainLionOrBetter] ? [byteFormatter stringFromByteCount: statsSession.downloadedBytes] : [NSString stringWithFormat: NSLocalizedString(@"%@ bytes", "stats -> bytes"), [NSString formattedUInteger: statsSession.downloadedBytes]]]; 187 [fDownloadedAllField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%@ total", "stats total"), [NSString stringForFileSize: statsAll.downloadedBytes]]]; 188 [fDownloadedAllField setToolTip: [NSApp isOnMountainLionOrBetter] ? [byteFormatter stringFromByteCount: statsAll.downloadedBytes] : [NSString stringWithFormat: NSLocalizedString(@"%@ bytes", "stats -> bytes"), [NSString formattedUInteger: statsAll.downloadedBytes]]]; 189 190 [byteFormatter release]; 191 192 [fRatioField setStringValue: [NSString stringForRatio: statsSession.ratio]]; 193 194 NSString * totalRatioString = statsAll.ratio != TR_RATIO_NA 195 ? [NSString stringWithFormat: NSLocalizedString(@"%@ total", "stats total"), [NSString stringForRatio: statsAll.ratio]] 196 : NSLocalizedString(@"Total N/A", "stats total"); 197 [fRatioAllField setStringValue: totalRatioString]; 198 199 [fTimeField setStringValue: [NSString timeString: statsSession.secondsActive showSeconds: NO]]; 200 [fTimeAllField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%@ total", "stats total"), [NSString timeString: statsAll.secondsActive showSeconds: NO]]]; 201 202 if (statsAll.sessionCount == 1) 203 [fNumOpenedField setStringValue: NSLocalizedString(@"1 time", "stats window -> times opened")]; 204 else 205 [fNumOpenedField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%@ times", "stats window -> times opened"), [NSString formattedUInteger: statsAll.sessionCount]]]; 206} 207 208- (void) performResetStats 209{ 210 tr_sessionClearStats(fLib); 211 [self updateStats]; 212} 213 214- (void) resetSheetClosed: (NSAlert *) alert returnCode: (NSInteger) code contextInfo: (void *) info 215{ 216 [[alert window] orderOut: nil]; 217 218 if ([[alert suppressionButton] state] == NSOnState) 219 [[NSUserDefaults standardUserDefaults] setBool: NO forKey: @"WarningResetStats"]; 220 221 if (code == NSAlertFirstButtonReturn) 222 [self performResetStats]; 223} 224 225@end 226