diff --git a/mozilla/mailnews/addrbook/public/nsIAbView.idl b/mozilla/mailnews/addrbook/public/nsIAbView.idl index 266ede50e93..f93522f8c07 100644 --- a/mozilla/mailnews/addrbook/public/nsIAbView.idl +++ b/mozilla/mailnews/addrbook/public/nsIAbView.idl @@ -39,11 +39,13 @@ #include "nsISupports.idl" interface nsIAbCard; +interface nsIAbDirectory; [scriptable, uuid(79ad5d6e-1dd2-11b2-addd-f547dab50d75)] interface nsIAbViewListener : nsISupports { void onSelectionChanged(); + void onCountChanged(in long total); }; [scriptable, uuid(e35c015c-1dd1-11b2-9494-f88326252aae)] @@ -56,6 +58,7 @@ interface nsIAbView : nsISupports readonly attribute string URI; readonly attribute wstring sortColumn; readonly attribute wstring sortDirection; + readonly attribute nsIAbDirectory directory; nsIAbCard getCardFromRow(in long row); void selectAll(); diff --git a/mozilla/mailnews/addrbook/resources/content/addressbook-panel.js b/mozilla/mailnews/addrbook/resources/content/addressbook-panel.js index 533413ac3bf..6384ab6e1a0 100644 --- a/mozilla/mailnews/addrbook/resources/content/addressbook-panel.js +++ b/mozilla/mailnews/addrbook/resources/content/addressbook-panel.js @@ -21,6 +21,12 @@ * Seth Spitzer */ +function GetAbViewListener() +{ + // the ab panel doesn't care if the total changes, or if the selection changes + return null; +} + function abPanelLoad() { InitCommonJS(); diff --git a/mozilla/mailnews/addrbook/src/nsAbView.cpp b/mozilla/mailnews/addrbook/src/nsAbView.cpp index 254ee986972..33f7131fe5c 100644 --- a/mozilla/mailnews/addrbook/src/nsAbView.cpp +++ b/mozilla/mailnews/addrbook/src/nsAbView.cpp @@ -49,9 +49,22 @@ #include "nsIAddrBookSession.h" #include "nsAbBaseCID.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsIPrefBranchInternal.h" + + #define CARD_NOT_FOUND -1 #define ALL_ROWS -1 +#define PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST "mail.addr_book.lastnamefirst" + +// also, our default primary sort +#define DISPLAY_NAME_COLUMN_ID "DisplayName" + +// also, our default secondary sort +#define PRIMARY_EMAIL_COLUMN_ID "PrimaryEmail" + static NS_DEFINE_CID(kCollationFactoryCID, NS_COLLATIONFACTORY_CID); NS_IMPL_ADDREF(nsAbView) @@ -62,6 +75,7 @@ NS_INTERFACE_MAP_BEGIN(nsAbView) NS_INTERFACE_MAP_ENTRY(nsIAbView) NS_INTERFACE_MAP_ENTRY(nsIOutlinerView) NS_INTERFACE_MAP_ENTRY(nsIAbListener) + NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_END nsAbView::nsAbView() @@ -69,6 +83,7 @@ nsAbView::nsAbView() NS_INIT_ISUPPORTS(); mMailListAtom = getter_AddRefs(NS_NewAtom("MailList")); mSuppressSelectionChange = PR_FALSE; + mSuppressCountChange = PR_FALSE; } nsAbView::~nsAbView() @@ -86,6 +101,10 @@ NS_IMETHODIMP nsAbView::Close() mAbViewListener = nsnull; nsresult rv = NS_OK; + + rv = RemovePrefObservers(); + NS_ENSURE_SUCCESS(rv,rv); + nsCOMPtr abSession = do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv); if(NS_SUCCEEDED(rv)) abSession->RemoveAddressBookListener(this); @@ -93,19 +112,28 @@ NS_IMETHODIMP nsAbView::Close() PRInt32 i = mCards.Count(); while(i-- > 0) { - RemoveCardAt(i); + rv = RemoveCardAt(i); + NS_ASSERTION(NS_SUCCEEDED(rv), "remove card failed\n"); } return NS_OK; } -void nsAbView::RemoveCardAt(PRInt32 row) +nsresult nsAbView::RemoveCardAt(PRInt32 row) { + nsresult rv; + AbCard *abcard = (AbCard*) (mCards.ElementAt(row)); NS_IF_RELEASE(abcard->card); mCards.RemoveElementAt(row); PR_FREEIF(abcard->primaryCollationKey); PR_FREEIF(abcard->secondaryCollationKey); PR_FREEIF(abcard); + + if (mAbViewListener && !mSuppressCountChange) { + rv = mAbViewListener->OnCountChanged(mCards.Count()); + NS_ENSURE_SUCCESS(rv,rv); + } + return NS_OK; } NS_IMETHODIMP nsAbView::GetURI(char **aURI) @@ -114,6 +142,46 @@ NS_IMETHODIMP nsAbView::GetURI(char **aURI) return NS_OK; } +nsresult nsAbView::AddPrefObservers() +{ + nsresult rv; + + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv,rv); + + nsCOMPtr prefBranch; + rv = prefs->GetBranch(nsnull, getter_AddRefs(prefBranch)); + NS_ENSURE_SUCCESS(rv,rv); + + nsCOMPtr pbi = do_QueryInterface(prefBranch, &rv); + NS_ENSURE_SUCCESS(rv,rv); + + rv = pbi->AddObserver(PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST, this, PR_FALSE); + NS_ENSURE_SUCCESS(rv,rv); + + return NS_OK; +} + +nsresult nsAbView::RemovePrefObservers() +{ + nsresult rv; + + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv,rv); + + nsCOMPtr prefBranch; + rv = prefs->GetBranch(nsnull, getter_AddRefs(prefBranch)); + NS_ENSURE_SUCCESS(rv,rv); + + nsCOMPtr pbi = do_QueryInterface(prefBranch, &rv); + NS_ENSURE_SUCCESS(rv,rv); + + rv = pbi->RemoveObserver(PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST, this); + NS_ENSURE_SUCCESS(rv,rv); + + return NS_OK; +} + NS_IMETHODIMP nsAbView::Init(const char *aURI, nsIAbViewListener *abViewListener, const PRUnichar *colID, const PRUnichar *sortDirection) { @@ -122,13 +190,8 @@ NS_IMETHODIMP nsAbView::Init(const char *aURI, nsIAbViewListener *abViewListener mURI = aURI; mAbViewListener = abViewListener; - /* todo: - register as a listener of "mail.addr_book.lastnamefirst" - const kDisplayName = 0; - const kLastNameFirst = 1; - const kFirstNameFirst = 2; - if it changes, rebuild and invalidate - */ + rv = AddPrefObservers(); + NS_ENSURE_SUCCESS(rv,rv); nsCOMPtr rdfService = do_GetService("@mozilla.org/rdf/rdf-service;1",&rv); NS_ENSURE_SUCCESS(rv, rv); @@ -151,9 +214,22 @@ NS_IMETHODIMP nsAbView::Init(const char *aURI, nsIAbViewListener *abViewListener rv = abSession->AddAddressBookListener(this); NS_ENSURE_SUCCESS(rv,rv); + + if (mAbViewListener && !mSuppressCountChange) { + rv = mAbViewListener->OnCountChanged(mCards.Count()); + NS_ENSURE_SUCCESS(rv,rv); + } return rv; } +NS_IMETHODIMP nsAbView::GetDirectory(nsIAbDirectory **aDirectory) +{ + NS_ENSURE_ARG_POINTER(aDirectory); + *aDirectory = mDirectory; + NS_IF_ADDREF(*aDirectory); + return NS_OK; +} + nsresult nsAbView::EnumerateCards() { nsresult rv; @@ -439,15 +515,20 @@ NS_IMETHODIMP nsAbView::SortBy(const PRUnichar *colID, const PRUnichar *sortDir) nsAutoString sortColumn; if (!colID) - sortColumn = NS_LITERAL_STRING("DisplayName"); // default sort + sortColumn = NS_LITERAL_STRING(DISPLAY_NAME_COLUMN_ID); // default sort else sortColumn = colID; PRInt32 count = mCards.Count(); PRInt32 i; - // if we are sorting by how we are already sorted, just reverse - if (!nsCRT::strcmp(mSortColumn.get(),sortColumn.get())) { + // if we are sorting by how we are already sorted, + // and just the sort direction changes, just reverse + // + // note, we'll call SortBy() with the existing sort column and the + // existing sort direction, and that needs to do a complete resort. + // for example, we do that when the PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST changes + if (!nsCRT::strcmp(mSortColumn.get(),sortColumn.get()) && !nsCRT::strcmp(mSortDirection.get(), sortDir)) { PRInt32 halfPoint = count / 2; for (i=0; i < halfPoint; i++) { // swap the elements. @@ -506,7 +587,7 @@ nsresult nsAbView::GenerateCollationKeysForCard(const PRUnichar *colID, AbCard * NS_ENSURE_SUCCESS(rv,rv); // XXX fix me, do this with const to avoid the strcpy - rv = abcard->card->GetCardUnicharValue(NS_LITERAL_STRING("PrimaryEmail").get(), getter_Copies(value)); + rv = abcard->card->GetCardUnicharValue(NS_LITERAL_STRING(PRIMARY_EMAIL_COLUMN_ID).get(), getter_Copies(value)); NS_ENSURE_SUCCESS(rv,rv); // XXX be smarter about the key, from an arena @@ -590,6 +671,41 @@ NS_IMETHODIMP nsAbView::OnItemAdded(nsISupports *parentDir, nsISupports *item) return rv; } +NS_IMETHODIMP nsAbView::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData) +{ + nsresult rv; + + if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { + nsDependentString prefName(someData); + + if (prefName.Equals(NS_LITERAL_STRING(PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST))) { + // the PREF_MAIL_ADDR_BOOK_LASTNAMEFIRST pref affects how the DisplayName column looks. + // so if the DisplayName is our primary or secondary sort, + // we need to resort. + // + // XXX optimize me + // PrimaryEmail is always the secondary sort, unless it is currently the + // primary sort. So, if PrimaryEmail is the primary sort, + // DisplayName might be the secondary sort. + // + // one day, we can get fancy and remember what the secondary sort is. + // we we do that, we can fix this code. at best, it will turn a sort into a invalidate. + // + // if neither the primary nor the secondary sorts are DisplayName, all we have to do is + // invalidate (to show the new DisplayNames), but the sort will not change. + if (!nsCRT::strcmp(mSortColumn.get(), NS_LITERAL_STRING(DISPLAY_NAME_COLUMN_ID).get()) || + !nsCRT::strcmp(mSortColumn.get(), NS_LITERAL_STRING(PRIMARY_EMAIL_COLUMN_ID).get())) { + rv = SortBy(mSortColumn.get(), mSortDirection.get()); + } + else { + rv = InvalidateOutliner(ALL_ROWS); + } + NS_ENSURE_SUCCESS(rv,rv); + } + } + return NS_OK; +} + nsresult nsAbView::AddCard(AbCard *abcard, PRBool selectCardAfterAdding, PRInt32 *index) { nsresult rv = NS_OK; @@ -607,6 +723,11 @@ nsresult nsAbView::AddCard(AbCard *abcard, PRBool selectCardAfterAdding, PRInt32 mOutlinerSelection->RangedSelect(*index, *index, PR_FALSE /* augment */); } + if (mAbViewListener && !mSuppressCountChange) { + rv = mAbViewListener->OnCountChanged(mCards.Count()); + NS_ENSURE_SUCCESS(rv,rv); + } + return rv; } @@ -636,6 +757,7 @@ NS_IMETHODIMP nsAbView::OnItemRemoved(nsISupports *parentDir, nsISupports *item) if (directory.get() == mDirectory.get()) { rv = RemoveCardAndSelectNextCard(item); + NS_ENSURE_SUCCESS(rv,rv); } return rv; } @@ -647,7 +769,9 @@ nsresult nsAbView::RemoveCardAndSelectNextCard(nsISupports *item) if (card) { PRInt32 index = FindIndexForCard(card); if (index != CARD_NOT_FOUND) { - RemoveCardAt(index); + rv = RemoveCardAt(index); + NS_ENSURE_SUCCESS(rv,rv); + if (mOutliner) rv = mOutliner->RowCountChanged(index, -1); NS_ENSURE_SUCCESS(rv,rv); @@ -731,14 +855,18 @@ NS_IMETHODIMP nsAbView::OnItemPropertyChanged(nsISupports *item, const char *pro } mSuppressSelectionChange = PR_TRUE; - + mSuppressCountChange = PR_TRUE; + // remove the old card - RemoveCardAt(index); - + rv = RemoveCardAt(index); + NS_ASSERTION(NS_SUCCEEDED(rv), "remove card failed\n"); + // add the card we created, and select it (to restore selection) if it was selected rv = AddCard(newCard, cardWasSelected /* select card */, &index); + NS_ASSERTION(NS_SUCCEEDED(rv), "add card failed\n"); + mSuppressSelectionChange = PR_FALSE; - NS_ENSURE_SUCCESS(rv,rv); + mSuppressCountChange = PR_FALSE; // ensure restored selection is visible if (cardWasSelected) { diff --git a/mozilla/mailnews/addrbook/src/nsAbView.h b/mozilla/mailnews/addrbook/src/nsAbView.h index 684b6134d9c..f15668f0ab4 100644 --- a/mozilla/mailnews/addrbook/src/nsAbView.h +++ b/mozilla/mailnews/addrbook/src/nsAbView.h @@ -50,6 +50,7 @@ #include "nsIAtom.h" #include "nsICollation.h" #include "nsIAbListener.h" +#include "nsIObserver.h" typedef struct AbCard { @@ -59,7 +60,7 @@ typedef struct AbCard } AbCard; -class nsAbView : public nsIAbView, public nsIOutlinerView, public nsIAbListener +class nsAbView : public nsIAbView, public nsIOutlinerView, public nsIAbListener, public nsIObserver { public: nsAbView(); @@ -69,6 +70,7 @@ public: NS_DECL_NSIABVIEW NS_DECL_NSIOUTLINERVIEW NS_DECL_NSIABLISTENER + NS_DECL_NSIOBSERVER private: nsCOMPtr mOutliner; @@ -78,11 +80,12 @@ private: PRInt32 FindIndexForCard(nsIAbCard *card); nsresult GenerateCollationKeysForCard(const PRUnichar *colID, AbCard *abcard); nsresult InvalidateOutliner(PRInt32 row); - void RemoveCardAt(PRInt32 row); + nsresult RemoveCardAt(PRInt32 row); nsresult AddCard(AbCard *abcard, PRBool selectCardAfterAdding, PRInt32 *index); nsresult RemoveCardAndSelectNextCard(nsISupports *item); nsresult EnumerateCards(); - PRBool mSuppressSelectionChange; + nsresult AddPrefObservers(); + nsresult RemovePrefObservers(); nsCString mURI; nsCOMPtr mDirectory; @@ -92,6 +95,9 @@ private: nsString mSortDirection; nsCOMPtr mCollationKeyGenerator; nsCOMPtr mAbViewListener; + + PRPackedBool mSuppressSelectionChange; + PRPackedBool mSuppressCountChange; }; #endif /* _nsAbView_H_ */