зеркало из https://github.com/mozilla/pjs.git
Fix for bug #6254 (Find/Replace needs to be implemented.)
First pass implementation of Find and Replace. sr=sfraser@netscape.com r=ducarroz@netscape.com New Files: editor/txtsvc/macbuild/txtsvcIDL.mcp editor/txtsvc/public/MANIFEST_IDL editor/txtsvc/public/nsIFindAndReplace.idl editor/txtsvc/src/nsFindAndReplace.cpp editor/txtsvc/src/nsFindAndReplace.h xpfe/components/find/resources/replacedialog.js xpfe/components/find/resources/replacedialog.xul xpfe/components/find/resources/locale/en-US/replacedialog.dtd Modified Files: build/mac/build_scripts/MozillaBuildList.pm editor/base/nsEditorShell.cpp editor/idl/nsIEditorShell.idl editor/txtsvc/macbuild/txtsvc.mcp editor/txtsvc/public/Makefile.in editor/txtsvc/public/makefile.win editor/txtsvc/public/MANIFEST editor/txtsvc/src/Makefile.in editor/txtsvc/src/makefile.win editor/txtsvc/src/nsTextServicesFactory.cpp editor/ui/composer/content/ComposerCommands.js editor/ui/composer/content/editor.js editor/ui/composer/content/editorOverlay.xul editor/ui/composer/locale/en-US/editorOverlay.dtd mailnews/compose/resources/content/messengercompose.xul mailnews/compose/resources/content/MsgComposeCommands.js mailnews/compose/resources/locale/en-US/messengercompose.dtd xpfe/components/jar.mn xpfe/components/find/public/nsIFindComponent.idl xpfe/components/find/public/nsISearchContext.idl xpfe/components/find/resources/makefile.win xpfe/components/find/resources/MANIFEST xpfe/components/find/resources/locale/en-US/MANIFEST xpfe/components/find/src/nsFindComponent.cpp xpfe/components/find/src/nsFindComponent.h
This commit is contained in:
Родитель
7d6fd5e381
Коммит
b24b2c40c3
|
@ -670,6 +670,7 @@ sub BuildClientDist()
|
|||
InstallFromManifest(":mozilla:editor:txmgr:idl:MANIFEST", "$distdirectory:idl:");
|
||||
InstallFromManifest(":mozilla:editor:public:MANIFEST", "$distdirectory:editor:");
|
||||
InstallFromManifest(":mozilla:editor:txmgr:public:MANIFEST", "$distdirectory:editor:txmgr");
|
||||
InstallFromManifest(":mozilla:editor:txtsvc:public:MANIFEST_IDL", "$distdirectory:idl:");
|
||||
InstallFromManifest(":mozilla:editor:txtsvc:public:MANIFEST", "$distdirectory:editor:txtsvc");
|
||||
|
||||
#SILENTDL
|
||||
|
@ -918,6 +919,7 @@ sub BuildIDLProjects()
|
|||
BuildIDLProject(":mozilla:widget:macbuild:widgetIDL.mcp", "widget");
|
||||
BuildIDLProject(":mozilla:editor:macbuild:EditorIDL.mcp", "editor");
|
||||
BuildIDLProject(":mozilla:editor:txmgr:macbuild:txmgrIDL.mcp", "txmgr");
|
||||
BuildIDLProject(":mozilla:editor:txtsvc:macbuild:txtsvcIDL.mcp", "txtsvc");
|
||||
BuildIDLProject(":mozilla:profile:macbuild:ProfileServicesIDL.mcp", "profileservices");
|
||||
BuildIDLProject(":mozilla:profile:pref-migrator:macbuild:prefmigratorIDL.mcp", "prefm");
|
||||
|
||||
|
|
|
@ -2920,7 +2920,7 @@ nsEditorShell::DoFind(PRBool aFindNext)
|
|||
return NS_ERROR_NOT_INITIALIZED;
|
||||
nsCOMPtr<nsIDOMWindowInternal> cwP = do_QueryReferent(mContentWindow);
|
||||
if (!cwP) return NS_ERROR_NOT_INITIALIZED;
|
||||
rv = findComponent->CreateContext(cwP, nsnull, getter_AddRefs(mSearchContext));
|
||||
rv = findComponent->CreateContext(cwP, this, getter_AddRefs(mSearchContext));
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
|
@ -2946,6 +2946,34 @@ 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
|
||||
|
|
|
@ -2920,7 +2920,7 @@ nsEditorShell::DoFind(PRBool aFindNext)
|
|||
return NS_ERROR_NOT_INITIALIZED;
|
||||
nsCOMPtr<nsIDOMWindowInternal> cwP = do_QueryReferent(mContentWindow);
|
||||
if (!cwP) return NS_ERROR_NOT_INITIALIZED;
|
||||
rv = findComponent->CreateContext(cwP, nsnull, getter_AddRefs(mSearchContext));
|
||||
rv = findComponent->CreateContext(cwP, this, getter_AddRefs(mSearchContext));
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
|
@ -2946,6 +2946,34 @@ 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
|
||||
|
|
|
@ -174,6 +174,7 @@ interface nsIEditorShell : nsISupports
|
|||
|
||||
void Find();
|
||||
void FindNext();
|
||||
void Replace();
|
||||
|
||||
/* General Utilities */
|
||||
|
||||
|
|
|
@ -23,14 +23,22 @@
|
|||
#include "nsIGenericFactory.h"
|
||||
|
||||
#include "nsTextServicesDocument.h"
|
||||
#include "nsFindAndReplace.h"
|
||||
#include "nsTextServicesCID.h"
|
||||
|
||||
#define NS_TEXTSERVICESFINDANDREPLACE_CID \
|
||||
{ /* 8B0EEFE1-C4AE-11d4-A401-000064657374 */ \
|
||||
0x8b0eefe1, 0xc4ae, 0x11d4, \
|
||||
{ 0xa4, 0x1, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Define the contructor function for the objects
|
||||
//
|
||||
// NOTE: This creates an instance of objects by using the default constructor
|
||||
//
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsTextServicesDocument)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFindAndReplace)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Define a table of CIDs implemented by this module along with other
|
||||
|
@ -38,7 +46,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsTextServicesDocument)
|
|||
// class name.
|
||||
//
|
||||
static nsModuleComponentInfo components[] = {
|
||||
{ NULL, NS_TEXTSERVICESDOCUMENT_CID, NULL, nsTextServicesDocumentConstructor },
|
||||
{ NULL, NS_TEXTSERVICESDOCUMENT_CID, "@mozilla.org/textservices/textservicesdocument;1", nsTextServicesDocumentConstructor },
|
||||
{ NULL, NS_TEXTSERVICESFINDANDREPLACE_CID, NS_FINDANDREPLACE_CONTRACTID, nsFindAndReplaceConstructor },
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -35,6 +35,10 @@ EXPORTS = \
|
|||
nsTextServicesCID.h \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIFindAndReplace.idl \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS))
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -31,5 +31,9 @@ EXPORTS = \
|
|||
|
||||
MODULE = txtsvc
|
||||
|
||||
XPIDLSRCS = \
|
||||
.\nsIFindAndReplace.idl \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/* -*- 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.org 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 "nsISupports.idl"
|
||||
|
||||
interface nsITextServicesDocument;
|
||||
|
||||
%{ C++
|
||||
#define NS_FINDANDREPLACE_CONTRACTID "@mozilla.org/textservices/findandreplace;1"
|
||||
%} C++
|
||||
|
||||
[scriptable, uuid(E0178A21-B9A2-11d4-A3FF-000064657374)]
|
||||
interface nsIFindAndReplace : nsISupports
|
||||
{
|
||||
[noscript] attribute nsITextServicesDocument tsDoc;
|
||||
attribute boolean findBackwards;
|
||||
attribute boolean caseSensitive;
|
||||
attribute boolean wrapFind;
|
||||
attribute boolean entireWord;
|
||||
readonly attribute boolean replaceEnabled;
|
||||
|
||||
/**
|
||||
* Find some text in the current context. The implementation is
|
||||
* responsible for performing the find and highliting the text.
|
||||
* @param aFindText The text to search for.
|
||||
* @retval Returns true if an instance of aFindText was found.
|
||||
*/
|
||||
boolean Find(in wstring aFindText);
|
||||
|
||||
/**
|
||||
* Finds the text specified by aFindText and replaces it with
|
||||
* the text specified by aReplaceText. The implementation is responsible
|
||||
* for performing the find, replacing the text, and finding the
|
||||
* next instance.
|
||||
* @param aFindText The text to search for.
|
||||
* @param aReplaceText The text to replace aFindText with.
|
||||
* @param aAllOccurrences If true, the Replace() call will replace all
|
||||
* instances of aFindText in the document with a ReplaceText.
|
||||
* @retval Returns true if another instance of aFindText was found.
|
||||
*/
|
||||
boolean Replace(in wstring aFindText, in wstring aReplaceText, in boolean aAllOccurrences);
|
||||
};
|
|
@ -32,6 +32,7 @@ IS_COMPONENT = 1
|
|||
REQUIRES = xpcom editor layout dom js locale widget
|
||||
|
||||
CPPSRCS = \
|
||||
nsFindAndReplace.cpp \
|
||||
nsTextServicesDocument.cpp \
|
||||
nsTextServicesFactory.cpp \
|
||||
nsTSDNotifier.cpp \
|
||||
|
|
|
@ -25,12 +25,14 @@ DEPTH=..\..\..
|
|||
LIBRARY_NAME=txtsvc
|
||||
|
||||
CPPSRCS = \
|
||||
nsFindAndReplace.cpp \
|
||||
nsTextServicesDocument.cpp \
|
||||
nsTextServicesFactory.cpp \
|
||||
nsTSDNotifier.cpp \
|
||||
$(NULL)
|
||||
|
||||
CPP_OBJS = \
|
||||
.\$(OBJDIR)\nsFindAndReplace.obj \
|
||||
.\$(OBJDIR)\nsTextServicesDocument.obj \
|
||||
.\$(OBJDIR)\nsTextServicesFactory.obj \
|
||||
.\$(OBJDIR)\nsTSDNotifier.obj \
|
||||
|
|
|
@ -0,0 +1,741 @@
|
|||
/* -*- 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.org 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 "nsFindAndReplace.h"
|
||||
#include "nsString.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsFindAndReplace, nsIFindAndReplace)
|
||||
|
||||
nsFindAndReplace::nsFindAndReplace()
|
||||
: mFindBackwards(PR_FALSE)
|
||||
, mCaseSensitive(PR_FALSE)
|
||||
, mWrapFind(PR_FALSE)
|
||||
, mEntireWord(PR_FALSE)
|
||||
, mStartBlockIndex(0)
|
||||
, mStartSelOffset(0)
|
||||
, mCurrentBlockIndex(0)
|
||||
, mCurrentSelOffset(0)
|
||||
, mWrappedOnce(PR_FALSE)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
}
|
||||
|
||||
nsFindAndReplace::~nsFindAndReplace()
|
||||
{
|
||||
/* destructor code */
|
||||
}
|
||||
|
||||
/* [noscript] attribute nsITextServicesDocument tsDoc; */
|
||||
NS_IMETHODIMP
|
||||
nsFindAndReplace::GetTsDoc(nsITextServicesDocument * *aTsDoc)
|
||||
{
|
||||
if (!aTsDoc)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
*aTsDoc = mTsDoc;
|
||||
NS_IF_ADDREF((*aTsDoc));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsFindAndReplace::SetTsDoc(nsITextServicesDocument * aTsDoc)
|
||||
{
|
||||
mTsDoc = aTsDoc;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute boolean findBackwards; */
|
||||
NS_IMETHODIMP
|
||||
nsFindAndReplace::GetFindBackwards(PRBool *aFindBackwards)
|
||||
{
|
||||
if (!aFindBackwards)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
*aFindBackwards = mFindBackwards;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsFindAndReplace::SetFindBackwards(PRBool aFindBackwards)
|
||||
{
|
||||
mFindBackwards = aFindBackwards;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute boolean caseSensitive; */
|
||||
NS_IMETHODIMP
|
||||
nsFindAndReplace::GetCaseSensitive(PRBool *aCaseSensitive)
|
||||
{
|
||||
if (!aCaseSensitive)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
*aCaseSensitive = mCaseSensitive;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsFindAndReplace::SetCaseSensitive(PRBool aCaseSensitive)
|
||||
{
|
||||
mCaseSensitive = aCaseSensitive;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute boolean wrapFind; */
|
||||
NS_IMETHODIMP
|
||||
nsFindAndReplace::GetWrapFind(PRBool *aWrapFind)
|
||||
{
|
||||
if (!aWrapFind)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
*aWrapFind = mWrapFind;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsFindAndReplace::SetWrapFind(PRBool aWrapFind)
|
||||
{
|
||||
mWrapFind = aWrapFind;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute boolean entireWord; */
|
||||
NS_IMETHODIMP
|
||||
nsFindAndReplace::GetEntireWord(PRBool *aEntireWord)
|
||||
{
|
||||
if (!aEntireWord)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
*aEntireWord = mEntireWord;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsFindAndReplace::SetEntireWord(PRBool aEntireWord)
|
||||
{
|
||||
mEntireWord = aEntireWord;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute boolean replaceEnabled; */
|
||||
NS_IMETHODIMP
|
||||
nsFindAndReplace::GetReplaceEnabled(PRBool *aReplaceEnabled)
|
||||
{
|
||||
if (!aReplaceEnabled)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
*aReplaceEnabled = PR_FALSE;
|
||||
|
||||
nsresult result = NS_OK;
|
||||
|
||||
if (mTsDoc)
|
||||
result = mTsDoc->CanEdit(aReplaceEnabled);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* boolean Find (in wstring aFindText); */
|
||||
NS_IMETHODIMP nsFindAndReplace::Find(const PRUnichar *aFindText, PRBool *aDidFind)
|
||||
{
|
||||
if (!aFindText || !aDidFind)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (!mTsDoc)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
nsAutoString findStr(aFindText);
|
||||
if (!mCaseSensitive)
|
||||
findStr.ToLowerCase();
|
||||
|
||||
nsresult result = SetupDocForFind(mTsDoc, &mStartSelOffset);
|
||||
if (NS_FAILED(result))
|
||||
return result;
|
||||
|
||||
// find out where we started
|
||||
result = GetCurrentBlockIndex(mTsDoc, &mStartBlockIndex);
|
||||
if (NS_FAILED(result))
|
||||
return result;
|
||||
|
||||
// and set the starting position again (hopefully, in future we won't have to do this)
|
||||
result = SetupDocForFind(mTsDoc, &mStartSelOffset);
|
||||
if (NS_FAILED(result))
|
||||
return result;
|
||||
|
||||
mCurrentBlockIndex = mStartBlockIndex;
|
||||
mCurrentSelOffset = mStartSelOffset;
|
||||
mWrappedOnce = PR_FALSE;
|
||||
|
||||
return DoFind(mTsDoc, findStr, aDidFind);
|
||||
}
|
||||
|
||||
/* boolean Replace (in wstring aFindText, in wstring aReplaceText, in boolean aAllOccurrences); */
|
||||
NS_IMETHODIMP
|
||||
nsFindAndReplace::Replace(const PRUnichar *aFindText, const PRUnichar *aReplaceText, PRBool aAllOccurrences, PRBool *aDidFind)
|
||||
{
|
||||
if (!aFindText || !aReplaceText || !aDidFind)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
*aDidFind = PR_FALSE;
|
||||
|
||||
if (!mTsDoc)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
PRBool enabled;
|
||||
|
||||
GetReplaceEnabled(&enabled);
|
||||
|
||||
if (!enabled)
|
||||
return NS_OK;
|
||||
|
||||
nsAutoString findStr(aFindText);
|
||||
if (!mCaseSensitive)
|
||||
findStr.ToLowerCase();
|
||||
|
||||
nsresult result = SetupDocForReplace(mTsDoc, findStr, &mStartSelOffset);
|
||||
if (NS_FAILED(result))
|
||||
return result;
|
||||
|
||||
// find out where we started
|
||||
result = GetCurrentBlockIndex(mTsDoc, &mStartBlockIndex);
|
||||
if (NS_FAILED(result))
|
||||
return result;
|
||||
|
||||
// and set the starting position again (hopefully, in future we won't have to do this)
|
||||
result = SetupDocForReplace(mTsDoc, findStr, &mStartSelOffset);
|
||||
if (NS_FAILED(result))
|
||||
return result;
|
||||
|
||||
mCurrentBlockIndex = mStartBlockIndex;
|
||||
mCurrentSelOffset = mStartSelOffset;
|
||||
mWrappedOnce = PR_FALSE;
|
||||
|
||||
nsAutoString replaceStr(aReplaceText);
|
||||
PRBool didReplace = PR_FALSE;
|
||||
|
||||
// Keep looping until DoFind() fails to find another instance
|
||||
// of the find string or has looped through the entire document.
|
||||
|
||||
do
|
||||
{
|
||||
result = DoFind(mTsDoc, findStr, aDidFind);
|
||||
|
||||
if (NS_FAILED(result))
|
||||
break;
|
||||
|
||||
if (!*aDidFind || (didReplace && !aAllOccurrences))
|
||||
break;
|
||||
|
||||
if (replaceStr.Length() == 0)
|
||||
result = mTsDoc->DeleteSelection();
|
||||
else
|
||||
{
|
||||
result = mTsDoc->InsertText(&replaceStr);
|
||||
|
||||
// DoFind() sets mCurrentSelOffset to the beginning
|
||||
// of the selection. If we are searching in the forward
|
||||
// direction, set the offset after the string we just
|
||||
// inserted so that we don't search through it when we
|
||||
// call DoFind() again.
|
||||
|
||||
if (!mFindBackwards)
|
||||
mCurrentSelOffset += replaceStr.Length();
|
||||
}
|
||||
|
||||
if (NS_FAILED(result))
|
||||
break;
|
||||
|
||||
didReplace = PR_TRUE;
|
||||
}
|
||||
while (*aDidFind);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// CharsMatch
|
||||
//
|
||||
// Compare chars. Match if both are whitespace, or both are
|
||||
// non whitespace and same char.
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
inline static PRBool
|
||||
CharsMatch(PRUnichar c1, PRUnichar c2)
|
||||
{
|
||||
return (nsCRT::IsAsciiSpace(c1) && nsCRT::IsAsciiSpace(c2)) || (c1 == c2);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// FindInString
|
||||
//
|
||||
// Routine to search in an nsString which is smart about extra
|
||||
// whitespace, can search backwards, and do case insensitive search.
|
||||
//
|
||||
// This uses a brute-force algorithm, which should be sufficient
|
||||
// for our purposes (text searching)
|
||||
//
|
||||
// searchStr contains the text from a content node, which can contain
|
||||
// extra white space between words, which we have to deal with.
|
||||
// The offsets passed in and back are offsets into searchStr,
|
||||
// and thus include extra white space.
|
||||
//
|
||||
// If we are ignoring case, the strings have already been lowercased
|
||||
// at this point.
|
||||
//
|
||||
// startOffset is the offset in the search string to start searching
|
||||
// at. If -1, it means search from the start (forwards) or end (backwards).
|
||||
//
|
||||
// Returns -1 if the string is not found, or if the pattern is an
|
||||
// empty string, or if startOffset is off the end of the string.
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
static PRInt32 FindInString(const nsString &searchStr, const nsString &patternStr,
|
||||
PRInt32 startOffset, PRBool searchBackwards)
|
||||
{
|
||||
PRInt32 foundOffset = -1;
|
||||
PRInt32 patternLen = patternStr.Length();
|
||||
PRInt32 searchStrLen = searchStr.Length();
|
||||
|
||||
if (patternLen == 0) // pattern is empty
|
||||
return -1;
|
||||
|
||||
if (startOffset < 0)
|
||||
startOffset = (searchBackwards) ? searchStrLen : 0;
|
||||
|
||||
if (startOffset > searchStrLen) // bad start offset
|
||||
return -1;
|
||||
|
||||
if (patternLen > searchStrLen) // pattern is longer than string to search
|
||||
return -1;
|
||||
|
||||
const PRUnichar *searchBuf = searchStr.GetUnicode();
|
||||
const PRUnichar *patternBuf = patternStr.GetUnicode();
|
||||
|
||||
const PRUnichar *searchEnd = searchBuf + searchStrLen;
|
||||
const PRUnichar *patEnd = patternBuf + patternLen;
|
||||
|
||||
if (searchBackwards)
|
||||
{
|
||||
// searching backwards
|
||||
const PRUnichar *s = searchBuf + startOffset - patternLen;
|
||||
|
||||
while (s >= searchBuf)
|
||||
{
|
||||
if (CharsMatch(*patternBuf, *s)) // start potential match
|
||||
{
|
||||
const PRUnichar *t = s;
|
||||
const PRUnichar *p = patternBuf;
|
||||
PRInt32 curMatchOffset = t - searchBuf;
|
||||
PRBool inWhitespace = nsCRT::IsAsciiSpace(*p);
|
||||
|
||||
while (p < patEnd && CharsMatch(*p, *t))
|
||||
{
|
||||
if (inWhitespace && !nsCRT::IsAsciiSpace(*p))
|
||||
{
|
||||
// leaving p whitespace. Eat up addition whitespace in s
|
||||
while (t < searchEnd - 1 && nsCRT::IsAsciiSpace(*(t + 1)))
|
||||
t ++;
|
||||
|
||||
inWhitespace = PR_FALSE;
|
||||
}
|
||||
else
|
||||
inWhitespace = nsCRT::IsAsciiSpace(*p);
|
||||
|
||||
t ++;
|
||||
p ++;
|
||||
}
|
||||
|
||||
if (p == patEnd)
|
||||
{
|
||||
foundOffset = curMatchOffset;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// could be smart about decrementing s here
|
||||
}
|
||||
|
||||
s --;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// searching forwards
|
||||
|
||||
const PRUnichar *s = &searchBuf[startOffset];
|
||||
|
||||
while (s < searchEnd)
|
||||
{
|
||||
if (CharsMatch(*patternBuf, *s)) // start potential match
|
||||
{
|
||||
const PRUnichar *t = s;
|
||||
const PRUnichar *p = patternBuf;
|
||||
PRInt32 curMatchOffset = t - searchBuf;
|
||||
PRBool inWhitespace = nsCRT::IsAsciiSpace(*p);
|
||||
|
||||
while (p < patEnd && CharsMatch(*p, *t))
|
||||
{
|
||||
if (inWhitespace && !nsCRT::IsAsciiSpace(*p))
|
||||
{
|
||||
// leaving p whitespace. Eat up addition whitespace in s
|
||||
while (t < searchEnd - 1 && nsCRT::IsAsciiSpace(*(t + 1)))
|
||||
t ++;
|
||||
|
||||
inWhitespace = PR_FALSE;
|
||||
}
|
||||
else
|
||||
inWhitespace = nsCRT::IsAsciiSpace(*p);
|
||||
|
||||
t ++;
|
||||
p ++;
|
||||
}
|
||||
|
||||
if (p == patEnd)
|
||||
{
|
||||
foundOffset = curMatchOffset;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// could be smart about incrementing s here
|
||||
}
|
||||
|
||||
s ++;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return foundOffset;
|
||||
}
|
||||
|
||||
// utility method to discover which block we're in. The TSDoc interface doesn't give
|
||||
// us this, because it can't assume a read-only document.
|
||||
nsresult
|
||||
nsFindAndReplace::GetCurrentBlockIndex(nsITextServicesDocument *aDoc, PRInt32 *outBlockIndex)
|
||||
{
|
||||
PRInt32 blockIndex = 0;
|
||||
PRBool isDone = PR_FALSE;
|
||||
|
||||
while (NS_SUCCEEDED(aDoc->IsDone(&isDone)) && !isDone)
|
||||
{
|
||||
aDoc->PrevBlock();
|
||||
blockIndex ++;
|
||||
}
|
||||
|
||||
*outBlockIndex = blockIndex;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFindAndReplace::SetupDocForFind(nsITextServicesDocument *aDoc, PRInt32 *outBlockOffset)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsITextServicesDocument::TSDBlockSelectionStatus blockStatus;
|
||||
PRInt32 selOffset;
|
||||
PRInt32 selLength;
|
||||
|
||||
// Set up the TSDoc. We are going to start searching thus:
|
||||
//
|
||||
// Searching forwards:
|
||||
// Look forward from the end of the selection
|
||||
// Searching backwards:
|
||||
// Look backwards from the start of the selection
|
||||
//
|
||||
|
||||
if (!mFindBackwards) // searching forwards
|
||||
{
|
||||
rv = aDoc->LastSelectedBlock(&blockStatus, &selOffset, &selLength);
|
||||
if (NS_SUCCEEDED(rv) && (blockStatus != nsITextServicesDocument::eBlockNotFound))
|
||||
{
|
||||
switch (blockStatus)
|
||||
{
|
||||
case nsITextServicesDocument::eBlockOutside: // No TB in S, but found one before/after S.
|
||||
case nsITextServicesDocument::eBlockPartial: // S begins or ends in TB but extends outside of TB.
|
||||
// the TS doc points to the block we want.
|
||||
*outBlockOffset = selOffset + selLength;
|
||||
break;
|
||||
|
||||
case nsITextServicesDocument::eBlockInside: // S extends beyond the start and end of TB.
|
||||
// we want the block after this one.
|
||||
rv = aDoc->NextBlock();
|
||||
*outBlockOffset = 0;
|
||||
break;
|
||||
|
||||
case nsITextServicesDocument::eBlockContains: // TB contains entire S.
|
||||
*outBlockOffset = selOffset + selLength;
|
||||
break;
|
||||
|
||||
case nsITextServicesDocument::eBlockNotFound: // There is no text block (TB) in or before the selection (S).
|
||||
default:
|
||||
NS_NOTREACHED("Shouldn't ever get this status");
|
||||
}
|
||||
}
|
||||
else //failed to get last sel block. Just start at beginning
|
||||
{
|
||||
rv = aDoc->FirstBlock();
|
||||
}
|
||||
|
||||
}
|
||||
else // searching backwards
|
||||
{
|
||||
rv = aDoc->FirstSelectedBlock(&blockStatus, &selOffset, &selLength);
|
||||
if (NS_SUCCEEDED(rv) && (blockStatus != nsITextServicesDocument::eBlockNotFound))
|
||||
{
|
||||
switch (blockStatus)
|
||||
{
|
||||
case nsITextServicesDocument::eBlockOutside: // No TB in S, but found one before/after S.
|
||||
// must be a text block before the selection, so
|
||||
// offset should be at end of block.
|
||||
*outBlockOffset = -1;
|
||||
break;
|
||||
case nsITextServicesDocument::eBlockPartial: // S begins or ends in TB but extends outside of TB.
|
||||
case nsITextServicesDocument::eBlockContains: // TB contains entire S.
|
||||
// the TS doc points to the block we want.
|
||||
*outBlockOffset = selOffset;
|
||||
// if (selOffset > 0 && selLength > 0)
|
||||
// *outBlockOffset -= 1;
|
||||
break;
|
||||
|
||||
case nsITextServicesDocument::eBlockInside: // S extends beyond the start and end of TB.
|
||||
// we want the block before this one.
|
||||
rv = aDoc->PrevBlock();
|
||||
*outBlockOffset = -1;
|
||||
break;
|
||||
case nsITextServicesDocument::eBlockNotFound: // There is no text block (TB) in or before the selection (S).
|
||||
default:
|
||||
NS_NOTREACHED("Shouldn't ever get this status");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = aDoc->LastBlock();
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsFindAndReplace::SetupDocForReplace(nsITextServicesDocument *aDoc, const nsString &aFindStr, PRInt32 *outBlockOffset)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsITextServicesDocument::TSDBlockSelectionStatus blockStatus;
|
||||
PRInt32 selOffset;
|
||||
PRInt32 selLength;
|
||||
|
||||
// Set up the TSDoc. We are going to start replacing thus:
|
||||
//
|
||||
// Searching forwards:
|
||||
// Look forward from the end of the selection
|
||||
// Searching backwards:
|
||||
// Look backwards from the start of the selection
|
||||
//
|
||||
|
||||
if (!mFindBackwards) // searching forwards
|
||||
{
|
||||
rv = aDoc->LastSelectedBlock(&blockStatus, &selOffset, &selLength);
|
||||
if (NS_SUCCEEDED(rv) && (blockStatus != nsITextServicesDocument::eBlockNotFound))
|
||||
{
|
||||
switch (blockStatus)
|
||||
{
|
||||
case nsITextServicesDocument::eBlockOutside: // No TB in S, but found one before/after S.
|
||||
case nsITextServicesDocument::eBlockPartial: // S begins or ends in TB but extends outside of TB.
|
||||
// the TS doc points to the block we want.
|
||||
*outBlockOffset = selOffset + selLength;
|
||||
break;
|
||||
|
||||
case nsITextServicesDocument::eBlockInside: // S extends beyond the start and end of TB.
|
||||
// we want the block after this one.
|
||||
rv = aDoc->NextBlock();
|
||||
*outBlockOffset = 0;
|
||||
break;
|
||||
|
||||
case nsITextServicesDocument::eBlockContains: // TB contains entire S.
|
||||
*outBlockOffset = selOffset;
|
||||
if (selLength != (PRInt32)aFindStr.Length())
|
||||
*outBlockOffset += selLength;
|
||||
break;
|
||||
|
||||
case nsITextServicesDocument::eBlockNotFound: // There is no text block (TB) in or before the selection (S).
|
||||
default:
|
||||
NS_NOTREACHED("Shouldn't ever get this status");
|
||||
}
|
||||
}
|
||||
else //failed to get last sel block. Just start at beginning
|
||||
{
|
||||
rv = aDoc->FirstBlock();
|
||||
}
|
||||
|
||||
}
|
||||
else // searching backwards
|
||||
{
|
||||
rv = aDoc->FirstSelectedBlock(&blockStatus, &selOffset, &selLength);
|
||||
if (NS_SUCCEEDED(rv) && (blockStatus != nsITextServicesDocument::eBlockNotFound))
|
||||
{
|
||||
switch (blockStatus)
|
||||
{
|
||||
case nsITextServicesDocument::eBlockOutside: // No TB in S, but found one before/after S.
|
||||
case nsITextServicesDocument::eBlockPartial: // S begins or ends in TB but extends outside of TB.
|
||||
// the TS doc points to the block we want.
|
||||
*outBlockOffset = selOffset;
|
||||
break;
|
||||
|
||||
case nsITextServicesDocument::eBlockInside: // S extends beyond the start and end of TB.
|
||||
// we want the block before this one.
|
||||
rv = aDoc->PrevBlock();
|
||||
*outBlockOffset = -1;
|
||||
break;
|
||||
|
||||
case nsITextServicesDocument::eBlockContains: // TB contains entire S.
|
||||
*outBlockOffset = selOffset;
|
||||
if (selLength == (PRInt32)aFindStr.Length())
|
||||
*outBlockOffset += selLength;
|
||||
break;
|
||||
|
||||
case nsITextServicesDocument::eBlockNotFound: // There is no text block (TB) in or before the selection (S).
|
||||
default:
|
||||
NS_NOTREACHED("Shouldn't ever get this status");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = aDoc->LastBlock();
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFindAndReplace::DoFind(nsITextServicesDocument *aTxtDoc, const nsString &aFindString, PRBool *aDidFind)
|
||||
{
|
||||
if (!aTxtDoc || !aDidFind)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
*aDidFind = PR_FALSE;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Set up the TSDoc. We are going to start searching thus:
|
||||
//
|
||||
// Searching forwards:
|
||||
// Look forward from the end of the selection
|
||||
// Searching backwards:
|
||||
// Look backwards from the start of the selection
|
||||
//
|
||||
|
||||
PRBool done = PR_FALSE;
|
||||
|
||||
// Loop till we find a match or fail.
|
||||
while ( !done )
|
||||
{
|
||||
PRBool atExtremum = PR_FALSE; // are we at the end (or start)
|
||||
|
||||
while ( NS_SUCCEEDED(aTxtDoc->IsDone(&atExtremum)) && !atExtremum )
|
||||
{
|
||||
nsString str;
|
||||
rv = aTxtDoc->GetCurrentTextBlock(&str);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (!mCaseSensitive)
|
||||
str.ToLowerCase();
|
||||
|
||||
PRInt32 foundOffset = FindInString(str, aFindString, mCurrentSelOffset, mFindBackwards);
|
||||
|
||||
if (foundOffset != -1)
|
||||
{
|
||||
mCurrentSelOffset = foundOffset; // reset for next call to DoFind().
|
||||
|
||||
// Match found. Select it, remember where it was, and quit.
|
||||
aTxtDoc->SetSelection(foundOffset, aFindString.Length());
|
||||
aTxtDoc->ScrollSelectionIntoView();
|
||||
done = PR_TRUE;
|
||||
*aDidFind = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCurrentSelOffset = -1; // reset for next block
|
||||
|
||||
// have we already been around once?
|
||||
if (mWrappedOnce && (mCurrentBlockIndex == mStartBlockIndex))
|
||||
{
|
||||
done = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
// No match found in this block, try the next (or previous) one.
|
||||
if (mFindBackwards) {
|
||||
aTxtDoc->PrevBlock();
|
||||
mCurrentBlockIndex--;
|
||||
} else {
|
||||
aTxtDoc->NextBlock();
|
||||
mCurrentBlockIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
} // while !atExtremum
|
||||
|
||||
// At end (or matched). Decide which it was...
|
||||
if (!done)
|
||||
{
|
||||
// Hit end without a match. If we haven't passed this way already,
|
||||
// then reset to the first/last block (depending on search direction).
|
||||
if (!mWrappedOnce)
|
||||
{
|
||||
// Reset now.
|
||||
mWrappedOnce = PR_TRUE;
|
||||
// If not wrapping, give up.
|
||||
if ( !mWrapFind ) {
|
||||
done = PR_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mFindBackwards ) {
|
||||
// Reset to last block.
|
||||
rv = aTxtDoc->LastBlock();
|
||||
// ugh
|
||||
rv = GetCurrentBlockIndex(aTxtDoc, &mCurrentBlockIndex);
|
||||
rv = aTxtDoc->LastBlock();
|
||||
} else {
|
||||
// Reset to first block.
|
||||
rv = aTxtDoc->FirstBlock();
|
||||
mCurrentBlockIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// already wrapped. This means no matches were found.
|
||||
done = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/* -*- 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.org 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):
|
||||
*/
|
||||
|
||||
#ifndef nsFindAndReplace_h__
|
||||
#define nsFindAndReplace_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIFindAndReplace.h"
|
||||
#include "nsITextServicesDocument.h"
|
||||
|
||||
class nsFindAndReplace : public nsIFindAndReplace
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIFINDANDREPLACE
|
||||
|
||||
nsFindAndReplace();
|
||||
virtual ~nsFindAndReplace();
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsITextServicesDocument> mTsDoc;
|
||||
PRPackedBool mFindBackwards;
|
||||
PRPackedBool mCaseSensitive;
|
||||
PRPackedBool mWrapFind;
|
||||
PRPackedBool mEntireWord;
|
||||
|
||||
PRInt32 mStartBlockIndex;
|
||||
PRInt32 mStartSelOffset;
|
||||
PRInt32 mCurrentBlockIndex;
|
||||
PRInt32 mCurrentSelOffset;
|
||||
PRPackedBool mWrappedOnce;
|
||||
|
||||
nsresult GetCurrentBlockIndex(nsITextServicesDocument *aDoc, PRInt32 *outBlockIndex);
|
||||
nsresult SetupDocForFind(nsITextServicesDocument *aDoc, PRInt32 *outBlockOffset);
|
||||
nsresult SetupDocForReplace(nsITextServicesDocument *aDoc, const nsString &aFindStr, PRInt32 *outBlockOffset);
|
||||
nsresult DoFind(nsITextServicesDocument *aTxtDoc, const nsString &aFindString, PRBool *aDidFind);
|
||||
};
|
||||
|
||||
#endif // nsFindAndReplace_h__
|
|
@ -23,14 +23,22 @@
|
|||
#include "nsIGenericFactory.h"
|
||||
|
||||
#include "nsTextServicesDocument.h"
|
||||
#include "nsFindAndReplace.h"
|
||||
#include "nsTextServicesCID.h"
|
||||
|
||||
#define NS_TEXTSERVICESFINDANDREPLACE_CID \
|
||||
{ /* 8B0EEFE1-C4AE-11d4-A401-000064657374 */ \
|
||||
0x8b0eefe1, 0xc4ae, 0x11d4, \
|
||||
{ 0xa4, 0x1, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Define the contructor function for the objects
|
||||
//
|
||||
// NOTE: This creates an instance of objects by using the default constructor
|
||||
//
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsTextServicesDocument)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFindAndReplace)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Define a table of CIDs implemented by this module along with other
|
||||
|
@ -38,7 +46,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsTextServicesDocument)
|
|||
// class name.
|
||||
//
|
||||
static nsModuleComponentInfo components[] = {
|
||||
{ NULL, NS_TEXTSERVICESDOCUMENT_CID, NULL, nsTextServicesDocumentConstructor },
|
||||
{ NULL, NS_TEXTSERVICESDOCUMENT_CID, "@mozilla.org/textservices/textservicesdocument;1", nsTextServicesDocumentConstructor },
|
||||
{ NULL, NS_TEXTSERVICESFINDANDREPLACE_CID, NS_FINDANDREPLACE_CONTRACTID, nsFindAndReplaceConstructor },
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -41,6 +41,7 @@ function SetupHTMLEditorCommands()
|
|||
|
||||
gHTMLEditorCommandManager.registerCommand("cmd_find", nsFindCommand);
|
||||
gHTMLEditorCommandManager.registerCommand("cmd_findNext", nsFindNextCommand);
|
||||
gHTMLEditorCommandManager.registerCommand("cmd_replace", nsReplaceCommand);
|
||||
gHTMLEditorCommandManager.registerCommand("cmd_spelling", nsSpellingCommand);
|
||||
|
||||
gHTMLEditorCommandManager.registerCommand("cmd_insertChars", nsInsertCharsCommand);
|
||||
|
@ -542,6 +543,20 @@ var nsFindNextCommand =
|
|||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
var nsReplaceCommand =
|
||||
{
|
||||
isCommandEnabled: function(aCommand, dummy)
|
||||
{
|
||||
return (window.editorShell != null);
|
||||
},
|
||||
|
||||
doCommand: function(aCommand)
|
||||
{
|
||||
window.editorShell.Replace();
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
var nsSpellingCommand =
|
||||
{
|
||||
|
|
|
@ -1225,6 +1225,7 @@ function DisableMenusForHTMLSource(disable)
|
|||
// Edit menu items
|
||||
DisableItem("menu_find", disable);
|
||||
DisableItem("menu_findnext", disable);
|
||||
DisableItem("menu_replace", disable);
|
||||
DisableItem("menu_checkspelling", disable);
|
||||
|
||||
// Disable all items in the view menu except mode switch items
|
||||
|
@ -1983,6 +1984,10 @@ function RemoveInapplicableUIElements()
|
|||
if (findMenuItem)
|
||||
findMenuItem.setAttribute("hidden", "true");
|
||||
|
||||
var replaceMenuItem = document.getElementById("menu_replace");
|
||||
if (replaceMenuItem)
|
||||
replaceMenuItem.setAttribute("hidden", "true");
|
||||
|
||||
var findSepItem = document.getElementById("sep_find");
|
||||
if (findSepItem)
|
||||
findSepItem.parentNode.removeChild(findSepItem);
|
||||
|
|
|
@ -168,6 +168,7 @@
|
|||
|
||||
<command id="cmd_find" oncommand="goDoCommand('cmd_find')"/>
|
||||
<command id="cmd_findNext" oncommand="goDoCommand('cmd_findNext')" value="&findAgainCmd.label;"/>
|
||||
<command id="cmd_replace" oncommand="goDoCommand('cmd_replace')" />
|
||||
<command id="cmd_spelling" oncommand="goDoCommand('cmd_spelling')"/>
|
||||
<command id="cmd_pasteQuote" oncommand="goDoCommand('cmd_pasteQuote')" value="&pasteAsQuotationCmd.label;"/>
|
||||
|
||||
|
@ -325,6 +326,7 @@
|
|||
<menuseparator id="sep_find" class="hide-in-IM"/>
|
||||
<menuitem id="menu_find" accesskey="&editfind.accesskey;" key="findkb" observes="cmd_find" value="&findCmd.label;"/>
|
||||
<menuitem id="menu_findnext" accesskey="&editfindnext.accesskey;" key="findnextkb" observes="cmd_findNext"/>
|
||||
<menuitem id="menu_replace" observes="cmd_replace" value="&replaceCmd.label;"/>
|
||||
<menuseparator id="sep_checkspelling" class="hide-in-IM" />
|
||||
<menuitem id="menu_checkspelling" accesskey="&editcheckspelling.accesskey;" key="checkspellingkb" observes="cmd_spelling" value="&checkSpellingCmd.label;"/>
|
||||
<menuseparator/>
|
||||
|
|
|
@ -93,6 +93,7 @@
|
|||
<!ENTITY findAgainCmd.label "Find Again">
|
||||
<!ENTITY editfindnext.accesskey "n">
|
||||
<!ENTITY editfindnext.keybinding "g">
|
||||
<!ENTITY replaceCmd.label "Replace...">
|
||||
<!ENTITY checkSpellingCmd.label "Check Spelling">
|
||||
<!ENTITY editcheckspelling.accesskey "s">
|
||||
<!ENTITY editcheckspelling.keybinding "k">
|
||||
|
|
|
@ -117,6 +117,7 @@ var defaultController =
|
|||
case "cmd_pasteQuote":
|
||||
case "cmd_find":
|
||||
case "cmd_findNext":
|
||||
case "cmd_replace":
|
||||
case "cmd_account":
|
||||
case "cmd_preferences":
|
||||
|
||||
|
@ -230,6 +231,7 @@ var defaultController =
|
|||
case "cmd_pasteQuote":
|
||||
case "cmd_find":
|
||||
case "cmd_findNext":
|
||||
case "cmd_replace":
|
||||
//Disable the editor specific edit commands if the focus is not into the body
|
||||
return /*!focusedElement*/false;
|
||||
case "cmd_account":
|
||||
|
@ -405,6 +407,7 @@ function CommandUpdate_MsgCompose()
|
|||
goUpdateCommand("cmd_pasteQuote");
|
||||
goUpdateCommand("cmd_find");
|
||||
goUpdateCommand("cmd_findNext");
|
||||
goUpdateCommand("cmd_replace");
|
||||
goUpdateCommand("cmd_account");
|
||||
goUpdateCommand("cmd_preferences");
|
||||
|
||||
|
|
|
@ -283,6 +283,7 @@
|
|||
<menuseparator/>
|
||||
<menuitem value="&findCmd.label;" key="key_find" accesskey="&findCmd.accesskey;" observes="cmd_find"/>
|
||||
<menuitem value="&findAgainCmd.label;" key="key_findNext" accesskey="&findAgainCmd.accesskey;" observes="cmd_findNext"/>
|
||||
<menuitem value="&replaceCmd.label;" observes="cmd_replace"/>
|
||||
<menuseparator/>
|
||||
<menuitem value="&accountManagerCmd.label;" accesskey="&accountManagerCmd.accesskey;" observes="cmd_account"/>
|
||||
<menuitem id="menu_preferences" observes="cmd_preferences"/>
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
<!ENTITY findAgainCmd.label "Find Again">
|
||||
<!ENTITY findAgainCmd.key "G">
|
||||
<!ENTITY findAgainCmd.accesskey "g">
|
||||
<!ENTITY replaceCmd.label "Replace...">
|
||||
<!ENTITY accountManagerCmd.label "Mail/News Account Settings...">
|
||||
<!ENTITY accountManagerCmd.accesskey "m">
|
||||
|
||||
|
|
|
@ -89,15 +89,6 @@ interface nsIFindComponent : nsIAppShellComponent
|
|||
--------------------------------------------------------------------------*/
|
||||
boolean find( in nsISupports aContext );
|
||||
|
||||
/*--------------------------------- Replace -----------------------------------
|
||||
| Replace the currently selected text. It is intended that the string used |
|
||||
| for replacement is sourced internally to the component (e.g. from a |
|
||||
| search/replace dialog). |
|
||||
| |
|
||||
| Returns an error if the current context does not allow replacement. |
|
||||
--------------------------------------------------------------------------*/
|
||||
void replace( in nsISupports aContext );
|
||||
|
||||
/*------------------------------- FindNext ---------------------------------
|
||||
| Finds the next occurrence (of the previously searched for string) in |
|
||||
| the given search context (document). |
|
||||
|
@ -107,6 +98,23 @@ interface nsIFindComponent : nsIAppShellComponent
|
|||
--------------------------------------------------------------------------*/
|
||||
boolean findNext( in nsISupports aContext );
|
||||
|
||||
/*--------------------------------- Replace --------------------------------
|
||||
| Replace the currently selected text. It is intended that the string used |
|
||||
| for replacement is sourced internally to the component (e.g. from a |
|
||||
| search/replace dialog). |
|
||||
| |
|
||||
| Returns an error if the current context does not allow replacement. |
|
||||
--------------------------------------------------------------------------*/
|
||||
void replace( in nsISupports aContext );
|
||||
|
||||
/*------------------------------- ReplaceNext ------------------------------
|
||||
| Replaces the currently selected text, then searches for next occurrence |
|
||||
| (of previously searched for string) in the given search context |
|
||||
| (document). If allOccurrences is TRUE, all occurrences of previously |
|
||||
| searched for string will be replaced during this method call.
|
||||
--------------------------------------------------------------------------*/
|
||||
boolean replaceNext( in nsISupports aContext, in boolean allOccurrences );
|
||||
|
||||
/*----------------------------- ResetContext -------------------------------
|
||||
| Reset the given search context to search a new web shell. Generally, |
|
||||
| this will be the equivalent of calling Release() on the old context and |
|
||||
|
|
|
@ -44,4 +44,5 @@ interface nsISearchContext : nsISupports {
|
|||
attribute boolean wrapSearch;
|
||||
readonly attribute nsIDOMWindowInternal targetWindow;
|
||||
attribute nsIDOMWindowInternal findDialog;
|
||||
attribute nsIDOMWindowInternal replaceDialog;
|
||||
};
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
|
||||
finddialog.xul
|
||||
finddialog.js
|
||||
replacedialog.xul
|
||||
replacedialog.js
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
finddialog.dtd
|
||||
replacedialog.dtd
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<!-- extracted from replacedialog.xul -->
|
||||
|
||||
<!ENTITY replaceDialog.title "Replace in This Page">
|
||||
<!ENTITY replaceDialogFrame.title "Replace in This Frame">
|
||||
<!ENTITY findField.label "Find what:">
|
||||
<!ENTITY replaceField.label "Replace with:">
|
||||
<!ENTITY caseSensitiveCheckbox.label "Match upper/lower case">
|
||||
<!ENTITY wrapCheckbox.label "Wrap around">
|
||||
<!ENTITY backwardsCheckbox.label "Search backwards">
|
||||
<!ENTITY findField.tooltip "Type one or more words to search for">
|
||||
<!ENTITY replaceField.tooltip "Type one or more words to replace with">
|
||||
<!ENTITY findNextButton.label "Find Next">
|
||||
<!ENTITY replaceButton.label "Replace">
|
||||
<!ENTITY replaceAllButton.label "Replace All">
|
||||
<!ENTITY closeButton.label "Close">
|
|
@ -32,10 +32,13 @@ CHROME_L10N_DIR = locales\en-US\global\locale
|
|||
CHROME_CONTENT = \
|
||||
.\finddialog.xul \
|
||||
.\finddialog.js \
|
||||
.\replacedialog.xul \
|
||||
.\replacedialog.js \
|
||||
$(NULL)
|
||||
|
||||
CHROME_L10N = \
|
||||
.\locale\en-US\finddialog.dtd \
|
||||
.\locale\en-US\replacedialog.dtd \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
/* -*- Mode: Java; 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, released March
|
||||
* 31, 1998.
|
||||
*
|
||||
* 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): Kin Blas <kin@netscape.com>
|
||||
*
|
||||
*/
|
||||
|
||||
var gFindComponent; // Find component.
|
||||
var gFindReplaceData; // Search context (passed as argument).
|
||||
var gReplaceDialog; // Quick access to document/form elements.
|
||||
|
||||
function string2Bool( value )
|
||||
{
|
||||
return value != "false";
|
||||
}
|
||||
|
||||
function bool2String( value )
|
||||
{
|
||||
if ( value )
|
||||
return "true";
|
||||
else
|
||||
return "false";
|
||||
}
|
||||
|
||||
function initDialog()
|
||||
{
|
||||
// Create gReplaceDialog object and initialize.
|
||||
gReplaceDialog = new Object;
|
||||
gReplaceDialog.findKey = document.getElementById("dialog.findKey");
|
||||
gReplaceDialog.replaceKey = document.getElementById("dialog.replaceKey");
|
||||
gReplaceDialog.caseSensitive = document.getElementById("dialog.caseSensitive");
|
||||
gReplaceDialog.wrap = document.getElementById("dialog.wrap");
|
||||
gReplaceDialog.searchBackwards = document.getElementById("dialog.searchBackwards");
|
||||
gReplaceDialog.findNext = document.getElementById("findNext");
|
||||
gReplaceDialog.replace = document.getElementById("replace");
|
||||
gReplaceDialog.replaceAll = document.getElementById("replaceAll");
|
||||
gReplaceDialog.close = document.getElementById("close");
|
||||
gReplaceDialog.enabled = false;
|
||||
}
|
||||
|
||||
function loadDialog()
|
||||
{
|
||||
// Set initial dialog field contents.
|
||||
gReplaceDialog.findKey.setAttribute( "value", gFindReplaceData.searchString );
|
||||
gReplaceDialog.replaceKey.setAttribute( "value", gFindReplaceData.replaceString );
|
||||
|
||||
if ( gFindReplaceData.caseSensitive ) {
|
||||
gReplaceDialog.caseSensitive.setAttribute( "checked", "" );
|
||||
} else {
|
||||
gReplaceDialog.caseSensitive.removeAttribute( "checked" );
|
||||
}
|
||||
|
||||
if ( gFindReplaceData.wrapSearch ) {
|
||||
gReplaceDialog.wrap.setAttribute( "checked", "" );
|
||||
} else {
|
||||
gReplaceDialog.wrap.removeAttribute( "checked" );
|
||||
}
|
||||
|
||||
if ( gFindReplaceData.searchBackwards ) {
|
||||
gReplaceDialog.searchBackwards.setAttribute( "checked", "" );
|
||||
} else {
|
||||
gReplaceDialog.searchBackwards.removeAttribute( "checked" );
|
||||
}
|
||||
|
||||
// disable the findNext button if no text
|
||||
if (gReplaceDialog.findKey.getAttribute("value") == "") {
|
||||
gReplaceDialog.findNext.setAttribute("disabled", "true");
|
||||
}
|
||||
|
||||
// disable the replace and replaceAll buttons if no
|
||||
// find or replace text
|
||||
if (gReplaceDialog.findKey.getAttribute("value") == "") {
|
||||
gReplaceDialog.replace.setAttribute("disabled", "true");
|
||||
gReplaceDialog.replaceAll.setAttribute("disabled", "true");
|
||||
}
|
||||
gReplaceDialog.findKey.focus();
|
||||
}
|
||||
|
||||
function loadData()
|
||||
{
|
||||
// Set gFindReplaceData attributes per user input.
|
||||
gFindReplaceData.searchString = gReplaceDialog.findKey.value;
|
||||
gFindReplaceData.replaceString = gReplaceDialog.replaceKey.value;
|
||||
gFindReplaceData.caseSensitive = gReplaceDialog.caseSensitive.checked;
|
||||
gFindReplaceData.wrapSearch = gReplaceDialog.wrap.checked;
|
||||
gFindReplaceData.searchBackwards = gReplaceDialog.searchBackwards.checked;
|
||||
}
|
||||
|
||||
function onLoad()
|
||||
{
|
||||
// Init gReplaceDialog.
|
||||
initDialog();
|
||||
|
||||
// Get find component.
|
||||
gFindComponent = Components.classes[ "@mozilla.org/appshell/component/find;1" ].getService();
|
||||
gFindComponent = gFindComponent.QueryInterface( Components.interfaces.nsIFindComponent );
|
||||
if ( !gFindComponent ) {
|
||||
alert( "Error accessing find component\n" );
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// Save search context.
|
||||
gFindReplaceData = window.arguments[0];
|
||||
|
||||
// Tell search context about this dialog.
|
||||
gFindReplaceData.replaceDialog = window;
|
||||
|
||||
// Fill dialog.
|
||||
loadDialog();
|
||||
|
||||
// Give focus to search text field.
|
||||
gReplaceDialog.findKey.focus();
|
||||
}
|
||||
|
||||
function onUnload() {
|
||||
// Disconnect context from this dialog.
|
||||
gFindReplaceData.replaceDialog = null;
|
||||
}
|
||||
|
||||
function onFindNext()
|
||||
{
|
||||
// Transfer dialog contents to data elements.
|
||||
loadData();
|
||||
|
||||
// Search.
|
||||
gFindComponent.findNext( gFindReplaceData );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function onReplace()
|
||||
{
|
||||
// Transfer dialog contents to data elements.
|
||||
loadData();
|
||||
|
||||
// Replace.
|
||||
gFindComponent.replaceNext( gFindReplaceData, false );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function onReplaceAll()
|
||||
{
|
||||
// Transfer dialog contents to data elements.
|
||||
loadData();
|
||||
|
||||
// Replace.
|
||||
gFindComponent.replaceNext( gFindReplaceData, true );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function onClose()
|
||||
{
|
||||
window.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
function onTyping()
|
||||
{
|
||||
if ( gReplaceDialog.enabled ) {
|
||||
// Disable findNext, replace, and replaceAll if they delete all the text.
|
||||
if ( gReplaceDialog.findKey.value == "" ) {
|
||||
gReplaceDialog.enabled = false;
|
||||
gReplaceDialog.findNext.setAttribute("disabled", "true");
|
||||
}
|
||||
} else {
|
||||
// Enable OK once the user types something.
|
||||
if ( gReplaceDialog.findKey.value != "" ) {
|
||||
gReplaceDialog.enabled = true;
|
||||
gReplaceDialog.findNext.removeAttribute("disabled");
|
||||
}
|
||||
}
|
||||
|
||||
if ( gReplaceDialog.enabled ) {
|
||||
gReplaceDialog.replace.removeAttribute("disabled");
|
||||
gReplaceDialog.replaceAll.removeAttribute("disabled");
|
||||
} else {
|
||||
gReplaceDialog.replace.setAttribute("disabled", "true");
|
||||
gReplaceDialog.replaceAll.setAttribute("disabled", "true");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<?xml version="1.0"?> <!-- -*- Mode: HTML -*- -->
|
||||
|
||||
<!--
|
||||
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, released
|
||||
March 31, 1998.
|
||||
|
||||
The Initial Developer of the Original Code is Netscape
|
||||
Communications Corporation. Portions created by Netscape are
|
||||
Copyright (C) 1998-1999 Netscape Communications Corporation. All
|
||||
Rights Reserved.
|
||||
|
||||
Contributor(s): Kin Blas <kin@netscape.com>
|
||||
-->
|
||||
|
||||
<?xml-stylesheet href="chrome://navigator/skin/" type="text/css"?>
|
||||
|
||||
<?xul-overlay href="chrome://global/content/dialogOverlay.xul"?>
|
||||
|
||||
<!DOCTYPE window SYSTEM "chrome://global/locale/replacedialog.dtd">
|
||||
|
||||
<window xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
id="replaceDialog"
|
||||
onload="onLoad();"
|
||||
onunload="onUnload();"
|
||||
title="&replaceDialog.title;"
|
||||
debug="false"
|
||||
class="dialog"
|
||||
align="vertical"
|
||||
persist="screenX screenY"
|
||||
screenX="24" screenY="24">
|
||||
|
||||
<html:script language="JavaScript" src="chrome://global/content/replacedialog.js"/>
|
||||
|
||||
<box>
|
||||
|
||||
<!-- hack. we seem to need this separator to get it to render -->
|
||||
<separator orient="vertical" class="thin"/>
|
||||
|
||||
<box orient="vertical">
|
||||
<text class="label" value="&findField.label;"/>
|
||||
<text class="label" value="&replaceField.label;"/>
|
||||
</box>
|
||||
|
||||
<box orient="vertical">
|
||||
<textfield id="dialog.findKey" oninput="return onTyping();"/>
|
||||
<textfield id="dialog.replaceKey" oninput="return onTyping();"/>
|
||||
<box orient="vertical" autostretch="never">
|
||||
<checkbox id="dialog.caseSensitive" value="&caseSensitiveCheckbox.label;"/>
|
||||
<checkbox id="dialog.wrap" value="&wrapCheckbox.label;"/>
|
||||
<checkbox id="dialog.searchBackwards" value="&backwardsCheckbox.label;"/>
|
||||
</box>
|
||||
</box>
|
||||
<box orient="vertical">
|
||||
<button class="dialog" id="findNext" value="&findNextButton.label;" oncommand="onFindNext();"/>
|
||||
<button class="dialog" id="replace" value="&replaceButton.label;" oncommand="onReplace();"/>
|
||||
<button class="dialog" id="replaceAll" value="&replaceAllButton.label;" oncommand="onReplaceAll();"/>
|
||||
<button class="dialog" id="close" value="&closeButton.label;" oncommand="onClose();"/>
|
||||
</box>
|
||||
</box>
|
||||
|
||||
<separator/>
|
||||
|
||||
<!-- Places to overlay common dialog buttons and keyset -->
|
||||
<keyset id="keyset"/>
|
||||
|
||||
</window>
|
|
@ -46,6 +46,8 @@
|
|||
#include "nsWidgetsCID.h" // ugh! contractID, please
|
||||
|
||||
#include "nsFindComponent.h"
|
||||
#include "nsIFindAndReplace.h"
|
||||
#include "nsIEditor.h"
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -56,7 +58,7 @@
|
|||
nsFindComponent::Context::Context()
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
// all our other members are self-initiating
|
||||
// all our other members are self-initiating
|
||||
}
|
||||
|
||||
|
||||
|
@ -65,11 +67,18 @@ nsFindComponent::Context::~Context()
|
|||
#ifdef DEBUG_law
|
||||
printf( "\nnsFindComponent::Context destructor called\n\n" );
|
||||
#endif
|
||||
|
||||
// Close the dialog (if there is one).
|
||||
if ( mFindDialog ) {
|
||||
mFindDialog->Close();
|
||||
mFindDialog = 0;
|
||||
}
|
||||
|
||||
// Close the dialog (if there is one).
|
||||
if ( mReplaceDialog ) {
|
||||
mReplaceDialog->Close();
|
||||
mReplaceDialog = 0;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -81,19 +90,23 @@ nsFindComponent::Context::Init( nsIDOMWindowInternal *aWindow,
|
|||
PRBool lastSearchBackward,
|
||||
PRBool lastWrapSearch)
|
||||
{
|
||||
if (!aWindow)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
if (!aWindow)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
mEditorShell = aEditorShell; // don't AddRef
|
||||
mTargetWindow = aWindow; // don't AddRef
|
||||
mSearchString = lastSearchString;
|
||||
mReplaceString = lastReplaceString;
|
||||
mCaseSensitive = lastCaseSensitive;
|
||||
mSearchBackwards = lastSearchBackward;
|
||||
mWrapSearch = lastWrapSearch;
|
||||
mFindDialog = 0;
|
||||
mEditorShell = aEditorShell; // don't AddRef
|
||||
mTargetWindow = aWindow; // don't AddRef
|
||||
mSearchString = lastSearchString;
|
||||
mReplaceString = lastReplaceString;
|
||||
mCaseSensitive = lastCaseSensitive;
|
||||
mSearchBackwards = lastSearchBackward;
|
||||
mWrapSearch = lastWrapSearch;
|
||||
mFindDialog = 0;
|
||||
mReplaceDialog = 0;
|
||||
|
||||
return NS_OK;
|
||||
nsresult rv = NS_OK;
|
||||
mTSFind = do_CreateInstance(NS_FINDANDREPLACE_CONTRACTID, &rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
@ -120,30 +133,45 @@ nsFindComponent::Context::MakeTSDocument(nsIDOMWindowInternal* aWindow, nsITextS
|
|||
if (NS_FAILED(rv) || !tempDoc)
|
||||
return rv;
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> globalObj = do_QueryInterface(aWindow, &rv);
|
||||
if (NS_FAILED(rv) || !globalObj)
|
||||
return NS_ERROR_FAILURE;
|
||||
if (mEditorShell)
|
||||
{
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
rv = mEditorShell->GetEditor(getter_AddRefs(editor));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
if (!editor)
|
||||
return NS_ERROR_FAILURE;
|
||||
rv = tempDoc->InitWithEditor(editor);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIScriptGlobalObject> globalObj = do_QueryInterface(aWindow, &rv);
|
||||
if (NS_FAILED(rv) || !globalObj)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
globalObj->GetDocShell(getter_AddRefs(docShell));
|
||||
if (!docShell)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
globalObj->GetDocShell(getter_AddRefs(docShell));
|
||||
if (!docShell)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
docShell->GetPresShell(getter_AddRefs(presShell));
|
||||
if (!presShell)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
docShell->GetPresShell(getter_AddRefs(presShell));
|
||||
if (!presShell)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIDocument> document;
|
||||
presShell->GetDocument(getter_AddRefs(document));
|
||||
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(document);
|
||||
if (!domDoc)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsCOMPtr<nsIDocument> document;
|
||||
presShell->GetDocument(getter_AddRefs(document));
|
||||
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(document);
|
||||
if (!domDoc)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Initialize the text services document.
|
||||
rv = tempDoc->InitWithDocument(domDoc, presShell);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
// Initialize the text services document.
|
||||
rv = tempDoc->InitWithDocument(domDoc, presShell);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Return the resulting text services document.
|
||||
*aDoc = tempDoc;
|
||||
|
@ -152,278 +180,16 @@ nsFindComponent::Context::MakeTSDocument(nsIDOMWindowInternal* aWindow, nsITextS
|
|||
return rv;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// CharsMatch
|
||||
//
|
||||
// Compare chars. Match if both are whitespace, or both are
|
||||
// non whitespace and same char.
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
inline static PRBool CharsMatch(PRUnichar c1, PRUnichar c2)
|
||||
{
|
||||
return (nsCRT::IsAsciiSpace(c1) && nsCRT::IsAsciiSpace(c2)) ||
|
||||
(c1 == c2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// FindInString
|
||||
//
|
||||
// Routine to search in an nsString which is smart about extra
|
||||
// whitespace, can search backwards, and do case insensitive search.
|
||||
//
|
||||
// This uses a brute-force algorithm, which should be sufficient
|
||||
// for our purposes (text searching)
|
||||
//
|
||||
// searchStr contains the text from a content node, which can contain
|
||||
// extra white space between words, which we have to deal with.
|
||||
// The offsets passed in and back are offsets into searchStr,
|
||||
// and thus include extra white space.
|
||||
//
|
||||
// If we are ignoring case, the strings have already been lowercased
|
||||
// at this point.
|
||||
//
|
||||
// startOffset is the offset in the search string to start seraching
|
||||
// at. If -1, it means search from the start (forwards) or end (backwards).
|
||||
//
|
||||
// Returns -1 if the string is not found, or if the pattern is an
|
||||
// empty string, or if startOffset is off the end of the string.
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
static PRInt32 FindInString(const nsString &searchStr, const nsString &patternStr,
|
||||
PRInt32 startOffset, PRBool searchBackwards)
|
||||
{
|
||||
PRInt32 foundOffset = -1;
|
||||
PRInt32 patternLen = patternStr.Length();
|
||||
PRInt32 searchStrLen = searchStr.Length();
|
||||
|
||||
if (patternLen == 0) // pattern is empty
|
||||
return -1;
|
||||
|
||||
if (startOffset < 0)
|
||||
startOffset = (searchBackwards) ? searchStrLen : 0;
|
||||
|
||||
if (startOffset > searchStrLen) // bad start offset
|
||||
return -1;
|
||||
|
||||
if (patternLen > searchStrLen) // pattern is longer than string to search
|
||||
return -1;
|
||||
|
||||
const PRUnichar *searchBuf = searchStr.GetUnicode();
|
||||
const PRUnichar *patternBuf = patternStr.GetUnicode();
|
||||
|
||||
const PRUnichar *searchEnd = searchBuf + searchStrLen;
|
||||
const PRUnichar *patEnd = patternBuf + patternLen;
|
||||
|
||||
if (searchBackwards)
|
||||
{
|
||||
// searching backwards
|
||||
const PRUnichar *s = searchBuf + startOffset - patternLen - 1;
|
||||
|
||||
while (s >= searchBuf)
|
||||
{
|
||||
if (CharsMatch(*patternBuf, *s)) // start potential match
|
||||
{
|
||||
const PRUnichar *t = s;
|
||||
const PRUnichar *p = patternBuf;
|
||||
PRInt32 curMatchOffset = t - searchBuf;
|
||||
PRBool inWhitespace = nsCRT::IsAsciiSpace(*p);
|
||||
|
||||
while (p < patEnd && CharsMatch(*p, *t))
|
||||
{
|
||||
if (inWhitespace && !nsCRT::IsAsciiSpace(*p))
|
||||
{
|
||||
// leaving p whitespace. Eat up addition whitespace in s
|
||||
while (t < searchEnd - 1 && nsCRT::IsAsciiSpace(*(t + 1)))
|
||||
t ++;
|
||||
|
||||
inWhitespace = PR_FALSE;
|
||||
}
|
||||
else
|
||||
inWhitespace = nsCRT::IsAsciiSpace(*p);
|
||||
|
||||
t ++;
|
||||
p ++;
|
||||
}
|
||||
|
||||
if (p == patEnd)
|
||||
{
|
||||
foundOffset = curMatchOffset;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// could be smart about decrementing s here
|
||||
}
|
||||
|
||||
s --;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// searching forwards
|
||||
|
||||
const PRUnichar *s = &searchBuf[startOffset];
|
||||
|
||||
while (s < searchEnd)
|
||||
{
|
||||
if (CharsMatch(*patternBuf, *s)) // start potential match
|
||||
{
|
||||
const PRUnichar *t = s;
|
||||
const PRUnichar *p = patternBuf;
|
||||
PRInt32 curMatchOffset = t - searchBuf;
|
||||
PRBool inWhitespace = nsCRT::IsAsciiSpace(*p);
|
||||
|
||||
while (p < patEnd && CharsMatch(*p, *t))
|
||||
{
|
||||
if (inWhitespace && !nsCRT::IsAsciiSpace(*p))
|
||||
{
|
||||
// leaving p whitespace. Eat up addition whitespace in s
|
||||
while (t < searchEnd - 1 && nsCRT::IsAsciiSpace(*(t + 1)))
|
||||
t ++;
|
||||
|
||||
inWhitespace = PR_FALSE;
|
||||
}
|
||||
else
|
||||
inWhitespace = nsCRT::IsAsciiSpace(*p);
|
||||
|
||||
t ++;
|
||||
p ++;
|
||||
}
|
||||
|
||||
if (p == patEnd)
|
||||
{
|
||||
foundOffset = curMatchOffset;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// could be smart about incrementing s here
|
||||
}
|
||||
|
||||
s ++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
done:
|
||||
return foundOffset;
|
||||
}
|
||||
|
||||
// utility method to discover which block we're in. The TSDoc interface doesn't give
|
||||
// us this, because it can't assume a read-only document.
|
||||
NS_IMETHODIMP
|
||||
nsFindComponent::Context::GetCurrentBlockIndex(nsITextServicesDocument *aDoc, PRInt32 *outBlockIndex)
|
||||
{
|
||||
PRInt32 blockIndex = 0;
|
||||
PRBool isDone = PR_FALSE;
|
||||
|
||||
while (NS_SUCCEEDED(aDoc->IsDone(&isDone)) && !isDone)
|
||||
{
|
||||
aDoc->PrevBlock();
|
||||
blockIndex ++;
|
||||
}
|
||||
|
||||
*outBlockIndex = blockIndex;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFindComponent::Context::SetupDocForSearch(nsITextServicesDocument *aDoc, PRInt32 *outBlockOffset)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsITextServicesDocument::TSDBlockSelectionStatus blockStatus;
|
||||
PRInt32 selOffset;
|
||||
PRInt32 selLength;
|
||||
|
||||
if (!mSearchBackwards) // searching forwards
|
||||
{
|
||||
rv = aDoc->LastSelectedBlock(&blockStatus, &selOffset, &selLength);
|
||||
if (NS_SUCCEEDED(rv) && (blockStatus != nsITextServicesDocument::eBlockNotFound))
|
||||
{
|
||||
switch (blockStatus)
|
||||
{
|
||||
case nsITextServicesDocument::eBlockOutside: // No TB in S, but found one before/after S.
|
||||
case nsITextServicesDocument::eBlockPartial: // S begins or ends in TB but extends outside of TB.
|
||||
// the TS doc points to the block we want.
|
||||
*outBlockOffset = selOffset + selLength;
|
||||
break;
|
||||
|
||||
case nsITextServicesDocument::eBlockInside: // S extends beyond the start and end of TB.
|
||||
// we want the block after this one.
|
||||
rv = aDoc->NextBlock();
|
||||
*outBlockOffset = 0;
|
||||
break;
|
||||
|
||||
case nsITextServicesDocument::eBlockContains: // TB contains entire S.
|
||||
*outBlockOffset = selOffset + selLength;
|
||||
break;
|
||||
|
||||
case nsITextServicesDocument::eBlockNotFound: // There is no text block (TB) in or before the selection (S).
|
||||
default:
|
||||
NS_NOTREACHED("Shouldn't ever get this status");
|
||||
}
|
||||
|
||||
}
|
||||
else //failed to get last sel block. Just start at beginning
|
||||
{
|
||||
rv = aDoc->FirstBlock();
|
||||
}
|
||||
|
||||
}
|
||||
else // searching backwards
|
||||
{
|
||||
rv = aDoc->FirstSelectedBlock(&blockStatus, &selOffset, &selLength);
|
||||
if (NS_SUCCEEDED(rv) && (blockStatus != nsITextServicesDocument::eBlockNotFound))
|
||||
{
|
||||
switch (blockStatus)
|
||||
{
|
||||
case nsITextServicesDocument::eBlockOutside: // No TB in S, but found one before/after S.
|
||||
case nsITextServicesDocument::eBlockPartial: // S begins or ends in TB but extends outside of TB.
|
||||
// the TS doc points to the block we want.
|
||||
*outBlockOffset = selOffset;
|
||||
break;
|
||||
|
||||
case nsITextServicesDocument::eBlockInside: // S extends beyond the start and end of TB.
|
||||
// we want the block before this one.
|
||||
rv = aDoc->PrevBlock();
|
||||
*outBlockOffset = -1;
|
||||
break;
|
||||
|
||||
case nsITextServicesDocument::eBlockContains: // TB contains entire S.
|
||||
*outBlockOffset = selOffset;
|
||||
break;
|
||||
|
||||
case nsITextServicesDocument::eBlockNotFound: // There is no text block (TB) in or before the selection (S).
|
||||
default:
|
||||
NS_NOTREACHED("Shouldn't ever get this status");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = aDoc->LastBlock();
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFindComponent::Context::DoFind(PRBool *aDidFind)
|
||||
{
|
||||
if (!aDidFind)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (!mTargetWindow)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
*aDidFind = PR_FALSE;
|
||||
|
||||
*aDidFind = PR_FALSE;
|
||||
|
||||
nsAutoString matchString(mSearchString);
|
||||
if (!mCaseSensitive)
|
||||
matchString.ToLowerCase();
|
||||
if (!mTargetWindow)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
|
@ -434,128 +200,63 @@ nsFindComponent::Context::DoFind(PRBool *aDidFind)
|
|||
if (NS_FAILED(rv) || !txtDoc)
|
||||
return rv;
|
||||
|
||||
// Set up the TSDoc. We are going to start searching thus:
|
||||
//
|
||||
// Searching forwards:
|
||||
// Look forward from the end of the selection
|
||||
// Searching backwards:
|
||||
// Look backwards from the start of the selection
|
||||
//
|
||||
PRInt32 selOffset = 0;
|
||||
rv = SetupDocForSearch(txtDoc, &selOffset);
|
||||
if (!mTSFind)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
rv = mTSFind->SetCaseSensitive(mCaseSensitive);
|
||||
rv = mTSFind->SetFindBackwards(mSearchBackwards);
|
||||
rv = mTSFind->SetWrapFind(mWrapSearch);
|
||||
|
||||
rv = mTSFind->SetTsDoc(txtDoc);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// find out where we started
|
||||
PRInt32 blockIndex;
|
||||
rv = GetCurrentBlockIndex(txtDoc, &blockIndex);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
rv = mTSFind->Find(mSearchString.GetUnicode(), aDidFind);
|
||||
|
||||
// remember where we started
|
||||
PRInt32 startingBlockIndex = blockIndex;
|
||||
mTSFind->SetTsDoc(nsnull);
|
||||
|
||||
// and set the starting position again (hopefully, in future we won't have to do this)
|
||||
rv = SetupDocForSearch(txtDoc, &selOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
PRBool wrappedOnce = PR_FALSE; // Remember whether we've already wrapped
|
||||
PRBool done = PR_FALSE;
|
||||
|
||||
// Loop till we find a match or fail.
|
||||
while ( !done )
|
||||
{
|
||||
PRBool atExtremum = PR_FALSE; // are we at the end (or start)
|
||||
|
||||
while ( NS_SUCCEEDED(txtDoc->IsDone(&atExtremum)) && !atExtremum )
|
||||
{
|
||||
nsString str;
|
||||
rv = txtDoc->GetCurrentTextBlock(&str);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (!mCaseSensitive)
|
||||
str.ToLowerCase();
|
||||
|
||||
PRInt32 foundOffset = FindInString(str, matchString, selOffset, mSearchBackwards);
|
||||
selOffset = -1; // reset for next block
|
||||
|
||||
if (foundOffset != -1)
|
||||
{
|
||||
// Match found. Select it, remember where it was, and quit.
|
||||
txtDoc->SetSelection(foundOffset, mSearchString.Length());
|
||||
txtDoc->ScrollSelectionIntoView();
|
||||
done = PR_TRUE;
|
||||
*aDidFind = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// have we already been around once?
|
||||
if (wrappedOnce && (blockIndex == startingBlockIndex))
|
||||
{
|
||||
done = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
// No match found in this block, try the next (or previous) one.
|
||||
if (mSearchBackwards) {
|
||||
txtDoc->PrevBlock();
|
||||
blockIndex--;
|
||||
} else {
|
||||
txtDoc->NextBlock();
|
||||
blockIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
} // while !atExtremum
|
||||
|
||||
// At end (or matched). Decide which it was...
|
||||
if (!done)
|
||||
{
|
||||
// Hit end without a match. If we haven't passed this way already,
|
||||
// then reset to the first/last block (depending on search direction).
|
||||
if (!wrappedOnce)
|
||||
{
|
||||
// Reset now.
|
||||
wrappedOnce = PR_TRUE;
|
||||
// If not wrapping, give up.
|
||||
if ( !mWrapSearch ) {
|
||||
done = PR_TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mSearchBackwards ) {
|
||||
// Reset to last block.
|
||||
rv = txtDoc->LastBlock();
|
||||
// ugh
|
||||
rv = GetCurrentBlockIndex(txtDoc, &blockIndex);
|
||||
rv = txtDoc->LastBlock();
|
||||
} else {
|
||||
// Reset to first block.
|
||||
rv = txtDoc->FirstBlock();
|
||||
blockIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// already wrapped. This means no matches were found.
|
||||
done = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFindComponent::Context::DoReplace()
|
||||
nsFindComponent::Context::DoReplace(PRBool aAllOccurrences, PRBool *aDidFind)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
if (!mTargetWindow)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (!aDidFind)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
*aDidFind = PR_FALSE;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Construct a text services document to use. This is freed when we
|
||||
// return from this function.
|
||||
nsCOMPtr<nsITextServicesDocument> txtDoc;
|
||||
rv = MakeTSDocument(mTargetWindow, getter_AddRefs(txtDoc));
|
||||
if (NS_FAILED(rv) || !txtDoc)
|
||||
return rv;
|
||||
|
||||
if (!mTSFind)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
rv = mTSFind->SetCaseSensitive(mCaseSensitive);
|
||||
rv = mTSFind->SetFindBackwards(mSearchBackwards);
|
||||
rv = mTSFind->SetWrapFind(mWrapSearch);
|
||||
|
||||
rv = mTSFind->SetTsDoc(txtDoc);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = mTSFind->Replace(mSearchString.GetUnicode(),
|
||||
mReplaceString.GetUnicode(),
|
||||
aAllOccurrences, aDidFind);
|
||||
|
||||
mTSFind->SetTsDoc(nsnull);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -688,6 +389,21 @@ nsFindComponent::Context::SetFindDialog( nsIDOMWindowInternal *aDialog )
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFindComponent::Context::GetReplaceDialog( nsIDOMWindowInternal * *aDialog)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDialog);
|
||||
NS_IF_ADDREF(*aDialog = mReplaceDialog);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFindComponent::Context::SetReplaceDialog( nsIDOMWindowInternal *aDialog )
|
||||
{
|
||||
mReplaceDialog = aDialog;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef XP_MAC
|
||||
#pragma mark -
|
||||
#endif
|
||||
|
@ -855,61 +571,129 @@ nsFindComponent::Find(nsISupports *aContext, PRBool *aDidFind)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFindComponent::Replace( nsISupports *aContext )
|
||||
nsFindComponent::FindNext(nsISupports *aContext, PRBool *aDidFind)
|
||||
{
|
||||
if (!aContext)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
if (!aContext)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
Context *context = (Context*)aContext;
|
||||
|
||||
// If we haven't searched yet, put up dialog (via Find).
|
||||
if ( context->mSearchString.IsEmpty() ) {
|
||||
return this->Find( aContext, aDidFind );
|
||||
}
|
||||
|
||||
context->DoFind(aDidFind);
|
||||
|
||||
// Record this for out-of-the-blue FindNext calls.
|
||||
mLastSearchString = context->mSearchString;
|
||||
mLastCaseSensitive = context->mCaseSensitive;
|
||||
mLastSearchBackwards = context->mSearchBackwards;
|
||||
mLastWrapSearch = context->mWrapSearch;
|
||||
|
||||
if (!*aDidFind)
|
||||
{
|
||||
static NS_DEFINE_IID(kSoundCID, NS_SOUND_CID);
|
||||
nsCOMPtr<nsISound> sound = do_CreateInstance(kSoundCID);
|
||||
if (sound)
|
||||
sound->Beep();
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFindComponent::FindNext(nsISupports *aContext, PRBool *aDidFind)
|
||||
nsFindComponent::Replace( nsISupports *aContext )
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (!aContext)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
Context *context = (Context*)aContext;
|
||||
|
||||
// If we haven't searched yet, put up dialog (via Find).
|
||||
if ( context->mSearchString.IsEmpty() ) {
|
||||
return this->Find( aContext, aDidFind );
|
||||
// See if replace dialog is already up.
|
||||
if ( aContext ) {
|
||||
nsCOMPtr<nsISearchContext> context = do_QueryInterface( aContext, &rv );
|
||||
if ( NS_SUCCEEDED( rv ) && context ) {
|
||||
nsCOMPtr<nsIDOMWindowInternal> dialog;
|
||||
rv = context->GetReplaceDialog( getter_AddRefs( dialog ) );
|
||||
if ( NS_SUCCEEDED( rv ) && dialog ) {
|
||||
// Just give focus back to the dialog.
|
||||
dialog->Focus();
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
// Test for error (GetReplaceDialog succeeds if there's no dialog).
|
||||
if ( NS_FAILED( rv ) ) {
|
||||
DEBUG_PRINTF( PR_STDOUT, "%s %d: Error getting replace dialog, rv=0x%08X\n",
|
||||
__FILE__, (int)__LINE__, (int)rv );
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
context->DoFind(aDidFind);
|
||||
|
||||
// Record this for out-of-the-blue FindNext calls.
|
||||
mLastSearchString = context->mSearchString;
|
||||
mLastCaseSensitive = context->mCaseSensitive;
|
||||
mLastSearchBackwards = context->mSearchBackwards;
|
||||
mLastWrapSearch = context->mWrapSearch;
|
||||
|
||||
if (!*aDidFind)
|
||||
if (aContext && GetAppShell())
|
||||
{
|
||||
static NS_DEFINE_IID(kSoundCID, NS_SOUND_CID);
|
||||
nsCOMPtr<nsISound> sound = do_CreateInstance(kSoundCID);
|
||||
if (sound)
|
||||
sound->Beep();
|
||||
nsCOMPtr<nsISearchContext> context = do_QueryInterface( aContext, &rv );
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Open Replace dialog and prompt for search parameters.
|
||||
char * urlStr = "chrome://global/content/replacedialog.xul";
|
||||
|
||||
// We need the parent's nsIDOMWindowInternal...
|
||||
// 1. Get topLevelWindow nsIWebShellContainer (chrome included).
|
||||
nsCOMPtr<nsIDOMWindowInternal> window;
|
||||
rv = context->GetTargetWindow( getter_AddRefs( window ) );
|
||||
if ( NS_SUCCEEDED( rv ) && window )
|
||||
{
|
||||
nsCOMPtr<nsIDOMWindow> topWindow;
|
||||
window->GetTop(getter_AddRefs(topWindow));
|
||||
if (topWindow) {
|
||||
nsCOMPtr<nsIDOMWindowInternal> topInternal = do_QueryInterface(topWindow);
|
||||
rv = OpenDialogWithArg(topInternal, context, urlStr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rv = NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFindComponent::ReplaceNext( nsISupports *aContext, PRBool aAllOccurrences, PRBool *aDidFind )
|
||||
{
|
||||
if (!aContext)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
Context *context = (Context*)aContext;
|
||||
|
||||
if (!context)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsresult rv = context->DoReplace(aAllOccurrences, aDidFind);
|
||||
|
||||
// Record this for out-of-the-blue FindNext calls.
|
||||
mLastSearchString = context->mSearchString;
|
||||
mLastCaseSensitive = context->mCaseSensitive;
|
||||
mLastSearchBackwards = context->mSearchBackwards;
|
||||
mLastWrapSearch = context->mWrapSearch;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFindComponent::ResetContext( nsISupports *aContext,
|
||||
nsIDOMWindowInternal *aNewWindow,
|
||||
nsIEditorShell* aEditorShell )
|
||||
{
|
||||
NS_ENSURE_ARG(aContext);
|
||||
NS_ENSURE_ARG(aNewWindow);
|
||||
NS_ENSURE_ARG(aContext);
|
||||
NS_ENSURE_ARG(aNewWindow);
|
||||
|
||||
// Pass on the new document to the context.
|
||||
Context *context = (Context*)aContext;
|
||||
context->Reset(aNewWindow);
|
||||
// Pass on the new document to the context.
|
||||
Context *context = (Context*)aContext;
|
||||
context->Reset(aNewWindow);
|
||||
|
||||
return NS_OK;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsFindComponent::Context implementation...
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include "nsIAppShellComponentImpl.h"
|
||||
#include "nsIFindComponent.h"
|
||||
#include "nsISearchContext.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIFindAndReplace.h"
|
||||
|
||||
class nsITextServicesDocument;
|
||||
|
||||
|
@ -50,37 +52,37 @@ public:
|
|||
// "Context" for this implementation.
|
||||
class Context : public nsISearchContext
|
||||
{
|
||||
public:
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISEARCHCONTEXT
|
||||
|
||||
Context();
|
||||
virtual ~Context();
|
||||
NS_IMETHOD Init( nsIDOMWindowInternal *aWindow,
|
||||
nsIEditorShell* aEditorShell,
|
||||
const nsString& lastSearchString,
|
||||
const nsString& lastReplaceString,
|
||||
PRBool lastCaseSensitive,
|
||||
PRBool lastSearchBackwards,
|
||||
PRBool lastWrapSearch);
|
||||
Context();
|
||||
virtual ~Context();
|
||||
NS_IMETHOD Init( nsIDOMWindowInternal *aWindow,
|
||||
nsIEditorShell* aEditorShell,
|
||||
const nsString& lastSearchString,
|
||||
const nsString& lastReplaceString,
|
||||
PRBool lastCaseSensitive,
|
||||
PRBool lastSearchBackwards,
|
||||
PRBool lastWrapSearch);
|
||||
|
||||
NS_IMETHOD Reset(nsIDOMWindowInternal *aNewWindow);
|
||||
NS_IMETHOD DoFind(PRBool *aDidFind);
|
||||
NS_IMETHOD DoReplace();
|
||||
NS_IMETHOD Reset(nsIDOMWindowInternal *aNewWindow);
|
||||
NS_IMETHOD DoFind(PRBool *aDidFind);
|
||||
NS_IMETHOD DoReplace(PRBool aAllOccurrences, PRBool *aDidFind);
|
||||
|
||||
// Utility to construct new TS document from our webshell.
|
||||
NS_IMETHOD MakeTSDocument(nsIDOMWindowInternal* aWindow, nsITextServicesDocument** aDoc);
|
||||
NS_IMETHOD GetCurrentBlockIndex(nsITextServicesDocument *aDoc, PRInt32 *outBlockIndex);
|
||||
NS_IMETHOD SetupDocForSearch(nsITextServicesDocument *aDoc, PRInt32 *outBlockOffset);
|
||||
|
||||
nsIDOMWindowInternal* mTargetWindow; // weak link. Don't hold a reference
|
||||
nsIEditorShell* mEditorShell; // weak link. Don't hold a reference
|
||||
nsIDOMWindowInternal* mTargetWindow; // weak link. Don't hold a reference
|
||||
nsIEditorShell* mEditorShell; // weak link. Don't hold a reference
|
||||
nsCOMPtr<nsIFindAndReplace> mTSFind;
|
||||
nsString mSearchString;
|
||||
nsString mReplaceString;
|
||||
PRBool mCaseSensitive;
|
||||
PRBool mSearchBackwards;
|
||||
PRBool mWrapSearch;
|
||||
nsIDOMWindowInternal* mFindDialog;
|
||||
nsIDOMWindowInternal* mReplaceDialog;
|
||||
|
||||
}; // nsFindComponent::Context
|
||||
|
||||
|
|
|
@ -167,6 +167,7 @@ en-US.jar:
|
|||
locale/en-US/global/console.properties (console/resources/locale/en-US/console.properties)
|
||||
locale/en-US/global/finddialog.dtd (find/resources/locale/en-US/finddialog.dtd)
|
||||
locale/en-US/global/finddialog.properties (find/resources/locale/en-US/finddialog.properties)
|
||||
locale/en-US/global/replacedialog.dtd (find/resources/locale/en-US/replacedialog.dtd)
|
||||
|
||||
toolkit.jar:
|
||||
content/global/console.js (console/resources/content/console.js)
|
||||
|
@ -175,6 +176,8 @@ toolkit.jar:
|
|||
content/global/consoleBindings.xml (console/resources/content/consoleBindings.xml)
|
||||
content/global/finddialog.js (find/resources/finddialog.js)
|
||||
content/global/finddialog.xul (find/resources/finddialog.xul)
|
||||
content/global/replacedialog.js (find/resources/replacedialog.js)
|
||||
content/global/replacedialog.xul (find/resources/replacedialog.xul)
|
||||
content/global/unknownContent.xul (ucth/resources/unknownContent.xul)
|
||||
content/global/unknownContent.js (ucth/resources/unknownContent.js)
|
||||
content/global/helperAppLauncher.xul (ucth/resources/helperAppLauncher.xul)
|
||||
|
|
Загрузка…
Ссылка в новой задаче