Back to index

lightning-sunbird  0.9+nobinonly
nsEditingSession.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Simon Fraser   <sfraser@netscape.com>
00024  *   Michael Judge  <mjudge@netscape.com>
00025  *   Charles Manske <cmanske@netscape.com>
00026  *   Kathleen Brade <brade@netscape.com>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either of the GNU General Public License Version 2 or later (the "GPL"),
00030  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include "nsIDOMWindow.h"
00043 #include "nsIDOMWindowUtils.h"
00044 #include "nsIDOMWindowInternal.h"
00045 #include "nsIDOMNSHTMLDocument.h"
00046 #include "nsIDocument.h"
00047 #include "nsIHTMLDocument.h"
00048 #include "nsIDOMDocument.h"
00049 #include "nsIURI.h"
00050 #include "nsIScriptGlobalObject.h"
00051 #include "nsISelectionPrivate.h"
00052 #include "nsITransactionManager.h"
00053 
00054 #include "nsIEditorDocShell.h"
00055 #include "nsIDocShell.h"
00056 
00057 #include "nsIChannel.h"
00058 #include "nsIWebProgress.h"
00059 #include "nsIWebNavigation.h"
00060 #include "nsIRefreshURI.h"
00061 
00062 #include "nsIControllers.h"
00063 #include "nsIController.h"
00064 #include "nsIControllerContext.h"
00065 #include "nsICommandManager.h"
00066 #include "nsPICommandUpdater.h"
00067 
00068 #include "nsIPresShell.h"
00069 
00070 #include "nsComposerCommandsUpdater.h"
00071 #include "nsEditingSession.h"
00072 
00073 #include "nsComponentManagerUtils.h"
00074 #include "nsIInterfaceRequestorUtils.h"
00075 
00076 #include "nsIContentViewer.h"
00077 #include "nsISelectionController.h"
00078 #include "nsIPlaintextEditor.h"
00079 #include "nsIEditor.h"
00080 
00081 #include "nsIDOMNSDocument.h"
00082 #include "nsIScriptContext.h"
00083 #include "imgIContainer.h"
00084 #include "nsPresContext.h"
00085 
00086 #if DEBUG
00087 //#define NOISY_DOC_LOADING  1
00088 #endif
00089 
00090 /*---------------------------------------------------------------------------
00091 
00092   nsEditingSession
00093 
00094 ----------------------------------------------------------------------------*/
00095 nsEditingSession::nsEditingSession()
00096 : mDoneSetup(PR_FALSE)
00097 , mCanCreateEditor(PR_FALSE)
00098 , mScriptsEnabled(PR_TRUE)
00099 , mPluginsEnabled(PR_TRUE)
00100 , mProgressListenerRegistered(PR_FALSE)
00101 , mImageAnimationMode(0)
00102 , mEditorFlags(0)
00103 , mEditorStatus(eEditorOK)
00104 , mBaseCommandControllerId(0)
00105 , mDocStateControllerId(0)
00106 , mHTMLCommandControllerId(0)
00107 {
00108 }
00109 
00110 /*---------------------------------------------------------------------------
00111 
00112   ~nsEditingSession
00113 
00114 ----------------------------------------------------------------------------*/
00115 nsEditingSession::~nsEditingSession()
00116 {
00117   // Must cancel previous timer?
00118   if (mLoadBlankDocTimer)
00119     mLoadBlankDocTimer->Cancel();
00120 }
00121 
00122 NS_IMPL_ISUPPORTS4(nsEditingSession, nsIEditingSession, nsIWebProgressListener, 
00123                    nsIURIContentListener, nsISupportsWeakReference)
00124 
00125 /*---------------------------------------------------------------------------
00126 
00127   MakeWindowEditable
00128 
00129   aEditorType string, "html" "htmlsimple" "text" "textsimple"
00130   void makeWindowEditable(in nsIDOMWindow aWindow, in string aEditorType, 
00131                           in boolean aDoAfterUriLoad);
00132 ----------------------------------------------------------------------------*/
00133 #define DEFAULT_EDITOR_TYPE "html"
00134 
00135 NS_IMETHODIMP
00136 nsEditingSession::MakeWindowEditable(nsIDOMWindow *aWindow,
00137                                      const char *aEditorType, 
00138                                      PRBool aDoAfterUriLoad)
00139 {
00140   mEditorType.Truncate();
00141   mEditorFlags = 0;
00142   mWindowToBeEdited = do_GetWeakReference(aWindow);
00143 
00144   // disable plugins
00145   nsIDocShell *docShell = GetDocShellFromWindow(aWindow);
00146   if (!docShell) return NS_ERROR_FAILURE;
00147 
00148   // register as a content listener, so that we can fend off URL
00149   // loads from sidebar
00150   nsresult rv;
00151   nsCOMPtr<nsIURIContentListener> listener = do_GetInterface(docShell, &rv);
00152   NS_ENSURE_SUCCESS(rv, rv);
00153 
00154   rv = listener->SetParentContentListener(this);
00155   NS_ENSURE_SUCCESS(rv, rv);
00156 
00157   // Disable JavaScript in this document:
00158   PRBool tmp;
00159   rv = docShell->GetAllowJavascript(&tmp);
00160   NS_ENSURE_SUCCESS(rv, rv);
00161 
00162   mScriptsEnabled = tmp;
00163 
00164   rv = docShell->SetAllowJavascript(PR_FALSE);
00165   NS_ENSURE_SUCCESS(rv, rv);
00166 
00167   // Disable plugins in this document:
00168   rv = docShell->GetAllowPlugins(&tmp);
00169   NS_ENSURE_SUCCESS(rv, rv);
00170 
00171   mPluginsEnabled = tmp;
00172 
00173   rv = docShell->SetAllowPlugins(PR_FALSE);
00174   NS_ENSURE_SUCCESS(rv, rv);
00175 
00176   // Always remove existing editor
00177   TearDownEditorOnWindow(aWindow);
00178   
00179   // Tells embedder that startup is in progress
00180   mEditorStatus = eEditorCreationInProgress;
00181 
00182   //temporary to set editor type here. we will need different classes soon.
00183   if (!aEditorType)
00184     aEditorType = DEFAULT_EDITOR_TYPE;
00185   mEditorType = aEditorType;
00186 
00187   // if all this does is setup listeners and I don't need listeners, 
00188   // can't this step be ignored?? (based on aDoAfterURILoad)
00189   rv = PrepareForEditing(aWindow);
00190   if (NS_FAILED(rv)) return rv;  
00191   
00192   nsCOMPtr<nsIEditorDocShell> editorDocShell;
00193   rv = GetEditorDocShellFromWindow(aWindow, getter_AddRefs(editorDocShell));
00194   if (NS_FAILED(rv)) return rv;  
00195   
00196   // set the flag on the docShell to say that it's editable
00197   rv = editorDocShell->MakeEditable(aDoAfterUriLoad);
00198   if (NS_FAILED(rv)) return rv;  
00199 
00200   // Setup commands common to plaintext and html editors,
00201   //  including the document creation observers
00202   // the first is an editor controller
00203   rv = SetupEditorCommandController("@mozilla.org/editor/editorcontroller;1",
00204                                     aWindow,
00205                                     NS_STATIC_CAST(nsIEditingSession*, this),
00206                                     &mBaseCommandControllerId);
00207   if (NS_FAILED(rv)) return rv;
00208 
00209   // The second is a controller to monitor doc state,
00210   // such as creation and "dirty flag"
00211   rv = SetupEditorCommandController("@mozilla.org/editor/editordocstatecontroller;1",
00212                                     aWindow,
00213                                     NS_STATIC_CAST(nsIEditingSession*, this),
00214                                     &mDocStateControllerId);
00215   if (NS_FAILED(rv)) return rv;
00216 
00217   // aDoAfterUriLoad can be false only when making an existing window editable
00218   if (!aDoAfterUriLoad)
00219   {
00220     rv = SetupEditorOnWindow(aWindow);
00221 
00222     // mEditorStatus is set to the error reason
00223     // Since this is used only when editing an existing page,
00224     //  it IS ok to destroy current editor
00225     if (NS_FAILED(rv))
00226       TearDownEditorOnWindow(aWindow);
00227   }
00228   return rv;
00229 }
00230 
00231 /*---------------------------------------------------------------------------
00232 
00233   WindowIsEditable
00234 
00235   boolean windowIsEditable (in nsIDOMWindow aWindow);
00236 ----------------------------------------------------------------------------*/
00237 NS_IMETHODIMP
00238 nsEditingSession::WindowIsEditable(nsIDOMWindow *aWindow, PRBool *outIsEditable)
00239 {
00240   nsCOMPtr<nsIEditorDocShell> editorDocShell;
00241   nsresult rv = GetEditorDocShellFromWindow(aWindow,
00242                                             getter_AddRefs(editorDocShell));
00243   if (NS_FAILED(rv)) return rv;  
00244 
00245   return editorDocShell->GetEditable(outIsEditable);
00246 }
00247 
00248 
00249 // These are MIME types that are automatically parsed as "text/plain"
00250 //   and thus we can edit them as plaintext
00251 // Note: in older versions, we attempted to convert the mimetype of
00252 //   the network channel for these and "text/xml" to "text/plain", 
00253 //   but further investigation reveals that strategy doesn't work
00254 const char* const gSupportedTextTypes[] = {
00255   "text/plain",
00256   "text/css",
00257   "text/rdf",
00258   "text/xsl",
00259   "text/javascript",           // obsolete type
00260   "text/ecmascript",           // obsolete type
00261   "application/javascript",
00262   "application/ecmascript",
00263   "application/x-javascript",  // obsolete type
00264   "text/xul",                  // obsolete type
00265   "application/vnd.mozilla.xul+xml",
00266   NULL      // IMPORTANT! Null must be at end
00267 };
00268 
00269 PRBool
00270 IsSupportedTextType(const char* aMIMEType)
00271 {
00272   if (!aMIMEType)
00273     return PR_FALSE;
00274 
00275   PRInt32 i = 0;
00276   while (gSupportedTextTypes[i])
00277   {
00278     if (strcmp(gSupportedTextTypes[i], aMIMEType) == 0)
00279     {
00280       return PR_TRUE;
00281     }
00282 
00283     i ++;
00284   }
00285   
00286   return PR_FALSE;
00287 }
00288 
00289 /*---------------------------------------------------------------------------
00290 
00291   SetupEditorOnWindow
00292 
00293   nsIEditor setupEditorOnWindow (in nsIDOMWindow aWindow);
00294 ----------------------------------------------------------------------------*/
00295 NS_IMETHODIMP
00296 nsEditingSession::SetupEditorOnWindow(nsIDOMWindow *aWindow)
00297 {
00298   nsresult rv;
00299 
00300   //MIME CHECKING
00301   //must get the content type
00302   // Note: the doc gets this from the network channel during StartPageLoad,
00303   //    so we don't have to get it from there ourselves
00304   nsCOMPtr<nsIDOMDocument> doc;
00305   nsCAutoString mimeCType;
00306 
00307   //then lets check the mime type
00308   if (NS_SUCCEEDED(aWindow->GetDocument(getter_AddRefs(doc))) && doc)
00309   {
00310     nsCOMPtr<nsIDOMNSDocument> nsdoc = do_QueryInterface(doc);
00311     if (nsdoc)
00312     {
00313       nsAutoString mimeType;
00314       if (NS_SUCCEEDED(nsdoc->GetContentType(mimeType)))
00315         AppendUTF16toUTF8(mimeType, mimeCType);
00316 
00317       if (IsSupportedTextType(mimeCType.get()))
00318       {
00319         mEditorType.AssignLiteral("text");
00320         mimeCType = "text/plain";
00321       }
00322       else if (!mimeCType.EqualsLiteral("text/html"))
00323       {
00324         // Neither an acceptable text or html type.
00325         mEditorStatus = eEditorErrorCantEditMimeType;
00326 
00327         // Turn editor into HTML -- we will load blank page later
00328         mEditorType.AssignLiteral("html");
00329         mimeCType.AssignLiteral("text/html");
00330       }
00331     }
00332 
00333     // Flush out frame construction to make sure that the subframe's
00334     // presshell is set up if it needs to be.
00335     nsCOMPtr<nsIDocument> document(do_QueryInterface(doc));
00336     if (document) {
00337       document->FlushPendingNotifications(Flush_Frames);
00338     }
00339   }
00340   PRBool needHTMLController = PR_FALSE;
00341 
00342   const char *classString = "@mozilla.org/editor/htmleditor;1";
00343   if (mEditorType.EqualsLiteral("textmail"))
00344   {
00345     mEditorFlags = nsIPlaintextEditor::eEditorPlaintextMask | 
00346                    nsIPlaintextEditor::eEditorEnableWrapHackMask | 
00347                    nsIPlaintextEditor::eEditorMailMask;
00348   }
00349   else if (mEditorType.EqualsLiteral("text"))
00350   {
00351     mEditorFlags = nsIPlaintextEditor::eEditorPlaintextMask | 
00352                    nsIPlaintextEditor::eEditorEnableWrapHackMask;
00353   }
00354   else if (mEditorType.EqualsLiteral("htmlmail"))
00355   {
00356     if (mimeCType.EqualsLiteral("text/html"))
00357     {
00358       needHTMLController = PR_TRUE;
00359       mEditorFlags = nsIPlaintextEditor::eEditorMailMask;
00360     }
00361     else //set the flags back to textplain.
00362       mEditorFlags = nsIPlaintextEditor::eEditorPlaintextMask | 
00363                      nsIPlaintextEditor::eEditorEnableWrapHackMask;
00364   }
00365   else // Defaulted to html
00366   {
00367     needHTMLController = PR_TRUE;
00368   }
00369 
00370   // make the UI state maintainer
00371   nsComposerCommandsUpdater *stateMaintainer;
00372   NS_NEWXPCOM(stateMaintainer, nsComposerCommandsUpdater);
00373   mStateMaintainer = NS_STATIC_CAST(nsISelectionListener*, stateMaintainer);
00374 
00375   if (!mStateMaintainer) return NS_ERROR_OUT_OF_MEMORY;
00376 
00377   // now init the state maintainer
00378   // This allows notification of error state
00379   //  even if we don't create an editor
00380   rv = stateMaintainer->Init(aWindow);
00381   if (NS_FAILED(rv)) return rv;
00382 
00383   if (mEditorStatus != eEditorCreationInProgress)
00384   {
00385     // We had an earlier error -- force notification of document creation
00386     nsCOMPtr<nsIDocumentStateListener> docListener =
00387                                           do_QueryInterface(mStateMaintainer);
00388     if (docListener)
00389       docListener->NotifyDocumentCreated();
00390 
00391     return NS_ERROR_FAILURE;
00392   }
00393 
00394   // Create editor and do other things 
00395   //  only if we haven't found some error above,
00396   nsIDocShell *docShell = GetDocShellFromWindow(aWindow);
00397   if (!docShell) return NS_ERROR_FAILURE;  
00398 
00399   // Disable animation of images in this document:
00400   nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(aWindow));
00401   if (!utils) return NS_ERROR_FAILURE;
00402 
00403   rv = utils->GetImageAnimationMode(&mImageAnimationMode);
00404   if (NS_FAILED(rv)) return rv;
00405   utils->SetImageAnimationMode(imgIContainer::kDontAnimMode);
00406 
00407   // create and set editor
00408   nsCOMPtr<nsIEditorDocShell> editorDocShell = do_QueryInterface(docShell, &rv);
00409   if (NS_FAILED(rv)) return rv;
00410 
00411   nsCOMPtr<nsIEditor> editor = do_CreateInstance(classString, &rv);
00412   if (NS_FAILED(rv)) return rv;
00413   // set the editor on the docShell. The docShell now owns it.
00414   rv = editorDocShell->SetEditor(editor);
00415   if (NS_FAILED(rv)) return rv;
00416 
00417   // setup the HTML editor command controller
00418   if (needHTMLController)
00419   {
00420     // The third controller takes an nsIEditor as the context
00421     rv = SetupEditorCommandController("@mozilla.org/editor/htmleditorcontroller;1",
00422                                       aWindow, editor,
00423                                       &mHTMLCommandControllerId);
00424     if (NS_FAILED(rv)) return rv;
00425   }
00426 
00427   // Set mimetype on editor
00428   rv = editor->SetContentsMIMEType(mimeCType.get());
00429   if (NS_FAILED(rv)) return rv;
00430 
00431   nsCOMPtr<nsIContentViewer> contentViewer;
00432   rv = docShell->GetContentViewer(getter_AddRefs(contentViewer));
00433   if (NS_FAILED(rv)) return rv;
00434   if (!contentViewer) return NS_ERROR_FAILURE;
00435 
00436   nsCOMPtr<nsIDOMDocument> domDoc;  
00437   rv = contentViewer->GetDOMDocument(getter_AddRefs(domDoc));
00438   if (NS_FAILED(rv)) return rv;
00439   if (!domDoc) return NS_ERROR_FAILURE;
00440 
00441   // Set up as a doc state listener
00442   // Important! We must have this to broadcast the "obs_documentCreated" message
00443   rv = editor->AddDocumentStateListener(
00444       NS_STATIC_CAST(nsIDocumentStateListener*, stateMaintainer));
00445   if (NS_FAILED(rv)) return rv;
00446 
00447   // XXXbz we really shouldn't need a presShell here!
00448   nsCOMPtr<nsIPresShell> presShell;
00449   rv = docShell->GetPresShell(getter_AddRefs(presShell));
00450   if (NS_FAILED(rv)) return rv;
00451   if (!presShell) return NS_ERROR_FAILURE;
00452 
00453   nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(presShell);
00454   rv = editor->Init(domDoc, presShell, nsnull /* root content */,
00455                     selCon, mEditorFlags);
00456   if (NS_FAILED(rv)) return rv;
00457 
00458   nsCOMPtr<nsISelection> selection;
00459   editor->GetSelection(getter_AddRefs(selection));
00460   nsCOMPtr<nsISelectionPrivate> selPriv = do_QueryInterface(selection);
00461   if (!selPriv) return NS_ERROR_FAILURE;
00462 
00463   rv = selPriv->AddSelectionListener(stateMaintainer);
00464   if (NS_FAILED(rv)) return rv;
00465 
00466   // and as a transaction listener
00467   nsCOMPtr<nsITransactionManager> txnMgr;
00468   editor->GetTransactionManager(getter_AddRefs(txnMgr));
00469   if (txnMgr)
00470     txnMgr->AddListener(NS_STATIC_CAST(nsITransactionListener*,
00471                         stateMaintainer));
00472 
00473   // Set context on all controllers to be the editor
00474   rv = SetEditorOnControllers(aWindow, editor);
00475   if (NS_FAILED(rv)) return rv;
00476 
00477   // Everything went fine!
00478   mEditorStatus = eEditorOK;
00479 
00480 
00481   // This will trigger documentCreation notification
00482   return editor->PostCreate();
00483 }
00484 
00485 /*---------------------------------------------------------------------------
00486 
00487   TearDownEditorOnWindow
00488 
00489   void tearDownEditorOnWindow (in nsIDOMWindow aWindow);
00490 ----------------------------------------------------------------------------*/
00491 NS_IMETHODIMP
00492 nsEditingSession::TearDownEditorOnWindow(nsIDOMWindow *aWindow)
00493 {
00494   if (!mDoneSetup)
00495     return NS_OK;
00496 
00497   nsresult rv;
00498   
00499   // Kill any existing reload timer
00500   if (mLoadBlankDocTimer)
00501   {
00502     mLoadBlankDocTimer->Cancel();
00503     mLoadBlankDocTimer = nsnull;
00504   }
00505 
00506   nsIDocShell *docShell = GetDocShellFromWindow(aWindow);
00507 
00508   mDoneSetup = PR_FALSE;
00509 
00510   nsCOMPtr<nsIDOMDocument> dom_doc;
00511   aWindow->GetDocument(getter_AddRefs(dom_doc));
00512 
00513   nsCOMPtr<nsIDOMNSHTMLDocument> html_doc(do_QueryInterface(dom_doc));
00514   PRBool isMidas = PR_FALSE;
00515 
00516   if (html_doc) {
00517     nsAutoString designMode;
00518     html_doc->GetDesignMode(designMode);
00519 
00520     isMidas = designMode.EqualsLiteral("on");
00521   }
00522 
00523   if (isMidas) {
00524     // We're tearing down a midas editor, unregister callbacks since
00525     // we're all done editing here.
00526 
00527     nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
00528     if (webProgress) {
00529       webProgress->RemoveProgressListener(this);
00530 
00531       mProgressListenerRegistered = PR_FALSE;
00532     }
00533   }
00534 
00535   nsCOMPtr<nsIEditorDocShell> editorDocShell;
00536   rv = GetEditorDocShellFromWindow(aWindow, getter_AddRefs(editorDocShell));
00537   NS_ENSURE_SUCCESS(rv, rv);
00538   
00539   nsCOMPtr<nsIEditor> editor;
00540   rv = editorDocShell->GetEditor(getter_AddRefs(editor));
00541   NS_ENSURE_SUCCESS(rv, rv);
00542 
00543   // null out the editor on the controllers first to prevent their weak 
00544   // references from pointing to a destroyed editor
00545   if (mStateMaintainer && editor)
00546   {
00547     // null out the editor on the controllers
00548     SetEditorOnControllers(aWindow, nsnull);
00549   }
00550 
00551   // null out the editor on the docShell to trigger PreDestroy which
00552   // needs to happen before document state listeners are removed below
00553   editorDocShell->SetEditor(nsnull);
00554 
00555   if (mStateMaintainer)
00556   {
00557     if (editor)
00558     {
00559       // If we had an editor -- we are loading a new URL into existing window
00560 
00561       // Remove all the listeners
00562       nsCOMPtr<nsISelection> selection;
00563       editor->GetSelection(getter_AddRefs(selection));
00564       nsCOMPtr<nsISelectionPrivate> selPriv = do_QueryInterface(selection);
00565       if (selPriv)
00566       {
00567         nsCOMPtr<nsISelectionListener> listener = 
00568           do_QueryInterface(mStateMaintainer);
00569         selPriv->RemoveSelectionListener(listener);
00570       }
00571 
00572       nsCOMPtr<nsIDocumentStateListener> docListener =
00573         do_QueryInterface(mStateMaintainer);
00574       editor->RemoveDocumentStateListener(docListener);
00575 
00576       nsCOMPtr<nsITransactionManager> txnMgr;
00577       editor->GetTransactionManager(getter_AddRefs(txnMgr));
00578       if (txnMgr)
00579       {
00580         nsCOMPtr<nsITransactionListener> transactionListener =
00581           do_QueryInterface(mStateMaintainer);
00582         txnMgr->RemoveListener(transactionListener);
00583       }
00584     }
00585 
00586     // Remove editor controllers from the window now that we're not
00587     // editing in that window any more.
00588 
00589     nsCOMPtr<nsIDOMWindowInternal> domWindowInt(do_QueryInterface(aWindow));
00590   
00591     nsCOMPtr<nsIControllers> controllers;      
00592     domWindowInt->GetControllers(getter_AddRefs(controllers));
00593 
00594     if (controllers) {
00595       nsCOMPtr<nsIController> controller;
00596 
00597       if (mBaseCommandControllerId) {
00598         controllers->GetControllerById(mBaseCommandControllerId,
00599                                        getter_AddRefs(controller));
00600 
00601         if (controller) {
00602           controllers->RemoveController(controller);
00603         }
00604       }
00605 
00606       if (mDocStateControllerId) {
00607         controllers->GetControllerById(mDocStateControllerId,
00608                                        getter_AddRefs(controller));
00609 
00610         if (controller) {
00611           controllers->RemoveController(controller);
00612         }
00613       }
00614 
00615       if (mHTMLCommandControllerId) {
00616         controllers->GetControllerById(mHTMLCommandControllerId,
00617                                        getter_AddRefs(controller));
00618 
00619         if (controller) {
00620           controllers->RemoveController(controller);
00621         }
00622       }
00623     }
00624 
00625     //   Clear IDs to trigger creation of new controllers
00626     mBaseCommandControllerId = 0;
00627     mDocStateControllerId = 0;
00628     mHTMLCommandControllerId = 0;
00629   }
00630 
00631   if (isMidas) {
00632     // Make things the way they were before we started editing.
00633     if (mScriptsEnabled) {
00634       docShell->SetAllowJavascript(PR_TRUE);
00635     }
00636 
00637     if (mPluginsEnabled) {
00638       docShell->SetAllowPlugins(PR_TRUE);
00639     }
00640 
00641     nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(aWindow));
00642     if (utils)
00643       utils->SetImageAnimationMode(mImageAnimationMode);
00644   }
00645 
00646   return rv;
00647 }
00648 
00649 /*---------------------------------------------------------------------------
00650 
00651   GetEditorForFrame
00652 
00653   nsIEditor getEditorForFrame (in nsIDOMWindow aWindow);
00654 ----------------------------------------------------------------------------*/
00655 NS_IMETHODIMP 
00656 nsEditingSession::GetEditorForWindow(nsIDOMWindow *aWindow,
00657                                      nsIEditor **outEditor)
00658 {
00659   nsCOMPtr<nsIEditorDocShell> editorDocShell;
00660   nsresult rv = GetEditorDocShellFromWindow(aWindow,
00661                                             getter_AddRefs(editorDocShell));
00662   if (NS_FAILED(rv)) return rv;  
00663   
00664   return editorDocShell->GetEditor(outEditor);
00665 }
00666 
00667 #ifdef XP_MAC
00668 #pragma mark -
00669 #endif
00670 
00671 /*---------------------------------------------------------------------------
00672 
00673   OnStateChange
00674 
00675 ----------------------------------------------------------------------------*/
00676 NS_IMETHODIMP
00677 nsEditingSession::OnStateChange(nsIWebProgress *aWebProgress,
00678                                 nsIRequest *aRequest,
00679                                 PRUint32 aStateFlags, nsresult aStatus)
00680 {
00681 
00682 #ifdef NOISY_DOC_LOADING
00683   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
00684   if (channel)
00685   {
00686     nsCAutoString contentType;
00687     channel->GetContentType(contentType);
00688     if (!contentType.IsEmpty())
00689       printf(" ++++++ MIMETYPE = %s\n", contentType.get());
00690   }
00691 #endif
00692 
00693   //
00694   // A Request has started...
00695   //
00696   if (aStateFlags & nsIWebProgressListener::STATE_START)
00697   {
00698 #ifdef NOISY_DOC_LOADING
00699   {
00700     nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
00701     if (channel)
00702     {
00703       nsCOMPtr<nsIURI> uri;
00704       channel->GetURI(getter_AddRefs(uri));
00705       if (uri)
00706       {
00707         nsXPIDLCString spec;
00708         uri->GetSpec(spec);
00709         printf(" **** STATE_START: CHANNEL URI=%s, flags=%x\n",
00710                spec.get(), aStateFlags);
00711       }
00712     }
00713     else
00714       printf("    STATE_START: NO CHANNEL flags=%x\n", aStateFlags);
00715   }
00716 #endif
00717     // Page level notification...
00718     if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK)
00719     {
00720       nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
00721       StartPageLoad(channel);
00722 #ifdef NOISY_DOC_LOADING
00723       printf("STATE_START & STATE_IS_NETWORK flags=%x\n", aStateFlags);
00724 #endif
00725     }
00726 
00727     // Document level notification...
00728     if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT &&
00729         !(aStateFlags & nsIWebProgressListener::STATE_RESTORING)) {
00730       PRBool progressIsForTargetDocument =
00731         IsProgressForTargetDocument(aWebProgress);
00732 
00733       if (progressIsForTargetDocument) {
00734         nsCOMPtr<nsIDOMWindow> window;
00735         aWebProgress->GetDOMWindow(getter_AddRefs(window));
00736 
00737         nsCOMPtr<nsIDOMDocument> doc;
00738         window->GetDocument(getter_AddRefs(doc));
00739 
00740         nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(doc));
00741 
00742         if (htmlDoc && htmlDoc->IsWriting()) {
00743           nsCOMPtr<nsIDOMNSHTMLDocument> htmlDomDoc(do_QueryInterface(doc));
00744           nsAutoString designMode;
00745 
00746           htmlDomDoc->GetDesignMode(designMode);
00747 
00748           if (designMode.EqualsLiteral("on")) {
00749             // This notification is for data coming in through
00750             // document.open/write/close(), ignore it.
00751 
00752             return NS_OK;
00753           }
00754         }
00755       }
00756 
00757       mCanCreateEditor = PR_TRUE;
00758       StartDocumentLoad(aWebProgress, progressIsForTargetDocument);
00759 #ifdef NOISY_DOC_LOADING
00760       printf("STATE_START & STATE_IS_DOCUMENT flags=%x\n", aStateFlags);
00761 #endif
00762     }
00763   }
00764   //
00765   // A Request is being processed
00766   //
00767   else if (aStateFlags & nsIWebProgressListener::STATE_TRANSFERRING)
00768   {
00769     if (aStateFlags * nsIWebProgressListener::STATE_IS_DOCUMENT)
00770     {
00771       // document transfer started
00772     }
00773   }
00774   //
00775   // Got a redirection
00776   //
00777   else if (aStateFlags & nsIWebProgressListener::STATE_REDIRECTING)
00778   {
00779     if (aStateFlags * nsIWebProgressListener::STATE_IS_DOCUMENT)
00780     {
00781       // got a redirect
00782     }
00783   }
00784   //
00785   // A network or document Request as finished...
00786   //
00787   else if (aStateFlags & nsIWebProgressListener::STATE_STOP)
00788   {
00789 
00790 #ifdef NOISY_DOC_LOADING
00791   {
00792     nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
00793     if (channel)
00794     {
00795       nsCOMPtr<nsIURI> uri;
00796       channel->GetURI(getter_AddRefs(uri));
00797       if (uri)
00798       {
00799         nsXPIDLCString spec;
00800         uri->GetSpec(spec);
00801         printf(" **** STATE_STOP: CHANNEL URI=%s, flags=%x\n",
00802                spec.get(), aStateFlags);
00803       }
00804     }
00805     else
00806       printf("     STATE_STOP: NO CHANNEL  flags=%x\n", aStateFlags);
00807   }
00808 #endif
00809 
00810     // Document level notification...
00811     if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT)
00812     {
00813       nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
00814       EndDocumentLoad(aWebProgress, channel, aStatus,
00815                       IsProgressForTargetDocument(aWebProgress));
00816 #ifdef NOISY_DOC_LOADING
00817       printf("STATE_STOP & STATE_IS_DOCUMENT flags=%x\n", aStateFlags);
00818 #endif
00819     }
00820 
00821     // Page level notification...
00822     if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK)
00823     {
00824       nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
00825       (void)EndPageLoad(aWebProgress, channel, aStatus);
00826 #ifdef NOISY_DOC_LOADING
00827       printf("STATE_STOP & STATE_IS_NETWORK flags=%x\n", aStateFlags);
00828 #endif
00829     }
00830   }
00831 
00832   return NS_OK;
00833 }
00834 
00835 /*---------------------------------------------------------------------------
00836 
00837   OnProgressChange
00838 
00839 ----------------------------------------------------------------------------*/
00840 NS_IMETHODIMP
00841 nsEditingSession::OnProgressChange(nsIWebProgress *aWebProgress,
00842                                    nsIRequest *aRequest,
00843                                    PRInt32 aCurSelfProgress,
00844                                    PRInt32 aMaxSelfProgress,
00845                                    PRInt32 aCurTotalProgress,
00846                                    PRInt32 aMaxTotalProgress)
00847 {
00848     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
00849     return NS_OK;
00850 }
00851 
00852 /*---------------------------------------------------------------------------
00853 
00854   OnLocationChange
00855 
00856 ----------------------------------------------------------------------------*/
00857 NS_IMETHODIMP
00858 nsEditingSession::OnLocationChange(nsIWebProgress *aWebProgress, 
00859                                    nsIRequest *aRequest, nsIURI *aURI)
00860 {
00861   nsCOMPtr<nsIDOMWindow> domWindow;
00862   nsresult rv = aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
00863   if (NS_FAILED(rv)) return rv;
00864 
00865   nsCOMPtr<nsIDOMDocument> domDoc;
00866   rv = domWindow->GetDocument(getter_AddRefs(domDoc));
00867   if (NS_FAILED(rv)) return rv;
00868 
00869   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
00870   if (!doc) return NS_ERROR_FAILURE;
00871 
00872   doc->SetDocumentURI(aURI);
00873 
00874   // Notify the location-changed observer that
00875   //  the document URL has changed
00876   nsIDocShell *docShell = GetDocShellFromWindow(domWindow);
00877   if (!docShell) return NS_ERROR_FAILURE;
00878 
00879   nsCOMPtr<nsICommandManager> commandManager = do_GetInterface(docShell);
00880   nsCOMPtr<nsPICommandUpdater> commandUpdater =
00881                                   do_QueryInterface(commandManager);
00882   if (!commandUpdater) return NS_ERROR_FAILURE;
00883 
00884   return commandUpdater->CommandStatusChanged("obs_documentLocationChanged");
00885 }
00886 
00887 /*---------------------------------------------------------------------------
00888 
00889   OnStatusChange
00890 
00891 ----------------------------------------------------------------------------*/
00892 NS_IMETHODIMP
00893 nsEditingSession::OnStatusChange(nsIWebProgress *aWebProgress,
00894                                  nsIRequest *aRequest,
00895                                  nsresult aStatus,
00896                                  const PRUnichar *aMessage)
00897 {
00898     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
00899     return NS_OK;
00900 }
00901 
00902 /*---------------------------------------------------------------------------
00903 
00904   OnSecurityChange
00905 
00906 ----------------------------------------------------------------------------*/
00907 NS_IMETHODIMP
00908 nsEditingSession::OnSecurityChange(nsIWebProgress *aWebProgress,
00909                                    nsIRequest *aRequest, PRUint32 state)
00910 {
00911     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
00912     return NS_OK;
00913 }
00914 
00915 
00916 #ifdef XP_MAC
00917 #pragma mark -
00918 #endif
00919 
00920 /* boolean onStartURIOpen (in nsIURI aURI); */
00921 NS_IMETHODIMP nsEditingSession::OnStartURIOpen(nsIURI *aURI, PRBool *aAbortOpen)
00922 {
00923   return NS_OK;
00924 }
00925 
00926 /* boolean doContent (in string aContentType, in boolean aIsContentPreferred, in nsIRequest aRequest, out nsIStreamListener aContentHandler); */
00927 NS_IMETHODIMP nsEditingSession::DoContent(const char *aContentType, PRBool aIsContentPreferred, nsIRequest *aRequest, nsIStreamListener **aContentHandler, PRBool *aAbortProcess)
00928 {
00929   NS_ENSURE_ARG_POINTER(aContentHandler);
00930   NS_ENSURE_ARG_POINTER(aAbortProcess);
00931   *aContentHandler = nsnull;
00932   *aAbortProcess = PR_FALSE;
00933   return NS_OK;
00934 }
00935 
00936 /* boolean isPreferred (in string aContentType, out string aDesiredContentType); */
00937 NS_IMETHODIMP nsEditingSession::IsPreferred(const char *aContentType, char **aDesiredContentType, PRBool *_retval)
00938 {
00939   NS_ENSURE_ARG_POINTER(aDesiredContentType);
00940   NS_ENSURE_ARG_POINTER(_retval);
00941   *aDesiredContentType = nsnull;
00942   *_retval = PR_FALSE;
00943   return NS_OK;
00944 }
00945 
00946 /* boolean canHandleContent (in string aContentType, in boolean aIsContentPreferred, out string aDesiredContentType); */
00947 NS_IMETHODIMP nsEditingSession::CanHandleContent(const char *aContentType, PRBool aIsContentPreferred, char **aDesiredContentType, PRBool *_retval)
00948 {
00949   NS_ENSURE_ARG_POINTER(aDesiredContentType);
00950   NS_ENSURE_ARG_POINTER(_retval);
00951   *aDesiredContentType = nsnull;
00952   *_retval = PR_FALSE;
00953   return NS_OK;
00954 }
00955 
00956 /* attribute nsISupports loadCookie; */
00957 NS_IMETHODIMP nsEditingSession::GetLoadCookie(nsISupports * *aLoadCookie)
00958 {
00959   NS_ENSURE_ARG_POINTER(aLoadCookie);
00960   *aLoadCookie = nsnull;
00961   return NS_OK;
00962 }
00963 NS_IMETHODIMP nsEditingSession::SetLoadCookie(nsISupports * aLoadCookie)
00964 {
00965   return NS_OK;
00966 }
00967 
00968 /* attribute nsIURIContentListener parentContentListener; */
00969 NS_IMETHODIMP nsEditingSession::GetParentContentListener(nsIURIContentListener * *aParentContentListener)
00970 {
00971   NS_ENSURE_ARG_POINTER(aParentContentListener);
00972   *aParentContentListener = nsnull;
00973   return NS_OK;
00974 }
00975 NS_IMETHODIMP nsEditingSession::SetParentContentListener(nsIURIContentListener * aParentContentListener)
00976 {
00977   return NS_OK;
00978 }
00979 
00980 #ifdef XP_MAC
00981 #pragma mark -
00982 #endif
00983 
00984 
00985 /*---------------------------------------------------------------------------
00986 
00987   IsProgressForTargetDocument
00988 
00989   Check that this notification is for our document.
00990 ----------------------------------------------------------------------------*/
00991 
00992 PRBool
00993 nsEditingSession::IsProgressForTargetDocument(nsIWebProgress *aWebProgress)
00994 {
00995   nsCOMPtr<nsIDOMWindow> domWindow;
00996   if (aWebProgress)
00997     aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
00998   nsCOMPtr<nsIDOMWindow> editedDOMWindow = do_QueryReferent(mWindowToBeEdited);
00999 
01000   return (domWindow && (domWindow == editedDOMWindow));
01001 }
01002 
01003 
01004 /*---------------------------------------------------------------------------
01005 
01006   GetEditorStatus
01007 
01008   Called during GetCommandStateParams("obs_documentCreated"...) 
01009   to determine if editor was created and document 
01010   was loaded successfully
01011 ----------------------------------------------------------------------------*/
01012 NS_IMETHODIMP
01013 nsEditingSession::GetEditorStatus(PRUint32 *aStatus)
01014 {
01015   NS_ENSURE_ARG_POINTER(aStatus);
01016   *aStatus = mEditorStatus;
01017   return NS_OK;
01018 }
01019 
01020 /*---------------------------------------------------------------------------
01021 
01022   StartDocumentLoad
01023 
01024   Called on start of load in a single frame
01025 ----------------------------------------------------------------------------*/
01026 nsresult
01027 nsEditingSession::StartDocumentLoad(nsIWebProgress *aWebProgress, 
01028                                     PRBool aIsToBeMadeEditable)
01029 {
01030 #ifdef NOISY_DOC_LOADING
01031   printf("======= StartDocumentLoad ========\n");
01032 #endif
01033 
01034   NS_ENSURE_ARG_POINTER(aWebProgress);
01035   
01036   // If we have an editor here, then we got a reload after making the editor.
01037   // We need to blow it away and make a new one at the end of the load.
01038   nsCOMPtr<nsIDOMWindow> domWindow;
01039   aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
01040   if (domWindow)
01041   {
01042     TearDownEditorOnWindow(domWindow);
01043   }
01044     
01045   if (aIsToBeMadeEditable)
01046     mEditorStatus = eEditorCreationInProgress;
01047 
01048   return NS_OK;
01049 }
01050 
01051 /*---------------------------------------------------------------------------
01052 
01053   EndDocumentLoad
01054 
01055   Called on end of load in a single frame
01056 ----------------------------------------------------------------------------*/
01057 nsresult
01058 nsEditingSession::EndDocumentLoad(nsIWebProgress *aWebProgress,
01059                                   nsIChannel* aChannel, nsresult aStatus,
01060                                   PRBool aIsToBeMadeEditable)
01061 {
01062   NS_ENSURE_ARG_POINTER(aWebProgress);
01063   
01064 #ifdef NOISY_DOC_LOADING
01065   printf("======= EndDocumentLoad ========\n");
01066   printf("with status %d, ", aStatus);
01067   nsCOMPtr<nsIURI> uri;
01068   nsXPIDLCString spec;
01069   if (NS_SUCCEEDED(aChannel->GetURI(getter_AddRefs(uri)))) {
01070     uri->GetSpec(spec);
01071     printf(" uri %s\n", spec.get());
01072   }
01073 #endif
01074 
01075   // We want to call the base class EndDocumentLoad,
01076   // but avoid some of the stuff
01077   // that nsWebShell does (need to refactor).
01078   
01079   // OK, time to make an editor on this document
01080   nsCOMPtr<nsIDOMWindow> domWindow;
01081   aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
01082   
01083   // Set the error state -- we will create an editor 
01084   // anyway and load empty doc later
01085   if (aIsToBeMadeEditable) {
01086     if (aStatus == NS_ERROR_FILE_NOT_FOUND)
01087       mEditorStatus = eEditorErrorFileNotFound;
01088   }
01089 
01090   nsIDocShell *docShell = GetDocShellFromWindow(domWindow);
01091   if (!docShell) return NS_ERROR_FAILURE;       // better error handling?
01092 
01093   // cancel refresh from meta tags
01094   // we need to make sure that all pages in editor (whether editable or not)
01095   // can't refresh contents being edited
01096   nsCOMPtr<nsIRefreshURI> refreshURI = do_QueryInterface(docShell);
01097   if (refreshURI)
01098     refreshURI->CancelRefreshURITimers();
01099 
01100   nsCOMPtr<nsIEditorDocShell> editorDocShell = do_QueryInterface(docShell);
01101 
01102   nsresult rv = NS_OK;
01103 
01104   // did someone set the flag to make this shell editable?
01105   if (aIsToBeMadeEditable && mCanCreateEditor && editorDocShell)
01106   {
01107     PRBool  makeEditable;
01108     editorDocShell->GetEditable(&makeEditable);
01109   
01110     if (makeEditable)
01111     {
01112       mCanCreateEditor = PR_FALSE;
01113       rv = SetupEditorOnWindow(domWindow);
01114       if (NS_FAILED(rv))
01115       {
01116         // If we had an error, setup timer to load a blank page later
01117         if (mLoadBlankDocTimer)
01118         {
01119           // Must cancel previous timer?
01120           mLoadBlankDocTimer->Cancel();
01121           mLoadBlankDocTimer = NULL;
01122         }
01123   
01124         mLoadBlankDocTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
01125         if (NS_FAILED(rv)) return rv;
01126 
01127         mEditorStatus = eEditorCreationInProgress;
01128         mLoadBlankDocTimer->InitWithFuncCallback(
01129                                         nsEditingSession::TimerCallback,
01130                                         (void*)docShell,
01131                                         10, nsITimer::TYPE_ONE_SHOT);
01132       }
01133     }
01134   }
01135   return rv;
01136 }
01137 
01138 
01139 void
01140 nsEditingSession::TimerCallback(nsITimer* aTimer, void* aClosure)
01141 {
01142   nsCOMPtr<nsIDocShell> docShell = (nsIDocShell*)aClosure;
01143   if (docShell)
01144   {
01145     nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
01146     if (webNav)
01147       webNav->LoadURI(NS_LITERAL_STRING("about:blank").get(),
01148                       0, nsnull, nsnull, nsnull);
01149   }
01150 }
01151 
01152 /*---------------------------------------------------------------------------
01153 
01154   StartPageLoad
01155 
01156   Called on start load of the entire page (incl. subframes)
01157 ----------------------------------------------------------------------------*/
01158 nsresult
01159 nsEditingSession::StartPageLoad(nsIChannel *aChannel)
01160 {
01161 #ifdef NOISY_DOC_LOADING
01162   printf("======= StartPageLoad ========\n");
01163 #endif
01164   return NS_OK;
01165 }
01166 
01167 /*---------------------------------------------------------------------------
01168 
01169   EndPageLoad
01170 
01171   Called on end load of the entire page (incl. subframes)
01172 ----------------------------------------------------------------------------*/
01173 nsresult
01174 nsEditingSession::EndPageLoad(nsIWebProgress *aWebProgress,
01175                               nsIChannel* aChannel, nsresult aStatus)
01176 {
01177 #ifdef NOISY_DOC_LOADING
01178   printf("======= EndPageLoad ========\n");
01179   printf("  with status %d, ", aStatus);
01180   nsCOMPtr<nsIURI> uri;
01181   nsXPIDLCString spec;
01182   if (NS_SUCCEEDED(aChannel->GetURI(getter_AddRefs(uri)))) {
01183     uri->GetSpec(spec);
01184     printf("uri %s\n", spec.get());
01185   }
01186  
01187   nsCAutoString contentType;
01188   aChannel->GetContentType(contentType);
01189   if (!contentType.IsEmpty())
01190     printf("   flags = %d, status = %d, MIMETYPE = %s\n", 
01191                mEditorFlags, mEditorStatus, contentType.get());
01192 #endif
01193 
01194   // Set the error state -- we will create an editor anyway 
01195   // and load empty doc later
01196   if (aStatus == NS_ERROR_FILE_NOT_FOUND)
01197     mEditorStatus = eEditorErrorFileNotFound;
01198 
01199   nsCOMPtr<nsIDOMWindow> domWindow;
01200   aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
01201 
01202   nsIDocShell *docShell = GetDocShellFromWindow(domWindow);
01203   if (!docShell) return NS_ERROR_FAILURE;
01204 
01205   // cancel refresh from meta tags
01206   // we need to make sure that all pages in editor (whether editable or not)
01207   // can't refresh contents being edited
01208   nsCOMPtr<nsIRefreshURI> refreshURI = do_QueryInterface(docShell);
01209   if (refreshURI)
01210     refreshURI->CancelRefreshURITimers();
01211 
01212 #if 0
01213   // Shouldn't we do this when we want to edit sub-frames?
01214   return MakeWindowEditable(domWindow, "html", PR_FALSE);
01215 #else
01216   return NS_OK;
01217 #endif
01218 }
01219 
01220 
01221 #ifdef XP_MAC
01222 #pragma mark -
01223 #endif
01224 
01225 /*---------------------------------------------------------------------------
01226 
01227   GetDocShellFromWindow
01228 
01229   Utility method. This will always return nsnull if no docShell is found.
01230 ----------------------------------------------------------------------------*/
01231 nsIDocShell *
01232 nsEditingSession::GetDocShellFromWindow(nsIDOMWindow *aWindow)
01233 {
01234   nsCOMPtr<nsIScriptGlobalObject> scriptGO = do_QueryInterface(aWindow);
01235   if (!scriptGO)
01236     return nsnull;
01237 
01238   return scriptGO->GetDocShell();
01239 }
01240 
01241 /*---------------------------------------------------------------------------
01242 
01243   GetEditorDocShellFromWindow
01244 
01245   Utility method. This will always return an error if no docShell
01246   is returned.
01247 ----------------------------------------------------------------------------*/
01248 nsresult
01249 nsEditingSession::GetEditorDocShellFromWindow(nsIDOMWindow *aWindow,
01250                                               nsIEditorDocShell** outDocShell)
01251 {
01252   nsIDocShell *docShell = GetDocShellFromWindow(aWindow);
01253   if (!docShell) return NS_ERROR_FAILURE;
01254   
01255   return docShell->QueryInterface(NS_GET_IID(nsIEditorDocShell), 
01256                                   (void **)outDocShell);
01257 }
01258 
01259 /*---------------------------------------------------------------------------
01260 
01261   PrepareForEditing
01262 
01263   Set up this editing session for one or more editors
01264 ----------------------------------------------------------------------------*/
01265 nsresult
01266 nsEditingSession::PrepareForEditing(nsIDOMWindow *aWindow)
01267 {
01268   if (mDoneSetup || mProgressListenerRegistered)
01269     return NS_OK;
01270     
01271   mDoneSetup = PR_TRUE;
01272 
01273   nsIDocShell *docShell = GetDocShellFromWindow(aWindow);
01274   
01275   // register callback
01276   nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
01277   if (!webProgress) return NS_ERROR_FAILURE;
01278 
01279   nsresult rv =
01280     webProgress->AddProgressListener(this,
01281                                      (nsIWebProgress::NOTIFY_STATE_NETWORK  | 
01282                                       nsIWebProgress::NOTIFY_STATE_DOCUMENT |
01283                                       nsIWebProgress::NOTIFY_LOCATION));
01284 
01285   mProgressListenerRegistered = NS_SUCCEEDED(rv);
01286 
01287   return rv;
01288 }
01289 
01290 /*---------------------------------------------------------------------------
01291 
01292   SetupEditorCommandController
01293 
01294   Create a command controller, append to controllers,
01295   get and return the controller ID, and set the context
01296 ----------------------------------------------------------------------------*/
01297 nsresult
01298 nsEditingSession::SetupEditorCommandController(
01299                                   const char *aControllerClassName,
01300                                   nsIDOMWindow *aWindow,
01301                                   nsISupports *aContext,
01302                                   PRUint32 *aControllerId)
01303 {
01304   NS_ENSURE_ARG_POINTER(aControllerClassName);
01305   NS_ENSURE_ARG_POINTER(aWindow);
01306   NS_ENSURE_ARG_POINTER(aContext);
01307   NS_ENSURE_ARG_POINTER(aControllerId);
01308 
01309   nsresult rv;
01310   nsCOMPtr<nsIDOMWindowInternal> domWindowInt =
01311                                     do_QueryInterface(aWindow, &rv);
01312   if (NS_FAILED(rv)) return rv;
01313   
01314   nsCOMPtr<nsIControllers> controllers;      
01315   rv = domWindowInt->GetControllers(getter_AddRefs(controllers));
01316   if (NS_FAILED(rv)) return rv;
01317 
01318   // We only have to create each singleton controller once
01319   // We know this has happened once we have a controllerId value
01320   if (!*aControllerId)
01321   {
01322     nsresult rv;
01323     nsCOMPtr<nsIController> controller;
01324     controller = do_CreateInstance(aControllerClassName, &rv);
01325     if (NS_FAILED(rv)) return rv;  
01326 
01327     // We must insert at head of the list to be sure our
01328     //   controller is found before other implementations
01329     //   (e.g., not-implemented versions by browser)
01330     rv = controllers->InsertControllerAt(0, controller);
01331     if (NS_FAILED(rv)) return rv;  
01332 
01333     // Remember the ID for the controller
01334     rv = controllers->GetControllerId(controller, aControllerId);
01335     if (NS_FAILED(rv)) return rv;  
01336   }  
01337 
01338   // Set the context
01339   return SetContextOnControllerById(controllers, aContext, *aControllerId);
01340 }
01341 
01342 /*---------------------------------------------------------------------------
01343 
01344   SetEditorOnControllers
01345 
01346   Set the editor on the controller(s) for this window
01347 ----------------------------------------------------------------------------*/
01348 NS_IMETHODIMP
01349 nsEditingSession::SetEditorOnControllers(nsIDOMWindow *aWindow,
01350                                          nsIEditor* aEditor)
01351 {
01352   nsresult rv;
01353   
01354   // set the editor on the controller
01355   nsCOMPtr<nsIDOMWindowInternal> domWindowInt =
01356                                      do_QueryInterface(aWindow, &rv);
01357   if (NS_FAILED(rv)) return rv;
01358   
01359   nsCOMPtr<nsIControllers> controllers;      
01360   rv = domWindowInt->GetControllers(getter_AddRefs(controllers));
01361   if (NS_FAILED(rv)) return rv;
01362 
01363   nsCOMPtr<nsISupports> editorAsISupports = do_QueryInterface(aEditor);
01364   if (mBaseCommandControllerId)
01365   {
01366     rv = SetContextOnControllerById(controllers, editorAsISupports,
01367                                     mBaseCommandControllerId);
01368     if (NS_FAILED(rv)) return rv;
01369   }
01370 
01371   if (mDocStateControllerId)
01372   {
01373     rv = SetContextOnControllerById(controllers, editorAsISupports,
01374                                     mDocStateControllerId);
01375     if (NS_FAILED(rv)) return rv;
01376   }
01377 
01378   if (mHTMLCommandControllerId)
01379     rv = SetContextOnControllerById(controllers, editorAsISupports,
01380                                     mHTMLCommandControllerId);
01381 
01382   return rv;
01383 }
01384 
01385 nsresult
01386 nsEditingSession::SetContextOnControllerById(nsIControllers* aControllers,
01387                                              nsISupports* aContext,
01388                                              PRUint32 aID)
01389 {
01390   NS_ENSURE_ARG_POINTER(aControllers);
01391 
01392   // aContext can be null (when destroying editor)
01393   nsCOMPtr<nsIController> controller;    
01394   aControllers->GetControllerById(aID, getter_AddRefs(controller));
01395   
01396   // ok with nil controller
01397   nsCOMPtr<nsIControllerContext> editorController =
01398                                        do_QueryInterface(controller);
01399   if (!editorController) return NS_ERROR_FAILURE;
01400 
01401   return editorController->SetCommandContext(aContext);
01402 }