Bug 342065: wrong order of Tags; r=neil, sr=bienvenu

This commit is contained in:
mnyromyr%tprac.de 2006-09-11 23:20:36 +00:00
Родитель f92a2e42f9
Коммит 2cd6f3b234
10 изменённых файлов: 395 добавлений и 202 удалений

Просмотреть файл

@ -593,10 +593,10 @@ function ToggleMessageTagKey(index)
var msgHdr = gDBView.hdrForFirstSelectedMessage;
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"]
.getService(Components.interfaces.nsIMsgTagService);
var allKeys = tagService.keyEnumerator;
while (allKeys.hasMore())
var tagArray = tagService.getAllTags({});
for (var i = 0; i < tagArray.length; ++i)
{
var key = allKeys.getNext();
var key = tagArray[i].key;
if (!--index)
{
// found the key, now toggle its state
@ -671,7 +671,7 @@ function AddTagCallback(name, color)
{
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"]
.getService(Components.interfaces.nsIMsgTagService);
tagService.addTag(name, color);
tagService.addTag(name, color, '');
try
{
ToggleMessageTag(tagService.getKeyForTag(name), true);
@ -700,8 +700,8 @@ function InitMessageTags(menuPopup)
{
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"]
.getService(Components.interfaces.nsIMsgTagService);
var allTags = tagService.tagEnumerator;
var allKeys = tagService.keyEnumerator;
var tagArray = tagService.getAllTags({});
var tagCount = tagArray.length;
// remove any existing non-static entries...
var menuseparator = menuPopup.lastChild.previousSibling;
@ -709,7 +709,7 @@ function InitMessageTags(menuPopup)
menuPopup.removeChild(menuseparator.previousSibling);
// hide double menuseparator
menuseparator.previousSibling.hidden = !allTags.hasMore();
menuseparator.previousSibling.hidden = !tagCount;
// create label and accesskey for the static remove item
var tagRemoveLabel = gMessengerBundle.getString("mailnews.tags.remove");
@ -721,18 +721,16 @@ function InitMessageTags(menuPopup)
if (msgHdr.label)
curKeys += " $label" + msgHdr.label;
var index = 0;
while (allTags.hasMore())
for (var i = 0; i < tagCount; ++i)
{
var tag = allTags.getNext();
var key = allKeys.getNext();
var taginfo = tagArray[i];
// TODO we want to either remove or "check" the tags that already exist
var newMenuItem = document.createElement("menuitem");
SetMessageTagLabel(newMenuItem, ++index, tag);
newMenuItem.setAttribute("value", key);
SetMessageTagLabel(newMenuItem, i + 1, taginfo.tag);
newMenuItem.setAttribute("value", taginfo.key);
newMenuItem.setAttribute("type", "checkbox");
newMenuItem.style.color = tagService.getColorForKey(key);
var removeKey = (" " + curKeys + " ").indexOf(" " + key + " ") > -1;
newMenuItem.style.color = tagService.getColorForKey(taginfo.key);
var removeKey = (" " + curKeys + " ").indexOf(" " + taginfo.key + " ") > -1;
newMenuItem.setAttribute('checked', removeKey);
newMenuItem.setAttribute('oncommand', 'ToggleMessageTagMenu(event.target);');
menuPopup.insertBefore(newMenuItem, menuseparator);

Просмотреть файл

@ -79,13 +79,13 @@ var gDisplayPane = {
buildTagList: function()
{
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"].getService(Components.interfaces.nsIMsgTagService);
var allTags = tagService.tagEnumerator;
var allKeys = tagService.keyEnumerator;
while (allTags.hasMore())
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"]
.getService(Components.interfaces.nsIMsgTagService);
var tagArray = tagService.getAllTags({});
for (var i = 0; i < tagArray.length; ++i)
{
var key = allKeys.getNext();
this.appendTagItem(allTags.getNext(), key, tagService.getColorForKey(key));
var taginfo = tagArray[i];
this.appendTagItem(taginfo.tag, taginfo.key, taginfo.color);
}
},
@ -173,7 +173,7 @@ var gDisplayPane = {
function addTagCallback(aName, aColor)
{
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"].getService(Components.interfaces.nsIMsgTagService);
tagService.addTag(aName, aColor);
tagService.addTag(aName, aColor, '');
var item = gDisplayPane.appendTagItem(aName, tagService.getKeyForTag(aName), aColor);
var tagListBox = document.getElementById('tagList');

Просмотреть файл

@ -21,6 +21,7 @@
*
* Contributor(s):
* David Bienvenu <bienvenu@mozilla.com>
* Karsten Düsterloh <mnyromyr@tprac.de>
*
* 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"),
@ -37,14 +38,13 @@
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
#include "nsIStringEnumerator.idl"
/*
* Keys are the internal representation of tags, and use a limited range of
/*
* Keys are the internal representation of tags, and use a limited range of
* characters, basically the characters allowed in imap keywords, which are
* alphanumeric characters, but don't include spaces. Keys are stored on
* the imap server, in local mail messages, and in summary files.
*
*
* Tags are the user visible representation of keys, and are full unicode
* strings. Tags should allow any unicode character.
*
@ -55,18 +55,40 @@
* sure that no other keyword has the same value since that algorithm
* doesn't guarantee a unique mapping.
*
* Tags are sorted internally by 'importance' by their ordinal strings (which by
* default are equal to a tag's key and thus only stored if different).
* The alphanumerically 'smallest' string is called the 'most important' one and
* comes first in any sorted array. The remainder follows in ascending order.
*/
[scriptable, uuid(ad04db53-cfcc-47eb-b409-b24b3a0b6130)]
interface nsIMsgTagService : nsISupports {
AString getTagForKey(in ACString key); // look up the tag for a key.
void setTagForKey(in ACString key, in AString tag); // this can be used to "rename" a tag
ACString getKeyForTag(in AString tag); // get the key representation of a given tag
void addTagForKey(in ACString key, in AString tag, in ACString color);
void addTag(in AString tag, in ACString color);
ACString getColorForKey(in ACString key);
void deleteKey(in ACString key);
// we need some way to enumerate all tags. Or return a list of all tags.
readonly attribute nsIStringEnumerator tagEnumerator;
readonly attribute nsIUTF8StringEnumerator keyEnumerator;
[scriptable, uuid(84d593a3-5d8a-45e6-96e2-9189acd422e1)]
interface nsIMsgTag : nsISupports {
readonly attribute ACString key; // distinct tag identifier
readonly attribute AString tag; // human readable tag name
readonly attribute ACString color; // tag color
readonly attribute ACString ordinal; // custom sort string (usually empty)
};
[scriptable, uuid(b897da55-8256-4cf5-892b-32e77bc7c50b)]
interface nsIMsgTagService : nsISupports {
// create new tag by deriving the key from the tag
void addTag(in AString tag, in ACString color, in ACString ordinal);
// create/update tag with known key
void addTagForKey(in ACString key, in AString tag, in ACString color, in ACString ordinal);
// get the key representation of a given tag
ACString getKeyForTag(in AString tag);
// get the first key by ordinal order
ACString getTopKey(in string keyList);
// support functions for single tag aspects
AString getTagForKey(in ACString key); // look up the tag for a key.
void setTagForKey(in ACString key, in AString tag); // this can be used to "rename" a tag
ACString getColorForKey(in ACString key);
void setColorForKey(in ACString key, in ACString color);
ACString getOrdinalForKey(in ACString key);
void setOrdinalForKey(in ACString key, in ACString ordinal);
// delete a tag from the list of known tags (but not from any messages)
void deleteKey(in ACString key);
// get all known tags
void getAllTags(out unsigned long count,
[retval, array, size_is(count)] out nsIMsgTag tagArray);
};

Просмотреть файл

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Karsten Düsterloh <mnyromyr@tprac.de>
*
* 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"),
@ -522,9 +523,10 @@
"@mozilla.org/messenger/tagservice;1"
#define NS_MSGTAGSERVICE_CID \
{ /* ad04db53-cfcc-47eb-b409-b24b3a0b6130 */ \
0xad04db53, 0xcfcc, 0x47eb, \
{ 0xb4, 0x09, 0xb2, 0x4b, 0x3a, 0x0b, 0x61, 0x30}}
{ /* b897da55-8256-4cf5-892b-32e77bc7c50b */ \
0xb897da55, 0x8256, 0x4cf5, \
{ 0x89, 0x2b, 0x32, 0xe7, 0x7b, 0xc7, 0xc5, 0x0b}}
//
// nsMessengerOSIntegration
//

Просмотреть файл

@ -1493,24 +1493,18 @@
<![CDATA[
var children = document.getAnonymousNodes(this);
var popupMenu = children[5].firstChild;
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"].getService(Components.interfaces.nsIMsgTagService);
var allTags = tagService.tagEnumerator;
var allKeys = tagService.keyEnumerator;
var tagNum = 0;
while (allTags.hasMore())
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"]
.getService(Components.interfaces.nsIMsgTagService);
var tagArray = tagService.getAllTags({});
for (var i = 0; i < tagArray.length; ++i)
{
var tag = allTags.getNext();
var key = allKeys.getNext();
var taginfo = tagArray[i];
var newMenuItem = document.createElement('menuitem');
newMenuItem.setAttribute('label', tag);
newMenuItem.setAttribute('value', key);
newMenuItem.setAttribute('label', taginfo.tag);
newMenuItem.setAttribute('value', taginfo.key);
popupMenu.appendChild(newMenuItem);
if (tagNum == 0)
{
if (!i)
children[5].selectedItem = newMenuItem;
children[5].value = key;
tagNum++;
}
}
]]>
</body>

Просмотреть файл

@ -551,10 +551,10 @@ function ToggleMessageTagKey(index)
var msgHdr = gDBView.hdrForFirstSelectedMessage;
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"]
.getService(Components.interfaces.nsIMsgTagService);
var allKeys = tagService.keyEnumerator;
while (allKeys.hasMore())
var tagArray = tagService.getAllTags({});
for (var i = 0; i < tagArray.length; ++i)
{
var key = allKeys.getNext();
var key = tagArray[i].key;
if (!--index)
{
// found the key, now toggle its state
@ -628,7 +628,7 @@ function AddTagCallback(name, color)
{
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"]
.getService(Components.interfaces.nsIMsgTagService);
tagService.addTag(name, color);
tagService.addTag(name, color, '');
try
{
ToggleMessageTag(tagService.getKeyForTag(name), true);
@ -657,8 +657,8 @@ function InitMessageTags(menuPopup)
{
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"]
.getService(Components.interfaces.nsIMsgTagService);
var allTags = tagService.tagEnumerator;
var allKeys = tagService.keyEnumerator;
var tagArray = tagService.getAllTags({});
var tagCount = tagArray.length;
// remove any existing non-static entries...
var menuseparator = menuPopup.lastChild.previousSibling;
@ -666,7 +666,7 @@ function InitMessageTags(menuPopup)
menuPopup.removeChild(menuseparator.previousSibling);
// hide double menuseparator
menuseparator.previousSibling.hidden = !allTags.hasMore();
menuseparator.previousSibling.hidden = !tagCount;
// create label and accesskey for the static remove item
var tagRemoveLabel = gMessengerBundle.getString("mailnews.tags.remove");
@ -677,17 +677,15 @@ function InitMessageTags(menuPopup)
var curKeys = msgHdr.getStringProperty("keywords");
if (msgHdr.label)
curKeys += " $label" + msgHdr.label;
var index = 0;
while (allTags.hasMore())
for (var i = 0; i < tagCount; ++i)
{
var tag = allTags.getNext();
var key = allKeys.getNext();
var taginfo = tagArray[i];
// TODO we want to either remove or "check" the tags that already exist
var newMenuItem = document.createElement("menuitem");
SetMessageTagLabel(newMenuItem, ++index, tag);
newMenuItem.setAttribute("value", key);
SetMessageTagLabel(newMenuItem, i + 1, taginfo.tag);
newMenuItem.setAttribute("value", taginfo.key);
newMenuItem.setAttribute("type", "checkbox");
var removeKey = (" " + curKeys + " ").indexOf(" " + key + " ") > -1;
var removeKey = (" " + curKeys + " ").indexOf(" " + taginfo.key + " ") > -1;
newMenuItem.setAttribute('checked', removeKey);
newMenuItem.setAttribute('oncommand', 'ToggleMessageTagMenu(event.target);');
menuPopup.insertBefore(newMenuItem, menuseparator);

Просмотреть файл

@ -401,16 +401,15 @@
<constructor>
<![CDATA[
var menuPopup = document.getAnonymousNodes(this)[0].menupopup;
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"].getService(Components.interfaces.nsIMsgTagService);
var allTags = tagService.tagEnumerator;
var allKeys = tagService.keyEnumerator;
while (allTags.hasMore())
var tagService = Components.classes["@mozilla.org/messenger/tagservice;1"]
.getService(Components.interfaces.nsIMsgTagService);
var tagArray = tagService.getAllTags({});
for (var i = 0; i < tagArray.length; ++i)
{
var tag = allTags.getNext();
var key = allKeys.getNext();
var taginfo = tagArray[i];
var newMenuItem = document.createElement('menuitem');
newMenuItem.setAttribute('label', tag);
newMenuItem.setAttribute('value', key);
newMenuItem.setAttribute('label', taginfo.tag);
newMenuItem.setAttribute('value', taginfo.key);
menuPopup.appendChild(newMenuItem);
}
// propagating a pre-existing hack to make the tag get displayed correctly in the menulist

Просмотреть файл

@ -21,7 +21,7 @@
*
* Contributor(s):
* Jan Varga (varga@ku.sk)
* Håkan Waara (hwaara@chello.se)
* Håkan Waara (hwaara@chello.se)
*
* 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"),
@ -360,23 +360,22 @@ nsresult nsMsgDBView::GetPrefLocalizedString(const char *aPrefName, nsString& aR
nsresult nsMsgDBView::AppendKeywordProperties(const char *keywords, nsISupportsArray *properties, PRBool addSelectedTextProperty)
{
// get last keyword, get its color, turn that into an atom, and and
// append that as a property.
nsCStringArray keywordsArray;
nsCAutoString color;
// skip leading spaces
while (*keywords == ' ')
keywords++;
if (!*keywords)
return NS_OK;
keywordsArray.ParseString(keywords, " ");
// get the top most keyword's color and append that as a property.
nsresult rv;
if (!mTagService)
{
mTagService = do_GetService(NS_MSGTAGSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = mTagService->GetColorForKey(*(keywordsArray[keywordsArray.Count() - 1]), color);
nsCString topKey;
rv = mTagService->GetTopKey(keywords, topKey);
NS_ENSURE_SUCCESS(rv, rv);
if (topKey.IsEmpty())
return NS_OK;
nsCString color;
rv = mTagService->GetColorForKey(topKey, color);
if (NS_SUCCEEDED(rv) && !color.IsEmpty())
{
if (addSelectedTextProperty)

Просмотреть файл

@ -21,6 +21,7 @@
*
* Contributor(s):
* David Bienvenu <bienvenu@mozilla.org>
* Karsten Düsterloh <mnyromyr@tprac.de>
*
* 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"),
@ -38,18 +39,123 @@
#include "msgCore.h"
#include "nsMsgTagService.h"
#include "nsMsgBaseCID.h"
#include "nsIPrefService.h"
#include "nsISupportsPrimitives.h"
#include "nsMsgI18N.h"
#include "nsIPrefLocalizedString.h"
#include "nsMsgDBView.h" // for labels migration
#include "nsStringEnumerator.h"
#include "nsQuickSort.h"
#define STRLEN(s) (sizeof(s) - 1)
#define TAG_PREF_VERSION "version"
#define TAG_PREF_SUFFIX_TAG ".tag"
#define TAG_PREF_SUFFIX_COLOR ".color"
#define TAG_PREF_SUFFIX_ORDINAL ".ordinal"
#define TAG_CMP_LESSER -1
#define TAG_CMP_EQUAL 0
#define TAG_CMP_GREATER 1
// comparison functions for nsQuickSort
PR_STATIC_CALLBACK(int)
CompareMsgTagKeys(const void* aTagPref1, const void* aTagPref2, void* aData)
{
return strcmp(*NS_STATIC_CAST(const char* const*, aTagPref1),
*NS_STATIC_CAST(const char* const*, aTagPref2));
}
PR_STATIC_CALLBACK(int)
CompareMsgTags(const void* aTagPref1, const void* aTagPref2, void* aData)
{
// Sort nsMsgTag objects by ascending order, using their ordinal or key.
// The "smallest" value will be first in the sorted array,
// thus being the most important element.
nsMsgTag *element1 = *(nsMsgTag**) aTagPref1;
nsMsgTag *element2 = *(nsMsgTag**) aTagPref2;
// if we have only one element, it wins
if (!element1 && !element2)
return TAG_CMP_EQUAL;
if (!element2)
return TAG_CMP_LESSER;
if (!element1)
return TAG_CMP_GREATER;
// only use the key if the ordinal is not defined or empty
nsCAutoString value1, value2;
element1->GetOrdinal(value1);
if (value1.IsEmpty())
element1->GetKey(value1);
element2->GetOrdinal(value2);
if (value2.IsEmpty())
element2->GetKey(value2);
return strcmp(value1.get(), value2.get());
}
//
// nsMsgTag
//
NS_IMPL_ISUPPORTS1(nsMsgTag, nsIMsgTag)
nsMsgTag::nsMsgTag(const nsACString &aKey,
const nsAString &aTag,
const nsACString &aColor,
const nsACString &aOrdinal)
: mTag(aTag),
mKey(aKey),
mColor(aColor),
mOrdinal(aOrdinal)
{
}
nsMsgTag::~nsMsgTag()
{
}
/* readonly attribute ACString key; */
NS_IMETHODIMP nsMsgTag::GetKey(nsACString & aKey)
{
aKey = mKey;
return NS_OK;
}
/* readonly attribute AString tag; */
NS_IMETHODIMP nsMsgTag::GetTag(nsAString & aTag)
{
aTag = mTag;
return NS_OK;
}
/* readonly attribute ACString color; */
NS_IMETHODIMP nsMsgTag::GetColor(nsACString & aColor)
{
aColor = mColor;
return NS_OK;
}
/* readonly attribute ACString ordinal; */
NS_IMETHODIMP nsMsgTag::GetOrdinal(nsACString & aOrdinal)
{
aOrdinal = mOrdinal;
return NS_OK;
}
//
// nsMsgTagService
//
NS_IMPL_ISUPPORTS1(nsMsgTagService, nsIMsgTagService)
nsMsgTagService::nsMsgTagService()
{
m_prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
m_prefBranch = nsnull;
nsCOMPtr<nsIPrefService> prefService(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (prefService)
prefService->GetBranch("mailnews.tags.", getter_AddRefs(m_prefBranch));
// need to figure out how to migrate the tags only once.
MigrateLabelsToTags();
}
@ -62,18 +168,16 @@ nsMsgTagService::~nsMsgTagService()
/* wstring getTagForKey (in string key); */
NS_IMETHODIMP nsMsgTagService::GetTagForKey(const nsACString &key, nsAString &_retval)
{
nsCAutoString prefName("mailnews.tags.");
prefName.Append(key);
prefName.AppendLiteral(".tag");
nsCAutoString prefName(key);
prefName.AppendLiteral(TAG_PREF_SUFFIX_TAG);
return GetUnicharPref(prefName.get(), _retval);
}
/* void setTagForKey (in string key); */
NS_IMETHODIMP nsMsgTagService::SetTagForKey(const nsACString &key, const nsAString &tag )
{
nsCAutoString prefName("mailnews.tags.");
prefName.Append(key);
prefName.AppendLiteral(".tag");
nsCAutoString prefName(key);
prefName.AppendLiteral(TAG_PREF_SUFFIX_TAG);
return SetUnicharPref(prefName.get(), tag);
}
@ -82,23 +186,21 @@ NS_IMETHODIMP nsMsgTagService::GetKeyForTag(const nsAString &aTag, nsACString &a
{
PRUint32 count;
char **prefList;
nsresult rv = m_prefBranch->GetChildList("mailnews.tags.", &count, &prefList);
nsresult rv = m_prefBranch->GetChildList("", &count, &prefList);
NS_ENSURE_SUCCESS(rv, rv);
// traverse the list, and look for a pref with the desired tag value.
for (PRUint32 i = count; i--; )
for (PRUint32 i = count; i--;)
{
// The prefname we passed to GetChildList was of the form
// "mailnews.tags." and we are returned the descendants
// in the form of ""mailnews.tags.<key>.tag"
// But we only want the tags, so check that the string
// ends with tag.
if (StringEndsWith(nsDependentCString(prefList[i]), NS_LITERAL_CSTRING(".tag")))
// We are returned the tag prefs in the form "<key>.<tag_data_type>", but
// since we only want the tags, just check that the string ends with "tag".
nsDependentCString prefName(prefList[i]);
if (StringEndsWith(prefName, NS_LITERAL_CSTRING(TAG_PREF_SUFFIX_TAG)))
{
nsAutoString curTag;
GetUnicharPref(prefList[i], curTag);
if (aTag.Equals(curTag))
{
aKey = Substring(nsDependentCString(prefList[i]), 14, strlen(prefList[i]) - 18);
aKey = Substring(prefName, 0, prefName.Length() - STRLEN(TAG_PREF_SUFFIX_TAG));
break;
}
}
@ -107,22 +209,62 @@ NS_IMETHODIMP nsMsgTagService::GetKeyForTag(const nsAString &aTag, nsACString &a
return aKey.IsEmpty() ? NS_ERROR_FAILURE : NS_OK;
}
/* void addTagForKey (in string key, in wstring tag, in long color); */
NS_IMETHODIMP nsMsgTagService::AddTagForKey(const nsACString &key, const nsAString &tag, const nsACString &color)
/* ACString getTopKey (in string keylist); */
NS_IMETHODIMP nsMsgTagService::GetTopKey(const char * keyList, nsACString & _retval)
{
nsCAutoString prefName("mailnews.tags.");
prefName.Append(key);
prefName.AppendLiteral(".tag");
SetUnicharPref(prefName.get(), tag);
prefName.Replace(prefName.Length() - 3, 3, NS_LITERAL_CSTRING("color"));
m_prefBranch->SetCharPref(prefName.get(), PromiseFlatCString(color).get());
_retval = EmptyCString();
// find the most important key
nsCStringArray keyArray;
keyArray.ParseString(keyList, " ");
PRUint32 keyCount = keyArray.Count();
nsCString *topKey = nsnull, *key, topOrdinal, ordinal;
for (PRUint32 i = 0; i < keyCount; ++i)
{
key = keyArray[i];
if (key->IsEmpty())
continue;
// new top key, judged by ordinal order?
nsresult rv = GetOrdinalForKey(*key, ordinal);
if (NS_FAILED(rv) || ordinal.IsEmpty())
ordinal = *key;
if ((ordinal < topOrdinal) || topOrdinal.IsEmpty())
{
topOrdinal = ordinal;
topKey = key; // copy actual result key only once - later
}
}
// return the most important key - if any
if (topKey)
_retval = *topKey;
return NS_OK;
}
/* void addTag (in wstring tag, in long color); */
NS_IMETHODIMP nsMsgTagService::AddTag(const nsAString &tag, const nsACString &color)
/* void addTagForKey (in string key, in wstring tag, in string color, in string ordinal); */
NS_IMETHODIMP nsMsgTagService::AddTagForKey(const nsACString &key,
const nsAString &tag,
const nsACString &color,
const nsACString &ordinal)
{
nsCAutoString prefName(key);
prefName.AppendLiteral(TAG_PREF_SUFFIX_TAG);
SetUnicharPref(prefName.get(), tag);
prefName.Replace(prefName.Length() - STRLEN(TAG_PREF_SUFFIX_TAG),
STRLEN(TAG_PREF_SUFFIX_TAG),
NS_LITERAL_CSTRING(TAG_PREF_SUFFIX_COLOR));
m_prefBranch->SetCharPref(prefName.get(), PromiseFlatCString(color).get());
prefName.Replace(prefName.Length() - STRLEN(TAG_PREF_SUFFIX_COLOR),
STRLEN(TAG_PREF_SUFFIX_COLOR),
NS_LITERAL_CSTRING(TAG_PREF_SUFFIX_ORDINAL));
if (prefName.IsEmpty())
return m_prefBranch->ClearUserPref(prefName.get());
return m_prefBranch->SetCharPref(prefName.get(), PromiseFlatCString(ordinal).get());
}
/* void addTag (in wstring tag, in long color); */
NS_IMETHODIMP nsMsgTagService::AddTag(const nsAString &tag,
const nsACString &color,
const nsACString &ordinal)
{
nsCAutoString prefName("mailnews.tags.");
// figure out key from tag. Apply transformation stripping out
// illegal characters like <SP> and then convert to imap mod utf7.
// Then, check if we have a tag with that key yet, and if so,
@ -132,13 +274,13 @@ NS_IMETHODIMP nsMsgTagService::AddTag(const nsAString &tag, const nsACString &c
transformedTag.ReplaceChar(" ()/{%*<>\\\"", '_');
nsCAutoString key;
CopyUTF16toMUTF7(transformedTag, key);
prefName.Append(key);
nsCAutoString prefName(key);
while (PR_TRUE)
{
nsAutoString tagValue;
GetUnicharPref(prefName.get(), tagValue);
if (tagValue.IsEmpty() || tagValue.Equals(tag))
return AddTagForKey(key, tag, color);
return AddTagForKey(key, tag, color, ordinal);
prefName.Append('A');
}
NS_ASSERTION(PR_FALSE, "can't get here");
@ -148,99 +290,128 @@ NS_IMETHODIMP nsMsgTagService::AddTag(const nsAString &tag, const nsACString &c
/* long getColorForKey (in string key); */
NS_IMETHODIMP nsMsgTagService::GetColorForKey(const nsACString &key, nsACString &_retval)
{
nsCAutoString prefName("mailnews.tags.");
prefName.Append(key);
prefName.AppendLiteral(".color");
nsCAutoString prefName(key);
prefName.AppendLiteral(TAG_PREF_SUFFIX_COLOR);
nsXPIDLCString color;
nsresult rv = m_prefBranch->GetCharPref(prefName.get(), getter_Copies(color));
_retval = color;
return rv;
}
/* void setColorForKey (in ACString key, in ACString color); */
NS_IMETHODIMP nsMsgTagService::SetColorForKey(const nsACString & key, const nsACString & color)
{
if (color.IsEmpty())
return NS_ERROR_ILLEGAL_VALUE;
nsCAutoString prefName(key);
prefName.AppendLiteral(TAG_PREF_SUFFIX_COLOR);
return m_prefBranch->SetCharPref(prefName.get(), PromiseFlatCString(color).get());
}
/* ACString getOrdinalForKey (in ACString key); */
NS_IMETHODIMP nsMsgTagService::GetOrdinalForKey(const nsACString & key, nsACString & _retval)
{
nsCAutoString prefName(key);
prefName.AppendLiteral(TAG_PREF_SUFFIX_ORDINAL);
nsXPIDLCString ordinal;
nsresult rv = m_prefBranch->GetCharPref(prefName.get(), getter_Copies(ordinal));
_retval = ordinal;
return rv;
}
/* void setOrdinalForKey (in ACString key, in ACString ordinal); */
NS_IMETHODIMP nsMsgTagService::SetOrdinalForKey(const nsACString & key, const nsACString & ordinal)
{
nsCAutoString prefName(key);
prefName.AppendLiteral(TAG_PREF_SUFFIX_ORDINAL);
if (ordinal.IsEmpty())
return m_prefBranch->ClearUserPref(prefName.get());
return m_prefBranch->SetCharPref(prefName.get(), PromiseFlatCString(ordinal).get());
}
/* void deleteTag (in wstring tag); */
NS_IMETHODIMP nsMsgTagService::DeleteKey(const nsACString &key)
{
// clear the associated prefs
nsCAutoString prefName("mailnews.tags.");
prefName.Append(key);
return m_prefBranch->DeleteBranch(prefName.get());
return m_prefBranch->DeleteBranch(PromiseFlatCString(key).get());
}
/* readonly attribute nsIStringEnumerator tagEnumerator; */
NS_IMETHODIMP nsMsgTagService::GetTagEnumerator(nsIStringEnumerator * *aTagEnumerator)
/* void getAllTags (out unsigned long count, [array, size_is (count), retval] out nsIMsgTag tagArray); */
NS_IMETHODIMP nsMsgTagService::GetAllTags(PRUint32 *aCount, nsIMsgTag ***aTagArray)
{
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// preset harmless default values
*aCount = 0;
*aTagArray = nsnull;
PRUint32 count;
// get the actual tag definitions
nsresult rv;
PRUint32 prefCount;
char **prefList;
rv = prefBranch->GetChildList("mailnews.tags.", &count, &prefList);
rv = m_prefBranch->GetChildList("", &prefCount, &prefList);
NS_ENSURE_SUCCESS(rv, rv);
nsStringArray *stringArray = new nsStringArray(count); // or should it be count / 2?
if (!stringArray)
// sort them by key for ease of processing
NS_QuickSort(prefList, prefCount, sizeof(char*), CompareMsgTagKeys, nsnull);
// build an array of nsIMsgTag elements from the orderered list
// it's at max the same size as the preflist, but usually only about half
*aTagArray = (nsIMsgTag**) NS_Alloc(sizeof(nsIMsgTag*) * prefCount);
if (!*aTagArray)
return NS_ERROR_OUT_OF_MEMORY;
// traverse the list, and truncate all the descendant strings to just
// one branch level below the root branch.
for (PRUint32 i = count; i--; )
PRUint32 currentTagIndex = 0;
nsMsgTag *newMsgTag;
nsString tag;
nsCString lastKey, color, ordinal;
for (PRUint32 i = prefCount; i--;)
{
// The prefname we passed to GetChildList was of the form
// "mailnews.tags." and we are returned the descendants
// in the form of ""mailnews.tags.<key>.tag"
// But we only want the tags, so check that the string
// ends with tag.
if (StringEndsWith(nsDependentCString(prefList[i]), NS_LITERAL_CSTRING(".tag")))
// extract just the key from <key>.<info=tag|color|ordinal>
char *info = strrchr(prefList[i], '.');
if (info)
{
nsAutoString tag;
GetUnicharPref(prefList[i], tag);
stringArray->AppendString(tag);
nsCAutoString key(Substring(prefList[i], info));
if (key != lastKey)
{
if (!key.IsEmpty())
{
// .tag MUST exist (but may be empty)
rv = GetTagForKey(key, tag);
if (NS_SUCCEEDED(rv))
{
// .color MAY exist
rv = GetColorForKey(key, color);
if (NS_FAILED(rv))
color = EmptyCString();
// .ordinal MAY exist
rv = GetOrdinalForKey(key, ordinal);
if (NS_FAILED(rv))
ordinal = EmptyCString();
// store the tag info in our array
newMsgTag = new nsMsgTag(key, tag, color, ordinal);
if (!newMsgTag)
return NS_ERROR_OUT_OF_MEMORY;
(*aTagArray)[currentTagIndex++] = newMsgTag;
NS_ADDREF(newMsgTag);
}
}
lastKey = key;
}
}
}
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, prefList);
return NS_NewAdoptingStringEnumerator(aTagEnumerator, stringArray);;
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefList);
// return the number of tags
// (the idl's size_is(count) parameter ensures that the array is cut accordingly)
*aCount = currentTagIndex;
// sort the non-null entries by ordinal
NS_QuickSort(*aTagArray, *aCount, sizeof(nsMsgTag*), CompareMsgTags, nsnull);
return NS_OK;
}
NS_IMETHODIMP nsMsgTagService::GetKeyEnumerator(nsIUTF8StringEnumerator * *aKeyEnumerator)
{
nsresult rv;
nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 count;
char **prefList;
rv = prefBranch->GetChildList("mailnews.tags.", &count, &prefList);
NS_ENSURE_SUCCESS(rv, rv);
nsCStringArray *stringArray = new nsCStringArray; // or should it be count / 2?
if (!stringArray)
return NS_ERROR_OUT_OF_MEMORY;
// traverse the list, and truncate all the descendant strings to just
// one branch level below the root branch.
for (PRUint32 i = count; i--; )
{
// The prefname we passed to GetChildList was of the form
// "mailnews.tags." and we are returned the descendants
// in the form of ""mailnews.tags.<key>.tag"
// But we only want the keys, so check that the string
// ends with tag.
if (StringEndsWith(nsDependentCString(prefList[i]), NS_LITERAL_CSTRING(".tag")))
{
nsCAutoString key;
nsDependentCString prefStr(prefList[i]);
prefStr.Mid(key, 14, strlen(prefList[i]) - 18);
stringArray->AppendCString(key);
}
}
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, prefList);
return NS_NewAdoptingUTF8StringEnumerator(aKeyEnumerator, stringArray);;
}
/* End of implementation class template. */
nsresult
nsMsgTagService::getPrefService()
nsMsgTagService::getPrefService()
{
if (m_prefBranch)
if (m_prefBranch)
return NS_OK;
nsresult rv;
@ -256,12 +427,12 @@ nsresult nsMsgTagService::SetUnicharPref(const char *prefName,
{
nsresult rv = getPrefService();
NS_ENSURE_SUCCESS(rv, rv);
if (!val.IsEmpty())
{
nsCOMPtr<nsISupportsString> supportsString =
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
if (supportsString)
if (supportsString)
{
supportsString->SetData(val);
rv = m_prefBranch->SetComplexValue(prefName,
@ -269,7 +440,7 @@ nsresult nsMsgTagService::SetUnicharPref(const char *prefName,
supportsString);
}
}
else
else
{
m_prefBranch->ClearUserPref(prefName);
}
@ -281,10 +452,10 @@ nsresult nsMsgTagService::GetUnicharPref(const char *prefName,
{
nsresult rv = getPrefService();
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISupportsString> supportsString =
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
if (supportsString)
if (supportsString)
{
rv = m_prefBranch->GetComplexValue(prefName,
NS_GET_IID(nsISupportsString),
@ -303,7 +474,7 @@ nsresult nsMsgTagService::MigrateLabelsToTags()
nsCString prefString;
PRInt32 prefVersion = 0;
nsresult rv = m_prefBranch->GetIntPref("mailnews.tags.version", &prefVersion);
nsresult rv = m_prefBranch->GetIntPref(TAG_PREF_VERSION, &prefVersion);
if (NS_SUCCEEDED(rv) && prefVersion == 1)
return rv;
nsCOMPtr<nsIPrefLocalizedString> pls;
@ -325,10 +496,9 @@ nsresult nsMsgTagService::MigrateLabelsToTags()
rv = m_prefBranch->GetCharPref(prefString.get(), getter_Copies(csval));
NS_ENSURE_SUCCESS(rv, rv);
rv = AddTagForKey(labelKey, ucsval, csval);
rv = AddTagForKey(labelKey, ucsval, csval, EmptyCString());
labelKey.SetCharAt(++i + '1', 6);
}
m_prefBranch->SetIntPref("mailnews.tags.version", 1);
m_prefBranch->SetIntPref(TAG_PREF_VERSION, 1);
return rv;
}

Просмотреть файл

@ -21,6 +21,7 @@
*
* Contributor(s):
* David Bienvenu <bienvenu@mozilla.org>
* Karsten Düsterloh <mnyromyr@tprac.de>
*
* 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"),
@ -42,15 +43,25 @@
#include "nsIMsgTagService.h"
#include "nsIPrefBranch.h"
class nsMsgTagEntry
class nsMsgTag : public nsIMsgTag
{
public:
nsMsgTagEntry(const char *key, const PRUnichar *tag, PRUint32 color);
nsString m_tag;
nsCString m_key;
PRUint32 m_color;
NS_DECL_ISUPPORTS
NS_DECL_NSIMSGTAG
nsMsgTag(const nsACString &aKey,
const nsAString &aTag,
const nsACString &aColor,
const nsACString &aOrdinal);
~nsMsgTag();
protected:
nsString mTag;
nsCString mKey, mColor, mOrdinal;
};
class nsMsgTagService : public nsIMsgTagService
{
public:
@ -65,9 +76,9 @@ private:
protected:
nsresult getPrefService() ;
nsresult SetUnicharPref(const char *prefName,
const nsAString &prefValue);
const nsAString &prefValue);
nsresult GetUnicharPref(const char *prefName,
nsAString &prefValue);
nsAString &prefValue);
nsresult MigrateLabelsToTags();
nsCOMPtr<nsIPrefBranch> m_prefBranch;