File:  [mozdev] / chimera / ProgressDlgController.mm
Revision 1.10: download - view: text, annotated - select for diffs - revision graph
Mon Feb 4 05:18:41 2002 UTC (15 years, 9 months ago) by macserv
Branches: MAIN
CVS tags: HEAD
Fixing toolbar customization crash.  The toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar: method gets called for three reasons: 1. To draw the toolbar itself.  2. To draw the allowed items in the customization sheet.  3. To draw the default toolbar in the customization sheet.  The crash occurred because, when the method was called to draw items in the customization sheet, the references were reassigned to the items in the sheet.  To fix this, i put an if ( willBeInserted ) around the reference assignment.  When the drawing method is called, willBeInserted will only be YES if the item is actually being drawn in the toolbar.  Thus, the reference is only assigned for actual, inserted toolbar items.  Whew!

//
//  ProgressDlgController.m
//  Chimera
//
//  Created by David Hyatt on Sat Feb 02 2002.
//  Copyright (c) 2001 __MyCompanyName__. All rights reserved.
//

#import "ProgressDlgController.h"

#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsIWebBrowserPersist.h"
#include "nsIInputStream.h"
#include "nsIURL.h"
#include "nsILocalFile.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIWebProgressListener.h"
#include "nsIComponentManager.h"
#include "nsIPrefBranch.h"

const char* prefContractID = "@mozilla.org/preferences-service;1";

class nsDownloadListener : public nsIWebProgressListener
{
public:
    nsDownloadListener(ProgressDlgController* aController,
                       nsIWebBrowserPersist* aPersist,
                       nsISupports* aSource,
                       NSString* aDestination,
                       const char* aContentType,
                       nsIInputStream* aPostData,
                       BOOL aBypassCache)
    {
        NS_INIT_REFCNT();
        mController = aController;
        mWebPersist = aPersist;
        // The source is either a simple URL or a complete document.
        mURL = do_QueryInterface(aSource);
        if (!mURL)
            mDocument = do_QueryInterface(aSource);
        nsCAutoString dstStr = [aDestination cString];
        NS_NewLocalFile(dstStr.get(), PR_FALSE, getter_AddRefs(mDestination));
        mContentType = aContentType;
        mPostData = aPostData;
        mBypassCache = aBypassCache;
    };
    
    virtual ~nsDownloadListener() {};

    NS_DECL_ISUPPORTS
    NS_DECL_NSIWEBPROGRESSLISTENER
  
public:
    void BeginDownload();
    void InitDialog();
    
private: // Member variables
    ProgressDlgController* mController; // Controller for our UI.
    nsCOMPtr<nsIWebBrowserPersist> mWebPersist; // Our web persist object.
    nsCOMPtr<nsIURL> mURL; // The URL of our source file. Null if we're saving a complete document.
    nsCOMPtr<nsILocalFile> mDestination; // Our destination URL.
    nsCString mContentType; // Our content type string.
    nsCOMPtr<nsIDOMHTMLDocument> mDocument; // A DOM document.  Null if we're only saving a simple URL.
    nsCOMPtr<nsIInputStream> mPostData;  // For complete documents, this is our post data from session history.
    PRBool mBypassCache; // Whether we should bypass the cache or not.
};

NS_IMPL_ISUPPORTS1(nsDownloadListener, nsIWebProgressListener)

/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP 
nsDownloadListener::OnProgressChange(nsIWebProgress *aWebProgress, 
					 nsIRequest *aRequest, 
					 PRInt32 aCurSelfProgress, 
					 PRInt32 aMaxSelfProgress, 
					 PRInt32 aCurTotalProgress, 
					 PRInt32 aMaxTotalProgress)
{
  return NS_OK;
}

/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
NS_IMETHODIMP 
nsDownloadListener::OnLocationChange(nsIWebProgress *aWebProgress, 
					 nsIRequest *aRequest, 
					 nsIURI *location)
{
  return NS_OK;
}

/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
NS_IMETHODIMP 
nsDownloadListener::OnStatusChange(nsIWebProgress *aWebProgress, 
				       nsIRequest *aRequest, 
				       nsresult aStatus, 
				       const PRUnichar *aMessage)
{
  return NS_OK;
}

/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long state); */
NS_IMETHODIMP 
nsDownloadListener::OnSecurityChange(nsIWebProgress *aWebProgress, 
					              nsIRequest *aRequest, 
                                  PRInt32 state)
{
  return NS_OK;
}

// Implementation of nsIWebProgressListener
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aStateFlags, in unsigned long aStatus); */
NS_IMETHODIMP 
nsDownloadListener::OnStateChange(nsIWebProgress *aWebProgress, 
				      nsIRequest *aRequest, 
				      PRInt32 aStateFlags, 
				      PRUint32 aStatus)
{
    return NS_OK;
}

void
nsDownloadListener::BeginDownload()
{
    if (mWebPersist) {
        mWebPersist->SetProgressListener(this);
        PRInt32 flags = nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION | 
                        nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES;
        if (mBypassCache)
            flags |= nsIWebBrowserPersist::PERSIST_FLAGS_BYPASS_CACHE;
        else
            flags |= nsIWebBrowserPersist::PERSIST_FLAGS_FROM_CACHE;
            
        if (mURL)
            mWebPersist->SaveURI(mURL, mPostData, mDestination);
        else {
            PRInt32 encodingFlags = 0;
            nsCOMPtr<nsILocalFile> filesFolder;
            
            if (!mContentType.Equals("text/plain")) {
                // Create a local directory in the same dir as our file.  It
                // will hold our associated files.
                filesFolder = do_CreateInstance("@mozilla.org/file/local;1");
                nsXPIDLString unicodePath;
                mDestination->GetUnicodePath(getter_Copies(unicodePath));
                filesFolder->InitWithUnicodePath(unicodePath.get());
                
                nsXPIDLCString leafName;
                filesFolder->GetLeafName(getter_Copies(leafName));
                nsCAutoString nameMinusExt(leafName.get());
                PRInt32 index = nameMinusExt.RFind(".");
                if (index >= 0)
                    nameMinusExt.Left(nameMinusExt, index);
                nameMinusExt += " Files"; // XXXdwh needs to be localizable!
                filesFolder->SetLeafName(nameMinusExt.get());
                PRBool exists = PR_FALSE;
                filesFolder->Exists(&exists);
                if (!exists)
                    filesFolder->Create(nsILocalFile::DIRECTORY_TYPE, 0755);
            }
            else
                encodingFlags |= nsIWebBrowserPersist::ENCODE_FLAGS_FORMATTED |
                                 nsIWebBrowserPersist::ENCODE_FLAGS_ABSOLUTE_LINKS |
                                 nsIWebBrowserPersist::ENCODE_FLAGS_NOFRAMES_CONTENT;
                                 
            mWebPersist->SaveDocument(mDocument, mDestination, filesFolder, mContentType.get(),
                                      encodingFlags, 80);
        }
    }
    
    InitDialog();
}

void
nsDownloadListener::InitDialog()
{
    if (!mURL && !mDocument)
        return;
        
    if (mWebPersist) {
        if (mURL) {
            nsXPIDLCString spec;
            mURL->GetSpec(getter_Copies(spec));
            [mController setSourceURL: spec.get()];
        }
        else {
            nsAutoString spec;
            mDocument->GetURL(spec);
            nsCAutoString spec2; spec2.AssignWithConversion(spec);
            [mController setSourceURL: spec2.get()];
        }
    }
    
    nsXPIDLString path;
    mDestination->GetUnicodePath(getter_Copies(path));
    nsCAutoString pathStr; pathStr.AssignWithConversion(path.get());
    [mController setDestination: pathStr.get()];
    
    
}

static NSString *SaveFileToolbarIdentifier			= @"Save File Dialog Toolbar";
static NSString *CancelToolbarItemIdentifier		= @"Cancel Toolbar Item";
static NSString *PauseResumeToolbarItemIdentifier	= @"Pause and Resume Toggle Toolbar Item";
static NSString *ShowFileToolbarItemIdentifier		= @"Show File Toolbar Item";
static NSString *OpenFileToolbarItemIdentifier		= @"Open File Toolbar Item";
static NSString *LeaveOpenToolbarItemIdentifier		= @"Leave Open Toggle Toolbar Item";

@interface ProgressDlgController(Private)
-(void)setupToolbar;
@end

@implementation ProgressDlgController

-(void)setWebPersist:(nsIWebBrowserPersist*)aPersist 
              source:(nsISupports*)aSource
         destination:(NSString*)aDestination
         contentType:(const char*)aContentType
            postData:(nsIInputStream*)aInputStream
         bypassCache:(BOOL)aBypassCache
{
    mDownloadListener = new nsDownloadListener(self, aPersist, aSource,
                                               aDestination, aContentType,
                                               aInputStream, aBypassCache);
    NS_ADDREF(mDownloadListener);
}

-(void) setSourceURL: (const char*)aSource
{
    [mFromField setStringValue: [NSString stringWithCString: aSource]];
}

-(void) setDestination: (const char*)aDestination
{
    [mToField setStringValue: [NSString stringWithCString: aDestination]];
}

- (void)windowDidLoad
{
    mDownloadIsPaused = NO; 
    nsCOMPtr<nsIPrefBranch> prefs(do_GetService(prefContractID));
    PRBool save = PR_FALSE;
    prefs->GetBoolPref("browser.download.progressDnldDialog.keepAlive", 
                        &save);
    mSaveFileDialogShouldStayOpen = save;

    [self setupToolbar];
    if (mDownloadListener)
        mDownloadListener->BeginDownload();
}

- (void)setupToolbar
{
    NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier:SaveFileToolbarIdentifier] autorelease];

    [toolbar setDisplayMode:NSToolbarDisplayModeDefault];
    [toolbar setAllowsUserCustomization:YES];
    [toolbar setAutosavesConfiguration:YES];
    [toolbar setDelegate:self];
    [[self window] setToolbar:toolbar];
}

- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
{
    NSLog(@"toolbarAllowedItemIdentifiers:");
    return [NSArray arrayWithObjects: CancelToolbarItemIdentifier,
        PauseResumeToolbarItemIdentifier,
        ShowFileToolbarItemIdentifier,
        OpenFileToolbarItemIdentifier,
        LeaveOpenToolbarItemIdentifier,
        NSToolbarCustomizeToolbarItemIdentifier,
        NSToolbarFlexibleSpaceItemIdentifier,
        NSToolbarSpaceItemIdentifier,
        NSToolbarSeparatorItemIdentifier,
        nil];
}

- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
{
    NSLog(@"toolbarDefaultItemIdentifiers:");
    return [NSArray arrayWithObjects: CancelToolbarItemIdentifier,
        PauseResumeToolbarItemIdentifier,
        NSToolbarFlexibleSpaceItemIdentifier,
        LeaveOpenToolbarItemIdentifier,
        NSToolbarFlexibleSpaceItemIdentifier,
        ShowFileToolbarItemIdentifier,
        OpenFileToolbarItemIdentifier,
        nil];
}

- (NSToolbarItem *) toolbar:(NSToolbar *)toolbar
      itemForItemIdentifier:(NSString *)itemIdent
  willBeInsertedIntoToolbar:(BOOL)willBeInserted
{
    NSLog(@"toolbar:itemForItemIdentifier:%@ willBeInsertedIntoToolbar:%d", itemIdent, willBeInserted);
    NSToolbarItem *toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier:itemIdent] autorelease];

    if ( [itemIdent isEqual:CancelToolbarItemIdentifier] ) {
        [toolbarItem setLabel:@"Cancel"];
        [toolbarItem setPaletteLabel:@"Cancel Download"];
        [toolbarItem setToolTip:@"Cancel this file download"];
        [toolbarItem setImage:[NSImage imageNamed:@"saveCancel"]];
        [toolbarItem setTarget:self];
        [toolbarItem setAction:@selector(cancel)];
    } else if ( [itemIdent isEqual:PauseResumeToolbarItemIdentifier] ) {
        [toolbarItem setLabel:@"Pause"];
        [toolbarItem setPaletteLabel:@"Pause Download"];
        [toolbarItem setToolTip:@"Pause this FTP file download"];
        [toolbarItem setImage:[NSImage imageNamed:@"savePause"]];
        [toolbarItem setTarget:self];
        [toolbarItem setAction:@selector(pauseAndResumeDownload)];
        if ( willBeInserted ) {
            pauseResumeToggleToolbarItem = toolbarItem; //establish reference
        }
    } else if ( [itemIdent isEqual:ShowFileToolbarItemIdentifier] ) {
        [toolbarItem setLabel:@"Show File"];
        [toolbarItem setPaletteLabel:@"Show File"];
        [toolbarItem setToolTip:@"Show the saved file in the Finder"];
        [toolbarItem setImage:[NSImage imageNamed:@"saveShowFile"]];
        [toolbarItem setTarget:self];
        [toolbarItem setAction:@selector(showFile)];
    } else if ( [itemIdent isEqual:OpenFileToolbarItemIdentifier] ) {
        [toolbarItem setLabel:@"Open File"];
        [toolbarItem setPaletteLabel:@"Open File"];
        [toolbarItem setToolTip:@"Open the saved file in its default application."];
        [toolbarItem setImage:[NSImage imageNamed:@"saveOpenFile"]];
        [toolbarItem setTarget:self];
        [toolbarItem setAction:@selector(openFile)];
    } else if ( [itemIdent isEqual:LeaveOpenToolbarItemIdentifier] ) {
        if ( mSaveFileDialogShouldStayOpen ) {
            [toolbarItem setLabel:@"Leave Open"];
            [toolbarItem setPaletteLabel:@"Toggle Close Behavior"];
            [toolbarItem setToolTip:@"Window will stay open when download finishes."];
            [toolbarItem setImage:[NSImage imageNamed:@"saveLeaveOpenYES"]];
            [toolbarItem setTarget:self];
            [toolbarItem setAction:@selector(toggleLeaveOpen)];
        } else {
            [toolbarItem setLabel:@"Close When Done"];
            [toolbarItem setPaletteLabel:@"Toggle Close Behavior"];
            [toolbarItem setToolTip:@"Window will close automatically when download finishes."];
            [toolbarItem setImage:[NSImage imageNamed:@"saveLeaveOpenNO"]];
            [toolbarItem setTarget:self];
            [toolbarItem setAction:@selector(toggleLeaveOpen)];
        }
        if ( willBeInserted ) {
            leaveOpenToggleToolbarItem = toolbarItem; //establish reference
        }
    } else {
        toolbarItem = nil;
    }

    return toolbarItem;
}

-(void)cancel
{
    NSLog(@"Request to cancel download.");
    //Put logic here!
}

-(void)pauseAndResumeDownload
{
    if ( ! mDownloadIsPaused ) {
        //Do logic to pause download
        mDownloadIsPaused = YES;
        [pauseResumeToggleToolbarItem setLabel:@"Resume"];
        [pauseResumeToggleToolbarItem setPaletteLabel:@"Resume Download"];
        [pauseResumeToggleToolbarItem setToolTip:@"Resume the paused FTP download"];
        [pauseResumeToggleToolbarItem setImage:[NSImage imageNamed:@"saveResume"]];
    } else {
        //Do logic to resume download
        mDownloadIsPaused = NO;
        [pauseResumeToggleToolbarItem setLabel:@"Pause"];
        [pauseResumeToggleToolbarItem setPaletteLabel:@"Pause Download"];
        [pauseResumeToggleToolbarItem setToolTip:@"Pause this FTP file download"];
        [pauseResumeToggleToolbarItem setImage:[NSImage imageNamed:@"savePause"]];
    }
}

-(void)showFile
{
    NSLog(@"Request to show file.");
}

-(void)openFile
{
    NSLog(@"Request to open file.");
}

-(void)toggleLeaveOpen
{
    if ( ! mSaveFileDialogShouldStayOpen ) {
        mSaveFileDialogShouldStayOpen = YES;
        [leaveOpenToggleToolbarItem setLabel:@"Leave Open"];
        [leaveOpenToggleToolbarItem setPaletteLabel:@"Toggle Close Behavior"];
        [leaveOpenToggleToolbarItem setToolTip:@"Window will stay open when download finishes."];
        [leaveOpenToggleToolbarItem setImage:[NSImage imageNamed:@"saveLeaveOpenYES"]];
    } else {
        mSaveFileDialogShouldStayOpen = NO;
        [leaveOpenToggleToolbarItem setLabel:@"Close When Done"];
        [leaveOpenToggleToolbarItem setPaletteLabel:@"Toggle Close Behavior"];
        [leaveOpenToggleToolbarItem setToolTip:@"Window will close automatically when download finishes."];
        [leaveOpenToggleToolbarItem setImage:[NSImage imageNamed:@"saveLeaveOpenNO"]];
    }
    
    nsCOMPtr<nsIPrefBranch> prefs(do_GetService(prefContractID));
    prefs->SetBoolPref("browser.download.progressDnldDialog.keepAlive", mSaveFileDialogShouldStayOpen);
}

- (void)windowWillClose:(NSNotification *)notification
{
    [self autorelease];
}

- (void)dealloc
{
    NS_IF_RELEASE(mDownloadListener);
    [super dealloc];
}

@end

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>