File:  [mozdev] / chimera / NSBrowserView.mm
Revision 1.3: download - view: text, annotated - select for diffs - revision graph
Sun Feb 3 06:26:15 2002 UTC (17 years, 9 months ago) by hyatt
Branches: MAIN
CVS tags: HEAD
Save as wired to thep oint of showing the progress UI.

    1: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
    2: /* ***** BEGIN LICENSE BLOCK *****
    3:  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
    4:  *
    5:  * The contents of this file are subject to the Netscape Public License
    6:  * Version 1.1 (the "License"); you may not use this file except in
    7:  * compliance with the License. You may obtain a copy of the License at
    8:  * http://www.mozilla.org/NPL/
    9:  *
   10:  * Software distributed under the License is distributed on an "AS IS" basis,
   11:  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
   12:  * for the specific language governing rights and limitations under the
   13:  * License.
   14:  *
   15:  * The Original Code is mozilla.org code.
   16:  *
   17:  * The Initial Developer of the Original Code is 
   18:  * Netscape Communications Corporation.
   19:  * Portions created by the Initial Developer are Copyright (C) 1998
   20:  * the Initial Developer. All Rights Reserved.
   21:  *
   22:  * Contributor(s):
   23:  *
   24:  * Alternatively, the contents of this file may be used under the terms of
   25:  * either the GNU General Public License Version 2 or later (the "GPL"), or 
   26:  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
   27:  * in which case the provisions of the GPL or the LGPL are applicable instead
   28:  * of those above. If you wish to allow use of your version of this file only
   29:  * under the terms of either the GPL or the LGPL, and not to allow others to
   30:  * use your version of this file under the terms of the NPL, indicate your
   31:  * decision by deleting the provisions above and replace them with the notice
   32:  * and other provisions required by the GPL or the LGPL. If you do not delete
   33:  * the provisions above, a recipient may use your version of this file under
   34:  * the terms of any one of the NPL, the GPL or the LGPL.
   35:  *
   36:  * ***** END LICENSE BLOCK ***** */
   37: 
   38: #import "NSBrowserView.h"
   39: #import "ProgressDlgController.h"
   40: #import "nsCocoaBrowserService.h"
   41: 
   42: // Embedding includes
   43: #include "nsCWebBrowser.h"
   44: #include "nsIInterfaceRequestor.h"
   45: #include "nsIWebBrowserChrome.h"
   46: #include "nsIEmbeddingSiteWindow.h"
   47: #include "nsIWebProgressListener.h"
   48: #include "nsIWebBrowser.h"
   49: #include "nsIWebNavigation.h"
   50: #include "nsIURI.h"
   51: #include "nsIDOMWindow.h"
   52: #include "nsWeakReference.h"
   53: 
   54: // XPCOM and String includes
   55: #include "nsCRT.h"
   56: #include "nsXPIDLString.h"
   57: #include "nsCOMPtr.h"
   58: 
   59: #include "nsIWebBrowserFocus.h"
   60: #include "nsIDOMHTMLDocument.h"
   61: #include "nsIDocument.h"
   62: #include "nsIURL.h"
   63: #include "nsIWebBrowserPersist.h"
   64: #include "nsIProperties.h"
   65: #include "nsIRequest.h"
   66: #include "nsIChannel.h"
   67: #include "nsIHttpChannel.h"
   68: #include "nsIPref.h"
   69: #include "nsIMIMEService.h"
   70: #include "nsIMIMEInfo.h"
   71: #include "nsISHistory.h"
   72: #include "nsIHistoryEntry.h"
   73: #include "nsISHEntry.h"
   74: 
   75: class nsCocoaBrowserListener : public nsSupportsWeakReference,
   76:                                public nsIInterfaceRequestor,
   77: 			       public nsIWebBrowserChrome,
   78: 			       public nsIEmbeddingSiteWindow,
   79:                                public nsIWebProgressListener
   80: {
   81: public:
   82:   nsCocoaBrowserListener(NSBrowserView* aView);
   83:   virtual ~nsCocoaBrowserListener();
   84: 
   85:   NS_DECL_ISUPPORTS
   86:   NS_DECL_NSIINTERFACEREQUESTOR
   87:   NS_DECL_NSIWEBBROWSERCHROME
   88:   NS_DECL_NSIEMBEDDINGSITEWINDOW
   89:   NS_DECL_NSIWEBPROGRESSLISTENER
   90: 
   91:   void AddListener(id <NSBrowserListener> aListener);
   92:   void RemoveListener(id <NSBrowserListener> aListener);
   93:   void SetContainer(id <NSBrowserContainer> aContainer);
   94: 
   95: private:
   96:   NSBrowserView* mView;     // WEAK - it owns us
   97:   NSMutableArray* mListeners;
   98:   id <NSBrowserContainer> mContainer;
   99:   PRBool mIsModal;
  100:   PRUint32 mChromeFlags;
  101: };
  102: 
  103: nsCocoaBrowserListener::nsCocoaBrowserListener(NSBrowserView* aView)
  104:   : mView(aView), mContainer(nsnull), mIsModal(PR_FALSE), mChromeFlags(0)
  105: {
  106:   NS_INIT_ISUPPORTS();
  107:   mListeners = [[NSMutableArray alloc] init];
  108: }
  109: 
  110: nsCocoaBrowserListener::~nsCocoaBrowserListener()
  111: {
  112:   [mListeners release];
  113:   mView = nsnull;
  114:   if (mContainer) {
  115:     [mContainer release];
  116:   }
  117: }
  118: 
  119: NS_IMPL_ISUPPORTS5(nsCocoaBrowserListener,
  120: 		   nsIInterfaceRequestor,
  121: 		   nsIWebBrowserChrome,
  122: 		   nsIEmbeddingSiteWindow,
  123: 		   nsIWebProgressListener,
  124:      		   nsISupportsWeakReference)
  125: 
  126: // Implementation of nsIInterfaceRequestor
  127: NS_IMETHODIMP 
  128: nsCocoaBrowserListener::GetInterface(const nsIID &aIID, void** aInstancePtr)
  129: {
  130:   if (aIID.Equals(NS_GET_IID(nsIDOMWindow))) {
  131:     nsCOMPtr<nsIWebBrowser> browser = dont_AddRef([mView getWebBrowser]);
  132:     if (browser)
  133:       return browser->GetContentDOMWindow((nsIDOMWindow **) aInstancePtr);
  134:   }
  135:   
  136:   return QueryInterface(aIID, aInstancePtr);
  137: }
  138: 
  139: // Implementation of nsIWebBrowserChrome
  140: /* void setStatus (in unsigned long statusType, in wstring status); */
  141: NS_IMETHODIMP 
  142: nsCocoaBrowserListener::SetStatus(PRUint32 statusType, const PRUnichar *status)
  143: {
  144:   if (!mContainer) {
  145:     return NS_ERROR_FAILURE;
  146:   }
  147: 
  148:   NSString* str = nsnull;
  149:   if (status && (*status != PRUnichar(0))) {
  150:     str = [NSString stringWithCharacters:status length:nsCRT::strlen(status)];
  151:   }
  152: 
  153:   [mContainer setStatus:str ofType:(NSStatusType)statusType];
  154: 
  155:   return NS_OK;
  156: }
  157: 
  158: /* attribute nsIWebBrowser webBrowser; */
  159: NS_IMETHODIMP 
  160: nsCocoaBrowserListener::GetWebBrowser(nsIWebBrowser * *aWebBrowser)
  161: {
  162:   NS_ENSURE_ARG_POINTER(aWebBrowser);
  163:   if (!mView) {
  164:     return NS_ERROR_FAILURE;
  165:   }
  166:   *aWebBrowser = [mView getWebBrowser];
  167: 
  168:   return NS_OK;
  169: }
  170: NS_IMETHODIMP 
  171: nsCocoaBrowserListener::SetWebBrowser(nsIWebBrowser * aWebBrowser)
  172: {
  173:   if (!mView) {
  174:     return NS_ERROR_FAILURE;
  175:   }
  176: 
  177:   [mView setWebBrowser:aWebBrowser];
  178: 
  179:   return NS_OK;
  180: }
  181: 
  182: /* attribute unsigned long chromeFlags; */
  183: NS_IMETHODIMP 
  184: nsCocoaBrowserListener::GetChromeFlags(PRUint32 *aChromeFlags)
  185: {
  186:   NS_ENSURE_ARG_POINTER(aChromeFlags);
  187:   *aChromeFlags = mChromeFlags;
  188:   return NS_OK;
  189: }
  190: NS_IMETHODIMP 
  191: nsCocoaBrowserListener::SetChromeFlags(PRUint32 aChromeFlags)
  192: {
  193:   // XXX Do nothing with them for now
  194:   mChromeFlags = aChromeFlags;
  195:   return NS_OK;
  196: }
  197: 
  198: /* void destroyBrowserWindow (); */
  199: NS_IMETHODIMP 
  200: nsCocoaBrowserListener::DestroyBrowserWindow()
  201: {
  202:   // XXX Could send this up to the container, but for now,
  203:   // we just destroy the enclosing window.
  204:   NSWindow* window = [mView window];
  205: 
  206:   if (window) {
  207:     [window close];
  208:   }
  209: 
  210:   return NS_OK;
  211: }
  212: 
  213: /* void sizeBrowserTo (in long aCX, in long aCY); */
  214: NS_IMETHODIMP 
  215: nsCocoaBrowserListener::SizeBrowserTo(PRInt32 aCX, PRInt32 aCY)
  216: {
  217:   if (mContainer) {
  218:     NSSize size;
  219:     
  220:     size.width = (float)aCX;
  221:     size.height = (float)aCY;
  222: 
  223:     [mContainer sizeBrowserTo:size];
  224:   }
  225:   
  226:   return NS_OK;
  227: }
  228: 
  229: /* void showAsModal (); */
  230: NS_IMETHODIMP 
  231: nsCocoaBrowserListener::ShowAsModal()
  232: {
  233:   if (!mView) {
  234:     return NS_ERROR_FAILURE;
  235:   }
  236: 
  237:   NSWindow* window = [mView window];
  238: 
  239:   if (!window) {
  240:     return NS_ERROR_FAILURE;
  241:   }
  242: 
  243:   mIsModal = PR_TRUE;
  244:   int result = [NSApp runModalForWindow:window];
  245:   mIsModal = PR_FALSE;
  246: 
  247:   return (nsresult)result;
  248: }
  249: 
  250: /* boolean isWindowModal (); */
  251: NS_IMETHODIMP 
  252: nsCocoaBrowserListener::IsWindowModal(PRBool *_retval)
  253: {
  254:   NS_ENSURE_ARG_POINTER(_retval);
  255: 
  256:   *_retval = mIsModal;
  257: 
  258:   return NS_OK;
  259: }
  260: 
  261: /* void exitModalEventLoop (in nsresult aStatus); */
  262: NS_IMETHODIMP 
  263: nsCocoaBrowserListener::ExitModalEventLoop(nsresult aStatus)
  264: {
  265:   [NSApp stopModalWithCode:(int)aStatus];
  266: 
  267:   return NS_OK;
  268: }
  269: 
  270: // Implementation of nsIEmbeddingSiteWindow
  271: /* void setDimensions (in unsigned long flags, in long x, in long y, in long cx, in long cy); */
  272: NS_IMETHODIMP 
  273: nsCocoaBrowserListener::SetDimensions(PRUint32 flags, 
  274: 				      PRInt32 x, 
  275: 				      PRInt32 y, 
  276: 				      PRInt32 cx, 
  277: 				      PRInt32 cy)
  278: {
  279:   if (!mView) {
  280:     return NS_ERROR_FAILURE;
  281:   }
  282: 
  283:   NSWindow* window = [mView window];
  284:   if (!window) {
  285:     return NS_ERROR_FAILURE;
  286:   }
  287: 
  288:   if (flags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION) {
  289:     NSPoint origin;
  290:     origin.x = (float)x;
  291:     origin.y = (float)y;
  292:     [window setFrameOrigin:origin];
  293:   }
  294: 
  295:   if (flags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER) {
  296:     NSRect frame = [window frame];
  297:     frame.size.width = (float)cx;
  298:     frame.size.height = (float)cy;
  299:     [window setFrame:frame display:YES];
  300:   }
  301:   else if (flags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER) {
  302:     NSSize size;
  303:     size.width = (float)cx;
  304:     size.height = (float)cy;
  305:     [window setContentSize:size];
  306:   }
  307: 
  308:   return NS_OK;
  309: }
  310: 
  311: /* void getDimensions (in unsigned long flags, out long x, out long y, out long cx, out long cy); */
  312: NS_IMETHODIMP 
  313: nsCocoaBrowserListener::GetDimensions(PRUint32 flags, 
  314: 				      PRInt32 *x, 
  315: 				      PRInt32 *y, 
  316: 				      PRInt32 *cx, 
  317: 				      PRInt32 *cy)
  318: {
  319:   NS_ENSURE_ARG_POINTER(x);
  320:   NS_ENSURE_ARG_POINTER(y);
  321:   NS_ENSURE_ARG_POINTER(cx);
  322:   NS_ENSURE_ARG_POINTER(cy);
  323: 
  324:   if (!mView) {
  325:     return NS_ERROR_FAILURE;
  326:   }
  327: 
  328:   NSWindow* window = [mView window];
  329:   if (!window) {
  330:     return NS_ERROR_FAILURE;
  331:   }
  332: 
  333:   NSRect frame = [window frame];
  334:   if (flags & nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION) {
  335:     *x = (PRInt32)frame.origin.x;
  336:     *y = (PRInt32)frame.origin.y;
  337:   }
  338:   if (flags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER) {
  339:     *cx = (PRInt32)frame.size.width;
  340:     *cy = (PRInt32)frame.size.height;
  341:   }
  342:   else if (flags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER) {
  343:     NSView* contentView = [window contentView];
  344:     NSRect contentFrame = [contentView frame];
  345:     *cx = (PRInt32)contentFrame.size.width;
  346:     *cy = (PRInt32)contentFrame.size.height;    
  347:   }
  348: 
  349:   return NS_OK;
  350: }
  351: 
  352: /* void setFocus (); */
  353: NS_IMETHODIMP 
  354: nsCocoaBrowserListener::SetFocus()
  355: {
  356:   if (!mView) {
  357:     return NS_ERROR_FAILURE;
  358:   }
  359: 
  360:   NSWindow* window = [mView window];
  361:   if (!window) {
  362:     return NS_ERROR_FAILURE;
  363:   }
  364: 
  365:   [window makeKeyAndOrderFront:window];
  366: 
  367:   return NS_OK;
  368: }
  369: 
  370: /* attribute boolean visibility; */
  371: NS_IMETHODIMP 
  372: nsCocoaBrowserListener::GetVisibility(PRBool *aVisibility)
  373: {
  374:   NS_ENSURE_ARG_POINTER(aVisibility);
  375: 
  376:   if (!mView) {
  377:     return NS_ERROR_FAILURE;
  378:   }
  379: 
  380:   NSWindow* window = [mView window];
  381:   if (!window) {
  382:     return NS_ERROR_FAILURE;
  383:   }
  384: 
  385:   *aVisibility = [window isMiniaturized];
  386: 
  387:   return NS_OK;
  388: }
  389: NS_IMETHODIMP 
  390: nsCocoaBrowserListener::SetVisibility(PRBool aVisibility)
  391: {
  392:   if (!mView) {
  393:     return NS_ERROR_FAILURE;
  394:   }
  395: 
  396:   NSWindow* window = [mView window];
  397:   if (!window) {
  398:     return NS_ERROR_FAILURE;
  399:   }
  400: 
  401:   if (aVisibility) {
  402:     [window deminiaturize:window];
  403:   }
  404:   else {
  405:     [window miniaturize:window];
  406:   }
  407: 
  408:   return NS_OK;
  409: }
  410: 
  411: /* attribute wstring title; */
  412: NS_IMETHODIMP 
  413: nsCocoaBrowserListener::GetTitle(PRUnichar * *aTitle)
  414: {
  415:   NS_ENSURE_ARG_POINTER(aTitle);
  416: 
  417:   if (!mContainer) {
  418:     return NS_ERROR_FAILURE;
  419:   }
  420: 
  421:   NSString* title = [mContainer title];
  422:   unsigned int length = [title length];
  423:   if (length) {
  424:     *aTitle = (PRUnichar*)nsMemory::Alloc((length+1)*sizeof(PRUnichar));
  425:     if (!*aTitle) {
  426:       return NS_ERROR_OUT_OF_MEMORY;
  427:     }
  428:     [title getCharacters:*aTitle];
  429:   }
  430:   else {
  431:     *aTitle = nsnull;
  432:   }
  433:   
  434:   return NS_OK;
  435: }
  436: NS_IMETHODIMP 
  437: nsCocoaBrowserListener::SetTitle(const PRUnichar * aTitle)
  438: {
  439:   NS_ENSURE_ARG(aTitle);
  440: 
  441:   if (!mContainer) {
  442:     return NS_ERROR_FAILURE;
  443:   }
  444: 
  445:   NSString* str = [NSString stringWithCharacters:aTitle length:nsCRT::strlen(aTitle)];
  446:   [mContainer setTitle:str];
  447: 
  448:   return NS_OK;
  449: }
  450: 
  451: /* [noscript] readonly attribute voidPtr siteWindow; */
  452: NS_IMETHODIMP 
  453: nsCocoaBrowserListener::GetSiteWindow(void * *aSiteWindow)
  454: {
  455:   NS_ENSURE_ARG_POINTER(aSiteWindow);
  456: 
  457:   if (!mView) {
  458:     return NS_ERROR_FAILURE;
  459:   }
  460: 
  461:   NSWindow* window = [mView window];
  462:   if (!window) {
  463:     return NS_ERROR_FAILURE;
  464:   }
  465: 
  466:   *aSiteWindow = (void*)window;
  467: 
  468:   return NS_OK;
  469: }
  470: 
  471: // Implementation of nsIWebProgressListener
  472: /* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aStateFlags, in unsigned long aStatus); */
  473: NS_IMETHODIMP 
  474: nsCocoaBrowserListener::OnStateChange(nsIWebProgress *aWebProgress, 
  475: 				      nsIRequest *aRequest, 
  476: 				      PRInt32 aStateFlags, 
  477: 				      PRUint32 aStatus)
  478: {
  479:   NSEnumerator* enumerator = [mListeners objectEnumerator];
  480:   id obj;
  481:   
  482:   if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) {
  483:     if (aStateFlags & nsIWebProgressListener::STATE_START) {
  484:       while ((obj = [enumerator nextObject])) {
  485: 	[obj onLoadingStarted];
  486:       }
  487:     }
  488:     else if (aStateFlags & nsIWebProgressListener::STATE_STOP) {
  489:       while ((obj = [enumerator nextObject])) {
  490: 	[obj onLoadingCompleted:(NS_SUCCEEDED(aStatus))];
  491:       }
  492:     }
  493:   }
  494: 
  495: 
  496:   return NS_OK;
  497: }
  498: 
  499: /* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
  500: NS_IMETHODIMP 
  501: nsCocoaBrowserListener::OnProgressChange(nsIWebProgress *aWebProgress, 
  502: 					 nsIRequest *aRequest, 
  503: 					 PRInt32 aCurSelfProgress, 
  504: 					 PRInt32 aMaxSelfProgress, 
  505: 					 PRInt32 aCurTotalProgress, 
  506: 					 PRInt32 aMaxTotalProgress)
  507: {
  508:   NSEnumerator* enumerator = [mListeners objectEnumerator];
  509:   id obj;
  510:  
  511:   while ((obj = [enumerator nextObject])) {
  512:     [obj onProgressChange:aCurTotalProgress outOf:aMaxTotalProgress];
  513:   }
  514:   
  515:   return NS_OK;
  516: }
  517: 
  518: /* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
  519: NS_IMETHODIMP 
  520: nsCocoaBrowserListener::OnLocationChange(nsIWebProgress *aWebProgress, 
  521: 					 nsIRequest *aRequest, 
  522: 					 nsIURI *location)
  523: {
  524:   nsXPIDLCString spec;
  525:   
  526:   location->GetSpec(getter_Copies(spec));
  527:   if (!spec) {
  528:     return NS_ERROR_FAILURE;
  529:   }
  530: 
  531:   const char* cstr = spec.get();
  532:   NSString* str = [NSString stringWithCString:cstr];
  533:   NSURL* url = [NSURL URLWithString:str];
  534: 
  535:   NSEnumerator* enumerator = [mListeners objectEnumerator];
  536:   id obj;
  537:  
  538:   while ((obj = [enumerator nextObject])) {
  539:     [obj onLocationChange:url];
  540:   }
  541: 
  542:   return NS_OK;
  543: }
  544: 
  545: /* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
  546: NS_IMETHODIMP 
  547: nsCocoaBrowserListener::OnStatusChange(nsIWebProgress *aWebProgress, 
  548: 				       nsIRequest *aRequest, 
  549: 				       nsresult aStatus, 
  550: 				       const PRUnichar *aMessage)
  551: {
  552:   return NS_OK;
  553: }
  554: 
  555: /* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long state); */
  556: NS_IMETHODIMP 
  557: nsCocoaBrowserListener::OnSecurityChange(nsIWebProgress *aWebProgress, 
  558: 					 nsIRequest *aRequest, 
  559: 					 PRInt32 state)
  560: {
  561:   return NS_OK;
  562: }
  563: 
  564: void 
  565: nsCocoaBrowserListener::AddListener(id <NSBrowserListener> aListener)
  566: {
  567:   [mListeners addObject:aListener];
  568: }
  569: 
  570: void 
  571: nsCocoaBrowserListener::RemoveListener(id <NSBrowserListener> aListener)
  572: {
  573:   [mListeners removeObject:aListener];
  574: }
  575: 
  576: void 
  577: nsCocoaBrowserListener::SetContainer(id <NSBrowserContainer> aContainer)
  578: {
  579:   [mContainer autorelease];
  580: 
  581:   mContainer = aContainer;
  582: 
  583:   [mContainer retain];
  584: }
  585: 
  586: // Implementation of a header sniffer class that is used when saving Web pages and images.
  587: class nsHeaderSniffer :  public nsIWebProgressListener
  588: {
  589: public:
  590:     nsHeaderSniffer(nsIWebBrowserPersist* aPersist, nsIFile* aFile, nsIURI* aURL,
  591:                     nsIDOMDocument* aDocument, nsIInputStream* aPostData, PRBool aBypassCache,
  592:                     NSView* aFilterView, NSPopUpButton* aFilterList)
  593:     {
  594:         NS_INIT_REFCNT();
  595:         mPersist = aPersist;
  596:         mTmpFile = aFile;
  597:         mURL = aURL;
  598:         mDocument = aDocument;
  599:         mPostData = aPostData;
  600:         mBypassCache = aBypassCache;
  601:         mFilterView = aFilterView;
  602:         mFilterList = aFilterList;
  603:     }
  604:                   
  605:     virtual ~nsHeaderSniffer() {};
  606: 
  607:     NS_DECL_ISUPPORTS
  608:     NS_DECL_NSIWEBPROGRESSLISTENER
  609:   
  610: protected:
  611:     void PerformSave();
  612:     
  613: private:
  614:     nsIWebBrowserPersist* mPersist; // Weak. It owns us as a listener.
  615:     nsCOMPtr<nsIFile> mTmpFile;
  616:     nsCOMPtr<nsIURI> mURL;
  617:     nsCOMPtr<nsIDOMDocument> mDocument;
  618:     nsCOMPtr<nsIInputStream> mPostData;
  619:     PRBool mBypassCache;
  620:     nsCString mContentType;
  621:     nsCString mContentDisposition;
  622:     NSView* mFilterView;
  623:     NSPopUpButton* mFilterList;
  624: };
  625: 
  626: NS_IMPL_ISUPPORTS1(nsHeaderSniffer, nsIWebProgressListener)
  627: 
  628: // Implementation of nsIWebProgressListener
  629: /* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aStateFlags, in unsigned long aStatus); */
  630: NS_IMETHODIMP 
  631: nsHeaderSniffer::OnStateChange(nsIWebProgress *aWebProgress, 
  632: 				      nsIRequest *aRequest, 
  633: 				      PRInt32 aStateFlags, 
  634: 				      PRUint32 aStatus)
  635: {
  636:     if (aStateFlags & nsIWebProgressListener::STATE_START) {
  637:         nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
  638:         nsXPIDLCString contentType;
  639:         channel->GetContentType(getter_Copies(contentType));
  640:         mContentType = contentType;
  641:         
  642:         // Get the content-disposition if we're an HTTP channel.
  643:         nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
  644:         if (httpChannel) {
  645:             nsXPIDLCString disp;
  646:             httpChannel->GetResponseHeader("content-disposition", getter_Copies(disp));
  647:             mContentDisposition = disp;
  648:         }
  649:         
  650:         mPersist->CancelSave();
  651:         PRBool exists;
  652:         mTmpFile->Exists(&exists);
  653:         if (exists)
  654:             mTmpFile->Remove(PR_FALSE);
  655:         PerformSave();
  656:     }
  657:     return NS_OK;
  658: }
  659: 
  660: void nsHeaderSniffer::PerformSave()
  661: {
  662:     // Are we an HTML document? If so, we will want to append an accessory view to
  663:     // the save dialog to provide the user with the option of doing a complete
  664:     // save vs. a single file save.
  665:     PRBool isHTML = (mDocument && mContentType.Equals("text/html") ||
  666:                      mContentType.Equals("text/xml") ||
  667:                      mContentType.Equals("application/xhtml+xml"));
  668:     
  669:     // Next find out the directory that we should start in.
  670:     nsCOMPtr<nsIPrefService> prefs(do_GetService("@mozilla.org/preferences-service;1"));
  671:     if (!prefs)
  672:         return;
  673:     nsCOMPtr<nsIPrefBranch> dirBranch;
  674:     prefs->GetBranch("browser.download.", getter_AddRefs(dirBranch));
  675:     PRInt32 filterIndex = 0;
  676:     if (dirBranch) {
  677:         nsresult rv = dirBranch->GetIntPref("save_converter_index", &filterIndex);
  678:         if (NS_FAILED(rv))
  679:             filterIndex = 0;
  680:     }
  681:     if (mFilterList)
  682:         [mFilterList selectItemAtIndex: filterIndex];
  683:         
  684:     // We need to figure out what file name to use.
  685:     nsCAutoString defaultFileName;
  686:     
  687:     if (!mContentDisposition.IsEmpty()) {
  688:         // (1) Use the HTTP header suggestion.
  689:         PRInt32 index = mContentDisposition.Find("filename=");
  690:         if (index >= 0) {
  691:             // Take the substring following the prefix.
  692:             index += 9;
  693:             nsCAutoString filename;
  694:             mContentDisposition.Right(filename, mContentDisposition.Length() - index);
  695:             defaultFileName = filename;
  696:         }
  697:     }
  698:     
  699:     if (defaultFileName.IsEmpty()) {
  700:         nsCOMPtr<nsIURL> url(do_QueryInterface(mURL));
  701:         if (url) {
  702:             nsXPIDLCString fileName;
  703:             url->GetFileName(getter_Copies(fileName));
  704:             defaultFileName = fileName; // (2) For file URLs, use the file name.
  705:         }
  706:     }
  707:     
  708:     if (defaultFileName.IsEmpty() && mDocument && isHTML) {
  709:         nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
  710:         nsAutoString title;
  711:         if (htmlDoc)
  712:             htmlDoc->GetTitle(title); // (3) Use the title of the document.
  713:         defaultFileName.AssignWithConversion(title);
  714:     }
  715:     
  716:     if (defaultFileName.IsEmpty()) {
  717:         // (4) Use the caller provided name. XXXdwh
  718:     }
  719: 
  720:     if (defaultFileName.IsEmpty()) {
  721:         // (5) Use the host.
  722:         nsXPIDLCString host;
  723:         mURL->GetHost(getter_Copies(host));
  724:         defaultFileName = host;
  725:     }
  726:     
  727:     // One last case to handle about:blank and other fruity untitled pages.
  728:     if (defaultFileName.IsEmpty())
  729:         defaultFileName = "untitled";
  730:         
  731:     // Validate the file name to ensure legality.
  732:     for (PRUint32 i = 0; i < defaultFileName.Length(); i++)
  733:         if (defaultFileName[i] == ':' || defaultFileName[i] == '/')
  734:             defaultFileName.SetCharAt(i, ' ');
  735:             
  736:     // Make sure the appropriate extension is appended to the suggested file name.
  737:     nsCOMPtr<nsIURI> fileURI(do_CreateInstance("@mozilla.org/network/standard-url;1"));
  738:     nsCOMPtr<nsIURL> fileURL(do_QueryInterface(fileURI));
  739:     if (!fileURL)
  740:         return;
  741:     fileURL->SetFilePath(defaultFileName.get());
  742:     
  743:     nsXPIDLCString fileEx;
  744:     fileURL->GetFileExtension(getter_Copies(fileEx));
  745:     nsDependentCString fileExtension(fileEx.get());
  746:     
  747:     PRBool setExtension = PR_FALSE;
  748:     if (mContentType.Equals("text/html")) {
  749:         if (fileExtension.IsEmpty() || (!fileExtension.Equals("htm") && !fileExtension.Equals("html"))) {
  750:             defaultFileName += ".html";
  751:             setExtension = PR_TRUE;
  752:         }
  753:     }
  754:     
  755:     if (!setExtension && fileExtension.IsEmpty()) {
  756:         nsCOMPtr<nsIMIMEService> mimeService(do_GetService("@mozilla.org/mime;1"));
  757:         if (!mimeService)
  758:             return;
  759:         nsCOMPtr<nsIMIMEInfo> mimeInfo;
  760:         mimeService->GetFromMIMEType(mContentType.get(), getter_AddRefs(mimeInfo));
  761:         
  762:         PRUint32 extCount;
  763:         char** extList;
  764:         mimeInfo->GetFileExtensions(&extCount, &extList);
  765:         
  766:         if (extCount > 0) {
  767:             defaultFileName += ".";
  768:             defaultFileName += extList[0];
  769:         }
  770:     }
  771:     
  772:     // Now it's time to pose the save dialog.
  773:     NSSavePanel* savePanel = [NSSavePanel savePanel];
  774:     NSString* file = nil;
  775:     if (!defaultFileName.IsEmpty())
  776:         file = [[NSString alloc] initWithCString: defaultFileName.get()];
  777:         
  778:     if (isHTML)
  779:         [savePanel setAccessoryView: mFilterView];
  780:         
  781:     if ([savePanel runModalForDirectory: nil file: file] == NSFileHandlingPanelCancelButton)
  782:         return;
  783:        
  784:     // Release the file string.
  785:     [file release];
  786:     
  787:     // Update the filter index.
  788:     if (isHTML && mFilterList) {
  789:         filterIndex = [mFilterList indexOfSelectedItem];
  790:         dirBranch->SetIntPref("save_converter_index", filterIndex);
  791:     }
  792:     
  793:     // Convert the content type to text/plain if it was selected in the filter.
  794:     if (isHTML && filterIndex == 2)
  795:         mContentType = "text/plain";
  796:     
  797:     nsCOMPtr<nsISupports> sourceData;
  798:     if (isHTML && filterIndex != 1)
  799:         sourceData = do_QueryInterface(mDocument);
  800:     else
  801:         sourceData = do_QueryInterface(mURL);
  802:         
  803:     ProgressDlgController* progressDialog = [[ProgressDlgController alloc] initWithWindowNibName: @"ProgressDialog"];
  804:     [progressDialog setWebPersist: mPersist 
  805:                     source: sourceData.get()
  806:                     destination: [savePanel filename]
  807:                     contentType: mContentType.get()
  808:                     postData: mPostData
  809:                     bypassCache: mBypassCache];
  810:                     
  811:     [progressDialog showWindow: progressDialog];
  812: }
  813: 
  814: /* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
  815: NS_IMETHODIMP 
  816: nsHeaderSniffer::OnProgressChange(nsIWebProgress *aWebProgress, 
  817: 					 nsIRequest *aRequest, 
  818: 					 PRInt32 aCurSelfProgress, 
  819: 					 PRInt32 aMaxSelfProgress, 
  820: 					 PRInt32 aCurTotalProgress, 
  821: 					 PRInt32 aMaxTotalProgress)
  822: {
  823:   return NS_OK;
  824: }
  825: 
  826: /* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
  827: NS_IMETHODIMP 
  828: nsHeaderSniffer::OnLocationChange(nsIWebProgress *aWebProgress, 
  829: 					 nsIRequest *aRequest, 
  830: 					 nsIURI *location)
  831: {
  832:   return NS_OK;
  833: }
  834: 
  835: /* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
  836: NS_IMETHODIMP 
  837: nsHeaderSniffer::OnStatusChange(nsIWebProgress *aWebProgress, 
  838: 				       nsIRequest *aRequest, 
  839: 				       nsresult aStatus, 
  840: 				       const PRUnichar *aMessage)
  841: {
  842:   return NS_OK;
  843: }
  844: 
  845: /* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long state); */
  846: NS_IMETHODIMP 
  847: nsHeaderSniffer::OnSecurityChange(nsIWebProgress *aWebProgress, 
  848: 					              nsIRequest *aRequest, 
  849:                                   PRInt32 state)
  850: {
  851:   return NS_OK;
  852: }
  853: 
  854: 
  855: @implementation NSBrowserView
  856: 
  857: - (id)initWithFrame:(NSRect)frame
  858: {
  859:   [super initWithFrame:frame];
  860: 
  861:   nsresult rv = nsCocoaBrowserService::InitEmbedding();
  862:   if (NS_FAILED(rv)) {
  863:     // XXX need to throw
  864:   }
  865:   
  866:   _listener = new nsCocoaBrowserListener(self);
  867:   NS_ADDREF(_listener);
  868: 
  869:   // Create the web browser instance
  870:   nsCOMPtr<nsIWebBrowser> browser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID, &rv);
  871:   if (NS_FAILED(rv)) {
  872:     // XXX need to throw
  873:   }
  874: 
  875:   _webBrowser = browser;
  876:   NS_ADDREF(_webBrowser);
  877: 
  878:   // Set the container nsIWebBrowserChrome
  879:   _webBrowser->SetContainerWindow(NS_STATIC_CAST(nsIWebBrowserChrome *, 
  880: 						 _listener));
  881:   
  882:   // Register as a listener for web progress
  883:   nsCOMPtr<nsIWeakReference> weak = do_GetWeakReference(NS_STATIC_CAST(nsIWebProgressListener*, _listener));
  884:   _webBrowser->AddWebBrowserListener(weak, NS_GET_IID(nsIWebProgressListener));
  885: 
  886:   // Hook up the widget hierarchy with us as the parent
  887:   nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(_webBrowser);
  888:   baseWin->InitWindow((NSView*)self, nsnull, 0, 0, 
  889: 		      frame.size.width, frame.size.height);
  890:   baseWin->Create();
  891: 
  892:   return self;
  893: }
  894: 
  895: - (void)dealloc 
  896: {
  897:   NS_RELEASE(_listener);
  898:   NS_IF_RELEASE(_webBrowser);
  899:   nsCocoaBrowserService::TermEmbedding();
  900: 
  901:   [super dealloc];
  902: }
  903: 
  904: - (void)setFrame:(NSRect)frameRect 
  905: {
  906:   [super setFrame:frameRect];
  907:   if (_webBrowser) {
  908:     nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(_webBrowser);
  909:     window->SetSize((PRInt32)frameRect.size.width, 
  910: 		    (PRInt32)frameRect.size.height,
  911: 		    PR_TRUE);
  912:   }
  913: }
  914: 
  915: - (void)addListener:(id <NSBrowserListener>)listener
  916: {
  917:   _listener->AddListener(listener);
  918: }
  919: 
  920: - (void)removeListener:(id <NSBrowserListener>)listener
  921: {
  922:   _listener->RemoveListener(listener);
  923: }
  924: 
  925: - (void)setContainer:(id <NSBrowserContainer>)container
  926: {
  927:   _listener->SetContainer(container);
  928: }
  929: 
  930: - (nsIDOMWindow*)getContentWindow
  931: {
  932:   nsIDOMWindow* window;
  933: 
  934:   _webBrowser->GetContentDOMWindow(&window);
  935: 
  936:   return window;
  937: }
  938: 
  939: - (void)loadURI:(NSURL *)url flags:(unsigned int)flags
  940: {
  941:   nsCOMPtr<nsIWebNavigation> nav = do_QueryInterface(_webBrowser);
  942:   
  943:   NSString* spec = [url absoluteString];
  944:   int length = [spec length];
  945:   PRUnichar* specStr = nsMemory::Alloc((length+1) * sizeof(PRUnichar));
  946:   [spec getCharacters:specStr];
  947:   specStr[length] = PRUnichar(0);
  948:   
  949: 
  950:   PRUint32 navFlags = nsIWebNavigation::LOAD_FLAGS_NONE;
  951:   if (flags & NSLoadFlagsDontPutInHistory) {
  952:     navFlags |= nsIWebNavigation::LOAD_FLAGS_BYPASS_HISTORY;
  953:   }
  954:   if (flags & NSLoadFlagsReplaceHistoryEntry) {
  955:     navFlags |= nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY;
  956:   }
  957:   if (flags & NSLoadFlagsBypassCacheAndProxy) {
  958:     navFlags |= nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE | 
  959:                 nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY;
  960:   }
  961: 
  962:   nsresult rv = nav->LoadURI(specStr, navFlags, nsnull, nsnull, nsnull);
  963:   if (NS_FAILED(rv)) {
  964:     // XXX need to throw
  965:   }
  966: 
  967:   nsMemory::Free(specStr);
  968: }
  969: 
  970: - (void)reload:(unsigned int)flags
  971: {
  972:   nsCOMPtr<nsIWebNavigation> nav = do_QueryInterface(_webBrowser);
  973: 
  974:   PRUint32 navFlags = nsIWebNavigation::LOAD_FLAGS_NONE;
  975:   if (flags & NSLoadFlagsBypassCacheAndProxy) {
  976:     navFlags |= nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE | 
  977:                 nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY;
  978:   }
  979: 
  980:   nsresult rv = nav->Reload(navFlags);
  981:   if (NS_FAILED(rv)) {
  982:     // XXX need to throw
  983:   }  
  984: }
  985: 
  986: - (BOOL)canGoBack
  987: {
  988:   nsCOMPtr<nsIWebNavigation> nav = do_QueryInterface(_webBrowser);
  989: 
  990:   PRBool can;
  991:   nav->GetCanGoBack(&can);
  992: 
  993:   return can ? YES : NO;
  994: }
  995: 
  996: - (BOOL)canGoForward
  997: {
  998:   nsCOMPtr<nsIWebNavigation> nav = do_QueryInterface(_webBrowser);
  999: 
 1000:   PRBool can;
 1001:   nav->GetCanGoForward(&can);
 1002: 
 1003:   return can ? YES : NO;
 1004: }
 1005: 
 1006: - (void)goBack
 1007: {
 1008:   nsCOMPtr<nsIWebNavigation> nav = do_QueryInterface(_webBrowser);
 1009: 
 1010:   nsresult rv = nav->GoBack();
 1011:   if (NS_FAILED(rv)) {
 1012:     // XXX need to throw
 1013:   }  
 1014: }
 1015: 
 1016: - (void)goForward
 1017: {
 1018:   nsCOMPtr<nsIWebNavigation> nav = do_QueryInterface(_webBrowser);
 1019: 
 1020:   nsresult rv = nav->GoForward();
 1021:   if (NS_FAILED(rv)) {
 1022:     // XXX need to throw
 1023:   }  
 1024: }
 1025: 
 1026: - (void)gotoIndex:(int)index
 1027: {
 1028:   nsCOMPtr<nsIWebNavigation> nav = do_QueryInterface(_webBrowser);
 1029: 
 1030:   nsresult rv = nav->GotoIndex(index);
 1031:   if (NS_FAILED(rv)) {
 1032:     // XXX need to throw
 1033:   }    
 1034: }
 1035: 
 1036: - (void)stop:(unsigned int)flags
 1037: {
 1038:   nsCOMPtr<nsIWebNavigation> nav = do_QueryInterface(_webBrowser);
 1039: 
 1040:   nsresult rv = nav->Stop(flags);
 1041:   if (NS_FAILED(rv)) {
 1042:     // XXX need to throw
 1043:   }    
 1044: }
 1045: 
 1046: - (NSURL*)getCurrentURI
 1047: {
 1048:   nsCOMPtr<nsIURI> uri;
 1049:   nsCOMPtr<nsIWebNavigation> nav = do_QueryInterface(_webBrowser);
 1050: 
 1051:   nav->GetCurrentURI(getter_AddRefs(uri));
 1052:   if (!uri) {
 1053:     return nsnull;
 1054:   }
 1055: 
 1056:   nsXPIDLCString spec;
 1057:   uri->GetSpec(getter_Copies(spec));
 1058:   
 1059:   const char* cstr = spec.get();
 1060:   NSString* str = [NSString stringWithCString:cstr];
 1061:   NSURL* url = [NSURL URLWithString:str];
 1062:   
 1063:   return url;
 1064: }
 1065: 
 1066: - (nsIWebBrowser*)getWebBrowser
 1067: {
 1068:   NS_IF_ADDREF(_webBrowser);
 1069:   return _webBrowser;
 1070: }
 1071: 
 1072: - (void)setWebBrowser:(nsIWebBrowser*)browser
 1073: {
 1074:   _webBrowser = browser;
 1075: 
 1076:   if (_webBrowser) {
 1077:     // Set the container nsIWebBrowserChrome
 1078:     _webBrowser->SetContainerWindow(NS_STATIC_CAST(nsIWebBrowserChrome *, 
 1079: 						   _listener));
 1080: 
 1081:     NSRect frame = [self frame];
 1082:  
 1083:     // Hook up the widget hierarchy with us as the parent
 1084:     nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(_webBrowser);
 1085:     baseWin->InitWindow((NSView*)self, nsnull, 0, 0, 
 1086: 			frame.size.width, frame.size.height);
 1087:     baseWin->Create();
 1088:   }
 1089: 
 1090: }
 1091: 
 1092: const char* persistContractID = "@mozilla.org/embedding/browser/nsWebBrowserPersist;1";
 1093: const char* dirServiceContractID = "@mozilla.org/file/directory_service;1";
 1094: 
 1095: -(void) saveInternal: (nsIURI*)aURI
 1096:         withDocument: (nsIDOMDocument*)aDocument
 1097:         bypassCache: (BOOL)aBypassCache
 1098:         filterView: (NSView*)aFilterView
 1099:         filterList: (NSPopUpButton*)aFilterList
 1100: {
 1101:     // Create our web browser persist object.  This is the object that knows
 1102:     // how to actually perform the saving of the page (and of the images
 1103:     // on the page).
 1104:     nsCOMPtr<nsIWebBrowserPersist> webPersist(do_CreateInstance(persistContractID));
 1105:     if (!webPersist)
 1106:         return;
 1107:     
 1108:     // Make a temporary file object that we can save to.
 1109:     nsCOMPtr<nsIProperties> dirService(do_GetService(dirServiceContractID));
 1110:     if (!dirService)
 1111:         return;
 1112:     nsCOMPtr<nsIFile> tmpFile;
 1113:     dirService->Get("TmpD", NS_GET_IID(nsIFile), getter_AddRefs(tmpFile));
 1114:     static short unsigned int tmpRandom = 0;
 1115:     nsCAutoString tmpNo; tmpNo.AssignWithConversion(tmpRandom++);
 1116:     nsCAutoString saveFile("-sav");
 1117:     saveFile += tmpNo;
 1118:     saveFile += "tmp";
 1119:     tmpFile->Append(saveFile.get()); 
 1120:     
 1121:     // Get the post data if we're an HTML doc.
 1122:     nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(_webBrowser));
 1123:     nsCOMPtr<nsISHistory> sessionHistory;
 1124:     webNav->GetSessionHistory(getter_AddRefs(sessionHistory));
 1125:     nsCOMPtr<nsIHistoryEntry> entry;
 1126:     PRInt32 sindex;
 1127:     sessionHistory->GetIndex(&sindex);
 1128:     sessionHistory->GetEntryAtIndex(sindex, PR_FALSE, getter_AddRefs(entry));
 1129:     nsCOMPtr<nsISHEntry> shEntry(do_QueryInterface(entry));
 1130:     nsCOMPtr<nsIInputStream> postData;
 1131:     if (shEntry)
 1132:         shEntry->GetPostData(getter_AddRefs(postData));
 1133:     
 1134:     nsHeaderSniffer* sniffer = new nsHeaderSniffer(webPersist, tmpFile, aURI, 
 1135:                                                    aDocument, postData, aBypassCache,
 1136:                                                    aFilterView, aFilterList);
 1137:     if (!sniffer)
 1138:         return;
 1139:     webPersist->SetProgressListener(sniffer);
 1140:     webPersist->SaveURI(aURI, nsnull, tmpFile);
 1141: }
 1142: 
 1143: -(void)saveDocument: (NSView*)aFilterView filterList: (NSPopUpButton*)aFilterList
 1144: {
 1145:     nsCOMPtr<nsIWebBrowserFocus> wbf(do_QueryInterface(_webBrowser));
 1146:     nsCOMPtr<nsIDOMWindow> domWindow;
 1147:     wbf->GetFocusedWindow(getter_AddRefs(domWindow));
 1148:     if (!domWindow)
 1149:         _webBrowser->GetContentDOMWindow(getter_AddRefs(domWindow));
 1150:     if (!domWindow)
 1151:         return;
 1152:     
 1153:     nsCOMPtr<nsIDOMDocument> domDocument;
 1154:     domWindow->GetDocument(getter_AddRefs(domDocument));
 1155:     if (!domDocument)
 1156:         return;
 1157:     nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDocument));
 1158:     if (!doc)
 1159:         return;
 1160:     nsCOMPtr<nsIURI> url;
 1161:     doc->GetDocumentURL(getter_AddRefs(url));
 1162:      
 1163:     [self saveInternal: url.get()
 1164:           withDocument: domDocument
 1165:           bypassCache: NO
 1166:           filterView: aFilterView
 1167:           filterList: aFilterList];
 1168: }
 1169: 
 1170: @end
 1171: 

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