fix 66771 add match all search term for filters and virtual folders, sr=mscott

This commit is contained in:
bienvenu%nventure.com 2006-05-30 20:02:41 +00:00
parent 79fd63f9d5
commit e612909b94
15 changed files with 115 additions and 29 deletions

View File

@ -1016,6 +1016,11 @@ function getSearchTermString(searchTerms)
if (condition.length > 1)
condition += ' ';
if (term.matchAll)
{
condition = "ALL";
break;
}
condition += (term.booleanAnd) ? "AND (" : "OR (";
condition += term.termAsString + ')';
}

View File

@ -2,6 +2,8 @@
<!ENTITY matchAll.accesskey "a">
<!ENTITY matchAny.label "Match any of the following">
<!ENTITY matchAny.accesskey "o">
<!ENTITY matchAllMsgs.label "Match all messages">
<!ENTITY matchAllMsgs.accesskey "m">
<!-- LOCALIZATION NOTE
The values below are used to control the widths of the search widgets.

View File

@ -1040,6 +1040,11 @@ function getSearchTermString(searchTerms)
if (condition.length > 1)
condition += ' ';
if (term.matchAll)
{
condition = "ALL";
break;
}
condition += (term.booleanAnd) ? "AND (" : "OR (";
condition += term.termAsString + ')';
}

View File

@ -55,8 +55,8 @@ interface nsIMsgSearchTerm : nsISupports {
attribute boolean booleanAnd;
attribute string arbitraryHeader;
attribute boolean beginsGrouping;
attribute boolean endsGrouping;
attribute boolean beginsGrouping;
attribute boolean endsGrouping;
boolean matchRfc822String(in string aString, in string charset, in boolean charsetOverride);
boolean matchRfc2047String(in string aString, in string charset, in boolean charsetOverride);
@ -65,8 +65,8 @@ interface nsIMsgSearchTerm : nsISupports {
boolean matchPriority(in nsMsgPriorityValue priority);
boolean matchAge(in PRTime days);
boolean matchSize(in unsigned long size);
boolean matchLabel(in nsMsgLabelValue aLabelValue);
boolean matchJunkStatus(in string aJunkScore);
boolean matchLabel(in nsMsgLabelValue aLabelValue);
boolean matchJunkStatus(in string aJunkScore);
boolean matchBody(in nsIMsgSearchScopeTerm scopeTerm,
in unsigned long offset,
@ -93,5 +93,6 @@ interface nsIMsgSearchTerm : nsISupports {
readonly attribute boolean matchAllBeforeDeciding;
readonly attribute ACString termAsString;
attribute boolean matchAll;
};

View File

@ -105,6 +105,7 @@ public:
nsMsgSearchBooleanOperator m_booleanOp; // boolean operator to be applied to this search term and the search term which precedes it.
nsCString m_arbitraryHeader; // user specified string for the name of the arbitrary header to be used in the search
// only has a value when m_attribute = attribOtherHeader!!!!
PRBool m_matchAll; // does this term match all headers?
protected:
nsresult MatchString (const char *stringToMatch, const char *charset,

View File

@ -314,7 +314,8 @@ function initializeSearchWindowWidgets()
gFolderPicker = document.getElementById("searchableFolders");
gSearchStopButton = document.getElementById("search-button");
gStatusBar = document.getElementById('statusbar-icon');
hideMatchAllItem();
msgWindow = Components.classes[msgWindowContractID].createInstance(nsIMsgWindow);
msgWindow.statusFeedback = gStatusFeedback;
msgWindow.SetDOMWindow(window);

View File

@ -22,6 +22,7 @@
* Contributor(s):
* Alec Flett <alecf@netscape.com>
* Seth Spitzer <sspitzer@netscape.com>
* David Bienvenu <bienvenu@nventure.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -142,6 +143,7 @@ searchTermContainer.prototype = {
this.searchvalue.saveTo(searchTerm.value);
searchTerm.value = this.searchvalue.value;
searchTerm.booleanAnd = this.booleanAnd;
searchTerm.matchAll = this.matchAll;
},
// if you have a search term element with no search term
saveTo: function(searchTerm) {
@ -166,13 +168,21 @@ function initializeSearchWidgets()
function initializeBooleanWidgets()
{
var booleanAnd = true;
var matchAll = false;
// get the boolean value from the first term
var firstTerm = gSearchTerms[0].searchTerm;
if (firstTerm)
{
booleanAnd = firstTerm.booleanAnd;
// target radio items have value="and" or value="or"
gSearchBooleanRadiogroup.value = booleanAnd ? "and" : "or";
matchAll = firstTerm.matchAll;
}
// target radio items have value="and" or value="or" or "all"
gSearchBooleanRadiogroup.value = matchAll
? "matchAll"
: (booleanAnd ? "and" : "or")
var searchTerms = document.getElementById("searchTermList");
if (searchTerms)
searchTerms.hidden = matchAll;
}
function initializeSearchRows(scope, searchTerms)
@ -257,6 +267,7 @@ function updateSearchAttributes()
function booleanChanged(event) {
// when boolean changes, we have to update all the attributes on the search terms
var newBoolValue = (event.target.getAttribute("value") == "and") ? true : false;
var matchAllValue = (event.target.getAttribute("value") == "matchAll") ? true : false;
if (document.getElementById("abPopup")) {
var selectedAB = document.getElementById("abPopup").selectedItem.id;
setSearchScope(GetScopeForDirectoryURI(selectedAB));
@ -264,6 +275,14 @@ function booleanChanged(event) {
for (var i=0; i<gSearchTerms.length; i++) {
var searchTerm = gSearchTerms[i].obj;
searchTerm.booleanAnd = newBoolValue;
searchTerm.matchAll = matchAllValue;
}
var searchTerms = document.getElementById("searchTermList");
if (searchTerms)
{
if (!matchAllValue && searchTerms.hidden)
onMore(null); // fake to get empty row.
searchTerms.hidden = matchAllValue;
}
}
@ -452,6 +471,7 @@ function removeSearchRow(index)
// via XPCOM)
function saveSearchTerms(searchTerms, termOwner)
{
var matchAll = gSearchBooleanRadiogroup.value == 'matchAll';
var i;
for (i = 0; i<gSearchTerms.length; i++) {
try {
@ -463,7 +483,7 @@ function saveSearchTerms(searchTerms, termOwner)
// is an existing term, but not initialize, so skip saving
continue;
}
searchTerm.matchAll = matchAll;
if (searchTerm)
gSearchTerms[i].obj.save();
else {
@ -485,7 +505,6 @@ function saveSearchTerms(searchTerms, termOwner)
gSearchRemovedTerms[i].QueryInterface(Components.interfaces.nsISupports);
searchTerms.RemoveElement(searchTermSupports);
}
}
function onReset(event)
@ -495,6 +514,13 @@ function onReset(event)
onMore(null);
}
function hideMatchAllItem()
{
var allItems = document.getElementById('matchAllItem');
if (allItems)
allItems.hidden = true;
}
// this is a helper routine used by our search term xbl widget
var gLabelStrings = new Array;
function GetLabelStrings()

View File

@ -51,6 +51,7 @@
selectedItem="or" oncommand="booleanChanged(event);">
<radio value="and" label="&matchAll.label;" accesskey="&matchAll.accesskey;"/>
<radio selected="true" value="or" label="&matchAny.label;" accesskey="&matchAny.accesskey;"/>
<radio value="matchAll" id="matchAllItem" label="&matchAllMsgs.label;" accesskey="&matchAllMsgs.accesskey;"/>
</radiogroup>
<hbox flex="1">

View File

@ -2,6 +2,8 @@
<!ENTITY matchAll.accesskey "a">
<!ENTITY matchAny.label "Match any of the following">
<!ENTITY matchAny.accesskey "o">
<!ENTITY matchAllMsgs.label "Match all messages">
<!ENTITY matchAllMsgs.accesskey "m">
<!-- LOCALIZATION NOTE
The values below are used to control the widths of the search widgets.
Change the values only when the localized strings in the popup menus

View File

@ -749,33 +749,40 @@ nsresult nsMsgFilter::SaveRule(nsIOFileStream *aStream)
PRUint32 count;
m_termList->Count(&count);
for (searchIndex = 0; searchIndex < count && NS_SUCCEEDED(err);
searchIndex++)
searchIndex++)
{
nsCAutoString stream;
nsCOMPtr<nsIMsgSearchTerm> term;
m_termList->QueryElementAt(searchIndex, NS_GET_IID(nsIMsgSearchTerm),
(void **)getter_AddRefs(term));
if (!term)
continue;
if (condition.Length() > 1)
condition += ' ';
PRBool booleanAnd;
PRBool matchAll;
term->GetBooleanAnd(&booleanAnd);
if (booleanAnd)
term->GetMatchAll(&matchAll);
if (matchAll)
{
condition += "ALL";
break;
}
else if (booleanAnd)
condition += "AND (";
else
condition += "OR (";
nsresult searchError = term->GetTermAsString(stream);
if (NS_FAILED(searchError))
{
err = searchError;
break;
}
condition += stream;
condition += ')';
}

View File

@ -115,7 +115,6 @@ protected:
PRPackedBool m_enabled;
PRPackedBool m_temporary;
PRPackedBool m_unparseable;
nsIMsgFilterList *m_filterList; /* owning filter list */
nsCOMPtr<nsISupportsArray> m_termList; /* linked list of criteria terms */
nsCOMPtr<nsIMsgSearchScopeTerm> m_scope; /* default for mail rules is inbox, but news rules could

View File

@ -719,11 +719,24 @@ nsresult nsMsgFilterList::LoadTextFilters(nsIOFileStream *aStream)
// what about values with close parens and quotes? e.g., (body, isn't, "foo")")
// I guess interior quotes will need to be escaped - ("foo\")")
// which will get written out as (\"foo\\")\") and read in as ("foo\")"
// ALL means match all messages.
NS_IMETHODIMP nsMsgFilterList::ParseCondition(nsIMsgFilter *aFilter, const char *aCondition)
{
PRBool done = PR_FALSE;
nsresult err = NS_OK;
const char *curPtr = aCondition;
if (!strcmp(aCondition, "ALL"))
{
nsMsgSearchTerm *newTerm = new nsMsgSearchTerm;
if (newTerm)
{
newTerm->m_matchAll = PR_TRUE;
aFilter->AppendTerm(newTerm);
}
return (newTerm) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
while (!done)
{
// insert code to save the boolean operator if there is one for this search term....

View File

@ -441,9 +441,16 @@ nsresult nsMsgSearchOfflineMail::ProcessSearchTerm(nsIMsgDBHdr *msgToMatch,
PRBool charsetOverride = PR_FALSE; /* XXX BUG 68706 */
PRUint32 msgFlags;
PRBool result;
PRBool matchAll;
NS_ENSURE_ARG_POINTER(pResult);
aTerm->GetMatchAll(&matchAll);
if (matchAll)
{
*pResult = PR_TRUE;
return NS_OK;
}
*pResult = PR_FALSE;
nsMsgSearchAttribValue attrib;

View File

@ -22,6 +22,7 @@
* Contributor(s):
* Seth Spitzer <sspitzer@netscape.com>
* Jungshik Shin <jshin@mailaps.org>
* David Bienvenu <bienvenu@nventure.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -342,6 +343,7 @@ nsMsgSearchTerm::nsMsgSearchTerm()
m_attribute = nsMsgSearchAttrib::Default;
mBeginsGrouping = PR_FALSE;
mEndsGrouping = PR_FALSE;
m_matchAll = PR_FALSE;
}
nsMsgSearchTerm::nsMsgSearchTerm (
@ -357,6 +359,7 @@ nsMsgSearchTerm::nsMsgSearchTerm (
if (attrib > nsMsgSearchAttrib::OtherHeader && attrib < nsMsgSearchAttrib::kNumMsgSearchAttributes && arbitraryHeader)
m_arbitraryHeader = arbitraryHeader;
nsMsgResultElement::AssignValues (val, &m_value);
m_matchAll = PR_FALSE;
}
@ -495,6 +498,11 @@ NS_IMETHODIMP nsMsgSearchTerm::GetTermAsString (nsACString &outStream)
nsCAutoString outputStr;
nsresult ret;
if (m_matchAll)
{
outStream = "ALL";
return NS_OK;
}
ret = NS_MsgGetStringForAttribute(m_attribute, &attrib);
if (ret != NS_OK)
return ret;
@ -641,18 +649,23 @@ nsMsgSearchTerm::ParseAttribute(char *inStream, nsMsgSearchAttribValue *attrib)
nsresult nsMsgSearchTerm::DeStreamNew (char *inStream, PRInt16 /*length*/)
{
char *commaSep = PL_strchr(inStream, ',');
nsresult rv = ParseAttribute(inStream, &m_attribute); // will allocate space for arbitrary header if necessary
if (!strcmp(inStream, "ALL"))
{
m_matchAll = PR_TRUE;
return NS_OK;
}
char *commaSep = PL_strchr(inStream, ',');
nsresult rv = ParseAttribute(inStream, &m_attribute); // will allocate space for arbitrary header if necessary
NS_ENSURE_SUCCESS(rv, rv);
if (!commaSep)
return NS_ERROR_INVALID_ARG;
char *secondCommaSep = PL_strchr(commaSep + 1, ',');
if (commaSep)
rv = ParseOperator(commaSep + 1, &m_operator);
if (!commaSep)
return NS_ERROR_INVALID_ARG;
char *secondCommaSep = PL_strchr(commaSep + 1, ',');
if (commaSep)
rv = ParseOperator(commaSep + 1, &m_operator);
NS_ENSURE_SUCCESS(rv, rv);
if (secondCommaSep)
ParseValue(secondCommaSep + 1);
return NS_OK;
if (secondCommaSep)
ParseValue(secondCommaSep + 1);
return NS_OK;
}
@ -1369,7 +1382,7 @@ nsresult nsMsgSearchTerm::InitHeaderAddressParser()
NS_IMPL_GETSET(nsMsgSearchTerm, Attrib, nsMsgSearchAttribValue, m_attribute)
NS_IMPL_GETSET(nsMsgSearchTerm, Op, nsMsgSearchOpValue, m_operator)
NS_IMPL_GETSET(nsMsgSearchTerm, MatchAll, PRBool, m_matchAll)
NS_IMETHODIMP
nsMsgSearchTerm::GetValue(nsIMsgSearchValue **aResult)

View File

@ -118,6 +118,9 @@ function initializeMailViewOverrides()
//orButton.setAttribute('label', 'Any of the following');
//var andButton = document.getElementById('and');
//andButton.setAttribute('label', 'All of the following');
// matchAll doesn't make sense for views, since views are a single folder
hideMatchAllItem();
}
function UpdateAfterCustomHeaderChange()