File:  [mozdev] / chimera / NSBrowserView.mm
Revision 1.2: download - view: text, annotated - select for diffs - revision graph
Sun Feb 3 05:53:12 2002 UTC (17 years, 9 months ago) by hyatt
Branches: MAIN
CVS tags: HEAD
A huge amount of code for File/Save As...

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

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