Back to index

lightning-sunbird  0.9+nobinonly
ProgressDlgController.mm
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #import "ProgressDlgController.h"
00039 
00040 #include "nsCOMPtr.h"
00041 #include "nsString.h"
00042 #include "nsCRT.h"
00043 #include "nsIWebBrowserPersist.h"
00044 #include "nsIInputStream.h"
00045 #include "nsIURL.h"
00046 #include "nsILocalFile.h"
00047 #include "nsIDOMHTMLDocument.h"
00048 #include "nsIWebProgressListener.h"
00049 #include "nsIDownload.h"
00050 #include "nsIComponentManager.h"
00051 #include "nsIPrefService.h"
00052 #include "nsIPrefBranch.h"
00053 
00054 static NSString *SaveFileToolbarIdentifier        = @"Save File Dialog Toolbar";
00055 static NSString *CancelToolbarItemIdentifier      = @"Cancel Toolbar Item";
00056 static NSString *ShowFileToolbarItemIdentifier    = @"Show File Toolbar Item";
00057 static NSString *OpenFileToolbarItemIdentifier    = @"Open File Toolbar Item";
00058 static NSString *LeaveOpenToolbarItemIdentifier   = @"Leave Open Toggle Toolbar Item";
00059 
00060 static NSString *ProgressWindowFrameSaveName      = @"ProgressWindow";
00061 
00062 @implementation ChimeraDownloadControllerFactory : DownloadControllerFactory
00063 
00064 - (NSWindowController<CHDownloadProgressDisplay> *)createDownloadController
00065 {
00066   NSWindowController* progressController = [[ProgressDlgController alloc] initWithWindowNibName: @"ProgressDialog"];
00067   NSAssert([progressController conformsToProtocol:@protocol(CHDownloadProgressDisplay)],
00068               @"progressController should conform to CHDownloadProgressDisplay protocol");
00069   return progressController;
00070 }
00071 
00072 @end
00073 
00074 #pragma mark -
00075 
00076 
00077 @interface ProgressDlgController(Private)
00078 -(void)setupToolbar;
00079 @end
00080 
00081 @implementation ProgressDlgController
00082 
00083 - (void)dealloc
00084 {
00085   // if we get here because we're quitting, the listener will still be alive
00086   // yet we're going away. As a result, we need to tell the d/l listener to
00087   // forget it ever met us and necko will clean it up on its own.
00088   if ( mDownloader) 
00089     mDownloader->DetachDownloadDisplay();
00090   NS_IF_RELEASE(mDownloader);
00091   [super dealloc];
00092 }
00093 
00094 - (void)windowDidLoad
00095 {
00096   [super windowDidLoad];
00097   
00098   mDownloadIsComplete = NO;
00099 
00100   if (!mIsFileSave) {
00101     nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
00102     PRBool save = PR_FALSE;
00103     prefs->GetBoolPref("browser.download.progressDnldDialog.keepAlive", &save);
00104     mSaveFileDialogShouldStayOpen = save;
00105   }
00106   
00107   [self setupToolbar];
00108   [mProgressBar setUsesThreadedAnimation:YES];      
00109   [mProgressBar startAnimation:self];   // move to onStateChange
00110 }
00111 
00112 - (void)setupToolbar
00113 {
00114     NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier:SaveFileToolbarIdentifier] autorelease];
00115 
00116     [toolbar setDisplayMode:NSToolbarDisplayModeDefault];
00117     [toolbar setAllowsUserCustomization:YES];
00118     [toolbar setAutosavesConfiguration:YES];
00119     [toolbar setDelegate:self];
00120     [[self window] setToolbar:toolbar];
00121 }
00122 
00123 - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
00124 {
00125     return [NSArray arrayWithObjects: CancelToolbarItemIdentifier,
00126         ShowFileToolbarItemIdentifier,
00127         OpenFileToolbarItemIdentifier,
00128         LeaveOpenToolbarItemIdentifier,
00129         NSToolbarCustomizeToolbarItemIdentifier,
00130         NSToolbarFlexibleSpaceItemIdentifier,
00131         NSToolbarSpaceItemIdentifier,
00132         NSToolbarSeparatorItemIdentifier,
00133         nil];
00134 }
00135 
00136 - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
00137 {
00138     return [NSArray arrayWithObjects: CancelToolbarItemIdentifier,
00139         NSToolbarFlexibleSpaceItemIdentifier,
00140         LeaveOpenToolbarItemIdentifier,
00141         NSToolbarFlexibleSpaceItemIdentifier,
00142         ShowFileToolbarItemIdentifier,
00143         OpenFileToolbarItemIdentifier,
00144         nil];
00145 }
00146 
00147 - (BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem
00148 {
00149   if ([toolbarItem action] == @selector(cancel))  // cancel button
00150     return (!mDownloadIsComplete);
00151   if ([toolbarItem action] == @selector(pauseAndResumeDownload))  // pause/resume button
00152     return (NO);  // Hey - it hasn't been hooked up yet. !mDownloadIsComplete when it is.
00153   if ([toolbarItem action] == @selector(showFile))  // show file
00154     return (mDownloadIsComplete);
00155   if ([toolbarItem action] == @selector(openFile))  // open file
00156     return (mDownloadIsComplete);
00157   return YES;           // turn it on otherwise.
00158 }
00159 
00160 -(void)autosaveWindowFrame
00161 {
00162   [[self window] saveFrameUsingName: ProgressWindowFrameSaveName];
00163 }
00164 
00165 - (NSToolbarItem *) toolbar:(NSToolbar *)toolbar
00166       itemForItemIdentifier:(NSString *)itemIdent
00167   willBeInsertedIntoToolbar:(BOOL)willBeInserted
00168 {
00169     NSToolbarItem *toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier:itemIdent] autorelease];
00170 
00171     if ( [itemIdent isEqual:CancelToolbarItemIdentifier] ) {
00172         [toolbarItem setLabel:NSLocalizedString(@"Cancel",@"Cancel")];
00173         [toolbarItem setPaletteLabel:NSLocalizedString(@"CancelPaletteLabel",@"Cancel Download")];
00174         [toolbarItem setToolTip:NSLocalizedString(@"CancelToolTip",@"Cancel this file download")];
00175         [toolbarItem setImage:[NSImage imageNamed:@"saveCancel"]];
00176         [toolbarItem setTarget:self];
00177         [toolbarItem setAction:@selector(cancel)];
00178     } else if ( [itemIdent isEqual:ShowFileToolbarItemIdentifier] ) {
00179         [toolbarItem setLabel:NSLocalizedString(@"Show File",@"Show File")];
00180         [toolbarItem setPaletteLabel:NSLocalizedString(@"Show File",@"Show File")];
00181         [toolbarItem setToolTip:NSLocalizedString(@"ShowToolTip",@"Show the saved file in the Finder")];
00182         [toolbarItem setImage:[NSImage imageNamed:@"saveShowFile"]];
00183         [toolbarItem setTarget:self];
00184         [toolbarItem setAction:@selector(showFile)];
00185     } else if ( [itemIdent isEqual:OpenFileToolbarItemIdentifier] ) {
00186         [toolbarItem setLabel:NSLocalizedString(@"Open File",@"Open File")];
00187         [toolbarItem setPaletteLabel:NSLocalizedString(@"Open File",@"Open File")];
00188         [toolbarItem setToolTip:NSLocalizedString(@"OpenToolTip",@"Open the saved file in its default application.")];
00189         [toolbarItem setImage:[NSImage imageNamed:@"saveOpenFile"]];
00190         [toolbarItem setTarget:self];
00191         [toolbarItem setAction:@selector(openFile)];
00192     } else if ( [itemIdent isEqual:LeaveOpenToolbarItemIdentifier] ) {
00193         if ( !mIsFileSave ) {
00194             if ( mSaveFileDialogShouldStayOpen ) {
00195                 [toolbarItem setLabel:NSLocalizedString(@"Leave Open",@"Leave Open")];
00196                 [toolbarItem setPaletteLabel:NSLocalizedString(@"Toggle Close Behavior",@"Toggle Close Behavior")];
00197                 [toolbarItem setToolTip:NSLocalizedString(@"LeaveOpenToolTip",@"Window will stay open when download finishes.")];
00198                 [toolbarItem setImage:[NSImage imageNamed:@"saveLeaveOpenYES"]];
00199                 [toolbarItem setTarget:self];
00200                 [toolbarItem setAction:@selector(toggleLeaveOpen)];
00201             } else {
00202                 [toolbarItem setLabel:NSLocalizedString(@"Close When Done",@"Close When Done")];
00203                 [toolbarItem setPaletteLabel:NSLocalizedString(@"Toggle Close Behavior",@"Toggle Close Behavior")];
00204                 [toolbarItem setToolTip:NSLocalizedString(@"CloseWhenDoneToolTip",@"Window will close automatically when download finishes.")];
00205                 [toolbarItem setImage:[NSImage imageNamed:@"saveLeaveOpenNO"]];
00206                 [toolbarItem setTarget:self];
00207                 [toolbarItem setAction:@selector(toggleLeaveOpen)];
00208             }
00209             if ( willBeInserted ) {
00210                 leaveOpenToggleToolbarItem = toolbarItem; //establish reference
00211          }
00212         }
00213     } else {
00214         toolbarItem = nil;
00215     }
00216 
00217     return toolbarItem;
00218 }
00219 
00220 -(void)cancel
00221 {
00222   if (mDownloader)    // we should always have one
00223     mDownloader->CancelDownload();
00224   
00225   // clean up downloaded file. - do it here on in CancelDownload?
00226   NSFileManager *fileManager = [NSFileManager defaultManager];
00227   NSString *thePath = [[mToField stringValue] stringByExpandingTildeInPath];
00228   if ([fileManager isDeletableFileAtPath:thePath])
00229     // if we delete it, fantastic.  if not, oh well.  better to move to trash instead?
00230     [fileManager removeFileAtPath:thePath handler:nil];
00231   
00232   // we can _not_ set the |mIsDownloadComplete| flag here because the download really
00233   // isn't done yet. We'll probably continue to process more PLEvents that are already
00234   // in the queue until we get a STATE_STOP state change. As a result, we just keep
00235   // going until that comes in (and it will, because we called CancelDownload() above).
00236   // Ensure that the window goes away when we get there by flipping the 'stay alive'
00237   // flag. (bug 154913)
00238   mSaveFileDialogShouldStayOpen = NO;
00239 }
00240 
00241 -(void)showFile
00242 {
00243   NSString *theFile = [[mToField stringValue] stringByExpandingTildeInPath];
00244   if ([[NSWorkspace sharedWorkspace] selectFile:theFile
00245                        inFileViewerRootedAtPath:[theFile stringByDeletingLastPathComponent]])
00246     return;
00247   // hmmm.  it didn't work.  that's odd. need localized error messages. for now, just beep.
00248   NSBeep();
00249 }
00250 
00251 -(void)openFile
00252 {
00253   NSString *theFile = [[mToField stringValue] stringByExpandingTildeInPath];
00254   if ([[NSWorkspace sharedWorkspace] openFile:theFile])
00255     return;
00256   // hmmm.  it didn't work.  that's odd.  need localized error message. for now, just beep.
00257   NSBeep();
00258     
00259 }
00260 
00261 -(void)toggleLeaveOpen
00262 {
00263     if ( ! mSaveFileDialogShouldStayOpen ) {
00264         mSaveFileDialogShouldStayOpen = YES;
00265         [leaveOpenToggleToolbarItem setLabel:NSLocalizedString(@"Leave Open",@"Leave Open")];
00266         [leaveOpenToggleToolbarItem setPaletteLabel:NSLocalizedString(@"Toggle Close Behavior",@"Toggle Close Behavior")];
00267         [leaveOpenToggleToolbarItem setToolTip:NSLocalizedString(@"LeaveOpenToolTip",@"Window will stay open when download finishes.")];
00268         [leaveOpenToggleToolbarItem setImage:[NSImage imageNamed:@"saveLeaveOpenYES"]];
00269     } else {
00270         mSaveFileDialogShouldStayOpen = NO;
00271         [leaveOpenToggleToolbarItem setLabel:NSLocalizedString(@"Close When Done",@"Close When Done")];
00272         [leaveOpenToggleToolbarItem setPaletteLabel:NSLocalizedString(@"Toggle Close Behavior",@"Toggle Close Behavior")];
00273         [leaveOpenToggleToolbarItem setToolTip:NSLocalizedString(@"CloseWhenDoneToolTip",@"Window will close automatically when download finishes.")];
00274         [leaveOpenToggleToolbarItem setImage:[NSImage imageNamed:@"saveLeaveOpenNO"]];
00275     }
00276     
00277     nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
00278     prefs->SetBoolPref("browser.download.progressDnldDialog.keepAlive", mSaveFileDialogShouldStayOpen);
00279 }
00280 
00281 - (void)windowWillClose:(NSNotification *)notification
00282 {
00283   [self autosaveWindowFrame];
00284   [self autorelease];
00285 }
00286 
00287 - (BOOL)windowShouldClose:(NSNotification *)notification
00288 {
00289   [self killDownloadTimer];
00290   if (!mDownloadIsComplete) { //whoops.  hard cancel.
00291     [self cancel];
00292     return NO;  // let setDownloadProgress handle the close.
00293   }
00294   return YES; 
00295 }
00296 
00297 - (void)killDownloadTimer
00298 {
00299   if (mDownloadTimer) {
00300     [mDownloadTimer invalidate];
00301     [mDownloadTimer release];
00302     mDownloadTimer = nil;
00303   }    
00304 }
00305 - (void)setupDownloadTimer
00306 {
00307   [self killDownloadTimer];
00308   mDownloadTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0
00309                                                      target:self
00310                                                    selector:@selector(setDownloadProgress:)
00311                                                    userInfo:nil
00312                                                     repeats:YES] retain];
00313 }
00314 
00315 -(NSString *)formatTime:(int)seconds
00316 {
00317   NSMutableString *theTime =[[[NSMutableString alloc] initWithCapacity:8] autorelease];
00318   [theTime setString:@""];
00319   NSString *padZero = [NSString stringWithString:@"0"];
00320   //write out new elapsed time
00321   if (seconds >= 3600){
00322     [theTime appendFormat:@"%d:",(seconds / 3600)];
00323     seconds = seconds % 3600;
00324   }
00325   NSString *elapsedMin = [NSString stringWithFormat:@"%d:",(seconds / 60)];
00326   if ([elapsedMin length] == 2)
00327     [theTime appendString:[padZero stringByAppendingString:elapsedMin]];
00328   else
00329     [theTime appendString:elapsedMin];
00330   seconds = seconds % 60;
00331   NSString *elapsedSec = [NSString stringWithFormat:@"%d",seconds];
00332   if ([elapsedSec length] == 2)
00333     [theTime appendString:elapsedSec];
00334   else
00335     [theTime appendString:[padZero stringByAppendingString:elapsedSec]];
00336   return theTime;
00337 }
00338 // fuzzy time gives back strings like "about 5 seconds"
00339 -(NSString *)formatFuzzyTime:(int)seconds
00340 {
00341   // check for seconds first
00342   if (seconds < 60) {
00343     if (seconds < 7)
00344       return [[[NSString alloc] initWithFormat:NSLocalizedString(@"UnderSec",@"Under %d seconds"),5] autorelease];
00345     if (seconds < 13)
00346       return [[[NSString alloc] initWithFormat:NSLocalizedString(@"UnderSec",@"Under %d seconds"),10] autorelease];
00347     return [[[NSString alloc] initWithString:NSLocalizedString(@"UnderMin",@"Under a minute")] autorelease];
00348   }    
00349   // seconds becomes minutes and we keep checking.  
00350   seconds = seconds/60;
00351   if (seconds < 60) {
00352     if (seconds < 2)
00353        return [[[NSString alloc] initWithString:NSLocalizedString(@"AboutMin",@"About a minute")] autorelease];
00354     // OK, tell the good people how much time we have left.
00355     return [[[NSString alloc] initWithFormat:NSLocalizedString(@"AboutMins",@"About %d minutes"),seconds] autorelease];
00356   }
00357   //this download will never seemingly never end. now seconds become hours.
00358   seconds = seconds/60;
00359   if (seconds < 2)
00360     return [[[NSString alloc] initWithString:NSLocalizedString(@"AboutHour",@"Over an hour")] autorelease];
00361   return [[[NSString alloc] initWithFormat:NSLocalizedString(@"AboutHours",@"Over %d hours"),seconds] autorelease];
00362 }
00363 
00364 
00365 -(NSString *)formatBytes:(float)bytes
00366 {   // this is simpler than my first try.  I peaked at Omnigroup byte formatting code.
00367     // if bytes are negative, we return question marks.
00368   if (bytes < 0)
00369     return [[[NSString alloc] initWithString:@"???"] autorelease];
00370   // bytes first.
00371   if (bytes < 1024)
00372     return [[[NSString alloc] initWithFormat:@"%.1f bytes",bytes] autorelease];
00373   // kb
00374   bytes = bytes/1024;
00375   if (bytes < 1024)
00376     return [[[NSString alloc] initWithFormat:@"%.1f KB",bytes] autorelease];
00377   // mb
00378   bytes = bytes/1024;
00379   if (bytes < 1024)
00380     return [[[NSString alloc] initWithFormat:@"%.1f MB",bytes] autorelease];
00381   // gb
00382   bytes = bytes/1024;
00383   return [[[NSString alloc] initWithFormat:@"%.1f GB",bytes] autorelease];
00384 }
00385 
00386 // this handles lots of things.
00387 - (void)setDownloadProgress:(NSTimer *)downloadTimer;
00388 {
00389   // XXX this logic needs cleaning up.
00390   
00391   // Ack! we're closing the window with the download still running!
00392   if (mDownloadIsComplete)
00393   {
00394     [[self window] performClose:self];  
00395     return;
00396   }
00397   // get the elapsed time
00398   NSArray *elapsedTimeArray = [[mElapsedTimeLabel stringValue] componentsSeparatedByString:@":"];
00399   int j = [elapsedTimeArray count];
00400   int elapsedSec = [[elapsedTimeArray objectAtIndex:(j-1)] intValue] + [[elapsedTimeArray objectAtIndex:(j-2)] intValue]*60;
00401   if (j==3)  // this download is taking forever.
00402     elapsedSec += [[elapsedTimeArray objectAtIndex:0] intValue]*3600;
00403   // update elapsed time
00404   [mElapsedTimeLabel setStringValue:[self formatTime:(++elapsedSec)]];
00405   // for status field & time left
00406   float maxBytes = ([mProgressBar maxValue]);
00407   float byteSec = mCurrentProgress/elapsedSec;
00408   // OK - if downloadTimer is nil, we're done - fix maxBytes value for status report.
00409   if (!downloadTimer)
00410     maxBytes = mCurrentProgress;
00411   // update status field
00412   NSString *labelString = NSLocalizedString(@"LabelString",@"%@ of %@ total (at %@/sec)");
00413   [mStatusLabel setStringValue: [NSString stringWithFormat:labelString, [self formatBytes:mCurrentProgress], [self formatBytes:maxBytes], [self formatBytes:byteSec]]];
00414   // updating estimated time left field
00415   // if maxBytes < 0, can't calc time left.
00416   // if !downloadTimer, download is finished.  either way, make sure time left is 0.
00417   if ((maxBytes > 0) && (downloadTimer))
00418   {
00419     int secToGo = (int)ceil((elapsedSec*maxBytes/mCurrentProgress) - elapsedSec);
00420     [mTimeLeftLabel setStringValue:[self formatFuzzyTime:secToGo]];
00421   }
00422   else if (!downloadTimer)
00423   {                            // download done.  Set remaining time to 0, fix progress bar & cancel button
00424     mDownloadIsComplete = YES;            // all done. we got a STATE_STOP
00425     [mTimeLeftLabel setStringValue:@""];
00426     [self setProgressTo:mCurrentProgress ofMax:mCurrentProgress];
00427     if (!mSaveFileDialogShouldStayOpen)
00428       [[self window] performClose:self];  // close window
00429     else
00430       [[self window] update];             // redraw window
00431   }
00432   else //maxBytes is undetermined.  Set remaining time to question marks.
00433       [mTimeLeftLabel setStringValue:@"???"];
00434 }
00435 
00436 #pragma mark -
00437 
00438 // CHDownloadProgressDisplay protocol methods
00439 
00440 - (void)onStartDownload:(BOOL)isFileSave;
00441 {
00442   mIsFileSave = isFileSave;
00443   
00444   [self window];            // make the window
00445   [[self window] setFrameUsingName: ProgressWindowFrameSaveName];
00446 
00447   [self showWindow: self];
00448   [self setupDownloadTimer];
00449 }
00450 
00451 - (void)onEndDownload
00452 {
00453   // if we're quitting, our progress window is already gone and we're in the
00454   // process of shutting down gecko and all the d/l listeners. The timer, at 
00455   // that point, is the only thing keeping us alive. Killing it will cause
00456   // us to go away immediately, so kung-fu deathgrip it until we're done twiddling
00457   // bits on ourself.
00458   [self retain];                           // Enter The Dragon!
00459     [self killDownloadTimer];
00460     [self setDownloadProgress:nil];
00461   [self release];
00462 }
00463 
00464 - (void)setProgressTo:(long)aCurProgress ofMax:(long)aMaxProgress
00465 {
00466   mCurrentProgress = aCurProgress;         // fall back for stat calcs
00467 
00468   if (![mProgressBar isIndeterminate])      //most likely - just update value
00469   {
00470     if (aCurProgress == aMaxProgress)      //handles little bug in FTP download size
00471       [mProgressBar setMaxValue:aMaxProgress];
00472 
00473     [mProgressBar setDoubleValue:aCurProgress];
00474   }
00475   else if (aMaxProgress > 0)                    // ok, we're starting up with good max & cur values
00476   {
00477     [mProgressBar setIndeterminate:NO];
00478     [mProgressBar setMaxValue:aMaxProgress];
00479     [mProgressBar setDoubleValue:aCurProgress];
00480   } // if neither case was true, it's barber pole city.
00481 }
00482 
00483 -(void) setDownloadListener: (CHDownloader*)aDownloader
00484 {
00485   if (mDownloader != aDownloader)
00486     NS_IF_RELEASE(mDownloader);
00487 
00488   NS_IF_ADDREF(mDownloader = aDownloader);
00489 }
00490 
00491 - (void)setSourceURL:(NSString*)aSourceURL
00492 {
00493   [mFromField setStringValue: aSourceURL];  
00494   [mFromField display];  // force an immmeditate update
00495 }
00496 
00497 - (void)setDestinationPath:(NSString*)aDestPath
00498 {
00499   [mToField setStringValue: [aDestPath stringByAbbreviatingWithTildeInPath]];
00500   [mToField display];   // force an immmeditate update
00501   
00502   // also set the window title
00503   NSString* downloadFileName = [aDestPath lastPathComponent];
00504   if ([downloadFileName length] == 0)
00505     downloadFileName = aDestPath;
00506   
00507   [[self window] setTitle:[NSString stringWithFormat:NSLocalizedString(@"DownloadingTitle", @""), downloadFileName]];
00508 }
00509 
00510 @end