diff --git a/editor/base/Makefile.in b/editor/base/Makefile.in index c80dd6e5ac8..68b3e2b8c83 100644 --- a/editor/base/Makefile.in +++ b/editor/base/Makefile.in @@ -91,6 +91,7 @@ CPPSRCS += nsAOLCiter.cpp \ nsWrapUtils.cpp \ TextEditorTest.cpp \ TypeInState.cpp \ + SetDocTitleTxn.cpp \ $(NULL) # Enable Editor API Logging! diff --git a/editor/base/TransactionFactory.cpp b/editor/base/TransactionFactory.cpp index 7c9833fbaf1..42198a6d1d5 100644 --- a/editor/base/TransactionFactory.cpp +++ b/editor/base/TransactionFactory.cpp @@ -35,6 +35,7 @@ #include "JoinElementTxn.h" #include "nsStyleSheetTxns.h" #include "IMETextTxn.h" +#include "SetDocTitleTxn.h" TransactionFactory::TransactionFactory() { @@ -75,6 +76,8 @@ TransactionFactory::GetNewTransaction(REFNSIID aTxnType, EditTxn **aResult) *aResult = new AddStyleSheetTxn(); else if (aTxnType.Equals(RemoveStyleSheetTxn::GetCID())) *aResult = new RemoveStyleSheetTxn(); + else if (aTxnType.Equals(SetDocTitleTxn::GetCID())) + *aResult = new SetDocTitleTxn(); else if (aTxnType.Equals(PlaceholderTxn::GetCID())) *aResult = new PlaceholderTxn(); else diff --git a/editor/base/makefile.win b/editor/base/makefile.win index d2d17baf351..af29fa9b071 100644 --- a/editor/base/makefile.win +++ b/editor/base/makefile.win @@ -126,6 +126,7 @@ CPPSRCS = $(CPPSRCS) \ nsWrapUtils.cpp \ TextEditorTest.cpp \ TypeInState.cpp \ + SetDocTitleTxn.cpp \ $(NULL) CPP_OBJS = $(CPP_OBJS) \ @@ -145,6 +146,7 @@ CPP_OBJS = $(CPP_OBJS) \ .\$(OBJDIR)\nsWrapUtils.obj \ .\$(OBJDIR)\TextEditorTest.obj \ .\$(OBJDIR)\TypeInState.obj \ + .\$(OBJDIR)\SetDocTitleTxn.obj \ $(NULL) # Enable Editor API Logging! diff --git a/editor/base/nsEditor.cpp b/editor/base/nsEditor.cpp index 9df3e0d1d21..fef60eda5ac 100644 --- a/editor/base/nsEditor.cpp +++ b/editor/base/nsEditor.cpp @@ -889,15 +889,23 @@ nsEditor::SaveFile(nsIFile *aFileSpec, PRBool aReplaceExisting, if (!diskDoc) return NS_ERROR_NO_INTERFACE; - // Should we prettyprint? PRUint32 flags = nsIDocumentEncoder::OutputEncodeEntities; - NS_WITH_SERVICE(nsIPref, prefService, kPrefServiceCID, &rv); - if (NS_SUCCEEDED(rv) && prefService) + if (aFormat == NS_LITERAL_STRING("text/plain")) { - PRBool prettyprint = PR_FALSE;; - rv = prefService->GetBoolPref("editor.prettyprint", &prettyprint); - if (NS_SUCCEEDED(rv) && prettyprint) - flags |= nsIDocumentEncoder::OutputFormatted; + // When saving in "text/plain" format, always do formatting + flags |= nsIDocumentEncoder::OutputFormatted; + } + else + { + // Should we prettyprint? Check the pref + NS_WITH_SERVICE(nsIPref, prefService, kPrefServiceCID, &rv); + if (NS_SUCCEEDED(rv) && prefService) + { + PRBool prettyprint = PR_FALSE;; + rv = prefService->GetBoolPref("editor.prettyprint", &prettyprint); + if (NS_SUCCEEDED(rv) && prettyprint) + flags |= nsIDocumentEncoder::OutputFormatted; + } } PRInt32 wrapColumn = 72; diff --git a/editor/base/nsEditorShell.cpp b/editor/base/nsEditorShell.cpp index 5bd402056fb..7db927b383d 100644 --- a/editor/base/nsEditorShell.cpp +++ b/editor/base/nsEditorShell.cpp @@ -583,7 +583,7 @@ nsEditorShell::PrepareDocumentForEditing(nsIDOMWindow* aDOMWindow, nsIURI *aUrl) } // Set the editor-specific Window caption - UpdateWindowTitle(); + UpdateWindowTitleAndRecentMenu(PR_TRUE); nsCOMPtr styleSheets = do_QueryInterface(mEditor); if (!styleSheets) @@ -878,16 +878,12 @@ nsEditorShell::SetEditorType(const PRUnichar *editorType) NS_IMETHODIMP nsEditorShell::GetEditorType(PRUnichar **_retval) { - *_retval = nsnull; + if (!_retval) + return NS_ERROR_NULL_POINTER; - nsresult err = NS_NOINTERFACE; - nsCOMPtr editor = do_QueryInterface(mEditor); + *_retval = mEditorTypeString.ToNewUnicode(); - if (editor) - { - *_retval = mEditorTypeString.ToNewUnicode(); - } - return err; + return NS_OK; } @@ -1701,11 +1697,20 @@ nsEditorShell::CheckOpenWindowForURLMatch(const PRUnichar* inFileURL, nsIDOMWind } NS_IMETHODIMP -nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) +nsEditorShell::SaveDocument(PRBool aSaveAs, PRBool aSaveCopy, const PRUnichar* aMimeType, PRBool *_retval) { nsresult res = NS_NOINTERFACE; *_retval = PR_FALSE; + NS_ENSURE_ARG_POINTER((aMimeType)); + + nsAutoString mimeType(aMimeType); + PRBool saveAsText = mimeType.EqualsWithConversion("text/plain"); + + // Currently, we only understand plain text and html + if (!mimeType.EqualsWithConversion("text/html") && !saveAsText) + return NS_ERROR_FAILURE; + switch (mEditorType) { case ePlainTextEditorType: @@ -1727,8 +1732,9 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) // find out if the doc already has a fileSpec associated with it. nsCOMPtr docFile; PRBool noFileSpec = (diskDoc->GetFileSpec(getter_AddRefs(docFile)) == NS_ERROR_NOT_INITIALIZED); - PRBool mustShowFileDialog = saveAs || noFileSpec; - PRBool replacing = !saveAs; + PRBool mustShowFileDialog = aSaveAs || noFileSpec; + PRBool replacing = !aSaveAs; + PRBool titleChanged = PR_FALSE; // Get existing document title nsAutoString title; @@ -1739,8 +1745,8 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) if (mustShowFileDialog) { - // Prompt for title ONLY if existing title is empty - if (!mMailCompose && (mEditorType == eHTMLTextEditorType) && (title.Length() == 0)) + // Prompt for title ONLY if existing title is empty and we are saving to HTML + if (!mMailCompose && (!saveAsText && mEditorType == eHTMLTextEditorType) && (title.Length() == 0)) { // Use a "prompt" common dialog to get title string from user NS_WITH_SERVICE(nsICommonDialogs, dialog, kCommonDialogsCID, &res); @@ -1770,11 +1776,12 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) *_retval = PR_FALSE; return NS_OK; } + // This sets title in HTML node + mEditor->SetDocumentTitle(titleUnicode); title = titleUnicode; nsCRT::free(titleUnicode); + titleChanged = PR_TRUE; } - // This sets title in HTML node - SetDocumentTitle(title.GetUnicode()); } nsCOMPtr filePicker = do_CreateInstance("@mozilla.org/filepicker;1", &res); @@ -1783,7 +1790,10 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) nsAutoString fileName; nsAutoString promptString; - GetBundleString(NS_LITERAL_STRING("SaveDocumentAs"), promptString); + if (saveAsText) + GetBundleString(NS_LITERAL_STRING("ExportToText"), promptString); + else + GetBundleString(NS_LITERAL_STRING("SaveDocumentAs"), promptString); // Initialize nsIFilePicker nsCOMPtr parentWindow(do_QueryReferent(mContentWindow)); @@ -1791,9 +1801,12 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) 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); + // Set filters according to the type of output + if (saveAsText) + filePicker->AppendFilters(nsIFilePicker::filterText); + else + filePicker->AppendFilters(nsIFilePicker::filterHTML); + filePicker->AppendFilters(nsIFilePicker::filterAll); if (noFileSpec) @@ -1802,10 +1815,6 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) 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) ) @@ -1836,15 +1845,18 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) } if (urlstring.Length() > 0) { - fileName.Assign( urlstring ); - fileName.AppendWithConversion(".html"); + title = urlstring; } } } } // Use page title as suggested name for new document - if (fileName.Length() == 0 && title.Length() > 0) + if (title.IsEmpty()) + { + title.AppendWithConversion("untitled"); + } + else { // Strip out quote character PRUnichar quote = (PRUnichar)'\"'; @@ -1852,9 +1864,13 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) //Replace "bad" filename characteres with "_" title.ReplaceChar(" .\\/@:", (PRUnichar)'_'); - fileName = title; - fileName.AppendWithConversion(".html"); } + + fileName = title; + if (saveAsText) + fileName.AppendWithConversion(".txt"); + else + fileName.AppendWithConversion(".html"); } else // have a file spec { @@ -1863,6 +1879,22 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) if (leafName.get() && *leafName) fileName.Assign(leafName); + if (saveAsText) + { + // Replace html-related extension with "txt" + PRInt32 index = fileName.RFind(".html", PR_TRUE); + if (index == -1) + index = fileName.RFind(".htm", PR_TRUE); + if (index == -1) + index = fileName.RFind(".shtml", PR_TRUE); + if (index > 0) + { + // Truncate after "." and append "txt" extension + fileName.SetLength(index+1); + fileName.AppendWithConversion("txt"); + } + } + nsCOMPtr parentPath; if (NS_SUCCEEDED(docFile->GetParent(getter_AddRefs(parentPath)))) { @@ -1884,6 +1916,8 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) if (dialogResult == nsIFilePicker::returnCancel) { // Note that *_retval = PR_FALSE at this point + if (titleChanged) + UpdateWindowTitleAndRecentMenu(PR_FALSE); return NS_OK; } replacing = (dialogResult == nsIFilePicker::returnReplace); @@ -1902,33 +1936,31 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) } // Set the new URL for the webshell - nsCOMPtr webShell(do_QueryInterface(mContentAreaDocShell)); - if (webShell) + if (!aSaveCopy) { - // would like to use nsIFile::GetURL here, but it is not implemented - // on all platforms - nsCOMPtr fileURL(do_CreateInstance(kStandardURLCID, &res)); - if (NS_FAILED(res)) return res; + nsCOMPtr webShell(do_QueryInterface(mContentAreaDocShell)); + if (webShell) + { + // would like to use nsIFile::GetURL here, but it is not implemented + // on all platforms + nsCOMPtr fileURL(do_CreateInstance(kStandardURLCID, &res)); + if (NS_FAILED(res)) return res; - res = fileURL->SetFile(docFile); - 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; + 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; + 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); + res = editor->SaveFile(docFile, replacing, aSaveCopy, mimeType); if (NS_FAILED(res)) { nsAutoString saveDocStr, failedStr; @@ -1938,11 +1970,11 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) } else { // File was saved successfully *_retval = PR_TRUE; - - // Update window title to show possibly different filename - if (mustShowFileDialog) - UpdateWindowTitle(); } + // Update window title to show possibly different filename + // This also covers problem that after undoing a title change, + // window title looses the extra [filename] part that this adds + UpdateWindowTitleAndRecentMenu(PR_TRUE); } break; } @@ -1952,6 +1984,7 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) return res; } + NS_IMETHODIMP nsEditorShell::CloseWindowWithoutSaving() { @@ -2094,7 +2127,7 @@ nsEditorShell::GetLocalFileURL(nsIDOMWindowInternal *parent, const PRUnichar *fi } nsresult -nsEditorShell::UpdateWindowTitle() +nsEditorShell::UpdateWindowTitleAndRecentMenu(PRBool aSaveToPrefs) { nsresult res = NS_ERROR_NOT_INITIALIZED; @@ -2137,6 +2170,17 @@ nsEditorShell::UpdateWindowTitle() NS_ASSERTION(contentAreaAsWin, "This object should implement nsIBaseWindow"); res = contentAreaAsWin->SetTitle(windowCaption.GetUnicode()); } + + // Rebuild Recent Pages menu and save any changed URLs or titles to editor prefs + // TODO: We need to pass on aSaveToPrefs to command, but must wait for + // new command system before we can do that. + // For now, don't update the menu at all if aSaveToPrefs is false + if (aSaveToPrefs) + { + nsAutoString commandName(NS_LITERAL_STRING("cmd_buildRecentPagesMenu")); + res = DoControllerCommand(commandName); + } + return res; } @@ -2197,107 +2241,14 @@ nsEditorShell::SetDocumentTitle(const PRUnichar *title) if (mEditorType != eHTMLTextEditorType) return NS_ERROR_NOT_IMPLEMENTED; - nsCOMPtr editor = do_QueryInterface(mEditor); - if (!editor) - return NS_ERROR_FAILURE; + res = mEditor->SetDocumentTitle(title); + if (NS_FAILED(res)) return res; - nsAutoString titleStr(title); - nsCOMPtr domDoc; - res = editor->GetDocument(getter_AddRefs(domDoc)); - - if (domDoc) - { - // Get existing document title node - nsCOMPtr HTMLDoc = do_QueryInterface(domDoc); - if (HTMLDoc) - { - // This sets the window title, and saves the title as a member varialble, - // but does NOT insert the 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; + // PR_FALSE means don't save menu to prefs + return UpdateWindowTitleAndRecentMenu(PR_FALSE); } + NS_IMETHODIMP nsEditorShell::CloneAttributes(nsIDOMNode *destNode, nsIDOMNode *sourceNode) { @@ -4342,7 +4293,7 @@ nsEditorShell::GetCellAt(nsIDOMElement *tableElement, PRInt32 rowIndex, PRInt32 nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor); if (tableEditor) { - result = tableEditor->GetCellAt(tableElement, rowIndex, colIndex, *_retval); + 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; @@ -4379,7 +4330,7 @@ nsEditorShell::GetCellDataAt(nsIDOMElement *tableElement, PRInt32 rowIndex, PRIn { nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor); if (tableEditor) - result = tableEditor->GetCellDataAt(tableElement, rowIndex, colIndex, *_retval, + result = tableEditor->GetCellDataAt(tableElement, rowIndex, colIndex, _retval, *aStartRowIndex, *aStartColIndex, *aRowSpan, *aColSpan, *aActualRowSpan, *aActualColSpan, @@ -4397,7 +4348,7 @@ nsEditorShell::GetCellDataAt(nsIDOMElement *tableElement, PRInt32 rowIndex, PRIn } NS_IMETHODIMP -nsEditorShell::GetFirstRow(nsIDOMElement *aTableElement, nsIDOMElement **_retval) +nsEditorShell::GetFirstRow(nsIDOMElement *aTableElement, nsIDOMNode **_retval) { if (!_retval || !aTableElement) return NS_ERROR_NULL_POINTER; @@ -4409,7 +4360,7 @@ nsEditorShell::GetFirstRow(nsIDOMElement *aTableElement, nsIDOMElement **_retval { nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor); if (tableEditor) - result = tableEditor->GetFirstRow(aTableElement, *_retval); + result = tableEditor->GetFirstRow(aTableElement, _retval); } break; default: @@ -4419,7 +4370,7 @@ nsEditorShell::GetFirstRow(nsIDOMElement *aTableElement, nsIDOMElement **_retval } NS_IMETHODIMP -nsEditorShell::GetNextRow(nsIDOMElement *aCurrentRow, nsIDOMElement **_retval) +nsEditorShell::GetNextRow(nsIDOMNode *aCurrentRow, nsIDOMNode **_retval) { if (!_retval || !*_retval || !aCurrentRow) return NS_ERROR_NULL_POINTER; @@ -4432,7 +4383,7 @@ nsEditorShell::GetNextRow(nsIDOMElement *aCurrentRow, nsIDOMElement **_retval) { nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor); if (tableEditor) - result = tableEditor->GetNextRow(aCurrentRow, *_retval); + result = tableEditor->GetNextRow(aCurrentRow, _retval); } break; default: diff --git a/editor/base/nsEditorShell.h b/editor/base/nsEditorShell.h index ca0149e0dfc..1eeb98200f9 100644 --- a/editor/base/nsEditorShell.h +++ b/editor/base/nsEditorShell.h @@ -153,7 +153,10 @@ class nsEditorShell : public nsIEditorShell, // Get the current document title an use it as part of the window title // Uses "(Untitled)" for empty title - nsresult UpdateWindowTitle(); + // Also rebuilds the "Recent Pages" menu. + // If aSaveToPrefs is true, then titles and URLs + // for menu are saved to prefs + nsresult UpdateWindowTitleAndRecentMenu(PRBool aSaveToPrefs); // Helper method which is called at the beginning of a new page load nsresult StartPageLoad(); @@ -241,7 +244,6 @@ class nsEditorShell : public nsIEditorShell, nsStringArray mDictionaryList; PRInt32 mDictionaryIndex; - }; #endif // nsEditorShell_h___ diff --git a/editor/base/nsHTMLEditor.cpp b/editor/base/nsHTMLEditor.cpp index 7758cf6cffb..56738ed5352 100644 --- a/editor/base/nsHTMLEditor.cpp +++ b/editor/base/nsHTMLEditor.cpp @@ -81,6 +81,7 @@ #include "nsInternetCiter.h" #include "nsISupportsPrimitives.h" #include "InsertTextTxn.h" +#include "SetDocTitleTxn.h" // netwerk #include "nsIURI.h" @@ -415,6 +416,25 @@ NS_IMETHODIMP nsHTMLEditor::InitRules() return res; } +NS_IMETHODIMP +nsHTMLEditor::SetDocumentTitle(const PRUnichar *aTitle) +{ + SetDocTitleTxn *txn; + nsresult result = TransactionFactory::GetNewTransaction(SetDocTitleTxn::GetCID(), (EditTxn **)&txn); + if (NS_SUCCEEDED(result)) + { + nsAutoString title(aTitle); + result = txn->Init(this, &title); + + if (NS_SUCCEEDED(result)) + { + result = nsEditor::Do(txn); + } + // The transaction system (if any) has taken ownwership of txn + NS_IF_RELEASE(txn); + } + return result; +} PRBool nsHTMLEditor::IsModifiable() { @@ -613,7 +633,7 @@ NS_IMETHODIMP nsHTMLEditor::TabInTable(PRBool inIsShift, PRBool *outHandled) &row, nsnull); if (NS_FAILED(res)) return res; // ...so that we can ask for first cell in that row... - res = GetCellAt(tblElement, row, 0, *(getter_AddRefs(cell))); + res = GetCellAt(tblElement, row, 0, getter_AddRefs(cell)); if (NS_FAILED(res)) return res; // ...and then set selection there. // (Note that normally you should use CollapseSelectionToDeepestNonTableFirstChild(), @@ -1792,7 +1812,7 @@ nsHTMLEditor::Align(const nsString& aAlignType) } NS_IMETHODIMP -nsHTMLEditor::GetElementOrParentByTagName(const nsString &aTagName, nsIDOMNode *aNode, nsIDOMElement** aReturn) +nsHTMLEditor::GetElementOrParentByTagName(const nsAReadableString& aTagName, nsIDOMNode *aNode, nsIDOMElement** aReturn) { if (aTagName.Length() == 0 || !aReturn ) return NS_ERROR_NULL_POINTER; @@ -1838,8 +1858,8 @@ nsHTMLEditor::GetElementOrParentByTagName(const nsString &aTagName, nsIDOMNode * { TagName.AssignWithConversion("a"); } - PRBool findTableCell = aTagName.EqualsIgnoreCase("td"); - PRBool findList = aTagName.EqualsIgnoreCase("list"); + PRBool findTableCell = TagName.EqualsWithConversion("td"); + PRBool findList = TagName.EqualsWithConversion("list"); // default is null - no element found *aReturn = nsnull; @@ -2159,13 +2179,14 @@ nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aRetu } NS_IMETHODIMP -nsHTMLEditor::CreateElementWithDefaults(const nsString& aTagName, nsIDOMElement** aReturn) +nsHTMLEditor::CreateElementWithDefaults(const nsAReadableString& aTagName, nsIDOMElement** aReturn) { nsresult res=NS_ERROR_NOT_INITIALIZED; if (aReturn) *aReturn = nsnull; if (aTagName.IsEmpty() || !aReturn) +// if (!aTagName || !aReturn) return NS_ERROR_NULL_POINTER; nsAutoString TagName(aTagName); diff --git a/editor/base/nsHTMLEditor.h b/editor/base/nsHTMLEditor.h index e469b35dcb4..2355b902410 100644 --- a/editor/base/nsHTMLEditor.h +++ b/editor/base/nsHTMLEditor.h @@ -143,9 +143,9 @@ public: NS_IMETHOD Indent(const nsString& aIndent); NS_IMETHOD Align(const nsString& aAlign); - NS_IMETHOD GetElementOrParentByTagName(const nsString& aTagName, nsIDOMNode *aNode, nsIDOMElement** aReturn); + NS_IMETHOD GetElementOrParentByTagName(const nsAReadableString& aTagName, nsIDOMNode *aNode, nsIDOMElement** aReturn); NS_IMETHOD GetSelectedElement(const nsString& aTagName, nsIDOMElement** aReturn); - NS_IMETHOD CreateElementWithDefaults(const nsString& aTagName, nsIDOMElement** aReturn); + NS_IMETHOD CreateElementWithDefaults(const nsAReadableString& aTagName, nsIDOMElement** aReturn); NS_IMETHOD GetNextElementByTagName(nsIDOMElement *aCurrentElement, const nsString *aTagName, nsIDOMElement **aReturn); @@ -204,14 +204,18 @@ public: NS_IMETHOD NormalizeTable(nsIDOMElement *aTable); NS_IMETHOD GetCellIndexes(nsIDOMElement *aCell, PRInt32& aRowIndex, PRInt32& aColIndex); NS_IMETHOD GetTableSize(nsIDOMElement *aTable, PRInt32& aRowCount, PRInt32& aColCount); - NS_IMETHOD GetCellAt(nsIDOMElement* aTable, PRInt32 aRowIndex, PRInt32 aColIndex, nsIDOMElement* &aCell); - NS_IMETHOD GetCellDataAt(nsIDOMElement* aTable, PRInt32 aRowIndex, PRInt32 aColIndex, nsIDOMElement* &aCell, + NS_IMETHOD GetCellAt(nsIDOMElement* aTable, PRInt32 aRowIndex, PRInt32 aColIndex, nsIDOMElement **aCell); + NS_IMETHOD GetCellDataAt(nsIDOMElement* aTable, PRInt32 aRowIndex, PRInt32 aColIndex, nsIDOMElement **aCell, PRInt32& aStartRowIndex, PRInt32& aStartColIndex, PRInt32& aRowSpan, PRInt32& aColSpan, PRInt32& aActualRowSpan, PRInt32& aActualColSpan, PRBool& aIsSelected); - NS_IMETHOD GetFirstRow(nsIDOMElement* aTableElement, nsIDOMElement* &aRow); - NS_IMETHOD GetNextRow(nsIDOMElement* aTableElement, nsIDOMElement* &aRow); + NS_IMETHOD GetFirstRow(nsIDOMElement* aTableElement, nsIDOMNode** aRowNode); + NS_IMETHOD GetNextRow(nsIDOMNode* aCurrentRowNode, nsIDOMNode** aRowNode); + NS_IMETHOD GetFirstCellInRow(nsIDOMNode* aRowNode, nsIDOMNode** aCellNode); + NS_IMETHOD GetNextCellInRow(nsIDOMNode* aCurrentCellNode, nsIDOMNode** aRowNode); + NS_IMETHOD GetLastCellInRow(nsIDOMNode* aRowNode, nsIDOMNode** aCellNode); + NS_IMETHOD SetSelectionAfterTableEdit(nsIDOMElement* aTable, PRInt32 aRow, PRInt32 aCol, PRInt32 aDirection, PRBool aSelected); NS_IMETHOD GetSelectedOrParentTableElement(nsIDOMElement* &aTableElement, nsString& aTagName, PRInt32 &aSelectedCount); @@ -237,6 +241,8 @@ public: // or calls into nsTextEditor to set the page background NS_IMETHOD SetBackgroundColor(const nsString& aColor); NS_IMETHOD SetBodyAttribute(const nsString& aAttr, const nsString& aValue); + // aTitle may be null or empty string to remove child contents of <title> + NS_IMETHOD SetDocumentTitle(const PRUnichar *aTitle); /* ------------ Overrides of nsEditor interface methods -------------- */ diff --git a/editor/base/nsHTMLEditorLog.cpp b/editor/base/nsHTMLEditorLog.cpp index 5108a87c663..74c6b7fcfd8 100644 --- a/editor/base/nsHTMLEditorLog.cpp +++ b/editor/base/nsHTMLEditorLog.cpp @@ -768,6 +768,25 @@ nsHTMLEditorLog::ApplyStyleSheet(const nsString& aURL, nsICSSStyleSheet **aStyle return nsHTMLEditor::ApplyStyleSheet(aURL, aStyleSheet); } +NS_IMETHODIMP +nsHTMLEditorLog::SetDocumentTitle(const PRUnichar* aTitle) +{ + nsAutoHTMLEditorLogLock logLock(this); + + if (!mLocked && mFileStream) + { + PrintSelection(); + + Write("window.editorShell.SetDocumentTitle(\""); + nsAutoString str(aTitle); + PrintUnicode(str); + Write("\");\n"); + Flush(); + } + + return nsHTMLEditor::SetDocumentTitle(aTitle); +} + NS_IMETHODIMP nsHTMLEditorLog::StartLogging(nsIFile *aLogFile) { diff --git a/editor/base/nsHTMLEditorLog.h b/editor/base/nsHTMLEditorLog.h index 6157e15168c..e4dc06639ad 100644 --- a/editor/base/nsHTMLEditorLog.h +++ b/editor/base/nsHTMLEditorLog.h @@ -81,6 +81,7 @@ public: NS_IMETHOD InsertAsCitedQuotation(const nsString& aQuotedText, const nsString& aCitation, PRBool aInsertHTML, const nsString& aCharset, nsIDOMNode** aNodeInserted); NS_IMETHOD ApplyStyleSheet(const nsString& aURL, nsICSSStyleSheet **aStyleSheet); + NS_IMETHOD SetDocumentTitle(const PRUnichar* aTitle); NS_IMETHOD SetBackgroundColor(const nsString& aColor); NS_IMETHOD SetBodyAttribute(const nsString& aAttr, const nsString& aValue); diff --git a/editor/composer/src/nsEditorShell.cpp b/editor/composer/src/nsEditorShell.cpp index 5bd402056fb..7db927b383d 100644 --- a/editor/composer/src/nsEditorShell.cpp +++ b/editor/composer/src/nsEditorShell.cpp @@ -583,7 +583,7 @@ nsEditorShell::PrepareDocumentForEditing(nsIDOMWindow* aDOMWindow, nsIURI *aUrl) } // Set the editor-specific Window caption - UpdateWindowTitle(); + UpdateWindowTitleAndRecentMenu(PR_TRUE); nsCOMPtr<nsIEditorStyleSheets> styleSheets = do_QueryInterface(mEditor); if (!styleSheets) @@ -878,16 +878,12 @@ nsEditorShell::SetEditorType(const PRUnichar *editorType) NS_IMETHODIMP nsEditorShell::GetEditorType(PRUnichar **_retval) { - *_retval = nsnull; + if (!_retval) + return NS_ERROR_NULL_POINTER; - nsresult err = NS_NOINTERFACE; - nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor); + *_retval = mEditorTypeString.ToNewUnicode(); - if (editor) - { - *_retval = mEditorTypeString.ToNewUnicode(); - } - return err; + return NS_OK; } @@ -1701,11 +1697,20 @@ nsEditorShell::CheckOpenWindowForURLMatch(const PRUnichar* inFileURL, nsIDOMWind } NS_IMETHODIMP -nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) +nsEditorShell::SaveDocument(PRBool aSaveAs, PRBool aSaveCopy, const PRUnichar* aMimeType, PRBool *_retval) { nsresult res = NS_NOINTERFACE; *_retval = PR_FALSE; + NS_ENSURE_ARG_POINTER((aMimeType)); + + nsAutoString mimeType(aMimeType); + PRBool saveAsText = mimeType.EqualsWithConversion("text/plain"); + + // Currently, we only understand plain text and html + if (!mimeType.EqualsWithConversion("text/html") && !saveAsText) + return NS_ERROR_FAILURE; + switch (mEditorType) { case ePlainTextEditorType: @@ -1727,8 +1732,9 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) // 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; + PRBool mustShowFileDialog = aSaveAs || noFileSpec; + PRBool replacing = !aSaveAs; + PRBool titleChanged = PR_FALSE; // Get existing document title nsAutoString title; @@ -1739,8 +1745,8 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) if (mustShowFileDialog) { - // Prompt for title ONLY if existing title is empty - if (!mMailCompose && (mEditorType == eHTMLTextEditorType) && (title.Length() == 0)) + // Prompt for title ONLY if existing title is empty and we are saving to HTML + if (!mMailCompose && (!saveAsText && mEditorType == eHTMLTextEditorType) && (title.Length() == 0)) { // Use a "prompt" common dialog to get title string from user NS_WITH_SERVICE(nsICommonDialogs, dialog, kCommonDialogsCID, &res); @@ -1770,11 +1776,12 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) *_retval = PR_FALSE; return NS_OK; } + // This sets title in HTML node + mEditor->SetDocumentTitle(titleUnicode); title = titleUnicode; nsCRT::free(titleUnicode); + titleChanged = PR_TRUE; } - // This sets title in HTML node - SetDocumentTitle(title.GetUnicode()); } nsCOMPtr<nsIFilePicker> filePicker = do_CreateInstance("@mozilla.org/filepicker;1", &res); @@ -1783,7 +1790,10 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) nsAutoString fileName; nsAutoString promptString; - GetBundleString(NS_LITERAL_STRING("SaveDocumentAs"), promptString); + if (saveAsText) + GetBundleString(NS_LITERAL_STRING("ExportToText"), promptString); + else + GetBundleString(NS_LITERAL_STRING("SaveDocumentAs"), promptString); // Initialize nsIFilePicker nsCOMPtr<nsIDOMWindowInternal> parentWindow(do_QueryReferent(mContentWindow)); @@ -1791,9 +1801,12 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) 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); + // Set filters according to the type of output + if (saveAsText) + filePicker->AppendFilters(nsIFilePicker::filterText); + else + filePicker->AppendFilters(nsIFilePicker::filterHTML); + filePicker->AppendFilters(nsIFilePicker::filterAll); if (noFileSpec) @@ -1802,10 +1815,6 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) 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) ) @@ -1836,15 +1845,18 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) } if (urlstring.Length() > 0) { - fileName.Assign( urlstring ); - fileName.AppendWithConversion(".html"); + title = urlstring; } } } } // Use page title as suggested name for new document - if (fileName.Length() == 0 && title.Length() > 0) + if (title.IsEmpty()) + { + title.AppendWithConversion("untitled"); + } + else { // Strip out quote character PRUnichar quote = (PRUnichar)'\"'; @@ -1852,9 +1864,13 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) //Replace "bad" filename characteres with "_" title.ReplaceChar(" .\\/@:", (PRUnichar)'_'); - fileName = title; - fileName.AppendWithConversion(".html"); } + + fileName = title; + if (saveAsText) + fileName.AppendWithConversion(".txt"); + else + fileName.AppendWithConversion(".html"); } else // have a file spec { @@ -1863,6 +1879,22 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) if (leafName.get() && *leafName) fileName.Assign(leafName); + if (saveAsText) + { + // Replace html-related extension with "txt" + PRInt32 index = fileName.RFind(".html", PR_TRUE); + if (index == -1) + index = fileName.RFind(".htm", PR_TRUE); + if (index == -1) + index = fileName.RFind(".shtml", PR_TRUE); + if (index > 0) + { + // Truncate after "." and append "txt" extension + fileName.SetLength(index+1); + fileName.AppendWithConversion("txt"); + } + } + nsCOMPtr<nsIFile> parentPath; if (NS_SUCCEEDED(docFile->GetParent(getter_AddRefs(parentPath)))) { @@ -1884,6 +1916,8 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) if (dialogResult == nsIFilePicker::returnCancel) { // Note that *_retval = PR_FALSE at this point + if (titleChanged) + UpdateWindowTitleAndRecentMenu(PR_FALSE); return NS_OK; } replacing = (dialogResult == nsIFilePicker::returnReplace); @@ -1902,33 +1936,31 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) } // Set the new URL for the webshell - nsCOMPtr<nsIWebShell> webShell(do_QueryInterface(mContentAreaDocShell)); - if (webShell) + if (!aSaveCopy) { - // 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; + 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; + res = fileURL->SetFile(docFile); + if (NS_FAILED(res)) return res; - nsXPIDLCString docURLSpec; - res = fileURL->GetSpec(getter_Copies(docURLSpec)); - 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; + 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); + res = editor->SaveFile(docFile, replacing, aSaveCopy, mimeType); if (NS_FAILED(res)) { nsAutoString saveDocStr, failedStr; @@ -1938,11 +1970,11 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) } else { // File was saved successfully *_retval = PR_TRUE; - - // Update window title to show possibly different filename - if (mustShowFileDialog) - UpdateWindowTitle(); } + // Update window title to show possibly different filename + // This also covers problem that after undoing a title change, + // window title looses the extra [filename] part that this adds + UpdateWindowTitleAndRecentMenu(PR_TRUE); } break; } @@ -1952,6 +1984,7 @@ nsEditorShell::SaveDocument(PRBool saveAs, PRBool saveCopy, PRBool *_retval) return res; } + NS_IMETHODIMP nsEditorShell::CloseWindowWithoutSaving() { @@ -2094,7 +2127,7 @@ nsEditorShell::GetLocalFileURL(nsIDOMWindowInternal *parent, const PRUnichar *fi } nsresult -nsEditorShell::UpdateWindowTitle() +nsEditorShell::UpdateWindowTitleAndRecentMenu(PRBool aSaveToPrefs) { nsresult res = NS_ERROR_NOT_INITIALIZED; @@ -2137,6 +2170,17 @@ nsEditorShell::UpdateWindowTitle() NS_ASSERTION(contentAreaAsWin, "This object should implement nsIBaseWindow"); res = contentAreaAsWin->SetTitle(windowCaption.GetUnicode()); } + + // Rebuild Recent Pages menu and save any changed URLs or titles to editor prefs + // TODO: We need to pass on aSaveToPrefs to command, but must wait for + // new command system before we can do that. + // For now, don't update the menu at all if aSaveToPrefs is false + if (aSaveToPrefs) + { + nsAutoString commandName(NS_LITERAL_STRING("cmd_buildRecentPagesMenu")); + res = DoControllerCommand(commandName); + } + return res; } @@ -2197,107 +2241,14 @@ nsEditorShell::SetDocumentTitle(const PRUnichar *title) if (mEditorType != eHTMLTextEditorType) return NS_ERROR_NOT_IMPLEMENTED; - nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor); - if (!editor) - return NS_ERROR_FAILURE; + res = mEditor->SetDocumentTitle(title); + if (NS_FAILED(res)) return res; - 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; + // PR_FALSE means don't save menu to prefs + return UpdateWindowTitleAndRecentMenu(PR_FALSE); } + NS_IMETHODIMP nsEditorShell::CloneAttributes(nsIDOMNode *destNode, nsIDOMNode *sourceNode) { @@ -4342,7 +4293,7 @@ nsEditorShell::GetCellAt(nsIDOMElement *tableElement, PRInt32 rowIndex, PRInt32 nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor); if (tableEditor) { - result = tableEditor->GetCellAt(tableElement, rowIndex, colIndex, *_retval); + 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; @@ -4379,7 +4330,7 @@ nsEditorShell::GetCellDataAt(nsIDOMElement *tableElement, PRInt32 rowIndex, PRIn { nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor); if (tableEditor) - result = tableEditor->GetCellDataAt(tableElement, rowIndex, colIndex, *_retval, + result = tableEditor->GetCellDataAt(tableElement, rowIndex, colIndex, _retval, *aStartRowIndex, *aStartColIndex, *aRowSpan, *aColSpan, *aActualRowSpan, *aActualColSpan, @@ -4397,7 +4348,7 @@ nsEditorShell::GetCellDataAt(nsIDOMElement *tableElement, PRInt32 rowIndex, PRIn } NS_IMETHODIMP -nsEditorShell::GetFirstRow(nsIDOMElement *aTableElement, nsIDOMElement **_retval) +nsEditorShell::GetFirstRow(nsIDOMElement *aTableElement, nsIDOMNode **_retval) { if (!_retval || !aTableElement) return NS_ERROR_NULL_POINTER; @@ -4409,7 +4360,7 @@ nsEditorShell::GetFirstRow(nsIDOMElement *aTableElement, nsIDOMElement **_retval { nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor); if (tableEditor) - result = tableEditor->GetFirstRow(aTableElement, *_retval); + result = tableEditor->GetFirstRow(aTableElement, _retval); } break; default: @@ -4419,7 +4370,7 @@ nsEditorShell::GetFirstRow(nsIDOMElement *aTableElement, nsIDOMElement **_retval } NS_IMETHODIMP -nsEditorShell::GetNextRow(nsIDOMElement *aCurrentRow, nsIDOMElement **_retval) +nsEditorShell::GetNextRow(nsIDOMNode *aCurrentRow, nsIDOMNode **_retval) { if (!_retval || !*_retval || !aCurrentRow) return NS_ERROR_NULL_POINTER; @@ -4432,7 +4383,7 @@ nsEditorShell::GetNextRow(nsIDOMElement *aCurrentRow, nsIDOMElement **_retval) { nsCOMPtr<nsITableEditor> tableEditor = do_QueryInterface(mEditor); if (tableEditor) - result = tableEditor->GetNextRow(aCurrentRow, *_retval); + result = tableEditor->GetNextRow(aCurrentRow, _retval); } break; default: diff --git a/editor/composer/src/nsEditorShell.h b/editor/composer/src/nsEditorShell.h index ca0149e0dfc..1eeb98200f9 100644 --- a/editor/composer/src/nsEditorShell.h +++ b/editor/composer/src/nsEditorShell.h @@ -153,7 +153,10 @@ class nsEditorShell : public nsIEditorShell, // Get the current document title an use it as part of the window title // Uses "(Untitled)" for empty title - nsresult UpdateWindowTitle(); + // Also rebuilds the "Recent Pages" menu. + // If aSaveToPrefs is true, then titles and URLs + // for menu are saved to prefs + nsresult UpdateWindowTitleAndRecentMenu(PRBool aSaveToPrefs); // Helper method which is called at the beginning of a new page load nsresult StartPageLoad(); @@ -241,7 +244,6 @@ class nsEditorShell : public nsIEditorShell, nsStringArray mDictionaryList; PRInt32 mDictionaryIndex; - }; #endif // nsEditorShell_h___ diff --git a/editor/libeditor/base/TransactionFactory.cpp b/editor/libeditor/base/TransactionFactory.cpp index 7c9833fbaf1..42198a6d1d5 100644 --- a/editor/libeditor/base/TransactionFactory.cpp +++ b/editor/libeditor/base/TransactionFactory.cpp @@ -35,6 +35,7 @@ #include "JoinElementTxn.h" #include "nsStyleSheetTxns.h" #include "IMETextTxn.h" +#include "SetDocTitleTxn.h" TransactionFactory::TransactionFactory() { @@ -75,6 +76,8 @@ TransactionFactory::GetNewTransaction(REFNSIID aTxnType, EditTxn **aResult) *aResult = new AddStyleSheetTxn(); else if (aTxnType.Equals(RemoveStyleSheetTxn::GetCID())) *aResult = new RemoveStyleSheetTxn(); + else if (aTxnType.Equals(SetDocTitleTxn::GetCID())) + *aResult = new SetDocTitleTxn(); else if (aTxnType.Equals(PlaceholderTxn::GetCID())) *aResult = new PlaceholderTxn(); else diff --git a/editor/libeditor/base/nsEditor.cpp b/editor/libeditor/base/nsEditor.cpp index 9df3e0d1d21..fef60eda5ac 100644 --- a/editor/libeditor/base/nsEditor.cpp +++ b/editor/libeditor/base/nsEditor.cpp @@ -889,15 +889,23 @@ nsEditor::SaveFile(nsIFile *aFileSpec, PRBool aReplaceExisting, if (!diskDoc) return NS_ERROR_NO_INTERFACE; - // Should we prettyprint? PRUint32 flags = nsIDocumentEncoder::OutputEncodeEntities; - NS_WITH_SERVICE(nsIPref, prefService, kPrefServiceCID, &rv); - if (NS_SUCCEEDED(rv) && prefService) + if (aFormat == NS_LITERAL_STRING("text/plain")) { - PRBool prettyprint = PR_FALSE;; - rv = prefService->GetBoolPref("editor.prettyprint", &prettyprint); - if (NS_SUCCEEDED(rv) && prettyprint) - flags |= nsIDocumentEncoder::OutputFormatted; + // When saving in "text/plain" format, always do formatting + flags |= nsIDocumentEncoder::OutputFormatted; + } + else + { + // Should we prettyprint? Check the pref + NS_WITH_SERVICE(nsIPref, prefService, kPrefServiceCID, &rv); + if (NS_SUCCEEDED(rv) && prefService) + { + PRBool prettyprint = PR_FALSE;; + rv = prefService->GetBoolPref("editor.prettyprint", &prettyprint); + if (NS_SUCCEEDED(rv) && prettyprint) + flags |= nsIDocumentEncoder::OutputFormatted; + } } PRInt32 wrapColumn = 72; diff --git a/editor/libeditor/html/nsHTMLEditor.cpp b/editor/libeditor/html/nsHTMLEditor.cpp index 7758cf6cffb..56738ed5352 100644 --- a/editor/libeditor/html/nsHTMLEditor.cpp +++ b/editor/libeditor/html/nsHTMLEditor.cpp @@ -81,6 +81,7 @@ #include "nsInternetCiter.h" #include "nsISupportsPrimitives.h" #include "InsertTextTxn.h" +#include "SetDocTitleTxn.h" // netwerk #include "nsIURI.h" @@ -415,6 +416,25 @@ NS_IMETHODIMP nsHTMLEditor::InitRules() return res; } +NS_IMETHODIMP +nsHTMLEditor::SetDocumentTitle(const PRUnichar *aTitle) +{ + SetDocTitleTxn *txn; + nsresult result = TransactionFactory::GetNewTransaction(SetDocTitleTxn::GetCID(), (EditTxn **)&txn); + if (NS_SUCCEEDED(result)) + { + nsAutoString title(aTitle); + result = txn->Init(this, &title); + + if (NS_SUCCEEDED(result)) + { + result = nsEditor::Do(txn); + } + // The transaction system (if any) has taken ownwership of txn + NS_IF_RELEASE(txn); + } + return result; +} PRBool nsHTMLEditor::IsModifiable() { @@ -613,7 +633,7 @@ NS_IMETHODIMP nsHTMLEditor::TabInTable(PRBool inIsShift, PRBool *outHandled) &row, nsnull); if (NS_FAILED(res)) return res; // ...so that we can ask for first cell in that row... - res = GetCellAt(tblElement, row, 0, *(getter_AddRefs(cell))); + res = GetCellAt(tblElement, row, 0, getter_AddRefs(cell)); if (NS_FAILED(res)) return res; // ...and then set selection there. // (Note that normally you should use CollapseSelectionToDeepestNonTableFirstChild(), @@ -1792,7 +1812,7 @@ nsHTMLEditor::Align(const nsString& aAlignType) } NS_IMETHODIMP -nsHTMLEditor::GetElementOrParentByTagName(const nsString &aTagName, nsIDOMNode *aNode, nsIDOMElement** aReturn) +nsHTMLEditor::GetElementOrParentByTagName(const nsAReadableString& aTagName, nsIDOMNode *aNode, nsIDOMElement** aReturn) { if (aTagName.Length() == 0 || !aReturn ) return NS_ERROR_NULL_POINTER; @@ -1838,8 +1858,8 @@ nsHTMLEditor::GetElementOrParentByTagName(const nsString &aTagName, nsIDOMNode * { TagName.AssignWithConversion("a"); } - PRBool findTableCell = aTagName.EqualsIgnoreCase("td"); - PRBool findList = aTagName.EqualsIgnoreCase("list"); + PRBool findTableCell = TagName.EqualsWithConversion("td"); + PRBool findList = TagName.EqualsWithConversion("list"); // default is null - no element found *aReturn = nsnull; @@ -2159,13 +2179,14 @@ nsHTMLEditor::GetSelectedElement(const nsString& aTagName, nsIDOMElement** aRetu } NS_IMETHODIMP -nsHTMLEditor::CreateElementWithDefaults(const nsString& aTagName, nsIDOMElement** aReturn) +nsHTMLEditor::CreateElementWithDefaults(const nsAReadableString& aTagName, nsIDOMElement** aReturn) { nsresult res=NS_ERROR_NOT_INITIALIZED; if (aReturn) *aReturn = nsnull; if (aTagName.IsEmpty() || !aReturn) +// if (!aTagName || !aReturn) return NS_ERROR_NULL_POINTER; nsAutoString TagName(aTagName); diff --git a/editor/libeditor/html/nsHTMLEditor.h b/editor/libeditor/html/nsHTMLEditor.h index e469b35dcb4..2355b902410 100644 --- a/editor/libeditor/html/nsHTMLEditor.h +++ b/editor/libeditor/html/nsHTMLEditor.h @@ -143,9 +143,9 @@ public: NS_IMETHOD Indent(const nsString& aIndent); NS_IMETHOD Align(const nsString& aAlign); - NS_IMETHOD GetElementOrParentByTagName(const nsString& aTagName, nsIDOMNode *aNode, nsIDOMElement** aReturn); + NS_IMETHOD GetElementOrParentByTagName(const nsAReadableString& aTagName, nsIDOMNode *aNode, nsIDOMElement** aReturn); NS_IMETHOD GetSelectedElement(const nsString& aTagName, nsIDOMElement** aReturn); - NS_IMETHOD CreateElementWithDefaults(const nsString& aTagName, nsIDOMElement** aReturn); + NS_IMETHOD CreateElementWithDefaults(const nsAReadableString& aTagName, nsIDOMElement** aReturn); NS_IMETHOD GetNextElementByTagName(nsIDOMElement *aCurrentElement, const nsString *aTagName, nsIDOMElement **aReturn); @@ -204,14 +204,18 @@ public: NS_IMETHOD NormalizeTable(nsIDOMElement *aTable); NS_IMETHOD GetCellIndexes(nsIDOMElement *aCell, PRInt32& aRowIndex, PRInt32& aColIndex); NS_IMETHOD GetTableSize(nsIDOMElement *aTable, PRInt32& aRowCount, PRInt32& aColCount); - NS_IMETHOD GetCellAt(nsIDOMElement* aTable, PRInt32 aRowIndex, PRInt32 aColIndex, nsIDOMElement* &aCell); - NS_IMETHOD GetCellDataAt(nsIDOMElement* aTable, PRInt32 aRowIndex, PRInt32 aColIndex, nsIDOMElement* &aCell, + NS_IMETHOD GetCellAt(nsIDOMElement* aTable, PRInt32 aRowIndex, PRInt32 aColIndex, nsIDOMElement **aCell); + NS_IMETHOD GetCellDataAt(nsIDOMElement* aTable, PRInt32 aRowIndex, PRInt32 aColIndex, nsIDOMElement **aCell, PRInt32& aStartRowIndex, PRInt32& aStartColIndex, PRInt32& aRowSpan, PRInt32& aColSpan, PRInt32& aActualRowSpan, PRInt32& aActualColSpan, PRBool& aIsSelected); - NS_IMETHOD GetFirstRow(nsIDOMElement* aTableElement, nsIDOMElement* &aRow); - NS_IMETHOD GetNextRow(nsIDOMElement* aTableElement, nsIDOMElement* &aRow); + NS_IMETHOD GetFirstRow(nsIDOMElement* aTableElement, nsIDOMNode** aRowNode); + NS_IMETHOD GetNextRow(nsIDOMNode* aCurrentRowNode, nsIDOMNode** aRowNode); + NS_IMETHOD GetFirstCellInRow(nsIDOMNode* aRowNode, nsIDOMNode** aCellNode); + NS_IMETHOD GetNextCellInRow(nsIDOMNode* aCurrentCellNode, nsIDOMNode** aRowNode); + NS_IMETHOD GetLastCellInRow(nsIDOMNode* aRowNode, nsIDOMNode** aCellNode); + NS_IMETHOD SetSelectionAfterTableEdit(nsIDOMElement* aTable, PRInt32 aRow, PRInt32 aCol, PRInt32 aDirection, PRBool aSelected); NS_IMETHOD GetSelectedOrParentTableElement(nsIDOMElement* &aTableElement, nsString& aTagName, PRInt32 &aSelectedCount); @@ -237,6 +241,8 @@ public: // or calls into nsTextEditor to set the page background NS_IMETHOD SetBackgroundColor(const nsString& aColor); NS_IMETHOD SetBodyAttribute(const nsString& aAttr, const nsString& aValue); + // aTitle may be null or empty string to remove child contents of <title> + NS_IMETHOD SetDocumentTitle(const PRUnichar *aTitle); /* ------------ Overrides of nsEditor interface methods -------------- */ diff --git a/editor/libeditor/html/nsHTMLEditorLog.cpp b/editor/libeditor/html/nsHTMLEditorLog.cpp index 5108a87c663..74c6b7fcfd8 100644 --- a/editor/libeditor/html/nsHTMLEditorLog.cpp +++ b/editor/libeditor/html/nsHTMLEditorLog.cpp @@ -768,6 +768,25 @@ nsHTMLEditorLog::ApplyStyleSheet(const nsString& aURL, nsICSSStyleSheet **aStyle return nsHTMLEditor::ApplyStyleSheet(aURL, aStyleSheet); } +NS_IMETHODIMP +nsHTMLEditorLog::SetDocumentTitle(const PRUnichar* aTitle) +{ + nsAutoHTMLEditorLogLock logLock(this); + + if (!mLocked && mFileStream) + { + PrintSelection(); + + Write("window.editorShell.SetDocumentTitle(\""); + nsAutoString str(aTitle); + PrintUnicode(str); + Write("\");\n"); + Flush(); + } + + return nsHTMLEditor::SetDocumentTitle(aTitle); +} + NS_IMETHODIMP nsHTMLEditorLog::StartLogging(nsIFile *aLogFile) { diff --git a/editor/libeditor/html/nsHTMLEditorLog.h b/editor/libeditor/html/nsHTMLEditorLog.h index 6157e15168c..e4dc06639ad 100644 --- a/editor/libeditor/html/nsHTMLEditorLog.h +++ b/editor/libeditor/html/nsHTMLEditorLog.h @@ -81,6 +81,7 @@ public: NS_IMETHOD InsertAsCitedQuotation(const nsString& aQuotedText, const nsString& aCitation, PRBool aInsertHTML, const nsString& aCharset, nsIDOMNode** aNodeInserted); NS_IMETHOD ApplyStyleSheet(const nsString& aURL, nsICSSStyleSheet **aStyleSheet); + NS_IMETHOD SetDocumentTitle(const PRUnichar* aTitle); NS_IMETHOD SetBackgroundColor(const nsString& aColor); NS_IMETHOD SetBodyAttribute(const nsString& aAttr, const nsString& aValue);