1. Factoring nsIChannel into a protocol specific part, the nsIChannel, and a socket specific, the nsITransport. 2. Derive the nsIChannel from a nsIRequest. 2. Changes the notification system from necko and the URILoader to pass the nsIRequest interface instead of nsIChannel interface. This goal stems from wanting to be able to have active AsyncRead and AsyncWrite operations on nsSocketTransport. This is desired because it would greatly simplify the task of maintaining persistent/reusable socket connections for FTP, HTTP, and Imap (and potentially other protocols). The problem with the existing nsIChannel interface is that it does not allow one to selectively suspend just one of the read or write operations while keeping the other active. The full details of the change on written up in the netlib newsgroup. r=darin@netscape.com sr=rpotts@netscape.com
5475 lines
145 KiB
C++
5475 lines
145 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is Mozilla Communicator client code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape Communications
|
|
* Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "nsEditorShell.h"
|
|
#include "nsIPlaintextEditor.h"
|
|
#include "nsIWebShell.h"
|
|
#include "nsIBaseWindow.h"
|
|
#include "nsIContentViewerFile.h"
|
|
#include "pratom.h"
|
|
#include "prprf.h"
|
|
#include "nsIComponentManager.h"
|
|
|
|
#include "nsIFocusController.h"
|
|
#include "nsIScriptContext.h"
|
|
#include "nsIScriptGlobalObject.h"
|
|
#include "nsIScriptGlobalObjectOwner.h"
|
|
#include "nsIDOMDocument.h"
|
|
#include "nsIMarkupDocumentViewer.h"
|
|
#include "nsIDOMHTMLDocument.h"
|
|
#include "nsIDiskDocument.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsIDOMWindowInternal.h"
|
|
#include "nsPIDOMWindow.h"
|
|
#include "nsIDOMNode.h"
|
|
#include "nsIDOMNodeList.h"
|
|
#include "nsICSSLoader.h"
|
|
#include "nsICSSStyleSheet.h"
|
|
#include "nsIStyleSheet.h"
|
|
#include "nsIStyleSet.h"
|
|
#include "nsIContent.h"
|
|
#include "nsIHTMLContentContainer.h"
|
|
#include "nsIURI.h"
|
|
#include "nsCURILoader.h"
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsIScriptGlobalObject.h"
|
|
#include "nsIWebNavigation.h"
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsIServiceManager.h"
|
|
#include "nsIURL.h"
|
|
#include "nsIWidget.h"
|
|
#include "nsIWindowMediator.h"
|
|
#include "plevent.h"
|
|
#include "nsXPIDLString.h"
|
|
|
|
#include "nsIAppShell.h"
|
|
#include "nsIAppShellService.h"
|
|
#include "nsAppShellCIDs.h"
|
|
|
|
#include "nsIDocumentViewer.h"
|
|
#include "nsIDOMHTMLImageElement.h"
|
|
#include "nsIPresShell.h"
|
|
#include "nsIPresContext.h"
|
|
#include "nsISelection.h"
|
|
#include "nsISelectionPrivate.h"
|
|
|
|
#include "nsIFilePicker.h"
|
|
#include "nsIFindComponent.h"
|
|
#include "nsIPrompt.h"
|
|
#include "nsICommonDialogs.h"
|
|
|
|
#include "nsIEditorController.h"
|
|
#include "nsEditorController.h"
|
|
#include "nsIControllers.h"
|
|
#include "nsIDocShell.h"
|
|
#include "nsIDocShellTreeItem.h"
|
|
#include "nsIDocShellTreeOwner.h"
|
|
#include "nsIDocShellTreeNode.h"
|
|
#include "nsITransactionManager.h"
|
|
#include "nsIDocumentEncoder.h"
|
|
|
|
#include "nsIRefreshURI.h"
|
|
#include "nsIPref.h"
|
|
|
|
#include "nsILookAndFeel.h"
|
|
|
|
#include "nsIChromeRegistry.h"
|
|
|
|
///////////////////////////////////////
|
|
// Editor Includes
|
|
///////////////////////////////////////
|
|
#include "nsIDOMEventCapturer.h"
|
|
#include "nsString.h"
|
|
#include "nsIDOMText.h"
|
|
#include "nsIDOMElement.h"
|
|
#include "nsIDOMWindowCollection.h"
|
|
#include "nsIWebProgress.h"
|
|
|
|
#include "nsIEditor.h"
|
|
#include "nsIHTMLEditor.h"
|
|
#include "nsIEditorStyleSheets.h"
|
|
#include "nsIEditorMailSupport.h"
|
|
#include "nsITableEditor.h"
|
|
#include "nsIEditorLogging.h"
|
|
|
|
#include "nsEditorCID.h"
|
|
|
|
#include "nsIComponentManager.h"
|
|
#include "nsTextServicesCID.h"
|
|
#include "nsITextServicesDocument.h"
|
|
#include "nsISpellChecker.h"
|
|
#include "nsInterfaceState.h"
|
|
|
|
#include "nsAOLCiter.h"
|
|
#include "nsInternetCiter.h"
|
|
#include "nsEditorShellMouseListener.h"
|
|
|
|
///////////////////////////////////////
|
|
|
|
// Drag & Drop, Clipboard
|
|
#include "nsWidgetsCID.h"
|
|
#include "nsIClipboard.h"
|
|
#include "nsITransferable.h"
|
|
#include "nsISupportsArray.h"
|
|
|
|
/* Define Class IDs */
|
|
static NS_DEFINE_CID(kHTMLEditorCID, NS_HTMLEDITOR_CID);
|
|
static NS_DEFINE_CID(kCTextServicesDocumentCID, NS_TEXTSERVICESDOCUMENT_CID);
|
|
static NS_DEFINE_CID(kCStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
|
|
static NS_DEFINE_CID(kCommonDialogsCID, NS_CommonDialog_CID );
|
|
static NS_DEFINE_CID(kDialogParamBlockCID, NS_DialogParamBlock_CID);
|
|
static NS_DEFINE_CID(kPrefServiceCID, NS_PREF_CID);
|
|
static NS_DEFINE_CID(kChromeRegistryCID, NS_CHROMEREGISTRY_CID);
|
|
static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
|
|
|
|
#define APP_DEBUG 0
|
|
|
|
#define EDITOR_BUNDLE_URL "chrome://editor/locale/editor.properties"
|
|
#define EDITOR_DEFAULT_DIR_PREF "editor.default.dir"
|
|
|
|
enum {
|
|
eEditorController,
|
|
eComposerController
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// Utility to extract document from a webshell object.
|
|
static nsresult
|
|
GetDocument(nsIDocShell *aDocShell, nsIDocument **aDoc )
|
|
{
|
|
// Get content viewer from the web shell.
|
|
nsCOMPtr<nsIContentViewer> contentViewer;
|
|
nsresult res = (aDocShell && aDoc) ?
|
|
aDocShell->GetContentViewer(getter_AddRefs(contentViewer))
|
|
: NS_ERROR_NULL_POINTER;
|
|
|
|
if ( NS_SUCCEEDED(res) && contentViewer )
|
|
{
|
|
// Up-cast to a document viewer.
|
|
nsCOMPtr<nsIDocumentViewer> docViewer(do_QueryInterface(contentViewer));
|
|
if ( docViewer )
|
|
{
|
|
// Get the document from the doc viewer.
|
|
res = docViewer->GetDocument(*aDoc);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
// Utility get a UI element
|
|
static nsresult
|
|
GetChromeElement(nsIDocShell *aShell, const char *aID, nsIDOMElement **aElement)
|
|
{
|
|
if (!aElement) return NS_ERROR_NULL_POINTER;
|
|
*aElement = nsnull;
|
|
|
|
nsCOMPtr<nsIDocument> doc;
|
|
nsresult rv = GetDocument( aShell, getter_AddRefs(doc) );
|
|
if(NS_SUCCEEDED(rv) && doc)
|
|
{
|
|
nsCOMPtr<nsIDOMDocument> dDoc( do_QueryInterface(doc) );
|
|
if ( dDoc )
|
|
{
|
|
nsCOMPtr<nsIDOMElement> elem;
|
|
rv = dDoc->GetElementById( NS_ConvertASCIItoUCS2(aID), getter_AddRefs(elem) );
|
|
if (elem)
|
|
{
|
|
*aElement = elem.get();
|
|
NS_ADDREF(*aElement);
|
|
}
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
// Utility to set and attribute of a UI element
|
|
static nsresult
|
|
SetChromeAttribute(nsIDocShell *aShell, const char *aID,
|
|
const char *aName, const nsString &aValue)
|
|
{
|
|
nsCOMPtr<nsIDOMElement> elem;
|
|
nsresult rv = GetChromeElement(aShell, aID, getter_AddRefs(elem));
|
|
if (NS_SUCCEEDED(rv) && elem)
|
|
// Set the text attribute.
|
|
rv = elem->SetAttribute( NS_ConvertASCIItoUCS2(aName), aValue);
|
|
|
|
return rv;
|
|
}
|
|
|
|
// Utility to get the treeOwner for a docShell
|
|
static nsresult
|
|
GetTreeOwner(nsIDocShell* aDocShell, nsIBaseWindow** aBaseWindow)
|
|
{
|
|
nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(aDocShell));
|
|
NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
|
|
|
|
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
|
|
docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
|
|
NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE);
|
|
|
|
NS_ENSURE_SUCCESS(CallQueryInterface(treeOwner, aBaseWindow),
|
|
NS_ERROR_FAILURE);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// nsEditorShell
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
nsEditorShell::nsEditorShell()
|
|
: mMailCompose(PR_FALSE)
|
|
, mDisplayMode(eDisplayModeNormal)
|
|
, mHTMLSourceMode(PR_FALSE)
|
|
, mWebShellWindow(nsnull)
|
|
, mContentWindow(nsnull)
|
|
, mParserObserver(nsnull)
|
|
, mStateMaintainer(nsnull)
|
|
, mEditorController(nsnull)
|
|
, mDocShell(nsnull)
|
|
, mContentAreaDocShell(nsnull)
|
|
, mInitted(PR_FALSE)
|
|
, mCloseWindowWhenLoaded(PR_FALSE)
|
|
, mCantEditReason(eCantEditNoReason)
|
|
, mEditorType(eUninitializedEditorType)
|
|
, mWrapColumn(0)
|
|
, mSuggestedWordIndex(0)
|
|
, mDictionaryIndex(0)
|
|
{
|
|
//TODO:Save last-used display mode in prefs so new window inherits?
|
|
NS_INIT_REFCNT();
|
|
}
|
|
|
|
nsEditorShell::~nsEditorShell()
|
|
{
|
|
NS_IF_RELEASE(mStateMaintainer);
|
|
NS_IF_RELEASE(mParserObserver);
|
|
|
|
// the only other references we hold are in nsCOMPtrs, so they'll take
|
|
// care of themselves.
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS5(nsEditorShell,
|
|
nsIEditorShell,
|
|
nsIWebProgressListener,
|
|
nsIURIContentListener,
|
|
nsIEditorSpellCheck,
|
|
nsISupportsWeakReference);
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::Init()
|
|
{
|
|
NS_ASSERTION(!mInitted, "Double init of nsEditorShell detected");
|
|
if (mInitted)
|
|
return NS_OK;
|
|
|
|
nsAutoString editorType; editorType.AssignWithConversion("html"); // default to creating HTML editor
|
|
mEditorTypeString = editorType;
|
|
mEditorTypeString.ToLowerCase();
|
|
|
|
// Get pointer to our string bundle
|
|
nsresult res;
|
|
nsCOMPtr<nsIStringBundleService> stringBundleService = do_GetService(kCStringBundleServiceCID, &res);
|
|
if (!stringBundleService) {
|
|
NS_WARNING("ERROR: Failed to get StringBundle Service instance.\n");
|
|
return res;
|
|
}
|
|
nsILocale* aLocale = nsnull;
|
|
res = stringBundleService->CreateBundle(EDITOR_BUNDLE_URL, aLocale, getter_AddRefs(mStringBundle));
|
|
|
|
// XXX: why are we returning NS_OK here rather than res?
|
|
// is it ok to fail to get a string bundle? if so, it should be documented.
|
|
mInitted = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::Shutdown()
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
nsCOMPtr<nsIEditor> editor(do_QueryInterface(mEditor));
|
|
if (editor)
|
|
{
|
|
editor->PreDestroy();
|
|
}
|
|
|
|
// Make sure we blow the spellchecker away, just in
|
|
// case it hasn't been destroyed already.
|
|
mSpellChecker = nsnull;
|
|
|
|
if (mDocShell)
|
|
mDocShell->SetParentURIContentListener(nsnull);
|
|
|
|
// Remove our WebProgress listener...
|
|
nsCOMPtr<nsIWebProgress> webProgress;
|
|
if (mContentAreaDocShell) {
|
|
webProgress = do_GetInterface(mContentAreaDocShell);
|
|
if (webProgress) {
|
|
(void) webProgress->RemoveProgressListener(this);
|
|
}
|
|
}
|
|
|
|
// Remove our document mouse event listener
|
|
if (mMouseListenerP)
|
|
{
|
|
nsCOMPtr<nsIDOMEventReceiver> erP;
|
|
rv = GetDocumentEventReceiver(getter_AddRefs(erP));
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
if (erP)
|
|
{
|
|
erP->RemoveEventListenerByIID(mMouseListenerP, NS_GET_IID(nsIDOMMouseListener));
|
|
mMouseListenerP = nsnull;
|
|
}
|
|
else rv = NS_ERROR_NULL_POINTER;
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsEditorShell::ResetEditingState()
|
|
{
|
|
if (!mEditor) return NS_OK; // nothing to do
|
|
|
|
// Mmm, we have an editor already. That means that someone loaded more than
|
|
// one URL into the content area. Let's tear down what we have, and rip 'em a
|
|
// new one.
|
|
|
|
nsCOMPtr<nsIEditor> editor(do_QueryInterface(mEditor));
|
|
if (editor)
|
|
{
|
|
editor->PreDestroy();
|
|
}
|
|
|
|
// Unload existing stylesheets
|
|
nsCOMPtr<nsIEditorStyleSheets> styleSheets = do_QueryInterface(mEditor);
|
|
if (styleSheets)
|
|
{
|
|
if (mBaseStyleSheet)
|
|
{
|
|
styleSheets->RemoveOverrideStyleSheet(mBaseStyleSheet);
|
|
mBaseStyleSheet = 0;
|
|
}
|
|
if (mEditModeStyleSheet)
|
|
{
|
|
styleSheets->RemoveOverrideStyleSheet(mEditModeStyleSheet);
|
|
mEditModeStyleSheet = 0;
|
|
}
|
|
if (mAllTagsModeStyleSheet)
|
|
{
|
|
styleSheets->RemoveOverrideStyleSheet(mAllTagsModeStyleSheet);
|
|
mAllTagsModeStyleSheet = 0;
|
|
}
|
|
if (mParagraphMarksStyleSheet)
|
|
{
|
|
styleSheets->RemoveOverrideStyleSheet(mParagraphMarksStyleSheet);
|
|
mParagraphMarksStyleSheet = 0;
|
|
}
|
|
}
|
|
|
|
nsresult rv;
|
|
// now, unregister the selection listener, if there was one
|
|
if (mStateMaintainer)
|
|
{
|
|
nsCOMPtr<nsISelection> domSelection;
|
|
// using a scoped result, because we don't really care if this fails
|
|
rv = GetEditorSelection(getter_AddRefs(domSelection));
|
|
if (NS_SUCCEEDED(rv) && domSelection)
|
|
{
|
|
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(domSelection));
|
|
selPriv->RemoveSelectionListener(mStateMaintainer);
|
|
NS_IF_RELEASE(mStateMaintainer);
|
|
}
|
|
}
|
|
|
|
// Remove our document mouse event listener
|
|
if (mMouseListenerP)
|
|
{
|
|
nsCOMPtr<nsIDOMEventReceiver> erP;
|
|
rv = GetDocumentEventReceiver(getter_AddRefs(erP));
|
|
if (NS_SUCCEEDED(rv) && erP)
|
|
{
|
|
erP->RemoveEventListenerByIID(mMouseListenerP, NS_GET_IID(nsIDOMMouseListener));
|
|
mMouseListenerP = nsnull;
|
|
}
|
|
}
|
|
|
|
// clear this editor out of the controller
|
|
if (mEditorController)
|
|
{
|
|
mEditorController->SetCommandRefCon(nsnull);
|
|
}
|
|
|
|
mEditorType = eUninitializedEditorType;
|
|
mEditor = 0; // clear out the nsCOMPtr
|
|
|
|
// and tell them that they are doing bad things
|
|
NS_WARNING("Multiple loads of the editor's document detected.");
|
|
// Note that if you registered doc state listeners before the second
|
|
// URL load, they don't get transferred to the new editor.
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsEditorShell::PrepareDocumentForEditing(nsIDOMWindow* aDOMWindow, nsIURI *aUrl)
|
|
{
|
|
if (!mContentAreaDocShell || !mContentWindow)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
NS_ASSERTION(!mEditor, "Should never have an editor here");
|
|
|
|
// get the docshell for this DOM Window. Need this, not mContentAreaDocShell, in
|
|
// case we are editing a frameset
|
|
nsCOMPtr<nsIScriptGlobalObject> scriptObject(do_QueryInterface(aDOMWindow));
|
|
nsCOMPtr<nsIDocShell> docshell;
|
|
|
|
if (scriptObject) {
|
|
scriptObject->GetDocShell(getter_AddRefs(docshell));
|
|
}
|
|
if (!docshell)
|
|
{
|
|
NS_ASSERTION(0, "Failed to get docShell from DOMWindow");
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
// turn off animated GIFs
|
|
nsCOMPtr<nsIPresContext> presContext;
|
|
docshell->GetPresContext(getter_AddRefs(presContext));
|
|
if (presContext)
|
|
presContext->SetImageAnimationMode(eImageAnimation_None);
|
|
|
|
nsresult rv = DoEditorMode(docshell);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// transfer the doc state listeners to the editor
|
|
rv = TransferDocumentStateListeners();
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// make the UI state maintainer
|
|
NS_NEWXPCOM(mStateMaintainer, nsInterfaceState);
|
|
if (!mStateMaintainer) return NS_ERROR_OUT_OF_MEMORY;
|
|
mStateMaintainer->AddRef(); // the owning reference
|
|
|
|
// get the Doc from the webshell
|
|
nsCOMPtr<nsIContentViewer> cv;
|
|
rv = mDocShell->GetContentViewer(getter_AddRefs(cv));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIDocumentViewer> docViewer = do_QueryInterface(cv, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIDocument> chromeDoc;
|
|
rv = docViewer->GetDocument(*getter_AddRefs(chromeDoc));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIDOMDocument> dDoc = do_QueryInterface(chromeDoc, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
// now init the state maintainer
|
|
rv = mStateMaintainer->Init(mEditor, dDoc);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// set it up as a selection listener
|
|
nsCOMPtr<nsISelection> domSelection;
|
|
rv = GetEditorSelection(getter_AddRefs(domSelection));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(domSelection));
|
|
rv = selPriv->AddSelectionListener(mStateMaintainer);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// and set it up as a doc state listener
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
rv = editor->AddDocumentStateListener(NS_STATIC_CAST(nsIDocumentStateListener*, mStateMaintainer));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// and as a transaction listener
|
|
nsCOMPtr<nsITransactionManager> txnMgr;
|
|
editor->GetTransactionManager(getter_AddRefs(txnMgr));
|
|
if (txnMgr)
|
|
{
|
|
txnMgr->AddListener(NS_STATIC_CAST(nsITransactionListener*, mStateMaintainer));
|
|
}
|
|
|
|
// set the editor in the editor controller
|
|
if (mEditorController)
|
|
{
|
|
nsCOMPtr<nsISupports> editorAsISupports = do_QueryInterface(editor);
|
|
mEditorController->SetCommandRefCon(editorAsISupports);
|
|
}
|
|
|
|
if (mEditorType == eHTMLTextEditorType)
|
|
{
|
|
// get a mouse listener for double click on tags
|
|
// We can't use nsEditor listener because core editor shouldn't call UI commands
|
|
rv = NS_NewEditorShellMouseListener(getter_AddRefs(mMouseListenerP), this);
|
|
if (NS_FAILED(rv))
|
|
{
|
|
mMouseListenerP = nsnull;
|
|
return rv;
|
|
}
|
|
|
|
// Add mouse listener to document
|
|
nsCOMPtr<nsIDOMEventReceiver> erP;
|
|
rv = GetDocumentEventReceiver(getter_AddRefs(erP));
|
|
if (NS_FAILED(rv))
|
|
{
|
|
mMouseListenerP = nsnull;
|
|
return rv;
|
|
}
|
|
|
|
rv = erP->AddEventListenerByIID(mMouseListenerP, NS_GET_IID(nsIDOMMouseListener));
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
|
|
// now all the listeners are set up, we can call PostCreate
|
|
rv = editor->PostCreate();
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// get the URL of the page we are editing
|
|
if (aUrl)
|
|
{
|
|
|
|
// if this is a file URL of a file that exists locally, we'll stash the nsIFile
|
|
// in the disk document, so that later saves save back to the same file.
|
|
nsCOMPtr<nsIFileURL> pageFileURL(do_QueryInterface(aUrl));
|
|
PRBool isFile=PR_FALSE;
|
|
rv = aUrl->SchemeIs(nsIURI::FILE, &isFile);
|
|
if (NS_SUCCEEDED(rv) && isFile && pageFileURL)
|
|
{
|
|
nsCOMPtr<nsIFile> pageFile;
|
|
pageFileURL->GetFile(getter_AddRefs(pageFile));
|
|
|
|
PRBool fileExists;
|
|
if (pageFile && NS_SUCCEEDED(pageFile->Exists(&fileExists)) && fileExists)
|
|
{
|
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
|
editor->GetDocument(getter_AddRefs(domDoc));
|
|
nsCOMPtr<nsIDiskDocument> diskDoc(do_QueryInterface(domDoc));
|
|
if (diskDoc)
|
|
diskDoc->InitDiskDocument(pageFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set the editor-specific Window caption
|
|
UpdateWindowTitle();
|
|
|
|
nsCOMPtr<nsIEditorStyleSheets> styleSheets = do_QueryInterface(mEditor);
|
|
if (!styleSheets)
|
|
return NS_NOINTERFACE;
|
|
|
|
// Load style sheet with settings that should never
|
|
// change, even in "Browser" mode
|
|
// We won't unload this, so we don't need to be returned the style sheet pointer
|
|
|
|
|
|
styleSheets->ApplyOverrideStyleSheet(NS_ConvertASCIItoUCS2("chrome://editor/content/EditorOverride.css"),
|
|
getter_AddRefs(mBaseStyleSheet));
|
|
|
|
SetDisplayMode(mDisplayMode);
|
|
|
|
#ifdef DEBUG
|
|
// Activate the debug menu only in debug builds
|
|
// by removing the "hidden" attribute set "true" in XUL
|
|
nsCOMPtr<nsIDOMElement> elem;
|
|
rv = dDoc->GetElementById(NS_ConvertASCIItoUCS2("debugMenu"), getter_AddRefs(elem));
|
|
if (elem)
|
|
elem->RemoveAttribute(NS_ConvertASCIItoUCS2("hidden"));
|
|
#endif
|
|
|
|
// Force initial focus to the content window except if in mail compose
|
|
// why aren't we doing this in JS?
|
|
if (!mMailCompose)
|
|
{
|
|
if(!mContentWindow)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
nsCOMPtr<nsIDOMWindowInternal> cwP = do_QueryReferent(mContentWindow);
|
|
if (!cwP) return NS_ERROR_NOT_INITIALIZED;
|
|
cwP->Focus();
|
|
|
|
//mContentWindow->Focus();
|
|
// Collapse the selection to the begining of the document
|
|
// (this also turns on the caret)
|
|
nsCOMPtr<nsIPlaintextEditor> textEditor (do_QueryInterface(mEditor));
|
|
if (textEditor)
|
|
textEditor->CollapseSelectionToStart();
|
|
}
|
|
|
|
// show the caret, if our window is focussed already
|
|
nsCOMPtr<nsIDOMWindowInternal> contentInternal = do_QueryReferent(mContentWindow);
|
|
nsCOMPtr<nsPIDOMWindow> privContent(do_QueryInterface(contentInternal));
|
|
|
|
if (privContent)
|
|
{
|
|
nsCOMPtr<nsIFocusController> focusController;
|
|
privContent->GetRootFocusController(getter_AddRefs(focusController));
|
|
|
|
if (focusController)
|
|
{
|
|
nsCOMPtr<nsIDOMWindowInternal> focussedWindow;
|
|
focusController->GetFocusedWindow(getter_AddRefs(focussedWindow));
|
|
|
|
if (focussedWindow.get() == contentInternal.get()) // now see if we are focussed
|
|
{
|
|
nsCOMPtr<nsISelectionController> selCon;
|
|
editor->GetSelectionController(getter_AddRefs(selCon));
|
|
|
|
PRInt32 pixelWidth = 1;
|
|
|
|
static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
|
|
|
|
nsCOMPtr<nsILookAndFeel> lookNFeel = do_GetService(kLookAndFeelCID);
|
|
if (lookNFeel)
|
|
lookNFeel->GetMetric(nsILookAndFeel::eMetric_MultiLineCaretWidth, pixelWidth);
|
|
|
|
selCon->SetCaretWidth(pixelWidth);
|
|
selCon->SetCaretEnabled(PR_FALSE);
|
|
selCon->SetCaretEnabled(PR_TRUE); // make damn sure it shows; the last SetVisible
|
|
// may have happened when we didn't have focus.
|
|
selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
|
|
}
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsEditorShell::GetDocumentEventReceiver(nsIDOMEventReceiver **aEventReceiver)
|
|
{
|
|
if (!aEventReceiver) return NS_ERROR_NULL_POINTER;
|
|
if (!mContentWindow || !mEditor) return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
|
|
|
if(!mContentWindow)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
nsCOMPtr<nsIDOMWindowInternal> cwP = do_QueryReferent(mContentWindow);
|
|
if (!cwP) return NS_ERROR_NOT_INITIALIZED;
|
|
cwP->GetDocument(getter_AddRefs(domDoc));
|
|
//mContentWindow->GetDocument(getter_AddRefs(domDoc));
|
|
|
|
if (!domDoc) return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsCOMPtr<nsIDOMElement> rootElement;
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
nsresult rv = editor->GetRootElement(getter_AddRefs(rootElement));
|
|
|
|
nsCOMPtr<nsIDOMEventReceiver> erP;
|
|
rv = rootElement->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), getter_AddRefs(erP));
|
|
|
|
if (erP)
|
|
{
|
|
*aEventReceiver = erP;
|
|
NS_ADDREF(*aEventReceiver);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SetContentWindow(nsIDOMWindowInternal* aWin)
|
|
{
|
|
NS_PRECONDITION(aWin != nsnull, "null ptr");
|
|
if (!aWin)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
mContentWindow = getter_AddRefs( NS_GetWeakReference(aWin) ); // weak reference to aWin
|
|
//mContentWindow = aWin;
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIScriptGlobalObject> globalObj = do_QueryReferent(mContentWindow, &rv);
|
|
if (NS_FAILED(rv) || !globalObj)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsCOMPtr<nsIDocShell> docShell;
|
|
globalObj->GetDocShell(getter_AddRefs(docShell));
|
|
if (!docShell)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
// Remove the WebProgress listener from the old docshell (if any...)
|
|
nsCOMPtr<nsIWebProgress> webProgress;
|
|
if (mContentAreaDocShell) {
|
|
webProgress = do_GetInterface(mContentAreaDocShell, &rv);
|
|
if (webProgress) {
|
|
(void) webProgress->RemoveProgressListener(this);
|
|
}
|
|
}
|
|
|
|
// Attach a WebProgress listener to the new docShell
|
|
webProgress = do_GetInterface(docShell, &rv);
|
|
if (webProgress) {
|
|
rv = webProgress->AddProgressListener(this);
|
|
}
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
mContentAreaDocShell = docShell; // dont AddRef
|
|
|
|
// we make two controllers
|
|
nsCOMPtr<nsIControllers> controllers;
|
|
if(!mContentWindow)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
nsCOMPtr<nsIDOMWindowInternal> cwP = do_QueryReferent(mContentWindow);
|
|
if (!cwP) return NS_ERROR_NOT_INITIALIZED;
|
|
cwP->GetControllers(getter_AddRefs(controllers));
|
|
//rv = mContentWindow->GetControllers(getter_AddRefs(controllers));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
{
|
|
// the first is an editor controller, and takes an nsIEditor as the refCon
|
|
nsCOMPtr<nsIController> controller = do_CreateInstance("@mozilla.org/editor/editorcontroller;1", &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
nsCOMPtr<nsIEditorController> editorController = do_QueryInterface(controller);
|
|
rv = editorController->Init(nsnull); // we set the editor later when we have one
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
mEditorController = editorController; // temp weak link, so we can get it and set the editor later
|
|
|
|
rv = controllers->InsertControllerAt(eEditorController, controller);
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
|
|
{
|
|
// the second is a composer controller, and takes an nsIEditorShell as the refCon
|
|
nsCOMPtr<nsIController> controller = do_CreateInstance("@mozilla.org/editor/composercontroller;1", &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
nsCOMPtr<nsIEditorController> editorController = do_QueryInterface(controller);
|
|
|
|
nsCOMPtr<nsISupports> shellAsISupports = do_QueryInterface((nsIEditorShell*)this);
|
|
rv = editorController->Init(shellAsISupports);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = controllers->InsertControllerAt(eComposerController, controller);
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetContentWindow(nsIDOMWindowInternal * *aContentWindow)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aContentWindow);
|
|
|
|
if(!mContentWindow)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
nsCOMPtr<nsIDOMWindowInternal> cwP = do_QueryReferent(mContentWindow);
|
|
if (!cwP)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
NS_IF_ADDREF(*aContentWindow = cwP);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SetWebShellWindow(nsIDOMWindowInternal* aWin)
|
|
{
|
|
NS_PRECONDITION(aWin != nsnull, "null ptr");
|
|
if (!aWin)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
mWebShellWindow = aWin; // no addref
|
|
|
|
nsCOMPtr<nsIScriptGlobalObject> globalObj( do_QueryInterface(aWin) );
|
|
if (!globalObj) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
nsCOMPtr<nsIDocShell> docShell;
|
|
globalObj->GetDocShell(getter_AddRefs(docShell));
|
|
if (!docShell)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
mDocShell = docShell;
|
|
|
|
// register as a content listener, so that we can fend off URL
|
|
// loads from sidebar
|
|
rv = mDocShell->SetParentURIContentListener(this);
|
|
|
|
/*
|
|
#ifdef APP_DEBUG
|
|
nsXPIDLString name;
|
|
nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(docShell));
|
|
docShellAsItem->GetName(getter_Copies(name));
|
|
nsAutoString str(name);
|
|
|
|
char* cstr = str.ToNewCString();
|
|
printf("Attaching to WebShellWindow[%s]\n", cstr);
|
|
nsCRT::free(cstr);
|
|
#endif
|
|
*/
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetWebShellWindow(nsIDOMWindowInternal * *aWebShellWindow)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aWebShellWindow);
|
|
NS_IF_ADDREF(*aWebShellWindow = mWebShellWindow);
|
|
return NS_OK;
|
|
}
|
|
|
|
// tell the appcore what type of editor to instantiate
|
|
// this must be called before the editor has been instantiated,
|
|
// otherwise, an error is returned.
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SetEditorType(const PRUnichar *editorType)
|
|
{
|
|
if (mEditor)
|
|
return NS_ERROR_ALREADY_INITIALIZED;
|
|
|
|
nsAutoString theType(editorType);
|
|
theType.ToLowerCase();
|
|
|
|
PRBool textMail = theType.EqualsWithConversion("textmail");
|
|
mMailCompose = theType.EqualsWithConversion("htmlmail") || textMail;
|
|
|
|
if (mMailCompose ||theType.EqualsWithConversion("text") || theType.EqualsWithConversion("html") || theType.IsEmpty())
|
|
{
|
|
// We don't store a separate type for textmail
|
|
if (textMail)
|
|
mEditorTypeString = NS_ConvertASCIItoUCS2("text");
|
|
else
|
|
mEditorTypeString = theType;
|
|
return NS_OK;
|
|
}
|
|
else
|
|
{
|
|
NS_WARNING("Editor type not recognized");
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetEditorType(PRUnichar **_retval)
|
|
{
|
|
*_retval = nsnull;
|
|
|
|
nsresult err = NS_NOINTERFACE;
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
|
|
if (editor)
|
|
{
|
|
*_retval = mEditorTypeString.ToNewUnicode();
|
|
}
|
|
return err;
|
|
}
|
|
|
|
|
|
nsresult
|
|
nsEditorShell::InstantiateEditor(nsIDOMDocument *aDoc, nsIPresShell *aPresShell)
|
|
{
|
|
NS_PRECONDITION(aDoc && aPresShell, "null ptr");
|
|
if (!aDoc || !aPresShell)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
if (mEditor)
|
|
return NS_ERROR_ALREADY_INITIALIZED;
|
|
|
|
nsresult err = NS_OK;
|
|
|
|
nsCOMPtr<nsIEditor> editor;
|
|
err = nsComponentManager::CreateInstance(kHTMLEditorCID, nsnull, NS_GET_IID(nsIEditor), getter_AddRefs(editor));
|
|
if(!editor)
|
|
err = NS_ERROR_OUT_OF_MEMORY;
|
|
nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(aPresShell);
|
|
|
|
if (NS_SUCCEEDED(err))
|
|
{
|
|
if (mEditorTypeString.EqualsWithConversion("text"))
|
|
{
|
|
err = editor->Init(aDoc, aPresShell, nsnull, selCon, nsIPlaintextEditor::eEditorPlaintextMask | nsIPlaintextEditor::eEditorEnableWrapHackMask);
|
|
mEditorType = ePlainTextEditorType;
|
|
}
|
|
else if (mEditorTypeString.EqualsWithConversion("html") || mEditorTypeString.IsEmpty()) // empty string default to HTML editor
|
|
{
|
|
err = editor->Init(aDoc, aPresShell, nsnull, selCon, 0);
|
|
mEditorType = eHTMLTextEditorType;
|
|
}
|
|
else if (mEditorTypeString.EqualsWithConversion("htmlmail")) // HTML editor with special mail rules
|
|
{
|
|
err = editor->Init(aDoc, aPresShell, nsnull, selCon, nsIPlaintextEditor::eEditorMailMask);
|
|
mEditorType = eHTMLTextEditorType;
|
|
}
|
|
else
|
|
{
|
|
err = NS_ERROR_INVALID_ARG; // this is not an editor we know about
|
|
#if DEBUG
|
|
nsAutoString errorMsg; errorMsg.AssignWithConversion("Failed to init editor. Unknown editor type \"");
|
|
errorMsg += mEditorTypeString;
|
|
errorMsg.AppendWithConversion("\"\n");
|
|
char *errorMsgCString = errorMsg.ToNewCString();
|
|
NS_WARNING(errorMsgCString);
|
|
nsCRT::free(errorMsgCString);
|
|
#endif
|
|
}
|
|
|
|
// disable the preference style sheet so we can override colors
|
|
if (NS_SUCCEEDED(err)) {
|
|
err = aPresShell->EnablePrefStyleRules(PR_FALSE,0);
|
|
}
|
|
|
|
if (NS_SUCCEEDED(err) && editor)
|
|
{
|
|
mEditor = do_QueryInterface(editor); // this does the addref that is the owning reference
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
nsresult
|
|
nsEditorShell::DoEditorMode(nsIDocShell *aDocShell)
|
|
{
|
|
nsresult err = NS_OK;
|
|
|
|
NS_PRECONDITION(aDocShell, "Need a webshell here");
|
|
if (!aDocShell)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsCOMPtr<nsIDocument> doc;
|
|
err = GetDocument(aDocShell, getter_AddRefs(doc));
|
|
if (NS_FAILED(err)) return err;
|
|
if (!doc) return NS_ERROR_FAILURE;
|
|
|
|
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc, &err);
|
|
if (NS_FAILED(err)) return err;
|
|
if (!domDoc) return NS_ERROR_FAILURE;
|
|
|
|
nsCOMPtr<nsIPresShell> presShell;
|
|
err = aDocShell->GetPresShell(getter_AddRefs(presShell));
|
|
if (NS_FAILED(err)) return err;
|
|
if (!presShell) return NS_ERROR_FAILURE;
|
|
|
|
return InstantiateEditor(domDoc, presShell);
|
|
}
|
|
|
|
// Deletion routines
|
|
nsresult
|
|
nsEditorShell::ScrollSelectionIntoView()
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (!editor) return NS_ERROR_NOT_INITIALIZED;
|
|
nsCOMPtr<nsISelectionController> selCon;
|
|
editor->GetSelectionController(getter_AddRefs(selCon));
|
|
if (!selCon)
|
|
return NS_ERROR_UNEXPECTED;
|
|
return selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
|
|
nsISelectionController::SELECTION_FOCUS_REGION);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::DeleteCharForward()
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (!editor) return NS_ERROR_NOT_INITIALIZED;
|
|
nsresult rv = editor->DeleteSelection(nsIEditor::eNext);
|
|
ScrollSelectionIntoView();
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::DeleteCharBackward()
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (!editor) return NS_ERROR_NOT_INITIALIZED;
|
|
nsresult rv = editor->DeleteSelection(nsIEditor::ePrevious);
|
|
ScrollSelectionIntoView();
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::DeleteWordForward()
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (!editor) return NS_ERROR_NOT_INITIALIZED;
|
|
nsresult rv = editor->DeleteSelection(nsIEditor::eNextWord);
|
|
ScrollSelectionIntoView();
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::DeleteWordBackward()
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (!editor) return NS_ERROR_NOT_INITIALIZED;
|
|
nsresult rv = editor->DeleteSelection(nsIEditor::ePreviousWord);
|
|
ScrollSelectionIntoView();
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::DeleteToEndOfLine()
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (!editor) return NS_ERROR_NOT_INITIALIZED;
|
|
nsresult rv = editor->DeleteSelection(nsIEditor::eToEndOfLine);
|
|
ScrollSelectionIntoView();
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::DeleteToBeginningOfLine()
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (!editor) return NS_ERROR_NOT_INITIALIZED;
|
|
nsresult rv = editor->DeleteSelection(nsIEditor::eToBeginningOfLine);
|
|
ScrollSelectionIntoView();
|
|
return rv;
|
|
}
|
|
|
|
// Generic attribute setting and removal
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SetAttribute(nsIDOMElement *element, const PRUnichar *attr, const PRUnichar *value)
|
|
{
|
|
if (!element || !attr || !value)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor) {
|
|
nsAutoString attributeStr(attr);
|
|
nsAutoString valueStr(value);
|
|
result = editor->SetAttribute(element, attributeStr, valueStr);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::RemoveAttribute(nsIDOMElement *element, const PRUnichar *attr)
|
|
{
|
|
if (!element || !attr)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor) {
|
|
nsAutoString attributeStr(attr);
|
|
result = editor->RemoveAttribute(element, attributeStr);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// the name of the attribute here should be the contents of the appropriate
|
|
// tag, e.g. 'b' for bold, 'i' for italics.
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SetTextProperty(const PRUnichar *prop, const PRUnichar *attr, const PRUnichar *value)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
nsCOMPtr<nsIAtom> styleAtom = getter_AddRefs(NS_NewAtom(prop)); /// XXX Hack alert! Look in nsIEditProperty.h for this
|
|
if (! styleAtom) return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nsAutoString attributeStr(attr);
|
|
nsAutoString valueStr(value);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
// should we allow this?
|
|
case eHTMLTextEditorType:
|
|
err = mEditor->SetInlineProperty(styleAtom, &attributeStr, &valueStr);
|
|
break;
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
nsEditorShell::RemoveOneProperty(const nsString& aProp, const nsString &aAttr)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
nsCOMPtr<nsIAtom> styleAtom = getter_AddRefs(NS_NewAtom(aProp)); /// XXX Hack alert! Look in nsIEditProperty.h for this
|
|
if (! styleAtom) return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
// should we allow this?
|
|
case eHTMLTextEditorType:
|
|
err = mEditor->RemoveInlineProperty(styleAtom, &aAttr);
|
|
break;
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
// the name of the attribute here should be the contents of the appropriate
|
|
// tag, e.g. 'b' for bold, 'i' for italics.
|
|
NS_IMETHODIMP
|
|
nsEditorShell::RemoveTextProperty(const PRUnichar *prop, const PRUnichar *attr)
|
|
{
|
|
// OK, I'm really hacking now. This is just so that we can accept 'all' as input.
|
|
nsAutoString allStr(prop);
|
|
nsAutoString aAttr(attr);
|
|
|
|
allStr.ToLowerCase();
|
|
PRBool doingAll = (allStr.EqualsWithConversion("all"));
|
|
nsresult err = NS_OK;
|
|
|
|
if (doingAll)
|
|
{
|
|
err = mEditor->RemoveAllInlineProperties();
|
|
}
|
|
else
|
|
{
|
|
nsAutoString aProp(prop);
|
|
err = RemoveOneProperty(aProp, aAttr);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetTextProperty(const PRUnichar *prop, const PRUnichar *attr, const PRUnichar *value, PRBool *firstHas, PRBool *anyHas, PRBool *allHas)
|
|
{
|
|
nsIAtom *styleAtom = nsnull;
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
styleAtom = NS_NewAtom(prop); /// XXX Hack alert! Look in nsIEditProperty.h for this
|
|
|
|
nsAutoString aAttr(attr);
|
|
nsAutoString aValue(value);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
// should we allow this?
|
|
case eHTMLTextEditorType:
|
|
err = mEditor->GetInlineProperty(styleAtom, &aAttr, &aValue, *firstHas, *anyHas, *allHas);
|
|
break;
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
NS_RELEASE(styleAtom);
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::IncreaseFontSize()
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
|
|
|
|
if (htmlEditor)
|
|
err = htmlEditor->IncreaseFontSize();
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::DecreaseFontSize()
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
|
|
|
|
if (htmlEditor)
|
|
err = htmlEditor->DecreaseFontSize();
|
|
return err;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SetBackgroundColor(const PRUnichar *color)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
|
|
nsAutoString aColor(color);
|
|
|
|
result = mEditor->SetBackgroundColor(aColor);
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetParagraphState(PRBool *aMixed, PRUnichar **_retval)
|
|
{
|
|
if (!aMixed || !_retval) return NS_ERROR_NULL_POINTER;
|
|
*_retval = nsnull;
|
|
*aMixed = PR_FALSE;
|
|
|
|
nsresult err = NS_NOINTERFACE;
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
|
|
|
|
if (htmlEditor)
|
|
{
|
|
PRBool bMixed;
|
|
nsAutoString state;
|
|
err = htmlEditor->GetParagraphState(bMixed, state);
|
|
if (!bMixed)
|
|
*_retval = state.ToNewUnicode();
|
|
}
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetListState(PRBool *aMixed, PRUnichar **_retval)
|
|
{
|
|
if (!aMixed || !_retval) return NS_ERROR_NULL_POINTER;
|
|
*_retval = nsnull;
|
|
*aMixed = PR_FALSE;
|
|
|
|
nsresult err = NS_NOINTERFACE;
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
|
|
if (htmlEditor)
|
|
{
|
|
PRBool bOL, bUL, bDL;
|
|
err = htmlEditor->GetListState(*aMixed, bOL, bUL, bDL);
|
|
if (NS_SUCCEEDED(err))
|
|
{
|
|
if (!*aMixed)
|
|
{
|
|
nsAutoString tagStr;
|
|
if (bOL) tagStr.AssignWithConversion("ol");
|
|
else if (bUL) tagStr.AssignWithConversion("ul");
|
|
else if (bDL) tagStr.AssignWithConversion("dl");
|
|
*_retval = tagStr.ToNewUnicode();
|
|
}
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetListItemState(PRBool *aMixed, PRUnichar **_retval)
|
|
{
|
|
if (!aMixed || !_retval) return NS_ERROR_NULL_POINTER;
|
|
*_retval = nsnull;
|
|
*aMixed = PR_FALSE;
|
|
|
|
nsresult err = NS_NOINTERFACE;
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
|
|
if (htmlEditor)
|
|
{
|
|
PRBool bLI,bDT,bDD;
|
|
err = htmlEditor->GetListItemState(*aMixed, bLI, bDT, bDD);
|
|
if (NS_SUCCEEDED(err))
|
|
{
|
|
if (!*aMixed)
|
|
{
|
|
nsAutoString tagStr;
|
|
if (bLI) tagStr.AssignWithConversion("li");
|
|
else if (bDT) tagStr.AssignWithConversion("dt");
|
|
else if (bDD) tagStr.AssignWithConversion("dd");
|
|
*_retval = tagStr.ToNewUnicode();
|
|
}
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetAlignment(PRBool *aMixed, PRUnichar **_retval)
|
|
{
|
|
if (!aMixed || !_retval) return NS_ERROR_NULL_POINTER;
|
|
*_retval = nsnull;
|
|
*aMixed = PR_FALSE;
|
|
|
|
nsresult err = NS_NOINTERFACE;
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
|
|
if (htmlEditor)
|
|
{
|
|
nsIHTMLEditor::EAlignment firstAlign;
|
|
err = htmlEditor->GetAlignment(*aMixed, firstAlign);
|
|
if (NS_SUCCEEDED(err))
|
|
{
|
|
nsAutoString tagStr;
|
|
if (firstAlign == nsIHTMLEditor::eLeft)
|
|
tagStr.AssignWithConversion("left");
|
|
else if (firstAlign == nsIHTMLEditor::eCenter)
|
|
tagStr.AssignWithConversion("center");
|
|
else if (firstAlign == nsIHTMLEditor::eRight)
|
|
tagStr.AssignWithConversion("right");
|
|
*_retval = tagStr.ToNewUnicode();
|
|
}
|
|
}
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::ApplyStyleSheet(const PRUnichar *url)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
|
|
nsAutoString aURL(url);
|
|
|
|
nsCOMPtr<nsIEditorStyleSheets> styleSheets = do_QueryInterface(mEditor);
|
|
if (styleSheets)
|
|
result = styleSheets->ApplyStyleSheet(aURL, nsnull);
|
|
|
|
return result;
|
|
}
|
|
|
|
// Note: This is not undoable action (on purpose!)
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SetDisplayMode(PRInt32 aDisplayMode)
|
|
{
|
|
if (aDisplayMode == eDisplayModeSource)
|
|
{
|
|
// We track only display modes that involve style sheet changes
|
|
// with mDisplayMode, so use a separate bool for source mode
|
|
mHTMLSourceMode = PR_TRUE;
|
|
// The HTML Source display mode is handled in editor.js
|
|
return NS_OK;
|
|
}
|
|
mHTMLSourceMode = PR_FALSE;
|
|
|
|
nsCOMPtr<nsIEditorStyleSheets> styleSheets = do_QueryInterface(mEditor);
|
|
if (!styleSheets) return NS_NOINTERFACE;
|
|
|
|
nsCOMPtr<nsIStyleSheet> nsISheet;
|
|
nsresult res = NS_OK;
|
|
|
|
// Extra style sheets to explain optimization testing:
|
|
// eDisplayModePreview: No extra style sheets
|
|
// eDisplayModePreview: 1 extra sheet: mEditModeStyleSheet
|
|
// eDisplayModeAllTags: 2 extra sheets: mEditModeStyleSheet and mAllTagsModeStyleSheet
|
|
|
|
if (aDisplayMode == eDisplayModePreview)
|
|
{
|
|
// Disable all extra "edit mode" style sheets
|
|
if (mEditModeStyleSheet)
|
|
{
|
|
nsISheet = do_QueryInterface(mEditModeStyleSheet);
|
|
res = nsISheet->SetEnabled(PR_FALSE);
|
|
if (NS_FAILED(res)) return res;
|
|
}
|
|
// Disable ShowAllTags mode if that was the previous mode
|
|
if (mDisplayMode == eDisplayModeAllTags && mAllTagsModeStyleSheet)
|
|
{
|
|
nsISheet = do_QueryInterface(mAllTagsModeStyleSheet);
|
|
res = nsISheet->SetEnabled(PR_FALSE);
|
|
}
|
|
}
|
|
else if (aDisplayMode == eDisplayModeNormal)
|
|
{
|
|
// Don't need to activate if AllTags was last mode
|
|
if (mDisplayMode != eDisplayModeAllTags)
|
|
{
|
|
// If loaded before, enable the sheet
|
|
if (mEditModeStyleSheet)
|
|
{
|
|
nsISheet = do_QueryInterface(mEditModeStyleSheet);
|
|
res = nsISheet->SetEnabled(PR_TRUE);
|
|
}
|
|
else
|
|
{
|
|
|
|
//Load the editmode style sheet
|
|
res = styleSheets->ApplyOverrideStyleSheet(NS_ConvertASCIItoUCS2("chrome://editor/content/EditorContent.css"),
|
|
getter_AddRefs(mEditModeStyleSheet));
|
|
}
|
|
if (NS_FAILED(res)) return res;
|
|
}
|
|
|
|
// Disable ShowAllTags mode if that was the previous mode
|
|
if (mDisplayMode == eDisplayModeAllTags && mAllTagsModeStyleSheet)
|
|
{
|
|
nsISheet = do_QueryInterface(mAllTagsModeStyleSheet);
|
|
res = nsISheet->SetEnabled(PR_FALSE);
|
|
}
|
|
}
|
|
else if (aDisplayMode == eDisplayModeAllTags)
|
|
{
|
|
// If loaded before, enable the sheet
|
|
if (mAllTagsModeStyleSheet)
|
|
{
|
|
nsISheet = do_QueryInterface(mAllTagsModeStyleSheet);
|
|
res = nsISheet->SetEnabled(PR_TRUE);
|
|
}
|
|
else
|
|
{
|
|
// else load it
|
|
res = styleSheets->ApplyOverrideStyleSheet(NS_ConvertASCIItoUCS2("chrome://editor/content/EditorAllTags.css"),
|
|
getter_AddRefs(mAllTagsModeStyleSheet));
|
|
}
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// We don't need to activate "normal" mode if that was the previous mode
|
|
if (mDisplayMode != eDisplayModeNormal)
|
|
{
|
|
if (mEditModeStyleSheet)
|
|
{
|
|
nsISheet = do_QueryInterface(mEditModeStyleSheet);
|
|
res = nsISheet->SetEnabled(PR_TRUE);
|
|
}
|
|
else
|
|
{
|
|
res = styleSheets->ApplyOverrideStyleSheet(NS_ConvertASCIItoUCS2("chrome://editor/content/EditorContent.css"),
|
|
getter_AddRefs(mEditModeStyleSheet));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remember the new mode
|
|
if (NS_SUCCEEDED(res)) mDisplayMode = aDisplayMode;
|
|
return res;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetEditMode(PRInt32 *_retval)
|
|
{
|
|
if (mHTMLSourceMode)
|
|
*_retval = eDisplayModeSource;
|
|
else
|
|
*_retval = mDisplayMode;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::IsHTMLSourceMode(PRBool *_retval)
|
|
{
|
|
*_retval = mHTMLSourceMode;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::FinishHTMLSource(void)
|
|
{
|
|
if (mHTMLSourceMode)
|
|
{
|
|
// Call the JS command to convert and switch to previous edit mode
|
|
nsAutoString command(NS_LITERAL_STRING("cmd_FinishHTMLSource"));
|
|
return DoControllerCommand(command);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::DisplayParagraphMarks(PRBool aShowMarks)
|
|
{
|
|
nsresult res = NS_OK;
|
|
|
|
nsCOMPtr<nsIEditorStyleSheets> styleSheets = do_QueryInterface(mEditor);
|
|
if (!styleSheets) return NS_NOINTERFACE;
|
|
nsCOMPtr<nsIStyleSheet> nsISheet;
|
|
if (aShowMarks)
|
|
{
|
|
// Check if style sheet is already loaded -- just enable it
|
|
if (mParagraphMarksStyleSheet)
|
|
{
|
|
nsISheet = do_QueryInterface(mParagraphMarksStyleSheet);
|
|
return nsISheet->SetEnabled(PR_TRUE);
|
|
}
|
|
//First time used -- load the style sheet
|
|
nsCOMPtr<nsICSSStyleSheet> styleSheet;
|
|
res = styleSheets->ApplyOverrideStyleSheet(NS_ConvertASCIItoUCS2("chrome://editor/content/EditorParagraphMarks.css"),
|
|
getter_AddRefs(mParagraphMarksStyleSheet));
|
|
}
|
|
else if (mParagraphMarksStyleSheet)
|
|
{
|
|
// Disable the style sheet
|
|
nsISheet = do_QueryInterface(mParagraphMarksStyleSheet);
|
|
res = nsISheet->SetEnabled(PR_FALSE);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SetBodyAttribute(const PRUnichar *attr, const PRUnichar *value)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
|
|
nsAutoString aAttr(attr);
|
|
nsAutoString aValue(value);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
result = mEditor->SetBodyAttribute(aAttr, aValue);
|
|
break;
|
|
}
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::LoadUrl(const PRUnichar *url)
|
|
{
|
|
if(!mContentAreaDocShell)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsresult rv = ResetEditingState();
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mContentAreaDocShell));
|
|
NS_ENSURE_SUCCESS(webNav->LoadURI(url, nsIWebNavigation::LOAD_FLAGS_NONE), NS_ERROR_FAILURE);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::RegisterDocumentStateListener(nsIDocumentStateListener *docListener)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
if (!docListener)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
// Make the array
|
|
if (!mDocStateListeners)
|
|
{
|
|
rv = NS_NewISupportsArray(getter_AddRefs(mDocStateListeners));
|
|
if (NS_FAILED(rv)) return rv;
|
|
}
|
|
nsCOMPtr<nsISupports> iSupports = do_QueryInterface(docListener, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
PRBool appended = mDocStateListeners->AppendElement(iSupports);
|
|
NS_ASSERTION(appended, "Append failed");
|
|
|
|
// if we have an editor already, register this right now.
|
|
if (mEditor)
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// this checks for duplicates
|
|
rv = editor->AddDocumentStateListener(docListener);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::UnregisterDocumentStateListener(nsIDocumentStateListener *docListener)
|
|
{
|
|
if (!docListener)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
// remove it from our list
|
|
if (mDocStateListeners)
|
|
{
|
|
nsCOMPtr<nsISupports> iSupports = do_QueryInterface(docListener, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
mDocStateListeners->RemoveElement(iSupports);
|
|
}
|
|
|
|
// if we have an editor already, remove it from there too
|
|
if (mEditor)
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
return editor->RemoveDocumentStateListener(docListener);
|
|
}
|
|
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// called after making an editor. Transfer the nsIDOcumentStateListeners
|
|
// that we have been stashing in mDocStateListeners to the editor.
|
|
nsresult
|
|
nsEditorShell::TransferDocumentStateListeners()
|
|
{
|
|
if (!mDocStateListeners)
|
|
return NS_OK;
|
|
|
|
if (!mEditor)
|
|
return NS_ERROR_NOT_INITIALIZED; // called too early.
|
|
|
|
nsresult rv;
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor, &rv);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
PRUint32 numListeners;
|
|
mDocStateListeners->Count(&numListeners);
|
|
|
|
for (PRUint32 i = 0; i < numListeners; i ++)
|
|
{
|
|
nsCOMPtr<nsISupports> iSupports = getter_AddRefs(mDocStateListeners->ElementAt(i));
|
|
nsCOMPtr<nsIDocumentStateListener> docStateListener = do_QueryInterface(iSupports);
|
|
if (docStateListener)
|
|
{
|
|
// this checks for duplicates
|
|
rv = editor->AddDocumentStateListener(docStateListener);
|
|
if (NS_FAILED(rv)) break;
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::CheckOpenWindowForURLMatch(const PRUnichar* inFileURL, nsIDOMWindowInternal* inCheckWindow, PRBool *aDidFind)
|
|
{
|
|
NS_ENSURE_ARG_POINTER((inCheckWindow && aDidFind));
|
|
|
|
*aDidFind = PR_FALSE;
|
|
|
|
|
|
// It's really hard to compare nsIFiles with file URLs; there seems to be
|
|
// a lot of work here. Ideally, we should be able to use nsIFile::GetURL,
|
|
// but it is only implemented on Windows.
|
|
nsCAutoString fileURL; fileURL.AssignWithConversion(inFileURL);
|
|
|
|
// make a temp URL for testing against
|
|
nsresult rv = NS_OK;
|
|
nsCOMPtr<nsIFileURL> tempFileURL(do_CreateInstance(kStandardURLCID, &rv));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = tempFileURL->SetSpec(fileURL.get());
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIFile> urlFile;
|
|
rv = tempFileURL->GetFile(getter_AddRefs(urlFile));
|
|
// We fail if inFileURL isn't a "file:" URL, but that's ok.
|
|
//TODO: When publishing is done, we should support checking remote URL as well
|
|
if (NS_FAILED(rv)) return NS_OK;
|
|
|
|
nsCOMPtr<nsIDOMWindowInternal> contentWindow;
|
|
inCheckWindow->Get_content(getter_AddRefs(contentWindow));
|
|
if (contentWindow)
|
|
{
|
|
// get the content doc
|
|
nsCOMPtr<nsIDOMDocument> contentDoc;
|
|
contentWindow->GetDocument(getter_AddRefs(contentDoc));
|
|
nsCOMPtr<nsIDiskDocument> diskDoc(do_QueryInterface(contentDoc)); // safe with NULL contentDoc
|
|
if (diskDoc)
|
|
{
|
|
nsCOMPtr<nsIFile> docFileSpec;
|
|
if (NS_SUCCEEDED(diskDoc->GetFileSpec(getter_AddRefs(docFileSpec))) && docFileSpec)
|
|
{
|
|
PRBool isSameFile;
|
|
if (NS_SUCCEEDED(docFileSpec->Equals(urlFile, &isSameFile)) && isSameFile)
|
|
{
|
|
*aDidFind = PR_TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval)
|
|
{
|
|
nsresult res = NS_NOINTERFACE;
|
|
*_retval = PR_FALSE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
{
|
|
// get the document
|
|
nsCOMPtr<nsIDOMDocument> doc;
|
|
res = editor->GetDocument(getter_AddRefs(doc));
|
|
if (NS_FAILED(res)) return res;
|
|
if (!doc) return NS_ERROR_NULL_POINTER;
|
|
|
|
nsCOMPtr<nsIDiskDocument> diskDoc = do_QueryInterface(doc);
|
|
if (!diskDoc)
|
|
return NS_ERROR_NO_INTERFACE;
|
|
|
|
// find out if the doc already has a fileSpec associated with it.
|
|
nsCOMPtr<nsIFile> docFile;
|
|
PRBool noFileSpec = (diskDoc->GetFileSpec(getter_AddRefs(docFile)) == NS_ERROR_NOT_INITIALIZED);
|
|
PRBool mustShowFileDialog = saveAs || noFileSpec;
|
|
PRBool replacing = !saveAs;
|
|
|
|
// Get existing document title
|
|
nsAutoString title;
|
|
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(doc);
|
|
if (!htmlDoc) return NS_ERROR_FAILURE;
|
|
res = htmlDoc->GetTitle(title);
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (mustShowFileDialog)
|
|
{
|
|
// Prompt for title ONLY if existing title is empty
|
|
if (!mMailCompose && (mEditorType == eHTMLTextEditorType) && (title.Length() == 0))
|
|
{
|
|
// Use a "prompt" common dialog to get title string from user
|
|
NS_WITH_SERVICE(nsICommonDialogs, dialog, kCommonDialogsCID, &res);
|
|
if (NS_SUCCEEDED(res))
|
|
{
|
|
PRUnichar *titleUnicode;
|
|
nsAutoString captionStr, msgStr1, msgStr2;
|
|
|
|
GetBundleString(NS_LITERAL_STRING("DocumentTitle"), captionStr);
|
|
GetBundleString(NS_LITERAL_STRING("NeedDocTitle"), msgStr1);
|
|
GetBundleString(NS_LITERAL_STRING("DocTitleHelp"), msgStr2);
|
|
msgStr1 += PRUnichar('\n');
|
|
msgStr1 += msgStr2;
|
|
|
|
PRBool retVal = PR_FALSE;
|
|
if(!mContentWindow)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
nsCOMPtr<nsIDOMWindowInternal> cwP = do_QueryReferent(mContentWindow);
|
|
if (!cwP) return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
res = dialog->Prompt(cwP, captionStr.GetUnicode(), msgStr1.GetUnicode(),
|
|
title.GetUnicode(), &titleUnicode, &retVal);
|
|
|
|
if( retVal == PR_FALSE)
|
|
{
|
|
// This indicates Cancel was used -- don't continue saving
|
|
*_retval = PR_FALSE;
|
|
return NS_OK;
|
|
}
|
|
title = titleUnicode;
|
|
nsCRT::free(titleUnicode);
|
|
}
|
|
// This sets title in HTML node
|
|
SetDocumentTitle(title.GetUnicode());
|
|
}
|
|
|
|
nsCOMPtr<nsIFilePicker> filePicker = do_CreateInstance("@mozilla.org/filepicker;1", &res);
|
|
if (filePicker)
|
|
{
|
|
nsAutoString fileName;
|
|
|
|
nsAutoString promptString;
|
|
GetBundleString(NS_LITERAL_STRING("SaveDocumentAs"), promptString);
|
|
|
|
// Initialize nsIFilePicker
|
|
nsCOMPtr<nsIDOMWindowInternal> parentWindow(do_QueryReferent(mContentWindow));
|
|
res = filePicker->Init(parentWindow, promptString.GetUnicode(), nsIFilePicker::modeSave);
|
|
if (NS_FAILED(res))
|
|
return res;
|
|
|
|
// append in order so that HTML comes first and is default. test me on windows
|
|
filePicker->AppendFilters(nsIFilePicker::filterHTML);
|
|
filePicker->AppendFilters(nsIFilePicker::filterText);
|
|
filePicker->AppendFilters(nsIFilePicker::filterAll);
|
|
|
|
if (noFileSpec)
|
|
{
|
|
// check the current url, use that file name if possible
|
|
nsString urlstring;
|
|
res = htmlDoc->GetURL(urlstring);
|
|
|
|
// ?????
|
|
// res = htmlDoc->GetSourceDocumentURL(jscx, uri);
|
|
// do a QI to get an nsIURL and then call GetFileName()
|
|
|
|
// if it's not a local file already, grab the current file name
|
|
if ( (urlstring.CompareWithConversion("file", PR_TRUE, 4) != 0 )
|
|
&& (urlstring.CompareWithConversion("about:blank", PR_TRUE, -1) != 0) )
|
|
{
|
|
// remove cruft before file name including '/'
|
|
// if the url ends with a '/' then the whole string will be cut
|
|
PRInt32 index = urlstring.RFindChar((PRUnichar)'/', PR_FALSE, -1, -1 );
|
|
if ( index != -1 )
|
|
{
|
|
urlstring.Cut(0, index + 1);
|
|
if (urlstring.Length() > 0)
|
|
{
|
|
// Then truncate at any existing "#", "?" or "." since we replace with ".html"
|
|
index = urlstring.RFindChar((PRUnichar)'.', PR_FALSE, -1, -1 );
|
|
if ( index != -1)
|
|
urlstring.Truncate(index);
|
|
if (urlstring.Length() > 0)
|
|
{
|
|
index = urlstring.RFindChar((PRUnichar)'#', PR_FALSE, -1, -1 );
|
|
if ( index != -1)
|
|
urlstring.Truncate(index);
|
|
if (urlstring.Length() > 0)
|
|
{
|
|
index = urlstring.RFindChar((PRUnichar)'?', PR_FALSE, -1, -1 );
|
|
if ( index != -1)
|
|
urlstring.Truncate(index);
|
|
}
|
|
}
|
|
if (urlstring.Length() > 0)
|
|
{
|
|
fileName.Assign( urlstring );
|
|
fileName.AppendWithConversion(".html");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Use page title as suggested name for new document
|
|
if (fileName.Length() == 0 && title.Length() > 0)
|
|
{
|
|
// Strip out quote character
|
|
PRUnichar quote = (PRUnichar)'\"';
|
|
title.StripChar(quote);
|
|
|
|
//Replace "bad" filename characteres with "_"
|
|
title.ReplaceChar(" .\\/@:", (PRUnichar)'_');
|
|
fileName = title;
|
|
fileName.AppendWithConversion(".html");
|
|
}
|
|
}
|
|
else // have a file spec
|
|
{
|
|
nsXPIDLString leafName;
|
|
docFile->GetUnicodeLeafName(getter_Copies(leafName));
|
|
if (leafName.get() && *leafName)
|
|
fileName.Assign(leafName);
|
|
|
|
nsCOMPtr<nsIFile> parentPath;
|
|
if (NS_SUCCEEDED(docFile->GetParent(getter_AddRefs(parentPath))))
|
|
{
|
|
nsCOMPtr<nsILocalFile> localParentPath(do_QueryInterface(parentPath));
|
|
if (localParentPath)
|
|
filePicker->SetDisplayDirectory(localParentPath);
|
|
}
|
|
}
|
|
|
|
if (fileName.Length() > 0)
|
|
filePicker->SetDefaultString(fileName.GetUnicode());
|
|
|
|
PRInt16 dialogResult;
|
|
// Finally show the dialog
|
|
res = filePicker->Show(&dialogResult);
|
|
if (NS_FAILED(res))
|
|
return res;
|
|
|
|
if (dialogResult == nsIFilePicker::returnCancel)
|
|
{
|
|
// Note that *_retval = PR_FALSE at this point
|
|
return NS_OK;
|
|
}
|
|
replacing = (dialogResult == nsIFilePicker::returnReplace);
|
|
|
|
nsCOMPtr<nsILocalFile> localFile;
|
|
res = filePicker->GetFile(getter_AddRefs(localFile));
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
docFile = do_QueryInterface(localFile, &res);
|
|
if (NS_FAILED(res)) return res;
|
|
}
|
|
else
|
|
{
|
|
NS_ASSERTION(0, "Failed to get file widget");
|
|
return res;
|
|
}
|
|
|
|
// Set the new URL for the webshell
|
|
nsCOMPtr<nsIWebShell> webShell(do_QueryInterface(mContentAreaDocShell));
|
|
if (webShell)
|
|
{
|
|
// would like to use nsIFile::GetURL here, but it is not implemented
|
|
// on all platforms
|
|
nsCOMPtr<nsIFileURL> fileURL(do_CreateInstance(kStandardURLCID, &res));
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = fileURL->SetFile(docFile);
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
nsXPIDLCString docURLSpec;
|
|
res = fileURL->GetSpec(getter_Copies(docURLSpec));
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
nsAutoString fileURLUnicode; fileURLUnicode.AssignWithConversion(docURLSpec);
|
|
res = webShell->SetURL(fileURLUnicode.GetUnicode());
|
|
if (NS_FAILED(res)) return res;
|
|
}
|
|
} // mustShowFileDialog
|
|
|
|
// TODO: Get the file type (from the extension?) the user set for the file
|
|
// How do we do this in an XP way???
|
|
// For now, just save as HTML type
|
|
nsString format;
|
|
format.AssignWithConversion("text/html");
|
|
res = editor->SaveFile(docFile, replacing, saveCopy, format);
|
|
if (NS_FAILED(res))
|
|
{
|
|
nsAutoString saveDocStr, failedStr;
|
|
GetBundleString(NS_LITERAL_STRING("SaveDocument"), saveDocStr);
|
|
GetBundleString(NS_LITERAL_STRING("SaveFileFailed"), failedStr);
|
|
Alert(saveDocStr, failedStr);
|
|
} else {
|
|
// File was saved successfully
|
|
*_retval = PR_TRUE;
|
|
|
|
// Update window title to show possibly different filename
|
|
if (mustShowFileDialog)
|
|
UpdateWindowTitle();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
res = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::CloseWindowWithoutSaving()
|
|
{
|
|
nsCOMPtr<nsIBaseWindow> baseWindow;
|
|
GetTreeOwner(mDocShell, getter_AddRefs(baseWindow));
|
|
NS_ENSURE_TRUE(baseWindow, NS_ERROR_FAILURE);
|
|
return baseWindow->Destroy();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::Print()
|
|
{
|
|
if (!mContentAreaDocShell)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsCOMPtr<nsIContentViewer> viewer;
|
|
mContentAreaDocShell->GetContentViewer(getter_AddRefs(viewer));
|
|
if (nsnull != viewer)
|
|
{
|
|
nsCOMPtr<nsIContentViewerFile> viewerFile = do_QueryInterface(viewer);
|
|
if (viewerFile) {
|
|
NS_ENSURE_SUCCESS(viewerFile->Print(PR_FALSE,nsnull), NS_ERROR_FAILURE);
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetLocalFileURL(nsIDOMWindowInternal *parent, const PRUnichar *filterType, PRUnichar **_retval)
|
|
{
|
|
nsAutoString FilterType(filterType);
|
|
PRBool htmlFilter = FilterType.EqualsIgnoreCase("html");
|
|
PRBool imgFilter = FilterType.EqualsIgnoreCase("img");
|
|
|
|
*_retval = nsnull;
|
|
|
|
// TODO: DON'T ACCEPT NULL PARENT AFTER WIDGET IS FIXED
|
|
if (/*parent||*/ !(htmlFilter || imgFilter))
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
|
|
nsAutoString HTMLTitle;
|
|
GetBundleString(NS_LITERAL_STRING("OpenHTMLFile"), HTMLTitle);
|
|
|
|
// An empty string should just result in "Open" for the dialog
|
|
nsAutoString title;
|
|
if (htmlFilter)
|
|
{
|
|
title = HTMLTitle;
|
|
} else
|
|
{
|
|
nsAutoString imageTitle;
|
|
GetBundleString(NS_LITERAL_STRING("SelectImageFile"), imageTitle);
|
|
|
|
if (imageTitle.Length() > 0 && imgFilter)
|
|
title = imageTitle;
|
|
}
|
|
|
|
nsresult res;
|
|
nsCOMPtr<nsIFilePicker> filePicker = do_CreateInstance("@mozilla.org/filepicker;1", &res);
|
|
if (filePicker)
|
|
{
|
|
res = filePicker->Init(parent, title.GetUnicode(), nsIFilePicker::modeOpen);
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (htmlFilter)
|
|
{
|
|
filePicker->AppendFilters(nsIFilePicker::filterHTML);
|
|
filePicker->AppendFilters(nsIFilePicker::filterText);
|
|
filePicker->AppendFilters(nsIFilePicker::filterAll);
|
|
}
|
|
else
|
|
{
|
|
filePicker->AppendFilters(nsIFilePicker::filterImages);
|
|
filePicker->AppendFilters(nsIFilePicker::filterAll);
|
|
}
|
|
|
|
#if 0
|
|
// get default directory from preference
|
|
NS_WITH_SERVICE( nsIPref, prefs, NS_PREF_CONTRACTID, &res );
|
|
if (prefs)
|
|
{
|
|
nsCOMPtr<nsILocalFile> defaultDir;
|
|
prefs->GetFileXPref(EDITOR_DEFAULT_DIR_PREF, getter_AddRefs(defaultDir));
|
|
if (defaultDir)
|
|
{
|
|
PRBool isValid = PR_FALSE;
|
|
defaultDir->Exists(&isValid);
|
|
if (isValid)
|
|
{
|
|
// Set file picker so startDir is used.
|
|
filePicker->SetDisplayDirectory(defaultDir);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
PRInt16 dialogResult;
|
|
res = filePicker->Show(&dialogResult);
|
|
if (NS_FAILED(res))
|
|
return res;
|
|
|
|
if (dialogResult != nsIFilePicker::returnCancel)
|
|
{
|
|
// Get the platform-specific format
|
|
// Convert it to the string version of the URL format
|
|
nsCOMPtr<nsIFileURL> fileURL;
|
|
res = filePicker->GetFileURL(getter_AddRefs(fileURL));
|
|
if (fileURL)
|
|
{
|
|
nsXPIDLCString url;
|
|
res = fileURL->GetSpec(getter_Copies(url));
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
nsAutoString returnVal;
|
|
returnVal.AssignWithConversion((const char*) url);
|
|
*_retval = returnVal.ToNewUnicode();
|
|
|
|
if (!*_retval)
|
|
res = NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
}
|
|
|
|
#if 0
|
|
// save default directory to preference
|
|
if (NS_SUCCEEDED(res) && prefs)
|
|
{
|
|
nsCOMPtr<nsILocalFile> defaultDir;
|
|
filePicker->GetDisplayDirectory(getter_AddRefs(defaultDir));
|
|
if (defaultDir)
|
|
{
|
|
prefs->SetFileXPref(EDITOR_DEFAULT_DIR_PREF, defaultDir);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
nsresult
|
|
nsEditorShell::UpdateWindowTitle()
|
|
{
|
|
nsresult res = NS_ERROR_NOT_INITIALIZED;
|
|
|
|
if (!mContentAreaDocShell || !mEditor)
|
|
return res;
|
|
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (!editor)
|
|
return res;
|
|
|
|
nsAutoString windowCaption;
|
|
res = GetDocumentTitleString(windowCaption);
|
|
// If title is empty, use "untitled"
|
|
if (windowCaption.Length() == 0)
|
|
GetBundleString(NS_LITERAL_STRING("untitled"), windowCaption);
|
|
|
|
// Append just the 'leaf' filename to the Doc. Title for the window caption
|
|
if (NS_SUCCEEDED(res))
|
|
{
|
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
|
editor->GetDocument(getter_AddRefs(domDoc));
|
|
if (domDoc)
|
|
{
|
|
nsCOMPtr<nsIDiskDocument> diskDoc = do_QueryInterface(domDoc);
|
|
if (diskDoc)
|
|
{
|
|
// find out if the doc already has a fileSpec associated with it.
|
|
nsCOMPtr<nsIFile> docFileSpec;
|
|
if (NS_SUCCEEDED(diskDoc->GetFileSpec(getter_AddRefs(docFileSpec))))
|
|
{
|
|
nsXPIDLString fileName;
|
|
docFileSpec->GetUnicodeLeafName(getter_Copies(fileName));
|
|
windowCaption.AppendWithConversion(" [");
|
|
windowCaption.Append(fileName);
|
|
windowCaption.AppendWithConversion("]");
|
|
}
|
|
}
|
|
}
|
|
nsCOMPtr<nsIBaseWindow> contentAreaAsWin(do_QueryInterface(mContentAreaDocShell));
|
|
NS_ASSERTION(contentAreaAsWin, "This object should implement nsIBaseWindow");
|
|
res = contentAreaAsWin->SetTitle(windowCaption.GetUnicode());
|
|
}
|
|
return res;
|
|
}
|
|
|
|
nsresult
|
|
nsEditorShell::GetDocumentTitleString(nsString& title)
|
|
{
|
|
nsresult res = NS_ERROR_NOT_INITIALIZED;
|
|
|
|
if (!mEditor)
|
|
return res;
|
|
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (!editor)
|
|
return res;
|
|
|
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
|
res = editor->GetDocument(getter_AddRefs(domDoc));
|
|
if (NS_SUCCEEDED(res) && domDoc)
|
|
{
|
|
// Get the document title
|
|
nsCOMPtr<nsIDOMHTMLDocument> HTMLDoc = do_QueryInterface(domDoc);
|
|
if (HTMLDoc)
|
|
res = HTMLDoc->GetTitle(title);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
// JavaScript version
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetDocumentTitle(PRUnichar **title)
|
|
{
|
|
if (!title)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsAutoString titleStr;
|
|
nsresult res = GetDocumentTitleString(titleStr);
|
|
if (NS_SUCCEEDED(res))
|
|
{
|
|
*title = titleStr.ToNewUnicode();
|
|
} else {
|
|
// Don't fail, just return an empty string
|
|
nsAutoString empty;
|
|
*title = empty.ToNewUnicode();
|
|
res = NS_OK;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SetDocumentTitle(const PRUnichar *title)
|
|
{
|
|
nsresult res = NS_ERROR_NOT_INITIALIZED;
|
|
|
|
if (!mEditor && !mContentAreaDocShell)
|
|
return res;
|
|
|
|
// This should only be allowed for HTML documents
|
|
if (mEditorType != eHTMLTextEditorType)
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (!editor)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsAutoString titleStr(title);
|
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
|
res = editor->GetDocument(getter_AddRefs(domDoc));
|
|
|
|
if (domDoc)
|
|
{
|
|
// Get existing document title node
|
|
nsCOMPtr<nsIDOMHTMLDocument> HTMLDoc = do_QueryInterface(domDoc);
|
|
if (HTMLDoc)
|
|
{
|
|
// This sets the window title, and saves the title as a member varialble,
|
|
// but does NOT insert the <title> node.
|
|
HTMLDoc->SetTitle(titleStr);
|
|
|
|
nsCOMPtr<nsIDOMNodeList> titleList;
|
|
nsCOMPtr<nsIDOMNode>titleNode;
|
|
nsCOMPtr<nsIDOMNode>headNode;
|
|
nsCOMPtr<nsIDOMNode> resultNode;
|
|
res = domDoc->GetElementsByTagName(NS_ConvertASCIItoUCS2("title"), getter_AddRefs(titleList));
|
|
if (NS_SUCCEEDED(res))
|
|
{
|
|
if(titleList)
|
|
{
|
|
/* I'm tempted to just get the 1st title element in the list
|
|
(there should always be just 1). But in case there's > 1,
|
|
I assume the last one will be used, so this finds that one.
|
|
*/
|
|
PRUint32 len = 0;
|
|
titleList->GetLength(&len);
|
|
if (len >= 1)
|
|
titleList->Item(len-1, getter_AddRefs(titleNode));
|
|
|
|
if (titleNode)
|
|
{
|
|
//Delete existing children (text) of title node
|
|
nsCOMPtr<nsIDOMNodeList> children;
|
|
res = titleNode->GetChildNodes(getter_AddRefs(children));
|
|
if(NS_SUCCEEDED(res) && children)
|
|
{
|
|
PRUint32 count = 0;
|
|
children->GetLength(&count);
|
|
for( PRUint32 i = 0; i < count; i++)
|
|
{
|
|
nsCOMPtr<nsIDOMNode> child;
|
|
res = children->Item(i,getter_AddRefs(child));
|
|
if(NS_SUCCEEDED(res) && child)
|
|
titleNode->RemoveChild(child,getter_AddRefs(resultNode));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Get the <HEAD> node, create a <TITLE> and insert it under the HEAD
|
|
nsCOMPtr<nsIDOMNodeList> headList;
|
|
res = domDoc->GetElementsByTagName(NS_ConvertASCIItoUCS2("head"),getter_AddRefs(headList));
|
|
if (NS_FAILED(res)) return res;
|
|
if (headList)
|
|
{
|
|
headList->Item(0, getter_AddRefs(headNode));
|
|
if (headNode)
|
|
{
|
|
PRBool newTitleNode = PR_FALSE;
|
|
if (!titleNode)
|
|
{
|
|
// Didn't find one above: Create a new one
|
|
nsCOMPtr<nsIDOMElement>titleElement;
|
|
res = domDoc->CreateElement(NS_ConvertASCIItoUCS2("title"), getter_AddRefs(titleElement));
|
|
if (NS_SUCCEEDED(res) && titleElement)
|
|
{
|
|
titleNode = do_QueryInterface(titleElement);
|
|
newTitleNode = PR_TRUE;
|
|
}
|
|
// Note: There should ALWAYS be a <title> in any HTML document,
|
|
// so we will insert the node and not make it undoable
|
|
res = headNode->AppendChild(titleNode, getter_AddRefs(resultNode));
|
|
if (NS_FAILED(res)) return res;
|
|
}
|
|
// Append a text node under the TITLE
|
|
// only if the title text isn't empty
|
|
if (titleNode && titleStr.Length() > 0)
|
|
{
|
|
nsCOMPtr<nsIDOMText> textNode;
|
|
res = domDoc->CreateTextNode(titleStr, getter_AddRefs(textNode));
|
|
if (NS_FAILED(res)) return res;
|
|
if (!textNode) return NS_ERROR_FAILURE;
|
|
// Do NOT use editor transaction -- we don't want this to be undoable
|
|
res = titleNode->AppendChild(textNode, getter_AddRefs(resultNode));
|
|
if (NS_FAILED(res)) return res;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::CloneAttributes(nsIDOMNode *destNode, nsIDOMNode *sourceNode)
|
|
{
|
|
if (!destNode || !sourceNode) { return NS_ERROR_NULL_POINTER; }
|
|
nsresult rv = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
rv = editor->CloneAttributes(destNode, sourceNode);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
rv = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::NodeIsBlock(nsIDOMNode *node, PRBool *_retval)
|
|
{
|
|
if (!node || !_retval) { return NS_ERROR_NULL_POINTER; }
|
|
nsresult rv = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
rv = editor->NodeIsBlock(node, *_retval);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
rv = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::Undo()
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
err = editor->Undo(1);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::Redo()
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
err = editor->Redo(1);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::Cut()
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
err = editor->Cut();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::Copy()
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
err = editor->Copy();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::Paste(PRInt32 aSelectionType)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
err = editor->Paste(aSelectionType);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::PasteAsQuotation(PRInt32 aSelectionType)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditorMailSupport> mailEditor = do_QueryInterface(mEditor);
|
|
if (mailEditor)
|
|
err = mailEditor->PasteAsQuotation(aSelectionType);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::PasteAsCitedQuotation(const PRUnichar *cite, PRInt32 aSelectionType)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
nsAutoString aCiteString(cite);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditorMailSupport> mailEditor = do_QueryInterface(mEditor);
|
|
if (mailEditor)
|
|
err = mailEditor->PasteAsCitedQuotation(aCiteString, aSelectionType);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::InsertAsQuotation(const PRUnichar *quotedText,
|
|
nsIDOMNode** aNodeInserted)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
nsAutoString aQuotedText(quotedText);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditorMailSupport> mailEditor = do_QueryInterface(mEditor);
|
|
if (mailEditor)
|
|
err = mailEditor->InsertAsQuotation(aQuotedText, aNodeInserted);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::InsertAsCitedQuotation(const PRUnichar *quotedText,
|
|
const PRUnichar *cite,
|
|
PRBool aInsertHTML,
|
|
const PRUnichar *charset,
|
|
nsIDOMNode** aNodeInserted)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
nsCOMPtr<nsIEditorMailSupport> mailEditor = do_QueryInterface(mEditor);
|
|
if (!mailEditor)
|
|
return NS_NOINTERFACE;
|
|
|
|
nsAutoString aQuotedText(quotedText);
|
|
nsAutoString aCiteString(cite);
|
|
nsAutoString aCharset(charset);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
err = mailEditor->InsertAsQuotation(aQuotedText, aNodeInserted);
|
|
break;
|
|
|
|
case eHTMLTextEditorType:
|
|
err = mailEditor->InsertAsCitedQuotation(aQuotedText, aCiteString,
|
|
aInsertHTML,
|
|
aCharset, aNodeInserted);
|
|
break;
|
|
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
// Utility routine to make a new citer. This addrefs, of course.
|
|
static nsICiter* MakeACiter()
|
|
{
|
|
// Make a citer of an appropriate type
|
|
nsICiter* citer = 0;
|
|
nsresult rv;
|
|
NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &rv);
|
|
if (NS_FAILED(rv)) return 0;
|
|
|
|
char *citationType = 0;
|
|
rv = prefs->CopyCharPref("mail.compose.citationType", &citationType);
|
|
|
|
if (NS_SUCCEEDED(rv) && citationType[0])
|
|
{
|
|
if (!strncmp(citationType, "aol", 3))
|
|
citer = new nsAOLCiter;
|
|
else
|
|
citer = new nsInternetCiter;
|
|
PL_strfree(citationType);
|
|
}
|
|
else
|
|
citer = new nsInternetCiter;
|
|
|
|
if (citer)
|
|
NS_ADDREF(citer);
|
|
return citer;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::Rewrap(PRBool aRespectNewlines)
|
|
{
|
|
PRInt32 wrapCol;
|
|
nsresult rv = GetWrapColumn(&wrapCol);
|
|
if (NS_FAILED(rv))
|
|
return NS_OK;
|
|
#ifdef DEBUG_akkana
|
|
printf("nsEditorShell::Rewrap to %ld columns\n", (long)wrapCol);
|
|
#endif
|
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
rv = GetEditorSelection(getter_AddRefs(selection));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (!selection)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
PRBool isCollapsed;
|
|
rv = selection->GetIsCollapsed(&isCollapsed);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// Variables we'll need either way
|
|
nsAutoString format; format.AssignWithConversion("text/plain");
|
|
nsAutoString current;
|
|
nsString wrapped;
|
|
nsCOMPtr<nsIEditor> nsied (do_QueryInterface(mEditor));
|
|
if (!nsied)
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
if (isCollapsed) // rewrap the whole document
|
|
{
|
|
rv = nsied->OutputToString(current, format,
|
|
nsIDocumentEncoder::OutputFormatted);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter());
|
|
if (NS_FAILED(rv)) return rv;
|
|
if (!citer) return NS_ERROR_UNEXPECTED;
|
|
|
|
rv = citer->Rewrap(current, wrapCol, 0, aRespectNewlines, wrapped);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = SelectAll();
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIPlaintextEditor> textEditor (do_QueryInterface(mEditor));
|
|
if (!textEditor)
|
|
return NS_NOINTERFACE;
|
|
return textEditor->InsertText(wrapped.GetUnicode());
|
|
}
|
|
else // rewrap only the selection
|
|
{
|
|
rv = nsied->OutputToString(current, format,
|
|
nsIDocumentEncoder::OutputFormatted
|
|
| nsIDocumentEncoder::OutputSelectionOnly);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter());
|
|
if (NS_FAILED(rv)) return rv;
|
|
if (!citer) return NS_ERROR_UNEXPECTED;
|
|
|
|
PRUint32 firstLineOffset = 0; // XXX need to get this
|
|
rv = citer->Rewrap(current, wrapCol, firstLineOffset, aRespectNewlines,
|
|
wrapped);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIPlaintextEditor> textEditor (do_QueryInterface(mEditor));
|
|
if (!textEditor)
|
|
return NS_NOINTERFACE;
|
|
return textEditor->InsertText(wrapped.GetUnicode());
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::StripCites()
|
|
{
|
|
#ifdef DEBUG_akkana
|
|
printf("nsEditorShell::StripCites()\n");
|
|
#endif
|
|
|
|
nsCOMPtr<nsISelection> selection;
|
|
nsresult rv = GetEditorSelection(getter_AddRefs(selection));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (!selection)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
PRBool isCollapsed;
|
|
rv = selection->GetIsCollapsed(&isCollapsed);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
// Variables we'll need either way
|
|
nsAutoString format; format.AssignWithConversion("text/plain");
|
|
nsAutoString current;
|
|
nsString stripped;
|
|
nsCOMPtr<nsIEditor> nsied (do_QueryInterface(mEditor));
|
|
if (!nsied)
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
if (isCollapsed) // rewrap the whole document
|
|
{
|
|
rv = nsied->OutputToString(current, format,
|
|
nsIDocumentEncoder::OutputFormatted);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter());
|
|
if (NS_FAILED(rv)) return rv;
|
|
if (!citer) return NS_ERROR_UNEXPECTED;
|
|
|
|
rv = citer->StripCites(current, stripped);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
rv = SelectAll();
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIPlaintextEditor> textEditor (do_QueryInterface(mEditor));
|
|
if (!textEditor)
|
|
return NS_NOINTERFACE;
|
|
return textEditor->InsertText(stripped.GetUnicode());
|
|
}
|
|
else // rewrap only the selection
|
|
{
|
|
rv = nsied->OutputToString(current, format,
|
|
nsIDocumentEncoder::OutputFormatted
|
|
| nsIDocumentEncoder::OutputSelectionOnly);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsICiter> citer = dont_AddRef(MakeACiter());
|
|
if (NS_FAILED(rv)) return rv;
|
|
if (!citer) return NS_ERROR_UNEXPECTED;
|
|
|
|
rv = citer->StripCites(current, stripped);
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
nsCOMPtr<nsIPlaintextEditor> textEditor (do_QueryInterface(mEditor));
|
|
if (!textEditor)
|
|
return NS_NOINTERFACE;
|
|
return textEditor->InsertText(stripped.GetUnicode());
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SelectAll()
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
err = editor->SelectAll();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::DeleteSelection(PRInt32 action)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
nsIEditor::EDirection selectionAction;
|
|
|
|
switch(action)
|
|
{
|
|
case 1:
|
|
selectionAction = nsIEditor::eNext;
|
|
break;
|
|
case 2:
|
|
selectionAction = nsIEditor::ePrevious;
|
|
break;
|
|
default:
|
|
selectionAction = nsIEditor::eNone;
|
|
break;
|
|
}
|
|
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
err = editor->DeleteSelection(selectionAction);
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::InsertText(const PRUnichar *textToInsert)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIPlaintextEditor> textEditor (do_QueryInterface(mEditor));
|
|
if (textEditor)
|
|
err = textEditor->InsertText(textToInsert);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::InsertSource(const PRUnichar *aSourceToInsert)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
nsAutoString sourceToInsert(aSourceToInsert);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
|
|
if (htmlEditor)
|
|
err = htmlEditor->InsertHTML(sourceToInsert);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_NOINTERFACE;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::InsertSourceWithCharset(const PRUnichar *aSourceToInsert,
|
|
const PRUnichar *aCharset)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
nsAutoString sourceToInsert(aSourceToInsert);
|
|
nsAutoString charset(aCharset);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
|
|
if (htmlEditor)
|
|
err = htmlEditor->InsertHTMLWithCharset(sourceToInsert, charset);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_NOINTERFACE;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::RebuildDocumentFromSource(const PRUnichar *aSource)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
nsAutoString source(aSource);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
|
|
if (htmlEditor)
|
|
err = htmlEditor->RebuildDocumentFromSource(source);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_NOINTERFACE;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::InsertBreak()
|
|
{
|
|
nsCOMPtr<nsIPlaintextEditor> textEditor (do_QueryInterface(mEditor));
|
|
if (!textEditor)
|
|
return NS_NOINTERFACE;
|
|
|
|
return textEditor->InsertLineBreak();
|
|
}
|
|
|
|
// Both Find and FindNext call through here.
|
|
nsresult
|
|
nsEditorShell::DoFind(PRBool aFindNext)
|
|
{
|
|
if (!mContentAreaDocShell)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
PRBool foundIt = PR_FALSE;
|
|
|
|
// Get find component.
|
|
nsresult rv;
|
|
NS_WITH_SERVICE(nsIFindComponent, findComponent, NS_IFINDCOMPONENT_CONTRACTID, &rv);
|
|
NS_ASSERTION(((NS_SUCCEEDED(rv)) && findComponent), "GetService failed for find component.");
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
|
|
// make the search context if we need to
|
|
if (!mSearchContext)
|
|
{
|
|
if(!mContentWindow)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
nsCOMPtr<nsIDOMWindowInternal> cwP = do_QueryReferent(mContentWindow);
|
|
if (!cwP) return NS_ERROR_NOT_INITIALIZED;
|
|
rv = findComponent->CreateContext(cwP, this, getter_AddRefs(mSearchContext));
|
|
}
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
if (aFindNext)
|
|
rv = findComponent->FindNext(mSearchContext, &foundIt);
|
|
else
|
|
rv = findComponent->Find(mSearchContext, &foundIt);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::Find()
|
|
{
|
|
return DoFind(PR_FALSE);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::FindNext()
|
|
{
|
|
return DoFind(PR_TRUE);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::Replace()
|
|
{
|
|
if (!mContentAreaDocShell)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
// Get find component.
|
|
nsresult rv;
|
|
NS_WITH_SERVICE(nsIFindComponent, findComponent, NS_IFINDCOMPONENT_CONTRACTID, &rv);
|
|
NS_ASSERTION(((NS_SUCCEEDED(rv)) && findComponent), "GetService failed for find component.");
|
|
if (NS_FAILED(rv)) { return rv; }
|
|
|
|
// make the search context if we need to
|
|
if (!mSearchContext)
|
|
{
|
|
if(!mContentWindow)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
nsCOMPtr<nsIDOMWindowInternal> cwP = do_QueryReferent(mContentWindow);
|
|
if (!cwP) return NS_ERROR_NOT_INITIALIZED;
|
|
rv = findComponent->CreateContext(cwP, this, getter_AddRefs(mSearchContext));
|
|
}
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
rv = findComponent->Replace(mSearchContext);
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* Get localized strings for UI from the Editor's string bundle */
|
|
// Use this version from JavaScript:
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetString(const PRUnichar *stringName, PRUnichar **_retval)
|
|
{
|
|
if (!stringName || !_retval)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
*_retval = NULL;
|
|
|
|
NS_ASSERTION(mStringBundle, "No string bundle!");
|
|
if (!mStringBundle) return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
return mStringBundle->GetStringFromName(stringName, _retval);
|
|
}
|
|
|
|
|
|
// Use this version within the shell:
|
|
void nsEditorShell::GetBundleString(const PRUnichar *stringName, nsString &outString)
|
|
{
|
|
outString.Truncate();
|
|
|
|
nsXPIDLString tempString;
|
|
if (NS_SUCCEEDED(GetString(stringName, getter_Copies(tempString))) && tempString)
|
|
outString = tempString.get();
|
|
}
|
|
|
|
// Utilities to bring up a Yes/No/Cancel dialog.
|
|
|
|
// For JavaScript:
|
|
NS_IMETHODIMP
|
|
nsEditorShell::ConfirmWithTitle(const PRUnichar *aTitle, const PRUnichar *aQuestion,
|
|
const PRUnichar *aYesButtonText, const PRUnichar *aNoButtonText, PRInt32 *_retval)
|
|
{
|
|
if (!aTitle || !aQuestion || !aYesButtonText || !_retval)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsAutoString title(aTitle);
|
|
nsAutoString question(aQuestion);
|
|
nsAutoString yesString(aYesButtonText);
|
|
nsAutoString noString(aNoButtonText);
|
|
|
|
*_retval = ConfirmWithCancel(title, question, &yesString, &noString);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsEditorShell::EConfirmResult
|
|
nsEditorShell::ConfirmWithCancel(const nsString& aTitle, const nsString& aQuestion,
|
|
const nsString *aYesString, const nsString *aNoString)
|
|
{
|
|
nsEditorShell::EConfirmResult result = nsEditorShell::eCancel;
|
|
|
|
nsIDialogParamBlock* block = NULL;
|
|
nsresult rv = nsComponentManager::CreateInstance(kDialogParamBlockCID, 0,
|
|
NS_GET_IID(nsIDialogParamBlock),
|
|
(void**)&block );
|
|
if ( NS_SUCCEEDED(rv) )
|
|
{
|
|
// Stuff in Parameters
|
|
block->SetString( nsICommonDialogs::eMsg, aQuestion.GetUnicode());
|
|
nsAutoString url; url.AssignWithConversion( "chrome://global/skin/question-icon.gif" );
|
|
block->SetString( nsICommonDialogs::eIconURL, url.GetUnicode());
|
|
|
|
nsAutoString yesStr, noStr;
|
|
// Default is Yes, No, Cancel
|
|
PRInt32 numberOfButtons = 3;
|
|
if (aYesString)
|
|
yesStr.Assign(*aYesString);
|
|
else
|
|
// We always want a "Yes" string, so supply the default
|
|
GetBundleString(NS_LITERAL_STRING("Yes"), yesStr);
|
|
|
|
if (aNoString && aNoString->Length() > 0)
|
|
{
|
|
noStr.Assign(*aNoString);
|
|
block->SetString( nsICommonDialogs::eButton2Text, noStr.GetUnicode() );
|
|
}
|
|
else
|
|
{
|
|
// No string for "No" means we only want Yes, Cancel
|
|
numberOfButtons = 2;
|
|
}
|
|
block->SetInt( nsICommonDialogs::eNumberButtons, numberOfButtons );
|
|
|
|
nsAutoString cancelStr;
|
|
GetBundleString(NS_LITERAL_STRING("Cancel"), cancelStr);
|
|
|
|
block->SetString( nsICommonDialogs::eDialogTitle, aTitle.GetUnicode() );
|
|
//Note: "button0" is always Ok or Yes action, "button1" is Cancel
|
|
block->SetString( nsICommonDialogs::eButton0Text, yesStr.GetUnicode() );
|
|
block->SetString( nsICommonDialogs::eButton1Text, cancelStr.GetUnicode() );
|
|
|
|
NS_WITH_SERVICE(nsICommonDialogs, dialog, kCommonDialogsCID, &rv);
|
|
if ( NS_SUCCEEDED( rv ) )
|
|
{
|
|
PRInt32 buttonPressed = 0;
|
|
if(!mContentWindow)
|
|
return result;
|
|
nsCOMPtr<nsIDOMWindowInternal> cwP = do_QueryReferent(mContentWindow);
|
|
if (!cwP) return result;
|
|
rv = dialog->DoDialog( cwP, block, "chrome://global/content/commonDialog.xul" );
|
|
block->GetInt( nsICommonDialogs::eButtonPressed, &buttonPressed );
|
|
// NOTE: If order of buttons changes in nsICommonDialogs,
|
|
// then we must change the EConfirmResult enums in nsEditorShell.h
|
|
result = nsEditorShell::EConfirmResult(buttonPressed);
|
|
}
|
|
NS_IF_RELEASE( block );
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Utility to bring up a OK/Cancel dialog.
|
|
PRBool
|
|
nsEditorShell::Confirm(const nsString& aTitle, const nsString& aQuestion)
|
|
{
|
|
nsresult rv;
|
|
PRBool result = PR_FALSE;
|
|
|
|
NS_WITH_SERVICE(nsICommonDialogs, dialog, kCommonDialogsCID, &rv);
|
|
if (NS_SUCCEEDED(rv) && dialog)
|
|
{
|
|
if(!mContentWindow)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
nsCOMPtr<nsIDOMWindowInternal> cwP = do_QueryReferent(mContentWindow);
|
|
if (!cwP) return NS_ERROR_NOT_INITIALIZED;
|
|
rv = dialog->Confirm(cwP, aTitle.GetUnicode(), aQuestion.GetUnicode(), &result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::AlertWithTitle(const PRUnichar *aTitle, const PRUnichar *aMsg)
|
|
{
|
|
if (!aTitle || !aMsg)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult rv = NS_ERROR_FAILURE;
|
|
NS_WITH_SERVICE(nsICommonDialogs, dialog, kCommonDialogsCID, &rv);
|
|
if (NS_SUCCEEDED(rv) && dialog)
|
|
{
|
|
if(!mContentWindow)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
nsCOMPtr<nsIDOMWindowInternal> cwP = do_QueryReferent(mContentWindow);
|
|
if (!cwP) return NS_ERROR_NOT_INITIALIZED;
|
|
rv = dialog->Alert(cwP, aTitle, aMsg);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
void
|
|
nsEditorShell::Alert(const nsString& aTitle, const nsString& aMsg)
|
|
{
|
|
nsresult rv;
|
|
NS_WITH_SERVICE(nsICommonDialogs, dialog, kCommonDialogsCID, &rv);
|
|
if (NS_SUCCEEDED(rv) && dialog)
|
|
{
|
|
if(!mContentWindow)
|
|
return;
|
|
nsCOMPtr<nsIDOMWindowInternal> cwP = do_QueryReferent(mContentWindow);
|
|
if (!cwP) return;
|
|
rv = dialog->Alert(cwP, aTitle.GetUnicode(), aMsg.GetUnicode());
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetDocumentCharacterSet(PRUnichar** characterSet)
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
|
|
if (editor)
|
|
return editor->GetDocumentCharacterSet(characterSet);
|
|
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SetDocumentCharacterSet(const PRUnichar* characterSet)
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
|
|
nsresult res = NS_OK;
|
|
if (editor)
|
|
res = editor->SetDocumentCharacterSet(characterSet);
|
|
|
|
if(NS_SUCCEEDED(res)) {
|
|
nsCOMPtr<nsIScriptGlobalObject> globalObj( do_QueryReferent(mContentWindow));
|
|
if (!globalObj) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsCOMPtr<nsIDocShell> docShell;
|
|
globalObj->GetDocShell(getter_AddRefs(docShell));
|
|
if (docShell)
|
|
{
|
|
nsCOMPtr<nsIContentViewer> childCV;
|
|
NS_ENSURE_SUCCESS(docShell->GetContentViewer(getter_AddRefs(childCV)), NS_ERROR_FAILURE);
|
|
if (childCV)
|
|
{
|
|
nsCOMPtr<nsIMarkupDocumentViewer> markupCV = do_QueryInterface(childCV);
|
|
if (markupCV) {
|
|
NS_ENSURE_SUCCESS(markupCV->SetDefaultCharacterSet(characterSet), NS_ERROR_FAILURE);
|
|
NS_ENSURE_SUCCESS(markupCV->SetForceCharacterSet(characterSet), NS_ERROR_FAILURE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetContentsAs(const PRUnichar *format, PRUint32 flags,
|
|
PRUnichar **aContentsAs)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
nsAutoString aFormat (format);
|
|
nsAutoString contentsAs;
|
|
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
err = editor->OutputToString(contentsAs, aFormat, flags);
|
|
|
|
*aContentsAs = contentsAs.ToNewUnicode();
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetHeadContentsAsHTML(PRUnichar **aHeadContents)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
nsAutoString headContents;
|
|
|
|
nsCOMPtr<nsIHTMLEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
err = editor->GetHeadContentsAsHTML(headContents);
|
|
|
|
*aHeadContents = headContents.ToNewUnicode();
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::ReplaceHeadContentsWithHTML(const PRUnichar *aSourceToInsert)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
nsAutoString sourceToInsert(aSourceToInsert);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
|
|
if (htmlEditor)
|
|
err = htmlEditor->ReplaceHeadContentsWithHTML(sourceToInsert);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_NOINTERFACE;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::DumpContentTree()
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (!editor)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
return editor->DumpContentTree();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetWrapColumn(PRInt32* aWrapColumn)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
if (!aWrapColumn)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
// fill result in case of failure
|
|
*aWrapColumn = mWrapColumn;
|
|
|
|
// If we don't have an editor yet, say we're not initialized
|
|
// even though mWrapColumn may have a value.
|
|
if (!mEditor)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIPlaintextEditor> textEditor = do_QueryInterface(mEditor);
|
|
if (textEditor)
|
|
{
|
|
PRInt32 wc;
|
|
err = textEditor->GetWrapWidth(&wc);
|
|
if (NS_SUCCEEDED(err))
|
|
*aWrapColumn = (PRInt32)wc;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SetWrapColumn(PRInt32 aWrapColumn)
|
|
{
|
|
nsresult err = NS_OK;
|
|
|
|
mWrapColumn = aWrapColumn;
|
|
|
|
if (mEditor)
|
|
{
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIPlaintextEditor> textEditor = do_QueryInterface(mEditor);
|
|
if (textEditor)
|
|
err = textEditor->SetWrapWidth(mWrapColumn);
|
|
}
|
|
break;
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SetParagraphFormat(const PRUnichar * paragraphFormat)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
nsAutoString aParagraphFormat(paragraphFormat);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
err = mEditor->SetParagraphFormat(aParagraphFormat);
|
|
break;
|
|
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetEditorDocument(nsIDOMDocument** aEditorDocument)
|
|
{
|
|
if (mEditor)
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
{
|
|
return editor->GetDocument(aEditorDocument);
|
|
}
|
|
}
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetEditor(nsIEditor** aEditor)
|
|
{
|
|
if (mEditor)
|
|
return mEditor->QueryInterface(NS_GET_IID(nsIEditor), (void **)aEditor); // the QI does the addref
|
|
|
|
*aEditor = nsnull;
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetEditorSelection(nsISelection** aEditorSelection)
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
return editor->GetSelection(aEditorSelection);
|
|
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetSelectionController(nsISelectionController** aSelectionController)
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (!editor)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsCOMPtr<nsISelectionController> selCont;
|
|
nsresult rv = editor->GetSelectionController(getter_AddRefs(selCont));
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
if (!selCont)
|
|
return NS_ERROR_NO_INTERFACE;
|
|
*aSelectionController = selCont;
|
|
NS_IF_ADDREF(*aSelectionController);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetDocumentModified(PRBool *aDocumentModified)
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
return editor->GetDocumentModified(aDocumentModified);
|
|
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetDocumentIsEmpty(PRBool *aDocumentIsEmpty)
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
return editor->GetDocumentIsEmpty(aDocumentIsEmpty);
|
|
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetDocumentEditable(PRBool *aDocumentEditable)
|
|
{
|
|
*aDocumentEditable = PR_FALSE; // default return value
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (!editor) return NS_OK;
|
|
|
|
PRUint32 editorFlags;
|
|
editor->GetFlags(&editorFlags);
|
|
|
|
if (editorFlags & nsIPlaintextEditor::eEditorReadonlyMask)
|
|
return NS_OK;
|
|
|
|
nsCOMPtr<nsIDOMDocument> doc;
|
|
editor->GetDocument(getter_AddRefs(doc));
|
|
if (!doc) return NS_OK;
|
|
|
|
*aDocumentEditable = PR_TRUE;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetDocumentLength(PRInt32 *aDocumentLength)
|
|
{
|
|
nsCOMPtr<nsIPlaintextEditor> textEditor = do_QueryInterface(mEditor);
|
|
if (textEditor)
|
|
return textEditor->GetTextLength(aDocumentLength);
|
|
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::MakeOrChangeList(const PRUnichar *listType, PRBool entireList)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
nsAutoString aListType(listType);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
if (aListType.IsEmpty())
|
|
{
|
|
err = mEditor->RemoveList(NS_ConvertASCIItoUCS2("ol"));
|
|
if(NS_SUCCEEDED(err))
|
|
{
|
|
err = mEditor->RemoveList(NS_ConvertASCIItoUCS2("ul"));
|
|
if(NS_SUCCEEDED(err))
|
|
err = mEditor->RemoveList(NS_ConvertASCIItoUCS2("dl"));
|
|
}
|
|
}
|
|
else
|
|
err = mEditor->MakeOrChangeList(aListType, entireList);
|
|
break;
|
|
|
|
case ePlainTextEditorType:
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::RemoveList(const PRUnichar *listType)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsAutoString aListType(listType);
|
|
err = mEditor->RemoveList(aListType);
|
|
break;
|
|
}
|
|
|
|
case ePlainTextEditorType:
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::Indent(const PRUnichar *indent)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
nsAutoString aIndent(indent);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
err = mEditor->Indent(aIndent);
|
|
break;
|
|
|
|
case ePlainTextEditorType:
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::Align(const PRUnichar *align)
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
nsAutoString aAlignType(align);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
err = mEditor->Align(aAlignType);
|
|
break;
|
|
|
|
case ePlainTextEditorType:
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetSelectedElement(const PRUnichar *aInTagName, nsIDOMElement **aOutElement)
|
|
{
|
|
if (!aInTagName || !aOutElement)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
nsAutoString tagName(aInTagName);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
result = mEditor->GetSelectedElement(tagName, aOutElement);
|
|
// Don't return NS_EDITOR_ELEMENT_NOT_FOUND (passes NS_SUCCEEDED macro)
|
|
// to JavaScript
|
|
if(NS_SUCCEEDED(result)) return NS_OK;
|
|
break;
|
|
|
|
case ePlainTextEditorType:
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetFirstSelectedCell(nsIDOMElement **aOutElement)
|
|
{
|
|
if (!aOutElement)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
{
|
|
result = tableEditor->GetFirstSelectedCell(aOutElement, nsnull);
|
|
// Don't return NS_EDITOR_ELEMENT_NOT_FOUND (passes NS_SUCCEEDED macro)
|
|
// to JavaScript
|
|
if(NS_SUCCEEDED(result)) return NS_OK;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ePlainTextEditorType:
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetFirstSelectedCellInTable(PRInt32 *aRowIndex, PRInt32 *aColIndex, nsIDOMElement **aOutElement)
|
|
{
|
|
if (!aOutElement || !aRowIndex || !aColIndex)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
{
|
|
result = tableEditor->GetFirstSelectedCellInTable(aOutElement, aRowIndex, aColIndex);
|
|
// Don't return NS_EDITOR_ELEMENT_NOT_FOUND (passes NS_SUCCEEDED macro)
|
|
// to JavaScript
|
|
if(NS_SUCCEEDED(result)) return NS_OK;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ePlainTextEditorType:
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetNextSelectedCell(nsIDOMElement **aOutElement)
|
|
{
|
|
if (!aOutElement)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->GetNextSelectedCell(aOutElement, nsnull);
|
|
break;
|
|
}
|
|
case ePlainTextEditorType:
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetElementOrParentByTagName(const PRUnichar *aInTagName, nsIDOMNode *node, nsIDOMElement **aOutElement)
|
|
{
|
|
//node can be null -- this signals using the selection anchorNode
|
|
if (!aInTagName || !aOutElement)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
nsAutoString tagName(aInTagName);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
result = mEditor->GetElementOrParentByTagName(tagName, node, aOutElement);
|
|
// Don't return NS_EDITOR_ELEMENT_NOT_FOUND (passes NS_SUCCEEDED macro)
|
|
// to JavaScript
|
|
if(NS_SUCCEEDED(result)) return NS_OK;
|
|
break;
|
|
|
|
case ePlainTextEditorType:
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::CreateElementWithDefaults(const PRUnichar *aInTagName, nsIDOMElement **aOutElement)
|
|
{
|
|
if (!aOutElement)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
nsAutoString tagName(aInTagName);
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
result = mEditor->CreateElementWithDefaults(tagName, aOutElement);
|
|
break;
|
|
|
|
case ePlainTextEditorType:
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::DeleteElement(nsIDOMElement *element)
|
|
{
|
|
if (!element)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor) {
|
|
// The nsIEditor::DeleteNode() wants a node
|
|
// but it actually requires that it is an element!
|
|
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(element);
|
|
result = editor->DeleteNode(node);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::InsertElement(nsIDOMElement *element, nsIDOMElement *parent, PRInt32 position)
|
|
{
|
|
if (!element || !parent)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor) {
|
|
// The nsIEditor::InsertNode() wants nodes as params,
|
|
// but it actually requires that they are elements!
|
|
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(element);
|
|
nsCOMPtr<nsIDOMNode> parentNode = do_QueryInterface(parent);
|
|
result = editor->InsertNode(node, parentNode, position);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::InsertElementAtSelection(nsIDOMElement *element, PRBool deleteSelection)
|
|
{
|
|
if (!element)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
result = mEditor->InsertElementAtSelection(element, deleteSelection);
|
|
break;
|
|
|
|
case ePlainTextEditorType:
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::InsertLinkAroundSelection(nsIDOMElement* aAnchorElement)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
result = mEditor->InsertLinkAroundSelection(aAnchorElement);
|
|
break;
|
|
|
|
case ePlainTextEditorType:
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SelectElement(nsIDOMElement* aElement)
|
|
{
|
|
if (!aElement)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
result = mEditor->SelectElement(aElement);
|
|
break;
|
|
|
|
case ePlainTextEditorType:
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SetSelectionAfterElement(nsIDOMElement* aElement)
|
|
{
|
|
if (!aElement)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
result = mEditor->SetCaretAfterElement(aElement);
|
|
break;
|
|
|
|
case ePlainTextEditorType:
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* Table Editing */
|
|
NS_IMETHODIMP
|
|
nsEditorShell::InsertTableRow(PRInt32 aNumber, PRBool bAfter)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->InsertTableRow(aNumber,bAfter);
|
|
}
|
|
break;
|
|
|
|
case ePlainTextEditorType:
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::InsertTableColumn(PRInt32 aNumber, PRBool bAfter)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->InsertTableColumn(aNumber,bAfter);
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::InsertTableCell(PRInt32 aNumber, PRBool bAfter)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
{
|
|
BeginBatchChanges();
|
|
result = tableEditor->InsertTableCell(aNumber, bAfter);
|
|
if (NS_SUCCEEDED(result))
|
|
{
|
|
// Fix disturbances in table layout because of inserted cells
|
|
result = CheckPrefAndNormalizeTable();
|
|
}
|
|
EndBatchChanges();
|
|
return result;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ePlainTextEditorType:
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::DeleteTable()
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
{
|
|
result = tableEditor->DeleteTable();
|
|
// Don't return NS_EDITOR_ELEMENT_NOT_FOUND (passes NS_SUCCEEDED macro)
|
|
// to JavaScript
|
|
if(NS_SUCCEEDED(result)) return NS_OK;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::DeleteTableCell(PRInt32 aNumber)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
{
|
|
BeginBatchChanges();
|
|
result = tableEditor->DeleteTableCell(aNumber);
|
|
if(NS_SUCCEEDED(result))
|
|
{
|
|
// Fix disturbances in table layout because of deleted cells
|
|
result = CheckPrefAndNormalizeTable();
|
|
}
|
|
EndBatchChanges();
|
|
return result;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::DeleteTableCellContents()
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
{
|
|
result = tableEditor->DeleteTableCellContents();
|
|
// Don't return NS_EDITOR_ELEMENT_NOT_FOUND (passes NS_SUCCEEDED macro)
|
|
// to JavaScript
|
|
if(NS_SUCCEEDED(result)) return NS_OK;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::DeleteTableRow(PRInt32 aNumber)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
{
|
|
result = tableEditor->DeleteTableRow(aNumber);
|
|
// Don't return NS_EDITOR_ELEMENT_NOT_FOUND (passes NS_SUCCEEDED macro)
|
|
// to JavaScript
|
|
if(NS_SUCCEEDED(result)) return NS_OK;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::DeleteTableColumn(PRInt32 aNumber)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
{
|
|
result = tableEditor->DeleteTableColumn(aNumber);
|
|
// Don't return NS_EDITOR_ELEMENT_NOT_FOUND (passes NS_SUCCEEDED macro)
|
|
// to JavaScript
|
|
if(NS_SUCCEEDED(result)) return NS_OK;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SwitchTableCellHeaderType(nsIDOMElement *aSourceCell, nsIDOMElement **aNewCell)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->SwitchTableCellHeaderType(aSourceCell, aNewCell);
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::JoinTableCells(PRBool aMergeNonContiguousContents)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->JoinTableCells(aMergeNonContiguousContents);
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SplitTableCell()
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->SplitTableCell();
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SelectTableCell()
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->SelectTableCell();
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SelectBlockOfCells(nsIDOMElement *aStartCell, nsIDOMElement *aEndCell)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->SelectBlockOfCells(aStartCell, aEndCell);
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SelectTableRow()
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->SelectTableRow();
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SelectTableColumn()
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->SelectTableColumn();
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SelectTable()
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->SelectTable();
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SelectAllTableCells()
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->SelectAllTableCells();
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::NormalizeTable(nsIDOMElement *aTable)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->NormalizeTable(aTable);
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// The next four methods are factored to return single items
|
|
// separately for row and column.
|
|
// Underlying implementation gets both at the same time for efficiency.
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetRowIndex(nsIDOMElement *cellElement, PRInt32 *_retval)
|
|
{
|
|
if (!_retval)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
{
|
|
// Get both row and column indexes - return just row
|
|
PRInt32 colIndex;
|
|
result = tableEditor->GetCellIndexes(cellElement, *_retval, colIndex);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetColumnIndex(nsIDOMElement *cellElement, PRInt32 *_retval)
|
|
{
|
|
if (!_retval)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
{
|
|
// Get both row and column indexes - return just column
|
|
PRInt32 rowIndex;
|
|
result = tableEditor->GetCellIndexes(cellElement, rowIndex, *_retval);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetTableRowCount(nsIDOMElement *tableElement, PRInt32 *_retval)
|
|
{
|
|
if (!_retval)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
{
|
|
// This returns both the number of rows and columns: return just rows
|
|
PRInt32 cols;
|
|
result = tableEditor->GetTableSize(tableElement, *_retval, cols);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetTableColumnCount(nsIDOMElement *tableElement, PRInt32 *_retval)
|
|
{
|
|
if (!_retval)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
{
|
|
// This returns both the number of rows and columns: return just columns
|
|
PRInt32 rows;
|
|
result = tableEditor->GetTableSize(tableElement, rows, *_retval);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetCellAt(nsIDOMElement *tableElement, PRInt32 rowIndex, PRInt32 colIndex, nsIDOMElement **_retval)
|
|
{
|
|
if (!_retval)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
{
|
|
result = tableEditor->GetCellAt(tableElement, rowIndex, colIndex, *_retval);
|
|
// Don't return NS_EDITOR_ELEMENT_NOT_FOUND (passes NS_SUCCEEDED macro)
|
|
// to JavaScript
|
|
if(NS_SUCCEEDED(result)) return NS_OK;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Note that the return param in the IDL must be the LAST out param here,
|
|
// so order of params is different from nsITableEditor
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetCellDataAt(nsIDOMElement *tableElement, PRInt32 rowIndex, PRInt32 colIndex,
|
|
PRInt32 *aStartRowIndex, PRInt32 *aStartColIndex,
|
|
PRInt32 *aRowSpan, PRInt32 *aColSpan,
|
|
PRInt32 *aActualRowSpan, PRInt32 *aActualColSpan,
|
|
PRBool *aIsSelected, nsIDOMElement **_retval)
|
|
{
|
|
if (!_retval ||
|
|
!aStartRowIndex || !aStartColIndex ||
|
|
!aRowSpan || !aColSpan ||
|
|
!aActualRowSpan || !aActualColSpan ||
|
|
!aIsSelected )
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->GetCellDataAt(tableElement, rowIndex, colIndex, *_retval,
|
|
*aStartRowIndex, *aStartColIndex,
|
|
*aRowSpan, *aColSpan,
|
|
*aActualRowSpan, *aActualColSpan,
|
|
*aIsSelected);
|
|
// Don't return NS_EDITOR_ELEMENT_NOT_FOUND (passes NS_SUCCEEDED macro)
|
|
// to JavaScript
|
|
if(NS_SUCCEEDED(result)) return NS_OK;
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetFirstRow(nsIDOMElement *aTableElement, nsIDOMElement **_retval)
|
|
{
|
|
if (!_retval || !aTableElement)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->GetFirstRow(aTableElement, *_retval);
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetNextRow(nsIDOMElement *aCurrentRow, nsIDOMElement **_retval)
|
|
{
|
|
if (!_retval || !*_retval || !aCurrentRow)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->GetNextRow(aCurrentRow, *_retval);
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetSelectedOrParentTableElement(PRUnichar **aTagName, PRInt32 *aSelectedCount, nsIDOMElement **_retval)
|
|
{
|
|
if (!_retval || !aTagName || !aSelectedCount)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
nsAutoString TagName(*aTagName);
|
|
if (tableEditor)
|
|
result = tableEditor->GetSelectedOrParentTableElement(*_retval, TagName, *aSelectedCount);
|
|
*aTagName = TagName.ToNewUnicode();
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetSelectedCellsType(nsIDOMElement *aElement, PRUint32 *_retval)
|
|
{
|
|
if (!_retval)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor);
|
|
if (tableEditor)
|
|
result = tableEditor->GetSelectedCellsType(aElement, *_retval);
|
|
}
|
|
break;
|
|
default:
|
|
result = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/* end of table editing */
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetEmbeddedObjects(nsISupportsArray **aObjectArray)
|
|
{
|
|
if (!aObjectArray)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
nsresult result = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditorMailSupport> mailEditor = do_QueryInterface(mEditor);
|
|
if (mailEditor)
|
|
result = mailEditor->GetEmbeddedObjects(aObjectArray);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
result = NS_NOINTERFACE;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::InitSpellChecker()
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
|
|
// We can spell check with any editor type
|
|
if (mEditor)
|
|
{
|
|
nsCOMPtr<nsITextServicesDocument>tsDoc;
|
|
|
|
result = nsComponentManager::CreateInstance(
|
|
kCTextServicesDocumentCID,
|
|
nsnull,
|
|
NS_GET_IID(nsITextServicesDocument),
|
|
(void **)getter_AddRefs(tsDoc));
|
|
|
|
if (NS_FAILED(result))
|
|
return result;
|
|
|
|
if (!tsDoc)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
// Pass the editor to the text services document
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (!editor)
|
|
return NS_NOINTERFACE;
|
|
|
|
result = tsDoc->InitWithEditor(editor);
|
|
|
|
if (NS_FAILED(result))
|
|
return result;
|
|
|
|
result = nsComponentManager::CreateInstance(NS_SPELLCHECKER_CONTRACTID,
|
|
nsnull,
|
|
NS_GET_IID(nsISpellChecker),
|
|
(void **)getter_AddRefs(mSpellChecker));
|
|
|
|
if (NS_FAILED(result))
|
|
return result;
|
|
|
|
if (!mSpellChecker)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
result = mSpellChecker->SetDocument(tsDoc, PR_TRUE);
|
|
|
|
if (NS_FAILED(result))
|
|
return result;
|
|
|
|
// Tell the spellchecker what dictionary to use:
|
|
|
|
PRUnichar *dictName = nsnull;
|
|
|
|
NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &result);
|
|
|
|
if (NS_SUCCEEDED(result) && prefs)
|
|
result = prefs->CopyUnicharPref("spellchecker.dictionary", &dictName);
|
|
|
|
if (! dictName || ! *dictName)
|
|
{
|
|
// Prefs didn't give us a dictionary name, so just get the current
|
|
// locale and use that as the default dictionary name!
|
|
|
|
if (dictName)
|
|
{
|
|
nsMemory::Free(dictName);
|
|
dictName = nsnull;
|
|
}
|
|
|
|
nsCOMPtr<nsIChromeRegistry> chromeRegistry = do_GetService(kChromeRegistryCID, &result);
|
|
|
|
if (NS_SUCCEEDED(result) && chromeRegistry)
|
|
result = chromeRegistry->GetSelectedLocale(NS_LITERAL_STRING("navigator"), &dictName);
|
|
}
|
|
|
|
if (NS_SUCCEEDED(result) && dictName && *dictName)
|
|
result = SetCurrentDictionary(dictName);
|
|
|
|
if (dictName)
|
|
nsMemory::Free(dictName);
|
|
|
|
// If an error was thrown while checking the dictionary pref, just
|
|
// fail silently so that the spellchecker dialog is allowed to come
|
|
// up. The user can manually reset the language to their choice on
|
|
// the dialog if it is wrong.
|
|
|
|
result = NS_OK;
|
|
|
|
DeleteSuggestedWordList();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetNextMisspelledWord(PRUnichar **aNextMisspelledWord)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
nsAutoString nextMisspelledWord;
|
|
|
|
// We can spell check with any editor type
|
|
if (mEditor && mSpellChecker)
|
|
{
|
|
DeleteSuggestedWordList();
|
|
result = mSpellChecker->NextMisspelledWord(&nextMisspelledWord, &mSuggestedWordList);
|
|
}
|
|
*aNextMisspelledWord = nextMisspelledWord.ToNewUnicode();
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetSuggestedWord(PRUnichar **aSuggestedWord)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
nsAutoString word;
|
|
// We can spell check with any editor type
|
|
if (mEditor)
|
|
{
|
|
if ( mSuggestedWordIndex < mSuggestedWordList.Count())
|
|
{
|
|
mSuggestedWordList.StringAt(mSuggestedWordIndex, word);
|
|
mSuggestedWordIndex++;
|
|
} else {
|
|
// A blank string signals that there are no more strings
|
|
word.SetLength(0);
|
|
}
|
|
result = NS_OK;
|
|
}
|
|
*aSuggestedWord = word.ToNewUnicode();
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::CheckCurrentWord(const PRUnichar *aSuggestedWord, PRBool *aIsMisspelled)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
nsAutoString suggestedWord(aSuggestedWord);
|
|
// We can spell check with any editor type
|
|
if (mEditor && mSpellChecker)
|
|
{
|
|
DeleteSuggestedWordList();
|
|
result = mSpellChecker->CheckWord(&suggestedWord, aIsMisspelled, &mSuggestedWordList);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::ReplaceWord(const PRUnichar *aMisspelledWord, const PRUnichar *aReplaceWord, PRBool allOccurrences)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
nsAutoString misspelledWord(aMisspelledWord);
|
|
nsAutoString replaceWord(aReplaceWord);
|
|
if (mEditor && mSpellChecker)
|
|
{
|
|
result = mSpellChecker->Replace(&misspelledWord, &replaceWord, allOccurrences);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::IgnoreWordAllOccurrences(const PRUnichar *aWord)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
nsAutoString word(aWord);
|
|
if (mEditor && mSpellChecker)
|
|
{
|
|
result = mSpellChecker->IgnoreAll(&word);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetPersonalDictionary()
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
// We can spell check with any editor type
|
|
if (mEditor && mSpellChecker)
|
|
{
|
|
mDictionaryList.Clear();
|
|
mDictionaryIndex = 0;
|
|
result = mSpellChecker->GetPersonalDictionary(&mDictionaryList);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetPersonalDictionaryWord(PRUnichar **aDictionaryWord)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
nsAutoString word;
|
|
if (mEditor)
|
|
{
|
|
if ( mDictionaryIndex < mDictionaryList.Count())
|
|
{
|
|
mDictionaryList.StringAt(mDictionaryIndex, word);
|
|
mDictionaryIndex++;
|
|
} else {
|
|
// A blank string signals that there are no more strings
|
|
word.SetLength(0);
|
|
}
|
|
result = NS_OK;
|
|
}
|
|
*aDictionaryWord = word.ToNewUnicode();
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::AddWordToDictionary(const PRUnichar *aWord)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
nsAutoString word(aWord);
|
|
if (mEditor && mSpellChecker)
|
|
{
|
|
result = mSpellChecker->AddWordToPersonalDictionary(&word);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::RemoveWordFromDictionary(const PRUnichar *aWord)
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
nsAutoString word(aWord);
|
|
if (mEditor && mSpellChecker)
|
|
{
|
|
result = mSpellChecker->RemoveWordFromPersonalDictionary(&word);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetDictionaryList(PRUnichar ***aDictionaryList, PRUint32 *aCount)
|
|
{
|
|
nsresult result = NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
if (!aDictionaryList || !aCount)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
*aDictionaryList = 0;
|
|
*aCount = 0;
|
|
|
|
if (mEditor && mSpellChecker)
|
|
{
|
|
nsStringArray dictList;
|
|
|
|
result = mSpellChecker->GetDictionaryList(&dictList);
|
|
|
|
if (NS_FAILED(result))
|
|
return result;
|
|
|
|
PRUnichar **tmpPtr = 0;
|
|
|
|
if (dictList.Count() < 1)
|
|
{
|
|
// If there are no dictionaries, return an array containing
|
|
// one element and a count of one.
|
|
|
|
tmpPtr = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *));
|
|
|
|
if (!tmpPtr)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
*tmpPtr = 0;
|
|
*aDictionaryList = tmpPtr;
|
|
*aCount = 0;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
tmpPtr = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * dictList.Count());
|
|
|
|
if (!tmpPtr)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
*aDictionaryList = tmpPtr;
|
|
*aCount = dictList.Count();
|
|
|
|
nsAutoString dictStr;
|
|
|
|
PRUint32 i;
|
|
|
|
for (i = 0; i < *aCount; i++)
|
|
{
|
|
dictList.StringAt(i, dictStr);
|
|
tmpPtr[i] = dictStr.ToNewUnicode();
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::GetCurrentDictionary(PRUnichar **aDictionary)
|
|
{
|
|
nsresult result = NS_ERROR_NOT_INITIALIZED;
|
|
|
|
if (!aDictionary)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
*aDictionary = 0;
|
|
|
|
if (mEditor && mSpellChecker)
|
|
{
|
|
nsAutoString dictStr;
|
|
result = mSpellChecker->GetCurrentDictionary(&dictStr);
|
|
|
|
if (NS_FAILED(result))
|
|
return result;
|
|
|
|
*aDictionary = dictStr.ToNewUnicode();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::SetCurrentDictionary(const PRUnichar *aDictionary)
|
|
{
|
|
nsresult result = NS_ERROR_NOT_INITIALIZED;
|
|
|
|
if (!aDictionary)
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
if (mEditor && mSpellChecker)
|
|
{
|
|
nsAutoString dictStr(aDictionary);
|
|
result = mSpellChecker->SetCurrentDictionary(&dictStr);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::UninitSpellChecker()
|
|
{
|
|
nsresult result = NS_NOINTERFACE;
|
|
// We can spell check with any editor type
|
|
if (mEditor)
|
|
{
|
|
// Save the last used dictionary to the user's preferences.
|
|
NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &result);
|
|
|
|
if (NS_SUCCEEDED(result) && prefs)
|
|
{
|
|
PRUnichar *dictName = nsnull;
|
|
|
|
result = GetCurrentDictionary(&dictName);
|
|
|
|
if (NS_SUCCEEDED(result) && dictName && *dictName)
|
|
result = prefs->SetUnicharPref("spellchecker.dictionary", dictName);
|
|
|
|
if (dictName)
|
|
nsMemory::Free(dictName);
|
|
}
|
|
|
|
// Cleanup - kill the spell checker
|
|
DeleteSuggestedWordList();
|
|
mDictionaryList.Clear();
|
|
mDictionaryIndex = 0;
|
|
mSpellChecker = 0;
|
|
result = NS_OK;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
nsresult
|
|
nsEditorShell::DeleteSuggestedWordList()
|
|
{
|
|
mSuggestedWordList.Clear();
|
|
mSuggestedWordIndex = 0;
|
|
return NS_OK;
|
|
}
|
|
|
|
#ifdef XP_MAC
|
|
#pragma mark -
|
|
#endif
|
|
|
|
/* void onStartURIOpen (in nsIURI aURI, in string aWindowTarget, out boolean aAbortOpen); */
|
|
NS_IMETHODIMP nsEditorShell::OnStartURIOpen(nsIURI *aURI, const char *aWindowTarget, PRBool *aAbortOpen)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
/* void getProtocolHandler (in nsIURI aURI, out nsIProtocolHandler aProtocolHandler); */
|
|
NS_IMETHODIMP nsEditorShell::GetProtocolHandler(nsIURI *aURI, nsIProtocolHandler **aProtocolHandler)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aProtocolHandler);
|
|
*aProtocolHandler = nsnull;
|
|
return NS_OK;
|
|
}
|
|
|
|
/* void doContent (in string aContentType, in nsURILoadCommand aCommand, in string aWindowTarget, in nsIChannel aOpenedChannel, out nsIStreamListener aContentHandler, out boolean aAbortProcess); */
|
|
NS_IMETHODIMP nsEditorShell::DoContent(const char *aContentType, nsURILoadCommand aCommand, const char *aWindowTarget, nsIRequest* request, nsIStreamListener **aContentHandler, PRBool *aAbortProcess)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aContentHandler);
|
|
NS_ENSURE_ARG_POINTER(aAbortProcess);
|
|
*aContentHandler = nsnull;
|
|
*aAbortProcess = PR_FALSE;
|
|
return NS_OK;
|
|
}
|
|
|
|
/* boolean isPreferred (in string aContentType, in nsURILoadCommand aCommand, in string aWindowTarget, out string aDesiredContentType); */
|
|
NS_IMETHODIMP nsEditorShell::IsPreferred(const char *aContentType, nsURILoadCommand aCommand, const char *aWindowTarget, char **aDesiredContentType, PRBool *_retval)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aDesiredContentType);
|
|
NS_ENSURE_ARG_POINTER(_retval);
|
|
*aDesiredContentType = nsnull;
|
|
*_retval = PR_FALSE;
|
|
return NS_OK;
|
|
}
|
|
|
|
/* boolean canHandleContent (in string aContentType, in nsURILoadCommand aCommand, in string aWindowTarget, out string aDesiredContentType); */
|
|
NS_IMETHODIMP nsEditorShell::CanHandleContent(const char *aContentType, nsURILoadCommand aCommand, const char *aWindowTarget, char **aDesiredContentType, PRBool *_retval)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aDesiredContentType);
|
|
NS_ENSURE_ARG_POINTER(_retval);
|
|
*aDesiredContentType = nsnull;
|
|
*_retval = PR_FALSE;
|
|
return NS_OK;
|
|
}
|
|
|
|
/* attribute nsISupports loadCookie; */
|
|
NS_IMETHODIMP nsEditorShell::GetLoadCookie(nsISupports * *aLoadCookie)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aLoadCookie);
|
|
*aLoadCookie = nsnull;
|
|
return NS_OK;
|
|
}
|
|
NS_IMETHODIMP nsEditorShell::SetLoadCookie(nsISupports * aLoadCookie)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
/* attribute nsIURIContentListener parentContentListener; */
|
|
NS_IMETHODIMP nsEditorShell::GetParentContentListener(nsIURIContentListener * *aParentContentListener)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aParentContentListener);
|
|
*aParentContentListener = nsnull;
|
|
return NS_OK;
|
|
}
|
|
NS_IMETHODIMP nsEditorShell::SetParentContentListener(nsIURIContentListener * aParentContentListener)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
#ifdef XP_MAC
|
|
#pragma mark -
|
|
#endif
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::BeginBatchChanges()
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
err = editor->BeginTransaction();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::EndBatchChanges()
|
|
{
|
|
nsresult err = NS_NOINTERFACE;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
err = editor->EndTransaction();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::RunUnitTests()
|
|
{
|
|
PRInt32 numTests = 0;
|
|
PRInt32 numTestsFailed = 0;
|
|
|
|
nsresult err = NS_OK;
|
|
nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
|
|
if (editor)
|
|
err = editor->DebugUnitTests(&numTests, &numTestsFailed);
|
|
|
|
#ifdef APP_DEBUG
|
|
printf("\nRan %ld tests, of which %ld failed\n", (long)numTests, (long)numTestsFailed);
|
|
#endif
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::StartLogging(nsIFile *logFile)
|
|
{
|
|
nsresult err = NS_OK;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditorLogging> logger = do_QueryInterface(mEditor);
|
|
if (logger)
|
|
err = logger->StartLogging(logFile);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::StopLogging()
|
|
{
|
|
nsresult err = NS_OK;
|
|
|
|
switch (mEditorType)
|
|
{
|
|
case ePlainTextEditorType:
|
|
case eHTMLTextEditorType:
|
|
{
|
|
nsCOMPtr<nsIEditorLogging> logger = do_QueryInterface(mEditor);
|
|
if (logger)
|
|
err = logger->StopLogging();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
err = NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
#ifdef XP_MAC
|
|
#pragma mark -
|
|
#endif
|
|
|
|
//----------------------------------------
|
|
// nsIWebProgessListener implementation
|
|
//----------------------------------------
|
|
NS_IMETHODIMP
|
|
nsEditorShell::OnProgressChange(nsIWebProgress *aProgress,
|
|
nsIRequest *aRequest,
|
|
PRInt32 aCurSelfProgress,
|
|
PRInt32 aMaxSelfProgress,
|
|
PRInt32 aCurTotalProgress,
|
|
PRInt32 aMaxTotalProgress)
|
|
{
|
|
if (mParserObserver)
|
|
{
|
|
PRBool cancelEdit;
|
|
mParserObserver->GetBadTagFound(&cancelEdit);
|
|
if (cancelEdit)
|
|
{
|
|
/*
|
|
nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(mWebShell);
|
|
if (docShell)
|
|
docShell->StopLoad();
|
|
*/
|
|
mParserObserver->End();
|
|
NS_RELEASE(mParserObserver);
|
|
|
|
if (mDocShell)
|
|
{
|
|
// where do we pop up a dialog telling the user they can't edit this doc?
|
|
// this next call will close the window, but do we want to do that? or tell the .js UI to do it?
|
|
mCloseWindowWhenLoaded = PR_TRUE;
|
|
mCantEditReason = eCantEditFramesets;
|
|
}
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::OnStateChange(nsIWebProgress *aProgress,
|
|
nsIRequest *aRequest,
|
|
PRInt32 aStateFlags,
|
|
nsresult aStatus)
|
|
{
|
|
//
|
|
// A Request has started...
|
|
//
|
|
if (aStateFlags & nsIWebProgressListener::STATE_START)
|
|
{
|
|
// Page level notification...
|
|
if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK)
|
|
{
|
|
StartPageLoad();
|
|
}
|
|
// Document level notification...
|
|
if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT)
|
|
{
|
|
nsCOMPtr<nsIDOMWindow> domWindow;
|
|
|
|
// Get the DOMWindow where the state change occurred...
|
|
aProgress->GetDOMWindow(getter_AddRefs(domWindow));
|
|
if (domWindow)
|
|
{
|
|
(void) StartDocumentLoad(domWindow);
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// A network or document Request as finished...
|
|
//
|
|
else if ((aStateFlags & nsIWebProgressListener::STATE_STOP) &&
|
|
((aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) ||
|
|
(aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK)))
|
|
{
|
|
nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
|
|
nsCOMPtr<nsIDOMWindow> domWindow;
|
|
|
|
// Get the DOMWindow where the state change occurred...
|
|
aProgress->GetDOMWindow(getter_AddRefs(domWindow));
|
|
|
|
if (domWindow)
|
|
{
|
|
// Document level notification...
|
|
if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT)
|
|
{
|
|
(void) EndDocumentLoad(domWindow, channel, aStatus);
|
|
}
|
|
// Page level notification...
|
|
if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK)
|
|
{
|
|
(void) EndPageLoad(domWindow, channel, aStatus);
|
|
}
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::OnLocationChange(nsIWebProgress *aProgress,
|
|
nsIRequest *aRequest,
|
|
nsIURI *aURI)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::OnStatusChange(nsIWebProgress* aWebProgress,
|
|
nsIRequest* aRequest,
|
|
nsresult aStatus,
|
|
const PRUnichar* aMessage)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::OnSecurityChange(nsIWebProgress *aWebProgress,
|
|
nsIRequest *aRequest,
|
|
PRInt32 state)
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsEditorShell::StartPageLoad()
|
|
{
|
|
// Start the throbber
|
|
// TODO: We should also start/stop it for saving and publishing?
|
|
SetChromeAttribute( mDocShell, "Editor:Throbber", "busy",
|
|
NS_ConvertASCIItoUCS2("true") );
|
|
|
|
// set up a parser observer
|
|
if (!mParserObserver)
|
|
{
|
|
mParserObserver = new nsEditorParserObserver();
|
|
if (!mParserObserver) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
NS_ADDREF(mParserObserver);
|
|
mParserObserver->RegisterTagToWatch("FRAMESET");
|
|
mParserObserver->Start();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// Called when the entire document, including any sub-documents (ie. frames)
|
|
// have been loaded...
|
|
nsresult nsEditorShell::EndPageLoad(nsIDOMWindow *aDOMWindow,
|
|
nsIChannel *aChannel,
|
|
nsresult aStatus)
|
|
{
|
|
// Make sure the ParserObserver is active through any frameset loads?
|
|
if (mParserObserver)
|
|
{
|
|
mParserObserver->End();
|
|
NS_RELEASE(mParserObserver);
|
|
}
|
|
|
|
SetChromeAttribute( mDocShell, "Editor:Throbber", "busy",
|
|
NS_ConvertASCIItoUCS2("false") );
|
|
|
|
nsAutoString doneText;
|
|
GetBundleString(NS_LITERAL_STRING("LoadingDone"), doneText);
|
|
SetChromeAttribute(mDocShell, "statusText", "value", doneText);
|
|
|
|
// Display an Alert dialog if the page cannot be edited...
|
|
if (mCloseWindowWhenLoaded)
|
|
{
|
|
nsAutoString alertLabel, alertMessage;
|
|
GetBundleString(NS_LITERAL_STRING("Alert"), alertLabel);
|
|
|
|
nsAutoString stringID;
|
|
switch (mCantEditReason)
|
|
{
|
|
case eCantEditFramesets:
|
|
stringID.AssignWithConversion("CantEditFramesetMsg");
|
|
break;
|
|
case eCantEditMimeType:
|
|
stringID.AssignWithConversion("CantEditMimeTypeMsg");
|
|
break;
|
|
case eCantEditOther:
|
|
stringID.AssignWithConversion("CantEditDocumentMsg");
|
|
break;
|
|
default:
|
|
// Do nothing.
|
|
break;
|
|
}
|
|
|
|
GetBundleString(stringID.GetUnicode(), alertMessage);
|
|
Alert(alertLabel, alertMessage);
|
|
|
|
nsCOMPtr<nsIBaseWindow> baseWindow;
|
|
GetTreeOwner(mDocShell, getter_AddRefs(baseWindow));
|
|
NS_ENSURE_TRUE(baseWindow, NS_ERROR_ABORT);
|
|
baseWindow->Destroy();
|
|
|
|
return NS_ERROR_ABORT;
|
|
}
|
|
//
|
|
// By this time, we know that the page did not contain any frames
|
|
// (since mCloseWindowWhenLoaded was PR_FALSE)... So, make an
|
|
// editor (assuming that the load succeeded)...
|
|
//
|
|
// for pages with charsets, this gets called the first time with a
|
|
// non-zero status value. Don't prepare the editor that time.
|
|
// aStatus will be NS_BINDING_ABORTED then.
|
|
//
|
|
if (NS_SUCCEEDED(aStatus))
|
|
{
|
|
nsCOMPtr<nsIURI> url;
|
|
aChannel->GetURI(getter_AddRefs(url));
|
|
(void) PrepareDocumentForEditing(aDOMWindow, url);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// Called when each new document, or sub-document (ie. frame) starts to
|
|
// load.
|
|
nsresult nsEditorShell::StartDocumentLoad(nsIDOMWindow *aDOMWindow)
|
|
{
|
|
// Disable JavaScript in this document:
|
|
nsCOMPtr<nsIScriptGlobalObject> sgo (do_QueryInterface(aDOMWindow));
|
|
|
|
if (sgo)
|
|
{
|
|
nsCOMPtr<nsIScriptContext> scriptContext;
|
|
sgo->GetContext(getter_AddRefs(scriptContext));
|
|
if (scriptContext)
|
|
scriptContext->SetScriptsEnabled(PR_FALSE);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// Called when each document, or sub-document (ie. frame) has finished
|
|
// loading...
|
|
nsresult nsEditorShell::EndDocumentLoad(nsIDOMWindow *aDOMWindow,
|
|
nsIChannel* aChannel,
|
|
nsresult aStatus)
|
|
{
|
|
// for pages with charsets, this gets called the first time with a
|
|
// non-zero status value. Don't prepare the editor that time.
|
|
// aStatus will be NS_BINDING_ABORTED then.
|
|
if (aStatus == NS_BINDING_ABORTED)
|
|
return NS_OK;
|
|
|
|
// note that we continue with other non-success status codes.
|
|
|
|
// Disable meta-refresh
|
|
nsCOMPtr<nsIRefreshURI> refreshURI = do_QueryInterface(mContentAreaDocShell);
|
|
if (refreshURI)
|
|
refreshURI->CancelRefreshURITimers();
|
|
|
|
// Is this a MIME type we can handle?
|
|
if (aChannel)
|
|
{
|
|
char *contentType;
|
|
aChannel->GetContentType(&contentType);
|
|
if (contentType)
|
|
{
|
|
if ( (nsCRT::strcmp(contentType, "text/html") != 0) &&
|
|
(nsCRT::strcmp(contentType, "text/plain") != 0))
|
|
{
|
|
mCloseWindowWhenLoaded = PR_TRUE;
|
|
mCantEditReason = eCantEditMimeType;
|
|
}
|
|
|
|
nsMemory::Free(contentType);
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
#ifdef XP_MAC
|
|
#pragma mark -
|
|
#endif
|
|
|
|
nsresult
|
|
nsEditorShell::CheckPrefAndNormalizeTable()
|
|
{
|
|
nsresult res = NS_NOINTERFACE;
|
|
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
|
|
|
|
if (htmlEditor)
|
|
{
|
|
NS_WITH_SERVICE(nsIPref, prefs, kPrefServiceCID, &res);
|
|
if (NS_FAILED(res)) return NS_OK;
|
|
|
|
PRBool normalizeTable = PR_FALSE;
|
|
if (NS_SUCCEEDED(prefs->GetBoolPref("editor.table.maintain_structure", &normalizeTable)) && normalizeTable)
|
|
return NormalizeTable(nsnull);
|
|
|
|
return NS_OK;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsEditorShell::HandleMouseClickOnElement(nsIDOMElement *aElement, PRInt32 aClickCount,
|
|
PRInt32 x, PRInt32 y, PRBool *_retval)
|
|
{
|
|
// Guess it's ok if we don't have an element
|
|
if (!aElement) return NS_OK;
|
|
if (!_retval) return NS_ERROR_NULL_POINTER;
|
|
|
|
*_retval = PR_FALSE;
|
|
|
|
// We'll only look at single and double-click
|
|
if (aClickCount > 2) return NS_OK;
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
/*
|
|
#if DEBUG_cmanske
|
|
nsAutoString TagName;
|
|
aElement->GetTagName(TagName);
|
|
TagName.ToLowerCase();
|
|
char szTagName[64];
|
|
TagName.ToCString(szTagName, 64);
|
|
printf("***** Element clicked on: %s, x=%d, y=%d\n", szTagName, x, y);
|
|
#endif
|
|
*/
|
|
if (mDisplayMode == eDisplayModeAllTags)
|
|
{
|
|
// Always select the element in AllTags mode
|
|
// in other modes, clicking on images, hline, etc
|
|
// already selects them correctly
|
|
// Selection here is used to make clicking on the
|
|
// background image in ShowAllTags mode select
|
|
// contents of a element
|
|
// TODO: It would be great if we could use x, y to restrict
|
|
// where you click for easier caret placement near border with content,
|
|
// but:
|
|
// 1. We can get x,y, relative to either screen or "widget" (contentWindow)
|
|
// origin, but not the element clicked on!
|
|
// 2. we need to get the size of the element!
|
|
|
|
rv = SelectElement(aElement);
|
|
if (NS_SUCCEEDED(rv))
|
|
*_retval = PR_TRUE;
|
|
}
|
|
|
|
// For double-click, edit element properties
|
|
if (aClickCount == 2)
|
|
{
|
|
nsAutoString commandName;
|
|
|
|
// In "All Tags" mode, use AdvancedProperties,
|
|
// in others use appriate object property dialog
|
|
if (mDisplayMode != eDisplayModeAllTags)
|
|
commandName = NS_LITERAL_STRING("cmd_objectProperties");
|
|
else
|
|
commandName = NS_LITERAL_STRING("cmd_advancedProperties");
|
|
|
|
rv = DoControllerCommand(commandName);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
*_retval = PR_TRUE;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsEditorShell::DoControllerCommand(nsString& aCommand)
|
|
{
|
|
// Get the list of controllers...
|
|
nsCOMPtr<nsIControllers> controllers;
|
|
if(!mContentWindow)
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
nsCOMPtr<nsIDOMWindowInternal> cwP = do_QueryReferent(mContentWindow);
|
|
if (!cwP) return NS_ERROR_NOT_INITIALIZED;
|
|
nsresult rv = cwP->GetControllers(getter_AddRefs(controllers));
|
|
if (NS_FAILED(rv)) return rv;
|
|
if (!controllers) return NS_ERROR_NULL_POINTER;
|
|
|
|
//... then find the specific controller supporting desired command
|
|
nsCOMPtr<nsIController> controller;
|
|
|
|
rv = controllers->GetControllerForCommand(aCommand.GetUnicode(), getter_AddRefs(controller));
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
if (!controller) return NS_ERROR_FAILURE;
|
|
|
|
nsCOMPtr<nsIEditorController> composerController = do_QueryInterface(controller);
|
|
// Execute the command
|
|
rv = composerController->DoCommand(aCommand.GetUnicode());
|
|
}
|
|
return rv;
|
|
}
|
|
|