From df7ab3a7c07227e752f495dc9da5210806276a28 Mon Sep 17 00:00:00 2001 From: "dmose%netscape.com" Date: Tue, 4 Sep 2001 05:25:08 +0000 Subject: [PATCH] Bug 92135: shows source of autocomplete items in the mail compose window using icons in the dropdown (default match, local addressbook, remote addressbook). Allows (via hidden pref; off by default) for more sophisticated info about each address -- specific addrbook name, or random ldap attribute, like department). Also fixes minor LDAP autocomplete i18n regression introduced post 0.9.3 and found while testing. r=sspitzer; sr=hewitt; a=asa --- .../public/nsIAbLDAPAutoCompFormatter.idl | 9 +- .../addrbook/src/nsAbAutoCompleteSession.cpp | 89 ++++++++++++++++--- .../addrbook/src/nsAbAutoCompleteSession.h | 25 +++++- .../src/nsAbLDAPAutoCompFormatter.cpp | 24 +++-- .../resources/content/MsgComposeCommands.js | 67 +++++++++++--- .../content/addressingWidgetOverlay.js | 5 ++ themes/classic/jar.mn | 1 + .../messenger/addressbook/remote-abook.gif | 0 .../messengercompose/messengercompose.css | 22 ++++- .../messengercompose/messengercompose.css | 18 ++++ .../resources/content/autocomplete.xml | 63 +++++++++++-- 11 files changed, 273 insertions(+), 50 deletions(-) create mode 100644 themes/classic/messenger/addressbook/remote-abook.gif diff --git a/mailnews/addrbook/public/nsIAbLDAPAutoCompFormatter.idl b/mailnews/addrbook/public/nsIAbLDAPAutoCompFormatter.idl index cf8f06177e7..a4f2809a153 100644 --- a/mailnews/addrbook/public/nsIAbLDAPAutoCompFormatter.idl +++ b/mailnews/addrbook/public/nsIAbLDAPAutoCompFormatter.idl @@ -42,11 +42,12 @@ interface nsIAbLDAPAutoCompFormatter: nsILDAPAutoCompFormatter { * If any of these are unset, components implementing this interface * are free to choose reasonable defaults. As an example, the *"@mozilla.org/ldap-autocomplete-formatter;1?type=addrbook" - * implementation currently happens to use the followingn defaults: + * implementation currently happens to use the following default + * strings: * - * nameFormat: [cn] - * addressFormat: {mail} - * commentFormat: [o] + * nameFormat: "[cn]" + * addressFormat: "{mail}" + * commentFormat: "" * * and generates autocomplete items like this: * diff --git a/mailnews/addrbook/src/nsAbAutoCompleteSession.cpp b/mailnews/addrbook/src/nsAbAutoCompleteSession.cpp index 46cc2886822..a361233002c 100644 --- a/mailnews/addrbook/src/nsAbAutoCompleteSession.cpp +++ b/mailnews/addrbook/src/nsAbAutoCompleteSession.cpp @@ -103,9 +103,16 @@ PRBool nsAbAutoCompleteSession::ItsADuplicate(PRUnichar* fullAddrStr, nsIAutoCom return PR_FALSE; } -void nsAbAutoCompleteSession::AddToResult(const PRUnichar* pNickNameStr, const PRUnichar* pDisplayNameStr, const PRUnichar* pFirstNameStr, - const PRUnichar* pLastNameStr, const PRUnichar* pEmailStr, const PRUnichar* pNotesStr, PRBool bIsMailList, MatchType type, - nsIAutoCompleteResults* results) +void +nsAbAutoCompleteSession::AddToResult(const PRUnichar* pNickNameStr, + const PRUnichar* pDisplayNameStr, + const PRUnichar* pFirstNameStr, + const PRUnichar* pLastNameStr, + const PRUnichar* pEmailStr, + const PRUnichar* pNotesStr, + const PRUnichar* pDirName, + PRBool bIsMailList, MatchType type, + nsIAutoCompleteResults* results) { nsresult rv; PRUnichar* fullAddrStr = nsnull; @@ -180,11 +187,37 @@ void nsAbAutoCompleteSession::AddToResult(const PRUnichar* pNickNameStr, const P rv = nsComponentManager::CreateInstance(kAutoCompleteItemCID, nsnull, NS_GET_IID(nsIAutoCompleteItem), getter_AddRefs(newItem)); if (NS_SUCCEEDED(rv)) { - nsAbAutoCompleteParam *param = new nsAbAutoCompleteParam(pNickNameStr, pDisplayNameStr, pFirstNameStr, pLastNameStr, pEmailStr, pNotesStr, bIsMailList, type); + nsAbAutoCompleteParam *param = new nsAbAutoCompleteParam(pNickNameStr, pDisplayNameStr, pFirstNameStr, pLastNameStr, pEmailStr, pNotesStr, pDirName, bIsMailList, type); NS_IF_ADDREF(param); newItem->SetParam(param); NS_IF_RELEASE(param); + // how to process the comment column, if at all. this value + // comes from "mail.autoComplete.commentColumn", or, if that + // doesn't exist, defaults to 0 + // + // 0 = none + // 1 = name of addressbook this card came from + // 2 = other per-addressbook format (currrently unused here) + // + if (mAutoCompleteCommentColumn == 1) { + rv = newItem->SetComment(pDirName); + if (NS_FAILED(rv)) { + NS_WARNING("nsAbAutoCompleteSession::AddToResult():" + " newItem->SetComment() failed\n"); + } + } + + // if this isn't a default match, set the class name so we can style + // this cell with the local addressbook icon (or whatever) + // + rv = newItem->SetClassName(type == DEFAULT_MATCH ? "default-match" : + "local-abook"); + if (NS_FAILED(rv)) { + NS_WARNING("nsAbAutoCompleteSession::AddToResult():" + " newItem->SetClassName() failed\n"); + } + newItem->SetValue(nsDependentString(fullAddrStr)); nsCOMPtr array; rv = results->GetItems(getter_AddRefs(array)); @@ -374,11 +407,26 @@ nsresult nsAbAutoCompleteSession::SearchCards(nsIAbDirectory* directory, nsAbAut continue; MatchType matchType; - if (CheckEntry(searchStr, (const PRUnichar*)pNickNameStr, (const PRUnichar*)pDisplayNameStr, - (const PRUnichar*)pFirstNameStr, (const PRUnichar*)pLastNameStr, (const PRUnichar*)pEmailStr, &matchType)) - AddToResult((const PRUnichar*)pNickNameStr, (const PRUnichar*)pDisplayNameStr, (const PRUnichar*)pFirstNameStr, - (const PRUnichar*)pLastNameStr, (const PRUnichar*)pEmailStr, (const PRUnichar*)pNotesStr, bIsMailList, - matchType, results); + if ( CheckEntry(searchStr, pNickNameStr.get(), + pDisplayNameStr.get(), + pFirstNameStr.get(), + pLastNameStr.get(), pEmailStr.get(), + &matchType)) { + + nsXPIDLString pDirName; + if ( mAutoCompleteCommentColumn == 1 ) { + rv = directory->GetDirName(getter_Copies(pDirName)); + if (NS_FAILED(rv)) { + continue; + } + } + + AddToResult(pNickNameStr.get(), pDisplayNameStr.get(), + pFirstNameStr.get(), pLastNameStr.get(), + pEmailStr.get(), pNotesStr.get(), + pDirName.get(), bIsMailList, matchType, + results); + } } } } @@ -489,9 +537,11 @@ nsresult nsAbAutoCompleteSession::SearchPreviousResults(nsAbAutoCompleteSearchSt MatchType matchType; if (CheckEntry(searchStr, param->mNickName, param->mDisplayName, param->mFirstName, param->mLastName, param->mEmailAddress, &matchType)) - AddToResult(param->mNickName, param->mDisplayName, param->mFirstName, param->mLastName, param->mEmailAddress, - param->mNotes, param->mIsMailList, matchType, results); - + AddToResult(param->mNickName, param->mDisplayName, + param->mFirstName, param->mLastName, + param->mEmailAddress, param->mNotes, + param->mDirName, param->mIsMailList, matchType, + results); } return NS_OK; } @@ -518,7 +568,16 @@ NS_IMETHODIMP nsAbAutoCompleteSession::OnStartLookup(const PRUnichar *uSearchStr listener->OnAutoComplete(nsnull, nsIAutoCompleteStatus::ignored); return NS_OK; } - + + // figure out what we're supposed to do about the comment column, and + // remember it for when the results start coming back + // + rv = pPref->GetIntPref("mail.autoComplete.commentColumn", + &mAutoCompleteCommentColumn); + if (NS_FAILED(rv)) { + mAutoCompleteCommentColumn = 0; + } + PRInt32 i; for (i = nsCRT::strlen(uSearchString) - 1; i >= 0; i --) if (uSearchString[i] == '@') @@ -549,7 +608,9 @@ NS_IMETHODIMP nsAbAutoCompleteSession::OnStartLookup(const PRUnichar *uSearchStr if (mDefaultDomain[0] != 0) { PRUnichar emptyStr = 0; - AddToResult(&emptyStr, uSearchString, &emptyStr, &emptyStr, &emptyStr, &emptyStr, PR_FALSE, DEFAULT_MATCH, results); + AddToResult(&emptyStr, uSearchString, &emptyStr, &emptyStr, + &emptyStr, &emptyStr, &emptyStr, PR_FALSE, + DEFAULT_MATCH, results); addedDefaultItem = PR_TRUE; } diff --git a/mailnews/addrbook/src/nsAbAutoCompleteSession.h b/mailnews/addrbook/src/nsAbAutoCompleteSession.h index 0d602b793bf..d2f3743bd31 100644 --- a/mailnews/addrbook/src/nsAbAutoCompleteSession.h +++ b/mailnews/addrbook/src/nsAbAutoCompleteSession.h @@ -82,9 +82,14 @@ public: protected: void ResetMatchTypeConters(); PRBool ItsADuplicate(PRUnichar* fullAddrStr, nsIAutoCompleteResults* results); - void AddToResult(const PRUnichar* pNickNameStr, const PRUnichar* pDisplayNameStr, const PRUnichar* pFirstNameStr, const PRUnichar* pLastNameStr, - const PRUnichar* pEmailStr, const PRUnichar* pNotes, PRBool bIsMailList, MatchType type, nsIAutoCompleteResults* results); - PRBool CheckEntry(nsAbAutoCompleteSearchString* searchStr, const PRUnichar* nickName,const PRUnichar* displayName, + void AddToResult(const PRUnichar* pNickNameStr, + const PRUnichar* pDisplayNameStr, + const PRUnichar* pFirstNameStr, + const PRUnichar* pLastNameStr, + const PRUnichar* pEmailStr, const PRUnichar* pNotes, + const PRUnichar* pDirName, PRBool bIsMailList, + MatchType type, nsIAutoCompleteResults* results); + PRBool CheckEntry(nsAbAutoCompleteSearchString* searchStr, const PRUnichar* nickName,const PRUnichar* displayName, const PRUnichar* firstName, const PRUnichar* lastName, const PRUnichar* emailAddress, MatchType* matchType); nsresult SearchCards(nsIAbDirectory* directory, nsAbAutoCompleteSearchString* searchStr, nsIAutoCompleteResults* results); nsresult SearchDirectory(nsString& fileName, nsAbAutoCompleteSearchString* searchStr, nsIAutoCompleteResults* results, PRBool searchSubDirectory = PR_FALSE); @@ -93,6 +98,16 @@ protected: nsCOMPtr mParser; nsString mDefaultDomain; PRUint32 mMatchTypeConters[LAST_MATCH_TYPE]; + + // how to process the comment column, if at all. this value + // comes from "mail.autoComplete.commentColumn", or, if that + // doesn't exist, defaults to 0 + // + // 0 = none + // 1 = name of addressbook this card came from + // 2 = other per-addressbook format (currrently unused here) + // + PRInt32 mAutoCompleteCommentColumn; }; @@ -113,6 +128,7 @@ public: const PRUnichar* lastName, const PRUnichar* emailAddress, const PRUnichar* notes, + const PRUnichar* dirName, PRBool isMailList, nsAbAutoCompleteSession::MatchType type) { @@ -123,6 +139,7 @@ public: mLastName = nsCRT::strdup(lastName ? lastName : NS_STATIC_CAST(const PRUnichar*, NS_LITERAL_STRING("").get())); mEmailAddress = nsCRT::strdup(emailAddress ? emailAddress : NS_STATIC_CAST(const PRUnichar*, NS_LITERAL_STRING("").get())); mNotes = nsCRT::strdup(notes ? notes : NS_STATIC_CAST(const PRUnichar*, NS_LITERAL_STRING("").get())); + mDirName = nsCRT::strdup(dirName ? dirName : NS_STATIC_CAST(const PRUnichar *, NS_LITERAL_STRING("").get())); mIsMailList = isMailList; mType = type; } @@ -135,6 +152,7 @@ public: CRTFREEIF(mLastName); CRTFREEIF(mEmailAddress); CRTFREEIF(mNotes); + CRTFREEIF(mDirName); }; protected: @@ -144,6 +162,7 @@ protected: PRUnichar* mLastName; PRUnichar* mEmailAddress; PRUnichar* mNotes; + PRUnichar* mDirName; PRBool mIsMailList; nsAbAutoCompleteSession::MatchType mType; diff --git a/mailnews/addrbook/src/nsAbLDAPAutoCompFormatter.cpp b/mailnews/addrbook/src/nsAbLDAPAutoCompFormatter.cpp index d86826e9b6b..6c817e73fab 100644 --- a/mailnews/addrbook/src/nsAbLDAPAutoCompFormatter.cpp +++ b/mailnews/addrbook/src/nsAbLDAPAutoCompFormatter.cpp @@ -43,8 +43,7 @@ NS_IMPL_ISUPPORTS2(nsAbLDAPAutoCompFormatter, nsAbLDAPAutoCompFormatter::nsAbLDAPAutoCompFormatter() : mNameFormat(NS_LITERAL_STRING("[cn]")), - mAddressFormat(NS_LITERAL_STRING("{mail}")), - mCommentFormat(NS_LITERAL_STRING("[o]")) + mAddressFormat(NS_LITERAL_STRING("{mail}")) { NS_INIT_ISUPPORTS(); } @@ -126,19 +125,18 @@ nsAbLDAPAutoCompFormatter::Format(nsILDAPMessage *aMsg, // nsCAutoString comment; rv = ProcessFormat(mCommentFormat, aMsg, &comment, 0); - if (NS_FAILED(rv)) { - // Something went wrong lower down the stack; a messagne should have - // already been logged there. Return an error rather than - // trying to generate a bogus nsIAutoCompleteItem. - // - return rv; + if (NS_SUCCEEDED(rv)) { + rv = item->SetComment(NS_ConvertUTF8toUCS2(comment).get()); + if (NS_FAILED(rv)) { + NS_WARNING("nsAbLDAPAutoCompFormatter::Format():" + " item->SetComment() failed"); + } } - rv = item->SetComment(NS_ConvertUTF8toUCS2(comment).get()); + rv = item->SetClassName("remote-abook"); if (NS_FAILED(rv)) { - NS_ERROR("nsAbLDAPAutoCompFormatter::Format():" - " item->SetComment failed"); - return rv; + NS_WARNING("nsAbLDAPAutoCompleteFormatter::Format():" + " item->SetClassName() failed"); } // all done; return the item @@ -347,7 +345,7 @@ nsAbLDAPAutoCompFormatter::ProcessFormat(const nsAReadableString & aFormat, // this character gets treated as a literal // - (*aValue).Append(NS_STATIC_CAST(char, *iter)); + (*aValue).Append(NS_ConvertUCS2toUTF8(*iter)); } } diff --git a/mailnews/compose/resources/content/MsgComposeCommands.js b/mailnews/compose/resources/content/MsgComposeCommands.js index aa171e58c35..71a6610e0da 100644 --- a/mailnews/compose/resources/content/MsgComposeCommands.js +++ b/mailnews/compose/resources/content/MsgComposeCommands.js @@ -712,17 +712,50 @@ function setupLdapAutocompleteSession() // nsAbLDAPAutoCompFormatter use its default. } - // override autocomplete entry comment format? - // try { - ldapFormatter.commentFormat = - prefs.CopyUnicharPref(autocompleteDirectory + - ".autoComplete.commentFormat"); + // figure out what goes in the comment column, if anything + // + // 0 = none + // 1 = name of addressbook this card came from + // 2 = other per-addressbook format + // + var showComments = 0; + showComments = prefs.GetIntPref( + "mail.autoComplete.commentColumn"); + + switch (showComments) { + + case 1: + // use the name of this directory + // + ldapFormatter.commentFormat = prefs.CopyUnicharPref( + autocompleteDirectory + ".description"); + break; + + case 2: + // override ldap-specific autocomplete entry? + // + try { + ldapFormatter.commentFormat = + prefs.CopyUnicharPref(autocompleteDirectory + + ".autoComplete.commentFormat"); + + } catch (innerException) { + // if nothing has been specified, use the ldap + // organization field + ldapFormatter.commentFormat = "[o]"; + } + break; + + case 0: + default: + // do nothing + } } catch (ex) { - // if this pref isn't there, no big deal. just let - // nsAbLDAPAutoCompFormatter use its default. + // if something went wrong while setting up comments, try and + // proceed anyway } - + // set the session's formatter, which also happens to // force a call to the formatter's getAttributes() method // -- which is why this needs to happen after we've set the @@ -2074,8 +2107,22 @@ function setupAutocomplete() var emailAddr = gCurrentIdentity.email; var start = emailAddr.lastIndexOf("@"); gAutocompleteSession.defaultDomain = emailAddr.slice(start + 1, emailAddr.length); - } - else { + + // if the pref is set to turn on the comment column, honor it here. + // this element then gets cloned for subsequent rows, so they should + // honor it as well + // + try { + if (prefs.GetIntPref("mail.autoComplete.commentColumn")) { + document.getElementById('msgRecipient#1').showCommentColumn = + true; + } + } catch (ex) { + // if we can't get this pref, then don't show the columns (which is + // what the XUL defaults to) + } + + } else { gAutocompleteSession = 1; } } diff --git a/mailnews/compose/resources/content/addressingWidgetOverlay.js b/mailnews/compose/resources/content/addressingWidgetOverlay.js index 2c1843dc9ba..4b2e0b2b922 100644 --- a/mailnews/compose/resources/content/addressingWidgetOverlay.js +++ b/mailnews/compose/resources/content/addressingWidgetOverlay.js @@ -432,6 +432,11 @@ function awAppendNewRow(setFocus) //this copies the autocomplete sessions list from recipient#1 input[0].syncSessions(document.getElementById('msgRecipient#1')); + // also clone the showCommentColumn setting + // + input[0].showCommentColumn = + document.getElementById("msgRecipient#1").showCommentColumn; + // We always clone the first row. The problem is that the first row // could be focused. When we clone that row, we end up with a cloned // XUL textbox that has a focused attribute set. Therefore we think diff --git a/themes/classic/jar.mn b/themes/classic/jar.mn index 86873fd5506..33f222ad298 100644 --- a/themes/classic/jar.mn +++ b/themes/classic/jar.mn @@ -481,6 +481,7 @@ classic.jar: skin/classic/messenger/addressbook/person-hover.gif (messenger/addressbook/person-hover.gif) skin/classic/messenger/addressbook/person.gif (messenger/addressbook/person.gif) skin/classic/messenger/addressbook/property.gif (messenger/addressbook/property.gif) + skin/classic/messenger/addressbook/remote-abook.gif (messenger/addressbook/remote-abook.gif) skin/classic/messenger/addressbook/searchold-disabled.gif (messenger/addressbook/searchold-disabled.gif) skin/classic/messenger/addressbook/searchold-hover-active.gif (messenger/addressbook/searchold-hover-active.gif) skin/classic/messenger/addressbook/searchold-hover.gif (messenger/addressbook/searchold-hover.gif) diff --git a/themes/classic/messenger/addressbook/remote-abook.gif b/themes/classic/messenger/addressbook/remote-abook.gif new file mode 100644 index 00000000000..e69de29bb2d diff --git a/themes/classic/messenger/messengercompose/messengercompose.css b/themes/classic/messenger/messengercompose/messengercompose.css index fd500426f0c..c36e6a8b216 100644 --- a/themes/classic/messenger/messengercompose/messengercompose.css +++ b/themes/classic/messenger/messengercompose/messengercompose.css @@ -257,7 +257,27 @@ list-style-image : url("chrome://messenger/skin/abcard.gif"); margin : 0px 3px 0px 3px; } - + +outlinerbody:-moz-outliner-cell-text(default-match) + { + margin: 2px -3px 2px 15px; + border: none; + } + +outlinerbody:-moz-outliner-image(local-abook) + { + margin: 2px -1px 2px 4px; + border: none; + list-style-image: url("chrome://messenger/skin/addressbook/myaddrbk.gif"); + } + +outlinerbody:-moz-outliner-image(remote-abook) + { + margin: 2px -3px 2px 2px; + border: none; + list-style-image: url("chrome://messenger/skin/addressbook/remote-abook.gif"); + } + #msgheaderstoolbar-box { margin-top : 2px; diff --git a/themes/modern/messenger/messengercompose/messengercompose.css b/themes/modern/messenger/messengercompose/messengercompose.css index aa2f5145817..ecb48dfa4ae 100644 --- a/themes/modern/messenger/messengercompose/messengercompose.css +++ b/themes/modern/messenger/messengercompose/messengercompose.css @@ -19,6 +19,7 @@ * * Contributor(s): * Joe Hewitt (hewitt@netscape.com) + * Dan Mosedale */ /* ===== messengercompose.css =========================================== @@ -226,6 +227,23 @@ list-style-image: url("chrome://messenger/skin/addressbook/icons/person.gif"); } +outlinerbody:-moz-outliner-cell-text(default-match) { + margin: 2px -3px 2px 15px; + border: none; +} + +outlinerbody:-moz-outliner-image(local-abook) { + margin: 2px -3px 2px 4px; + border: none; + list-style-image: url("chrome://messenger/skin/addressbook/icons/myaddrbk.gif"); +} + +outlinerbody:-moz-outliner-image(remote-abook) { + margin: 2px -4px 2px 3px; + border: none; + list-style-image: url("chrome://messenger/skin/addressbook/icons/directory.gif"); +} + /* ::::: status bar border tweaks ::::: */ statusbarpanel, diff --git a/xpfe/components/autocomplete/resources/content/autocomplete.xml b/xpfe/components/autocomplete/resources/content/autocomplete.xml index 6353a5d4e51..769d5c16a2c 100644 --- a/xpfe/components/autocomplete/resources/content/autocomplete.xml +++ b/xpfe/components/autocomplete/resources/content/autocomplete.xml @@ -58,7 +58,7 @@ this.ifSetAttribute("disableAutocomplete", false); this.ifSetAttribute("forceComplete", false); this.ifSetAttribute("tabScrolling", false); - + this.ifSetAttribute("showCommentColumn", false); // initialize the search sessions this.searchSessions = this.getAttribute("searchSessions"); @@ -154,11 +154,40 @@ onset="return this.setAttribute('autoFillAfterMatch', val);" onget="return this.getAttribute('autoFillAfterMatch') == 'true';"/> - + + onget= + "return this.getAttribute('showCommentColumn') == 'true';"> + + + @@ -1057,6 +1086,21 @@ getCellProperties: function(aIndex, aColId, aProperties) { this.getRowProperties(aIndex, aProperties); + + // for the value column, append nsIAutoCompleteItem::className + // to the property list so that we can style this column + // using that property + try { + if (aColId == "value") { + var className = this.mTextbox.getResultAt(aIndex).className; + if ( className != "" ) { + aProperties.AppendElement(this.createAtom(className)); + } + } + } catch (ex) { + // the ability to style here is a frill, so don't abort + // if there's a problem + } }, getColumnProperties: function(aColId, aColElt, aProperties) @@ -1182,6 +1226,15 @@ ]]> + + + + + +