/* -*- 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.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include "nsCOMPtr.h" #include "nsVoidArray.h" #include "nsIContentViewer.h" #include "nsIDocumentViewer.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" #include "nsIDOMXULDocument.h" #include "nsIDiskDocument.h" #include "nsIDOMElement.h" #include "nsIDOMSelection.h" #include "nsIEditor.h" #include "nsIHTMLEditor.h" #include "nsInterfaceState.h" nsInterfaceState::nsInterfaceState() : mEditor(nsnull) , mWebShell(nsnull) , mBoldState(eStateUninitialized) , mItalicState(eStateUninitialized) , mUnderlineState(eStateUninitialized) , mDirtyState(eStateUninitialized) { NS_INIT_REFCNT(); } nsInterfaceState::~nsInterfaceState() { } NS_IMPL_ADDREF(nsInterfaceState); NS_IMPL_RELEASE(nsInterfaceState); NS_IMETHODIMP nsInterfaceState::QueryInterface(const nsIID& aIID, void** aInstancePtr) { if (nsnull == aInstancePtr) { return NS_ERROR_NULL_POINTER; } *aInstancePtr = nsnull; if (aIID.Equals(nsIDOMSelectionListener::GetIID())) { *aInstancePtr = (void*)(nsIDOMSelectionListener*)this; AddRef(); return NS_OK; } if (aIID.Equals(nsIDocumentStateListener::GetIID())) { *aInstancePtr = (void*)(nsIDocumentStateListener*)this; AddRef(); return NS_OK; } if (aIID.Equals(nsCOMTypeInfo::GetIID())) { *aInstancePtr = (void*)(nsISupports *)(nsIDOMSelectionListener*)this; AddRef(); return NS_OK; } return NS_NOINTERFACE; } NS_IMETHODIMP nsInterfaceState::Init(nsIHTMLEditor* aEditor, nsIWebShell *aChromeWebShell) { if (!aEditor) return NS_ERROR_INVALID_ARG; if (!aChromeWebShell) return NS_ERROR_INVALID_ARG; mEditor = aEditor; // no addreffing here mWebShell = aChromeWebShell; return NS_OK; } NS_IMETHODIMP nsInterfaceState::NotifyDocumentCreated() { return NS_OK; } NS_IMETHODIMP nsInterfaceState::NotifyDocumentWillBeDestroyed() { return NS_OK; } NS_IMETHODIMP nsInterfaceState::NotifyDocumentStateChanged(PRBool aNowDirty) { // update document modified. We should have some other notifications for this too. return UpdateDirtyState(aNowDirty); } NS_IMETHODIMP nsInterfaceState::NotifySelectionChanged() { nsresult rv; // we don't really care if any of these fail. // update bold rv = UpdateTextState("b", "Editor:Style:IsBold", "bold", mBoldState); // update italic rv = UpdateTextState("i", "Editor:Style:IsItalic", "italic", mItalicState); // update underline rv = UpdateTextState("u", "Editor:Style:IsUnderline", "underline", mUnderlineState); // udpate the font face rv = UpdateFontFace("Editor:Font:Face", "font", mFontString); // update the paragraph format popup rv = UpdateParagraphState("Editor:Paragraph:Format", "format", mParagraphFormat); // update the list buttons rv = UpdateListState("Editor:Paragraph:ListType"); return NS_OK; } nsresult nsInterfaceState::UpdateParagraphState(const char* observerName, const char* attributeName, nsString& ioParaFormat) { nsStringArray tagList; mEditor->GetParagraphStyle(&tagList); PRInt32 numTags = tagList.Count(); if (numTags > 0) { nsAutoString thisTag; tagList.StringAt(0, thisTag); if (thisTag != mParagraphFormat) { nsresult rv = SetNodeAttribute(observerName, attributeName, thisTag); if (NS_FAILED(rv)) return rv; mParagraphFormat = thisTag; } } return NS_OK; } nsresult nsInterfaceState::UpdateListState(const char* observerName) { nsresult rv = NS_ERROR_NO_INTERFACE; nsCOMPtr domSelection; { nsCOMPtr editor = do_QueryInterface(mEditor); editor->GetSelection(getter_AddRefs(domSelection)); } PRBool inOL = PR_FALSE; PRBool inUL = PR_FALSE; nsCOMPtr domNode; if (domSelection) domSelection->GetAnchorNode(getter_AddRefs(domNode)); // tagStr will hold the list state when we're done. nsAutoString tagStr("ol"); nsCOMPtr parentElement; rv = mEditor->GetElementOrParentByTagName(tagStr, domNode, getter_AddRefs(parentElement)); if (NS_FAILED(rv)) return rv; if (!parentElement) { tagStr = "ul"; rv = mEditor->GetElementOrParentByTagName(tagStr, domNode, getter_AddRefs(parentElement)); if (NS_FAILED(rv)) return rv; if (!parentElement) tagStr = ""; } if (tagStr != mListTag) { rv = SetNodeAttribute(observerName, "format", tagStr); mListTag = tagStr; } return rv; } nsresult nsInterfaceState::UpdateFontFace(const char* observerName, const char* attributeName, nsString& ioFontString) { nsresult rv; PRBool firstOfSelectionHasProp = PR_FALSE; PRBool anyOfSelectionHasProp = PR_FALSE; PRBool allOfSelectionHasProp = PR_FALSE; nsCOMPtr styleAtom = getter_AddRefs(NS_NewAtom("font")); nsAutoString faceStr("face"); rv = mEditor->GetInlineProperty(styleAtom, &faceStr, nsnull, firstOfSelectionHasProp, anyOfSelectionHasProp, allOfSelectionHasProp); return rv; } nsresult nsInterfaceState::UpdateTextState(const char* tagName, const char* observerName, const char* attributeName, PRInt8& ioState) { nsresult rv; PRBool firstOfSelectionHasProp = PR_FALSE; PRBool anyOfSelectionHasProp = PR_FALSE; PRBool allOfSelectionHasProp = PR_FALSE; nsCOMPtr styleAtom = getter_AddRefs(NS_NewAtom(tagName)); rv = mEditor->GetInlineProperty(styleAtom, nsnull, nsnull, firstOfSelectionHasProp, anyOfSelectionHasProp, allOfSelectionHasProp); PRBool &behaviour = allOfSelectionHasProp; // change this to alter the behaviour if (behaviour != ioState) { rv = SetNodeAttribute(observerName, attributeName, behaviour ? "true" : "false"); if (NS_FAILED(rv)) return rv; ioState = behaviour; } return rv; } nsresult nsInterfaceState::UpdateDirtyState(PRBool aNowDirty) { if (mDirtyState != aNowDirty) { nsresult rv = SetNodeAttribute("Editor:Document:Dirty", "dirty", aNowDirty ? "true" : "false"); if (NS_FAILED(rv)) return rv; mDirtyState = aNowDirty; } return NS_OK; } nsresult nsInterfaceState::SetNodeAttribute(const char* nodeID, const char* attributeName, const nsString& newValue) { nsresult rv = NS_OK; if (!mWebShell) return NS_ERROR_NOT_INITIALIZED; nsCOMPtr cv; rv = mWebShell->GetContentViewer(getter_AddRefs(cv)); if (NS_FAILED(rv)) return rv; nsCOMPtr docViewer = do_QueryInterface(cv, &rv); if (NS_FAILED(rv)) return rv; nsCOMPtr chromeDoc; rv = docViewer->GetDocument(*getter_AddRefs(chromeDoc)); if (NS_FAILED(rv)) return rv; nsCOMPtr xulDoc = do_QueryInterface(chromeDoc, &rv); if (NS_FAILED(rv)) return rv; nsCOMPtr elem; rv = xulDoc->GetElementById( nodeID, getter_AddRefs(elem) ); if (NS_FAILED(rv) || !elem) return rv; return elem->SetAttribute(attributeName, newValue); } nsresult NS_NewInterfaceState(nsIHTMLEditor* aEditor, nsIWebShell* aWebShell, nsIDOMSelectionListener** aInstancePtrResult) { nsInterfaceState* newThang = new nsInterfaceState; if (!newThang) return NS_ERROR_OUT_OF_MEMORY; *aInstancePtrResult = nsnull; nsresult rv = newThang->Init(aEditor, aWebShell); if (NS_FAILED(rv)) { delete newThang; return rv; } return newThang->QueryInterface(nsIDOMSelectionListener::GetIID(), (void **)aInstancePtrResult); }