2 * Adium is the legal property of its developers, whose names are listed in the copyright file included
3 * with this source distribution.
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
10 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11 * Public License for more details.
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 #import "ESFileTransferProgressRow.h"
18 #import "ESFileTransferProgressView.h"
19 #import <AIUtilities/AIParagraphStyleAdditions.h>
20 #import <AIUtilities/AIRolloverButton.h>
21 #import <AIUtilities/AIImageAdditions.h>
22 #import <AIUtilities/AIStringAdditions.h>
24 #define NORMAL_TEXT_COLOR [NSColor controlTextColor]
25 #define SELECTED_TEXT_COLOR [NSColor whiteColor]
26 #define TRANSFER_STATUS_COLOR [NSColor disabledControlTextColor]
28 @interface ESFileTransferProgressView (PRIVATE)
29 - (void)updateHeaderLine;
30 - (void)updateButtonReveal;
31 - (void)updateButtonStopResume;
34 @implementation ESFileTransferProgressView
38 if ([[self superclass] instancesRespondToSelector:@selector(awakeFromNib)]) {
42 [progressIndicator setUsesThreadedAnimation:YES];
43 [progressIndicator setIndeterminate:YES];
44 progressVisible = YES;
47 [view_details retain];
49 [button_stopResume setDelegate:self];
50 [button_reveal setDelegate:self];
52 buttonStopResumeIsHovered = NO;
53 buttonRevealIsHovered = NO;
58 [view_details release];
63 #pragma mark Source and destination
64 - (void)setSourceName:(NSString *)inSourceName
66 [textField_source setStringValue:(inSourceName ? inSourceName : @"")];
68 - (void)setSourceIcon:(NSImage *)inSourceIcon
70 [imageView_source setImage:inSourceIcon];
72 - (void)setDestinationName:(NSString *)inDestinationName
74 [textField_destination setStringValue:(inDestinationName ? inDestinationName : @"")];
76 - (void)setDestinationIcon:(NSImage *)inDestinationIcon
78 [imageView_destination setImage:inDestinationIcon];
81 #pragma mark File and its icon
82 - (void)setFileName:(NSString *)inFileName
84 [textField_fileName setStringValue:(inFileName ?
86 [AILocalizedString(@"Initializing transfer",nil) stringByAppendingEllipsis])];
88 - (void)setIconImage:(NSImage *)inIconImage
90 [button_icon setImage:inIconImage];
94 - (void)setProgressDoubleValue:(double)inPercent
96 [progressIndicator setDoubleValue:inPercent];
98 - (void)setProgressIndeterminate:(BOOL)flag
100 [progressIndicator setIndeterminate:flag];
102 - (void)setProgressAnimation:(BOOL)flag
105 [progressIndicator startAnimation:self];
107 [progressIndicator stopAnimation:self];
110 - (void)setProgressVisible:(BOOL)flag
112 if (flag != progressVisible) {
113 progressVisible = flag;
114 if (progressVisible) {
115 //Redisplay the progress bar. We never do this at present, so unimplemented for now.
117 NSRect progressRect = [progressIndicator frame];
119 float distanceToMove = progressRect.size.height / 2;
121 [progressIndicator setDisplayedWhenStopped:NO];
122 [progressIndicator setIndeterminate:YES];
123 [progressIndicator stopAnimation:self];
125 //I don't trust setDisplayedWhenStopped... call me crazy.
126 [progressIndicator setFrame:NSZeroRect];
127 [progressIndicator setNeedsDisplay:YES];
129 //Top objects moving down
131 frame = [textField_fileName frame];
132 frame.origin.y -= distanceToMove;
133 //Don't let it be any further right than the progress bar used to be to avoid our buttons
134 frame.size.width = (progressRect.origin.x + progressRect.size.width) - frame.origin.x;
135 [textField_fileName setFrame:frame];
138 //Bottom objects moving up
140 frame = [twiddle_details frame];
141 frame.origin.y += distanceToMove;
142 [twiddle_details setFrame:frame];
144 frame = [textField_detailsLabel frame];
145 frame.origin.y += distanceToMove;
146 [textField_detailsLabel setFrame:frame];
148 frame = [box_transferStatusFrame frame];
149 frame.origin.y += distanceToMove;
150 //Don't let it be any further right than the progress bar used to be to avoid our buttons
151 frame.size.width = (progressRect.origin.x + progressRect.size.width) - frame.origin.x;
152 [box_transferStatusFrame setFrame:frame];
156 //Display immediately
157 [[self window] display];
161 - (void)setTransferBytesStatus:(NSString *)inTransferBytesStatus
162 remainingStatus:(NSString *)inTransferRemainingStatus
163 speedStatus:(NSString *)inTransferSpeedStatus
165 [transferStatus release];
167 if (inTransferBytesStatus && inTransferRemainingStatus) {
168 transferStatus = [NSString stringWithFormat:@"%@ - %@",
169 inTransferBytesStatus,
170 inTransferRemainingStatus];
171 } else if (inTransferBytesStatus) {
172 transferStatus = inTransferBytesStatus;
173 } else if (inTransferRemainingStatus) {
174 transferStatus = inTransferRemainingStatus;
176 transferStatus = @"";
179 [transferStatus retain];
181 // [textField_transferStatus setStringValue:transferStatus];
182 [self setNeedsDisplayInRect:[box_transferStatusFrame frame]];
183 [textField_rate setStringValue:(inTransferSpeedStatus ? inTransferSpeedStatus : @"")];
187 //Sent when the details twiddle is clicked
188 - (IBAction)toggleDetails:(id)sender
190 NSRect detailsFrame = [view_details frame];
191 NSRect primaryControlsFrame = [box_primaryControls frame];
192 NSRect oldFrame = [self frame];
193 NSRect newFrame = oldFrame;
195 showingDetails = !showingDetails;
197 if (showingDetails) {
198 //Increase our height to make space
199 newFrame.size.height += detailsFrame.size.height;
200 newFrame.origin.y -= detailsFrame.size.height;
201 [self setFrame:newFrame];
203 //Move the box with our primary controls up
204 primaryControlsFrame.origin.y += detailsFrame.size.height;
205 [box_primaryControls setFrame:primaryControlsFrame];
207 //Add the details subview
208 [self addSubview:view_details];
210 //Line up the details frame with the twiddle which revealed it
211 detailsFrame.origin.x = [twiddle_details frame].origin.x;
212 detailsFrame.origin.y = 0;
214 [view_details setFrame:detailsFrame];
217 [twiddle_details setState:NSOnState];
219 newFrame.size.height -= detailsFrame.size.height;
220 newFrame.origin.y += detailsFrame.size.height;
222 [self setFrame:newFrame];
224 //Move the box with our primary controls back down
225 primaryControlsFrame.origin.y -= detailsFrame.size.height;
226 [box_primaryControls setFrame:primaryControlsFrame];
228 [view_details removeFromSuperview];
231 [twiddle_details setState:NSOffState];
234 //Let the owner know our height changed so other rows can be adjusted accordingly
235 [owner fileTransferProgressView:self
236 heightChangedFrom:oldFrame.size.height
237 to:newFrame.size.height];
240 - (void)setShowsDetails:(BOOL)flag
242 if (showingDetails != flag) {
243 [self toggleDetails:nil];
247 - (void)setAllowsCancel:(BOOL)flag
249 [button_stopResume setEnabled:flag];
256 if (isSelected && [[self window] isKeyWindow]) {
257 newColor = SELECTED_TEXT_COLOR;
259 newColor = NORMAL_TEXT_COLOR;
262 [textField_rate setTextColor:newColor];
263 [textField_source setTextColor:newColor];
264 [textField_destination setTextColor:newColor];
265 [textField_fileName setTextColor:newColor];
267 [self updateButtonStopResume];
268 [self updateButtonReveal];
269 [self setNeedsDisplay:YES];
272 - (void)windowDidChangeKey:(NSNotification *)notification
277 - (void)viewDidMoveToWindow
279 [[NSNotificationCenter defaultCenter] removeObserver:self
280 name:NSWindowDidBecomeKeyNotification
282 [[NSNotificationCenter defaultCenter] removeObserver:self
283 name:NSWindowDidResignKeyNotification
286 [[NSNotificationCenter defaultCenter] addObserver:self
287 selector:@selector(windowDidChangeKey:)
288 name:NSWindowDidBecomeKeyNotification
289 object:[self window]];
290 [[NSNotificationCenter defaultCenter] addObserver:self
291 selector:@selector(windowDidChangeKey:)
292 name:NSWindowDidResignKeyNotification
293 object:[self window]];
297 #pragma mark Selection
298 - (void)setIsHighlighted:(BOOL)flag
300 if (isSelected != flag) {
307 - (void)updateButtonStopResume
310 [button_stopResume setImage:[NSImage imageNamed:(buttonStopResumeIsHovered ? @"FTProgressStopRollover_Selected" : @"FTProgressStop_Selected")
311 forClass:[self class]]];
313 [button_stopResume setAlternateImage:[NSImage imageNamed:@"FTProgressStopPressed_Selected" forClass:[self class]]];
316 [button_stopResume setImage:[NSImage imageNamed:(buttonStopResumeIsHovered ? @"FTProgressStopRollover" : @"FTProgressStop")
317 forClass:[self class]]];
319 [button_stopResume setAlternateImage:[NSImage imageNamed:@"FTProgressStopPressed" forClass:[self class]]];
323 - (void)updateButtonReveal
326 [button_reveal setImage:[NSImage imageNamed:(buttonRevealIsHovered ? @"FTProgressRevealRollover_Selected" : @"FTProgressReveal_Selected")
327 forClass:[self class]]];
329 [button_reveal setAlternateImage:[NSImage imageNamed:@"FTProgressRevealPressed_Selected" forClass:[self class]]];
332 [button_reveal setImage:[NSImage imageNamed:(buttonRevealIsHovered ? @"FTProgressRevealRollover" : @"FTProgressReveal")
333 forClass:[self class]]];
335 [button_reveal setAlternateImage:[NSImage imageNamed:@"FTProgressRevealPressed" forClass:[self class]]];
339 - (void)rolloverButton:(AIRolloverButton *)inButton mouseChangedToInsideButton:(BOOL)isInside
341 if (inButton == button_stopResume) {
342 buttonStopResumeIsHovered = isInside;
343 [self updateButtonStopResume];
345 } else if (inButton == button_reveal) {
346 buttonRevealIsHovered = isInside;
347 [self updateButtonReveal];
352 static NSDictionary *transferStatusAttributes = nil;
353 static NSDictionary *transferStatusSelectedAttributes = nil;
355 //Draw the transfer status after other views draw. This lets us use custom drawing behavior including the
356 //NSLineBreakByTruncatingTail paragraph style. We draw into a frame reserved for us by box_transferStatusFrame;
357 //this lets us not worry about autosizing and positioning since the view takes care of that for us.
358 - (void)drawRect:(NSRect)rect
360 [super drawRect:rect];
362 NSDictionary *attributes;
363 NSRect primaryControlsRect = [box_primaryControls frame];
364 NSRect targetRect = [box_transferStatusFrame frame];
366 targetRect.origin.x += primaryControlsRect.origin.x;
367 targetRect.origin.y += primaryControlsRect.origin.y;
369 if (isSelected && [[self window] isKeyWindow]) {
370 if (!transferStatusSelectedAttributes) {
371 NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle styleWithAlignment:NSLeftTextAlignment
372 lineBreakMode:NSLineBreakByTruncatingTail];
373 [paragraphStyle setMaximumLineHeight:[box_transferStatusFrame frame].size.height];
375 transferStatusSelectedAttributes = [[NSDictionary dictionaryWithObjectsAndKeys:
376 paragraphStyle, NSParagraphStyleAttributeName,
377 [NSFont systemFontOfSize:9], NSFontAttributeName,
378 SELECTED_TEXT_COLOR, NSForegroundColorAttributeName, nil] retain];
381 attributes = transferStatusSelectedAttributes;
383 if (!transferStatusAttributes) {
384 NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle styleWithAlignment:NSLeftTextAlignment
385 lineBreakMode:NSLineBreakByTruncatingTail];
386 [paragraphStyle setMaximumLineHeight:[box_transferStatusFrame frame].size.height];
388 transferStatusAttributes = [[NSDictionary dictionaryWithObjectsAndKeys:
389 paragraphStyle, NSParagraphStyleAttributeName,
390 [NSFont systemFontOfSize:9], NSFontAttributeName,
391 TRANSFER_STATUS_COLOR, NSForegroundColorAttributeName, nil] retain];
394 attributes = transferStatusAttributes;
397 [transferStatus drawInRect:targetRect
398 withAttributes:attributes];
402 - (NSMenu *)menuForEvent:(NSEvent *)inEvent
404 return [owner menuForEvent:inEvent];
407 #pragma mark Accessibility
409 - (id)accessibilityAttributeValue:(NSString *)attribute
413 if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
414 value = NSAccessibilityRowRole;
416 } else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
417 if (![progressIndicator isIndeterminate]) {
418 //We are in the concrete phase of an active transfer
419 value = [NSString stringWithFormat:
420 AILocalizedString(@"Transferring %@ from %@ to %@ at %@ : %@", "e.g: Transferring file.zip from Evan to Joel at 45 kb/sec : 5 minutes remaining. Keep the spaces around the colon."),
421 [textField_fileName stringValue],
422 [textField_source stringValue],
423 [textField_destination stringValue],
424 [textField_rate stringValue],
425 (transferStatus ? transferStatus : @"")];
428 value = [NSString stringWithFormat:
429 AILocalizedString(@"Transfer of %@ from %@ to %@ : %@", "e.g: Transfer of file.zip from Evan to Joel : Upload complete. Keep the spaces around the colon"),
430 [textField_fileName stringValue],
431 [textField_source stringValue],
432 [textField_destination stringValue],
433 (transferStatus ? transferStatus : @"")];
436 } else if ([attribute isEqualToString:NSAccessibilityTitleAttribute]) {
437 value = AILocalizedString(@"File transfer", nil);
439 } else if ([attribute isEqualToString:NSAccessibilityEnabledAttribute]) {
440 //Never report as disabled, so we don't say 'dimmed' all the time
441 value = [NSNumber numberWithBool:YES];
444 value = [super accessibilityAttributeValue:attribute];