Fixes 17427, 17288. r=bienvenu. NextUnreadThread works and Next Unread Messages uses it

for optimization.  Thread counts work in thread pane.  Can now mark a replied or forwarded message
as unread.
This commit is contained in:
putterman%netscape.com 2000-01-05 00:56:27 +00:00
Родитель 77ae5fdf0d
Коммит d00e9f8117
14 изменённых файлов: 458 добавлений и 101 удалений

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

@ -370,8 +370,8 @@ function ToggleMessageRead(treeItem)
{
var tree = GetThreadTree();
var status = treeItem.getAttribute('Status');
var unread = (status == " ") || (status == "new");
var isUnread = treeItem.getAttribute('IsUnread');
var unread = (isUnread == "true");
messenger.MarkMessageRead(tree.database, treeItem.resource, unread);
}

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

@ -370,6 +370,8 @@ Rights Reserved.
<menuitem value="&nextMsgCmd.label;" oncommand="MsgNextMessage();"/>
<menuitem value="&nextUnreadMsgCmd.label;" oncommand="MsgNextUnreadMessage();"/>
<menuitem value="&nextFlaggedMsgCmd.label;" oncommand="MsgNextFlaggedMessage();"/>
<menuseparator/>
<menuitem value="&nextUnreadThread.label;" oncommand="MsgNextUnreadThread();"/>
</menupopup>
</menu>
<menu value="&prevMenu.label;">

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

@ -32,14 +32,14 @@ function ResourceGoMessage(message)
function GoUnreadMessage(message)
{
var status = message.getAttribute('Status');
return(status == ' ' || status == 'New');
var isUnread = message.getAttribute('IsUnread');
return(isUnread == 'true');
}
function ResourceGoUnreadMessage(message)
{
var statusValue = GetMessageValue(message, "http://home.netscape.com/NC-rdf#Status");
return(statusValue == ' ' || statusValue == 'New');
var isUnreadValue = GetMessageValue(message, "http://home.netscape.com/NC-rdf#IsUnread");
return(isUnreadValue == 'true');
}
function GoFlaggedMessage(message)
@ -67,13 +67,26 @@ function GetMessageValue(message, propertyURI)
return null;
}
function GoUnreadThread(messageElement)
{
var messageuri = messageElement.getAttribute('id');
var messageResource = RDF.GetResource(messageuri);
var unreadCount = GetMessageValue(messageResource, "http://home.netscape.com/NC-rdf#TotalUnreadMessages");
return (unreadCount !="");
}
/*GoNextMessage finds the message that matches criteria and selects it.
nextFunction is the function that will be used to detertime if a message matches criteria.
It must take a node and return a boolean.
nextResourceFunction is the function that will be used to determine if a message in the form of a resource
matches criteria. Takes a resource and returns a boolean
nextThreadFunction is an optional function that can be used to optimize whether or not a thread will have a
message that matches the criteria. Takes the top level message in the form of a node and returns a boolean.
startFromBeginning is a boolean that states whether or not we should start looking at the beginning
if we reach the end
*/
function GoNextMessage(nextFunction, nextResourceFunction, startFromBeginning)
function GoNextMessage(nextFunction, nextResourceFunction, nextThreadFunction, startFromBeginning)
{
var tree = GetThreadTree();
@ -93,7 +106,7 @@ function GoNextMessage(nextFunction, nextResourceFunction, startFromBeginning)
if(messageView.showThreads)
{
nextMessage = GetNextMessageInThreads(tree, currentMessage, nextFunction, nextResourceFunction, startFromBeginning);
nextMessage = GetNextMessageInThreads(tree, currentMessage, nextFunction, nextResourceFunction, nextThreadFunction, startFromBeginning);
}
else
{
@ -157,7 +170,7 @@ function GetNextMessage(tree, currentMessage, nextFunction, startFromBeginning)
return nextMessage;
}
function GetNextMessageInThreads(tree, currentMessage, nextFunction, nextResourceFunction, startFromBeginning)
function GetNextMessageInThreads(tree, currentMessage, nextFunction, nextResourceFunction, nextThreadFunction, startFromBeginning)
{
var checkStartMessage = false;
@ -168,11 +181,14 @@ function GetNextMessageInThreads(tree, currentMessage, nextFunction, nextResourc
checkStartMessage = true;
}
return FindNextMessageInThreads(currentMessage, currentMessage, nextFunction, nextResourceFunction, startFromBeginning, checkStartMessage);
return FindNextMessageInThreads(currentMessage, currentMessage, nextFunction, nextResourceFunction, nextThreadFunction, startFromBeginning, checkStartMessage);
}
function FindNextMessageInThreads(startMessage, originalStartMessage, nextFunction, nextResourceFunction, startFromBeginning, checkStartMessage)
function FindNextMessageInThreads(startMessage, originalStartMessage, nextFunction, nextResourceFunction, nextThreadFunction, startFromBeginning, checkStartMessage)
{
var nextMessage;
var nextChildMessage;
//First check startMessage if we are supposed to
if(checkStartMessage)
{
@ -180,6 +196,17 @@ function FindNextMessageInThreads(startMessage, originalStartMessage, nextFuncti
return startMessage;
}
//if we're on the top level and a thread function has been passed in, we might be able to search faster.
if(startMessage.parentNode.parentNode.nodeName != "treeitem" && nextThreadFunction)
{
var nextTopMessage = FindNextThread(startMessage, nextThreadFunction, startFromBeginning, true);
nextMessage = GetNextInThread(nextTopMessage, nextFunction, nextResourceFunction);
if(nextMessage)
{
return nextMessage;
}
}
//Next, search the current messages children.
nextChildMessage = FindNextInChildren(startMessage, originalStartMessage, nextFunction, nextResourceFunction);
if(nextChildMessage)
@ -210,7 +237,7 @@ function FindNextMessageInThreads(startMessage, originalStartMessage, nextFuncti
{
if(parentMessage.nextSibling != null)
{
nextMessage = FindNextMessageInThreads(parentMessage.nextSibling, originalStartMessage, nextFunction, nextResourceFunction, startFromBeginning, true);
nextMessage = FindNextMessageInThreads(parentMessage.nextSibling, originalStartMessage, nextFunction, nextResourceFunction, nextThreadFunction, startFromBeginning, true);
return nextMessage;
}
parentMessage = parentMessage.parentNode.parentNode;
@ -218,7 +245,7 @@ function FindNextMessageInThreads(startMessage, originalStartMessage, nextFuncti
//otherwise it's the tree so we need to stop and potentially start from the beginning
if(startFromBeginning)
{
nextMessage = FindNextMessageInThreads(FindFirstMessage(parentMessage), originalStartMessage, nextFunction, nextResourceFunction, false, true);
nextMessage = FindNextMessageInThreads(FindFirstMessage(parentMessage), originalStartMessage, nextFunction, nextResourceFunction, nextThreadFunction, false, true);
return nextMessage;
}
return null;
@ -390,11 +417,19 @@ function ChangeSelection(tree, newMessage)
function FindFirstMessage(tree)
{
var treeChildren = tree.getElementsByTagName('treechildren');
if(treeChildren.length > 1)
//getElementsByTagName is too slow which is why I'm using this loop. Just find the first
//child of the tree that has the 'treechildren' tag and return it's first child. This will
//be the first message.
var children = tree.childNodes;
var numChildren = children.length;
for(var i = 0; i < numChildren; i++)
{
//The first treeChildren will be for the template.
return treeChildren[1].firstChild;
if(children[i].nodeName == 'treechildren')
{
return children[i].firstChild;
}
}
@ -402,3 +437,130 @@ function FindFirstMessage(tree)
}
// nextThreadFunction is the function that determines whether a top level message is part of a thread that fits criteria.
// nextMessageFunction is the function that would be used to find the next message in a thread if gotoNextInThread is true
// nextResourceFunction is the function that would be used to find the next message in a thread as a resource if gotoNextInThread is true
// startFromBeginning is true if we should start looking from the beginning after we get to the end of the thread pane.
// gotoNextInThread is true if once we find an unrad thread we should select the first message in that thread that fits criteria
function GoNextThread(nextThreadFunction, nextMessageFunction, nextResourceFunction, startFromBeginning, gotoNextInThread)
{
if(messageView.showThreads)
{
var tree = GetThreadTree();
var selArray = tree.selectedItems;
var length = selArray.length;
if ( selArray && ((length == 0) || (length == 1)) )
{
var currentMessage;
if(length == 0)
currentMessage = null;
else
currentMessage = selArray[0];
var nextMessage;
var currentTopMessage;
var checkCurrentTopMessage;
//Need to get the parent message for the current selection to begin to find thread
if(currentMessage)
{
//need to find its top level message and we don't want it to be checked for criteria
currentTopMessage = FindTopLevelMessage(currentMessage);
checkCurrentTopMessage = false;
}
else
{
//currentTopmessage is the first one in the tree and we want it to be checked for criteria.
currentTopMessage = FindFirstMessage(tree);
checkCurrentTopMessage = true;
}
var nextTopMessage = FindNextThread(currentTopMessage, nextThreadFunction, startFromBeginning, checkCurrentTopMessage);
var changeSelection = (nextTopMessage != null && ((currentTopMessage != nextTopMessage) || checkCurrentTopMessage));
if(changeSelection)
{
if(gotoNextInThread)
{
nextMessage = GetNextInThread(nextTopMessage, nextMessageFunction, nextResourceFunction);
ChangeSelection(tree, nextMessage);
}
else
ChangeSelection(tree, nextTopMessage);
}
}
}
}
//Given the top level message of a thread and the searching functions, this returns the first message in that thread that matches
//the criteria
function GetNextInThread(topMessage, nextMessageFunction, nextResourceFunction)
{
var nextMessage;
if(nextMessageFunction(topMessage))
nextMessage = topMessage;
else
{
nextMessage = FindNextInChildren(topMessage, null, nextMessageFunction, nextResourceFunction);
}
return nextMessage;
}
function FindTopLevelMessage(startMessage)
{
var currentTop = startMessage;
var parent = startMessage.parentNode.parentNode;
while(parent.nodeName == 'treeitem')
{
currentTop = parent;
parent = parent.parentNode.parentNode;
}
return currentTop;
}
function FindNextThread(startThread, nextThreadFunction, startFromBeginning, checkStartThread)
{
if(checkStartThread)
{
if(nextThreadFunction(startThread))
return startThread;
dump("start thread doesn't match\n");
}
var nextThread = startThread.nextSibling;
//In case we are currently the bottom message
if(!nextThread && startFromBeginning)
{
var parent = startThread.parentNode;
nextThread = parent.firstChild;
}
while(nextThread && (nextThread != startThread))
{
if(nextThreadFunction(nextThread))
{
break;
}
nextThread = nextThread.nextSibling;
/*If there's no nextMessage we may have to start from top.*/
if(!nextThread && (nextThread!= startThread) && startFromBeginning)
{
var parent = startThread.parentNode;
nextThread = parent.firstChild;
}
}
return nextThread;
}

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

@ -51,7 +51,8 @@ Rights Reserved.
<treeitem uri="..."
Status="rdf:http://home.netscape.com/NC-rdf#Status"
Flagged="rdf:http://home.netscape.com/NC-rdf#Flagged"
Priority="rdf:http://home.netscape.com/NC-rdf#Priority">
Priority="rdf:http://home.netscape.com/NC-rdf#Priority"
IsUnread="rdf:http://home.netscape.com/NC-rdf#IsUnread">
<treerow>
<treecell value="rdf:http://home.netscape.com/NC-rdf#Thread"/>
<treecell indent="true" value="rdf:http://home.netscape.com/NC-rdf#Subject"/>

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

@ -840,16 +840,21 @@ function MsgStop() {
function MsgNextMessage()
{
GoNextMessage(GoMessage, ResourceGoMessage, false);
GoNextMessage(GoMessage, ResourceGoMessage, null, false);
}
function MsgNextUnreadMessage()
{
GoNextMessage(GoUnreadMessage, ResourceGoUnreadMessage, true);
GoNextMessage(GoUnreadMessage, ResourceGoUnreadMessage, GoUnreadThread, true);
}
function MsgNextFlaggedMessage()
{
GoNextMessage(GoFlaggedMessage, ResourceGoFlaggedMessage, true);
GoNextMessage(GoFlaggedMessage, ResourceGoFlaggedMessage, null, true);
}
function MsgNextUnreadThread()
{
GoNextThread(GoUnreadThread, GoUnreadMessage, ResourceGoUnreadMessage, true, true);
}
function MsgPreviousMessage()

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

@ -203,6 +203,7 @@ Rights Reserved.
<!ENTITY nextUnreadMsgCmd.label "Unread Message">
<!ENTITY nextFlaggedMsgCmd.label "Flagged Message">
<!ENTITY nextUnflaggedMsgCmd.label "Unflagged Message">
<!ENTITY nextUnreadThread.label "Unread Thread">
<!ENTITY prevMenu.label "Previous">
<!ENTITY prevMsgCmd.label "Message">
<!ENTITY prevUnreadMsgCmd.label "Unread Message">

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

@ -18,11 +18,7 @@
* Rights Reserved.
*/
treeitem[Status=" "] > treerow {
font-weight: bold;
}
treeitem[Status="new"] > treerow{
treeitem[IsUnread="true"] > treerow {
font-weight: bold;
}
@ -59,11 +55,7 @@ treecell.unreadcol > .tree-button {
list-style-image: url("chrome://messenger/skin/readmail.gif");
}
treeitem[Status=" "] > treerow > treecell.unreadcol > .tree-button {
list-style-image: url("chrome://messenger/skin/unreadmail.gif");
}
treeitem[Status="new"] > treerow > treecell.unreadcol > tree-button {
treeitem[IsUnread="true"] > treerow > treecell.unreadcol > .tree-button {
list-style-image: url("chrome://messenger/skin/unreadmail.gif");
}

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

@ -732,7 +732,7 @@ nsresult nsMsgFolderDataSource::OnItemAddedOrRemoved(nsISupports *parentItem, ns
if(NS_SUCCEEDED(rv))
{
//Notify folders that a message was added or deleted.
NotifyObservers(parentResource, kNC_MessageChild, itemNode, added);
NotifyObservers(parentResource, kNC_MessageChild, itemNode, added, PR_FALSE);
}
}
}
@ -743,7 +743,7 @@ nsresult nsMsgFolderDataSource::OnItemAddedOrRemoved(nsISupports *parentItem, ns
if(NS_SUCCEEDED(rv))
{
//Notify folders that a message was added or deleted.
NotifyObservers(parentResource, kNC_Child, itemNode, added);
NotifyObservers(parentResource, kNC_Child, itemNode, added, PR_FALSE);
}
}
return NS_OK;
@ -796,15 +796,12 @@ NS_IMETHODIMP nsMsgFolderDataSource::OnItemPropertyFlagChanged(nsISupports *item
{
if(PL_strcmp("BiffState", property) == 0)
{
nsCAutoString oldBiffStateStr, newBiffStateStr;
nsCAutoString newBiffStateStr;
rv = GetBiffStateString(oldFlag, oldBiffStateStr);
if(NS_FAILED(rv))
return rv;
rv = GetBiffStateString(newFlag, newBiffStateStr);
if(NS_FAILED(rv))
return rv;
NotifyPropertyChanged(resource, kNC_BiffState, oldBiffStateStr, newBiffStateStr);
NotifyPropertyChanged(resource, kNC_BiffState, newBiffStateStr);
}
}
@ -1208,12 +1205,10 @@ nsMsgFolderDataSource::OnUnreadMessagePropertyChanged(nsIMsgFolder *folder, PRIn
if(folderResource)
{
//First send a regular unread message changed notification
nsCOMPtr<nsIRDFNode> oldNode;
nsCOMPtr<nsIRDFNode> newNode;
GetNumMessagesNode(oldValue, getter_AddRefs(oldNode));
GetNumMessagesNode(newValue, getter_AddRefs(newNode));
NotifyPropertyChanged(folderResource, kNC_TotalUnreadMessages, oldNode, newNode);
NotifyPropertyChanged(folderResource, kNC_TotalUnreadMessages, newNode);
//Now see if hasUnreadMessages has changed
nsCOMPtr<nsIRDFNode> oldHasUnreadMessages;
@ -1222,13 +1217,12 @@ nsMsgFolderDataSource::OnUnreadMessagePropertyChanged(nsIMsgFolder *folder, PRIn
{
oldHasUnreadMessages = kFalseLiteral;
newHasUnreadMessages = kTrueLiteral;
NotifyPropertyChanged(folderResource, kNC_HasUnreadMessages, oldHasUnreadMessages, newHasUnreadMessages);
NotifyPropertyChanged(folderResource, kNC_HasUnreadMessages, newHasUnreadMessages);
}
else if(oldValue > 0 && newValue <= 0)
{
oldHasUnreadMessages = kTrueLiteral;
newHasUnreadMessages = kFalseLiteral;
NotifyPropertyChanged(folderResource, kNC_HasUnreadMessages, oldHasUnreadMessages, newHasUnreadMessages);
NotifyPropertyChanged(folderResource, kNC_HasUnreadMessages, newHasUnreadMessages);
}
//We will have to change the folderTreeName also
@ -1236,18 +1230,14 @@ nsMsgFolderDataSource::OnUnreadMessagePropertyChanged(nsIMsgFolder *folder, PRIn
nsresult rv = folder->GetAbbreviatedName(getter_Copies(name));
if (NS_SUCCEEDED(rv))
{
nsAutoString oldNameString(name);
nsAutoString newNameString(name);
CreateUnreadMessagesNameString(oldValue, oldNameString);
CreateUnreadMessagesNameString(newValue, newNameString);
nsCOMPtr<nsIRDFNode> oldNameNode;
nsCOMPtr<nsIRDFNode> newNameNode;
createNode(oldNameString, getter_AddRefs(oldNameNode), getRDFService());
createNode(newNameString, getter_AddRefs(newNameNode), getRDFService());
NotifyPropertyChanged(folderResource, kNC_FolderTreeName, oldNameNode, newNameNode);
NotifyPropertyChanged(folderResource, kNC_FolderTreeName, newNameNode);
}
@ -1263,12 +1253,10 @@ nsMsgFolderDataSource::OnTotalMessagePropertyChanged(nsIMsgFolder *folder, PRInt
if(folderResource)
{
//First send a regular unread message changed notification
nsCOMPtr<nsIRDFNode> oldNode;
nsCOMPtr<nsIRDFNode> newNode;
GetNumMessagesNode(oldValue, getter_AddRefs(oldNode));
GetNumMessagesNode(newValue, getter_AddRefs(newNode));
NotifyPropertyChanged(folderResource, kNC_TotalMessages, oldNode, newNode);
NotifyPropertyChanged(folderResource, kNC_TotalMessages, newNode);
}
return NS_OK;
}

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

@ -61,6 +61,7 @@ nsIRDFResource* nsMsgMessageDataSource::kNC_Size= nsnull;
nsIRDFResource* nsMsgMessageDataSource::kNC_Total = nsnull;
nsIRDFResource* nsMsgMessageDataSource::kNC_Unread = nsnull;
nsIRDFResource* nsMsgMessageDataSource::kNC_MessageChild = nsnull;
nsIRDFResource* nsMsgMessageDataSource::kNC_IsUnread = nsnull;
//commands
@ -107,6 +108,7 @@ nsMsgMessageDataSource::~nsMsgMessageDataSource (void)
NS_RELEASE2(kNC_Total, refcnt);
NS_RELEASE2(kNC_Unread, refcnt);
NS_RELEASE2(kNC_MessageChild, refcnt);
NS_RELEASE2(kNC_IsUnread, refcnt);
NS_RELEASE2(kNC_MarkRead, refcnt);
NS_RELEASE2(kNC_MarkUnread, refcnt);
@ -155,6 +157,7 @@ nsresult nsMsgMessageDataSource::Init()
rdf->GetResource(NC_RDF_TOTALMESSAGES, &kNC_Total);
rdf->GetResource(NC_RDF_TOTALUNREADMESSAGES, &kNC_Unread);
rdf->GetResource(NC_RDF_MESSAGECHILD, &kNC_MessageChild);
rdf->GetResource(NC_RDF_ISUNREAD, &kNC_IsUnread);
rdf->GetResource(NC_RDF_MARKREAD, &kNC_MarkRead);
rdf->GetResource(NC_RDF_MARKUNREAD, &kNC_MarkUnread);
@ -198,7 +201,10 @@ nsresult nsMsgMessageDataSource::CreateLiterals(nsIRDFService *rdf)
createNode(str, getter_AddRefs(kNewLiteral), rdf);
str = "read";
createNode(str, getter_AddRefs(kReadLiteral), rdf);
str = "true";
createNode(str, getter_AddRefs(kTrueLiteral), rdf);
str = "false";
createNode(str, getter_AddRefs(kFalseLiteral), rdf);
return NS_OK;
}
@ -355,7 +361,8 @@ NS_IMETHODIMP nsMsgMessageDataSource::GetTargets(nsIRDFResource* source,
}
else if((kNC_Subject == property) || (kNC_Date == property) ||
(kNC_Status == property) || (kNC_Flagged == property) ||
(kNC_Priority == property) || (kNC_Size == property))
(kNC_Priority == property) || (kNC_Size == property) ||
(kNC_IsUnread == property))
{
nsSingletonEnumerator* cursor =
new nsSingletonEnumerator(source);
@ -479,7 +486,7 @@ nsMsgMessageDataSource::getMessageArcLabelsOut(PRBool showThreads,
(*arcs)->AppendElement(kNC_Flagged);
(*arcs)->AppendElement(kNC_Priority);
(*arcs)->AppendElement(kNC_Size);
(*arcs)->AppendElement(kNC_IsUnread);
return NS_OK;
}
@ -608,8 +615,20 @@ nsresult nsMsgMessageDataSource::OnItemAddedOrRemoved(nsISupports *parentItem, n
if(NS_SUCCEEDED(rv))
{
//Notify folders that a message was deleted.
NotifyObservers(parentResource, kNC_MessageChild, itemNode, added);
NotifyObservers(parentResource, kNC_MessageChild, itemNode, added, PR_FALSE);
}
//Unread and total message counts will have changed.
PRUint32 flags;
//use the changed message to get the flags, but use the parent message to change the counts since
//it hasn't been removed from the thread yet.
rv = message->GetFlags(&flags);
if(NS_SUCCEEDED(rv))
{
if(!(flags & MSG_FLAG_READ))
OnChangeUnreadMessageCount(parentMessage);
}
OnChangeTotalMessageCount(parentMessage);
}
}
return NS_OK;
@ -648,25 +667,15 @@ NS_IMETHODIMP nsMsgMessageDataSource::OnItemPropertyFlagChanged(nsISupports *ite
{
if(PL_strcmp("Status", property) == 0)
{
nsCAutoString oldStatusStr, newStatusStr;
rv = createStatusStringFromFlag(oldFlag, oldStatusStr);
if(NS_FAILED(rv))
return rv;
rv = createStatusStringFromFlag(newFlag, newStatusStr);
if(NS_FAILED(rv))
return rv;
rv = NotifyPropertyChanged(resource, kNC_Status, oldStatusStr, newStatusStr);
OnChangeStatus(resource, oldFlag, newFlag);
}
else if(PL_strcmp("Flagged", property) == 0)
{
nsCAutoString oldFlaggedStr, newFlaggedStr;
rv = createFlaggedStringFromFlag(oldFlag, oldFlaggedStr);
if(NS_FAILED(rv))
return rv;
nsCAutoString newFlaggedStr;
rv = createFlaggedStringFromFlag(newFlag, newFlaggedStr);
if(NS_FAILED(rv))
return rv;
rv = NotifyPropertyChanged(resource, kNC_Flagged, oldFlaggedStr, newFlaggedStr);
rv = NotifyPropertyChanged(resource, kNC_Flagged, newFlaggedStr);
}
}
return rv;
@ -678,7 +687,121 @@ NS_IMETHODIMP nsMsgMessageDataSource::OnFolderLoaded(nsIFolder *folder)
return rv;
}
nsresult nsMsgMessageDataSource::OnChangeStatus(nsIRDFResource *resource, PRUint32 oldFlag, PRUint32 newFlag)
{
OnChangeStatusString(resource, oldFlag, newFlag);
PRUint32 changedFlag = oldFlag ^ newFlag;
if(changedFlag & MSG_FLAG_READ)
{
OnChangeIsUnread(resource, oldFlag, newFlag);
PRBool showThreads;
GetIsThreaded(&showThreads);
if(showThreads)
{
nsCOMPtr<nsIMessage> message = do_QueryInterface(resource);
if(message)
OnChangeUnreadMessageCount(message);
}
}
return NS_OK;
}
nsresult nsMsgMessageDataSource::OnChangeStatusString(nsIRDFResource *resource, PRUint32 oldFlag, PRUint32 newFlag)
{
nsresult rv;
nsCAutoString newStatusStr;
rv = createStatusStringFromFlag(newFlag, newStatusStr);
if(NS_FAILED(rv))
return rv;
rv = NotifyPropertyChanged(resource, kNC_Status, newStatusStr);
return rv;
}
nsresult nsMsgMessageDataSource::OnChangeIsUnread(nsIRDFResource *resource, PRUint32 oldFlag, PRUint32 newFlag)
{
nsresult rv;
nsCOMPtr<nsIRDFNode> newIsUnreadNode;
newIsUnreadNode = (newFlag & MSG_FLAG_READ) ? kFalseLiteral : kTrueLiteral;
rv = NotifyPropertyChanged(resource, kNC_IsUnread, newIsUnreadNode);
return rv;
}
nsresult nsMsgMessageDataSource::OnChangeUnreadMessageCount(nsIMessage *message)
{
nsresult rv;
nsCOMPtr<nsIMsgFolder> folder;
nsCOMPtr<nsIMsgThread> thread;
rv = message->GetMsgFolder(getter_AddRefs(folder));
if(NS_FAILED(rv))
return rv;
rv = folder->GetThreadForMessage(message, getter_AddRefs(thread));
if(NS_FAILED(rv))
return rv;
nsCOMPtr<nsIRDFNode> unreadChildrenNode;
rv = GetUnreadChildrenNode(thread, getter_AddRefs(unreadChildrenNode));
if(NS_FAILED(rv))
return rv;
nsCOMPtr<nsIMessage> firstMessage;
rv = GetThreadsFirstMessage(thread, folder, getter_AddRefs(firstMessage));
if(NS_FAILED(rv))
return rv;
nsCOMPtr<nsIRDFResource> firstMessageResource = do_QueryInterface(firstMessage);
if(firstMessageResource)
rv = NotifyPropertyChanged(firstMessageResource, kNC_Unread, unreadChildrenNode);
else
return NS_ERROR_FAILURE;
return rv;
}
nsresult nsMsgMessageDataSource::OnChangeTotalMessageCount(nsIMessage *message)
{
nsresult rv;
nsCOMPtr<nsIMsgFolder> folder;
nsCOMPtr<nsIMsgThread> thread;
rv = message->GetMsgFolder(getter_AddRefs(folder));
if(NS_FAILED(rv))
return rv;
rv = folder->GetThreadForMessage(message, getter_AddRefs(thread));
if(NS_FAILED(rv))
return rv;
nsCOMPtr<nsIRDFNode> numChildrenNode;
rv = GetTotalChildrenNode(thread, getter_AddRefs(numChildrenNode));
if(NS_FAILED(rv))
return rv;
nsCOMPtr<nsIMessage> firstMessage;
rv = GetThreadsFirstMessage(thread, folder, getter_AddRefs(firstMessage));
if(NS_FAILED(rv))
return rv;
nsCOMPtr<nsIRDFResource> firstMessageResource = do_QueryInterface(firstMessage);
if(firstMessageResource)
rv = NotifyPropertyChanged(firstMessageResource, kNC_Total, numChildrenNode);
else
return NS_ERROR_FAILURE;
return rv;
}
nsresult
nsMsgMessageDataSource::createMessageNode(nsIMessage *message,
nsIRDFResource *property,
@ -708,6 +831,8 @@ nsMsgMessageDataSource::createMessageNode(nsIMessage *message,
rv = createMessageTotalNode(message, target);
else if ((kNC_Unread == property))
rv = createMessageUnreadNode(message, target);
else if((kNC_IsUnread == property))
rv = createMessageIsUnreadNode(message, target);
else if ((kNC_MessageChild == property))
rv = createMessageMessageChildNode(message, target);
@ -819,6 +944,23 @@ nsMsgMessageDataSource::createMessageStatusNode(nsIMessage *message,
return NS_OK;
}
nsresult
nsMsgMessageDataSource::createMessageIsUnreadNode(nsIMessage *message, nsIRDFNode **target)
{
nsresult rv;
PRUint32 flags;
rv = message->GetFlags(&flags);
if(NS_FAILED(rv))
return rv;
if(flags & MSG_FLAG_READ)
*target = kFalseLiteral;
else
*target = kTrueLiteral;
NS_IF_ADDREF(*target);
return NS_OK;
}
nsresult
nsMsgMessageDataSource::createMessageFlaggedNode(nsIMessage *message,
nsIRDFNode **target)
@ -971,15 +1113,7 @@ nsresult nsMsgMessageDataSource::createMessageTotalNode(nsIMessage *message, nsI
{
if(IsThreadsFirstMessage(thread, message))
{
PRUint32 numChildren;
rv = thread->GetNumChildren(&numChildren);
if(NS_SUCCEEDED(rv))
{
if(numChildren > 1)
rv = createNode(numChildren, target, getRDFService());
else
rv = createNode(emptyString, target, getRDFService());
}
rv = GetTotalChildrenNode(thread, target);
}
else
{
@ -1000,7 +1134,7 @@ nsresult nsMsgMessageDataSource::createMessageUnreadNode(nsIMessage *message, ns
nsCOMPtr<nsIMsgFolder> folder;
nsCOMPtr<nsIMsgThread> thread;
nsresult rv;
nsString emptyString("");
nsAutoString emptyString("");
PRBool showThreads;
rv = GetIsThreaded(&showThreads);
@ -1015,15 +1149,7 @@ nsresult nsMsgMessageDataSource::createMessageUnreadNode(nsIMessage *message, ns
{
if(IsThreadsFirstMessage(thread, message))
{
PRUint32 numUnread;
rv = thread->GetNumUnreadChildren(&numUnread);
if(NS_SUCCEEDED(rv))
{
if(numUnread > 0)
rv = createNode(numUnread, target, getRDFService());
else
rv = createNode(emptyString, target, getRDFService());
}
rv = GetUnreadChildrenNode(thread, target);
}
else
{
@ -1038,6 +1164,40 @@ nsresult nsMsgMessageDataSource::createMessageUnreadNode(nsIMessage *message, ns
return NS_RDF_NO_VALUE;
}
nsresult nsMsgMessageDataSource::GetUnreadChildrenNode(nsIMsgThread *thread, nsIRDFNode **target)
{
nsresult rv;
nsAutoString emptyString("");
PRUint32 numUnread;
rv = thread->GetNumUnreadChildren(&numUnread);
if(NS_SUCCEEDED(rv))
{
if(numUnread > 0)
rv = createNode(numUnread, target, getRDFService());
else
rv = createNode(emptyString, target, getRDFService());
}
return rv;
}
nsresult nsMsgMessageDataSource::GetTotalChildrenNode(nsIMsgThread *thread, nsIRDFNode **target)
{
nsresult rv;
nsAutoString emptyString("");
PRUint32 numChildren;
rv = thread->GetNumChildren(&numChildren);
if(NS_SUCCEEDED(rv))
{
if(numChildren > 0)
rv = createNode(numChildren, target, getRDFService());
else
rv = createNode(emptyString, target, getRDFService());
}
return rv;
}
nsresult
nsMsgMessageDataSource::createMessageMessageChildNode(nsIMessage *message,
nsIRDFNode **target)
@ -1098,6 +1258,20 @@ PRBool nsMsgMessageDataSource::IsThreadsFirstMessage(nsIMsgThread *thread, nsIMe
}
nsresult nsMsgMessageDataSource::GetThreadsFirstMessage(nsIMsgThread *thread, nsIMsgFolder *folder, nsIMessage **message)
{
nsCOMPtr<nsIMsgDBHdr> firstHdr;
nsresult rv;
rv = thread->GetRootHdr(nsnull, getter_AddRefs(firstHdr));
if(NS_FAILED(rv))
return rv;
rv = folder->CreateMessageFromMsgDBHdr(firstHdr, message);
return rv;
}
nsresult
nsMsgMessageDataSource::DoMarkMessagesRead(nsISupportsArray *messages, PRBool markRead)
{

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

@ -141,12 +141,15 @@ protected:
nsresult createMessageSizeNode(nsIMessage *message,
nsIRDFNode **target);
nsresult createMessageIsUnreadNode(nsIMessage *message, nsIRDFNode **target);
nsresult createMessageUnreadNode(nsIMessage *message, nsIRDFNode **target);
nsresult createMessageTotalNode(nsIMessage *message, nsIRDFNode **target);
nsresult createMessageMessageChildNode(nsIMessage* message, nsIRDFNode **target);
nsresult GetMessageFolderAndThread(nsIMessage *message, nsIMsgFolder **folder,
nsIMsgThread **thread);
PRBool IsThreadsFirstMessage(nsIMsgThread *thread, nsIMessage *message);
nsresult GetThreadsFirstMessage(nsIMsgThread *thread, nsIMsgFolder *folder, nsIMessage **message);
nsresult DoMarkMessagesRead(nsISupportsArray *messages, PRBool markRead);
nsresult DoMarkMessagesFlagged(nsISupportsArray *messages, PRBool markFlagged);
@ -166,6 +169,15 @@ protected:
nsresult OnItemAddedOrRemoved(nsISupports *parentItem, nsISupports *item, const char *viewString,
PRBool added);
nsresult OnChangeStatus(nsIRDFResource *resource, PRUint32 oldFlag, PRUint32 newFlag);
nsresult OnChangeStatusString(nsIRDFResource *resource, PRUint32 oldFlag, PRUint32 newFlag);
nsresult OnChangeIsUnread(nsIRDFResource *resource, PRUint32 oldFlag, PRUint32 newFlag);
nsresult OnChangeUnreadMessageCount(nsIMessage *message);
nsresult OnChangeTotalMessageCount(nsIMessage *message);
nsresult GetUnreadChildrenNode(nsIMsgThread *thread, nsIRDFNode **target);
nsresult GetTotalChildrenNode(nsIMsgThread *thread, nsIRDFNode **target);
static nsIRDFResource* kNC_Subject;
static nsIRDFResource* kNC_SubjectCollation;
static nsIRDFResource* kNC_Sender;
@ -178,6 +190,7 @@ protected:
static nsIRDFResource* kNC_Total;
static nsIRDFResource* kNC_Unread;
static nsIRDFResource* kNC_MessageChild;
static nsIRDFResource* kNC_IsUnread;
// commands
@ -199,6 +212,8 @@ protected:
nsCOMPtr<nsIRDFNode> kForwardedLiteral;
nsCOMPtr<nsIRDFNode> kNewLiteral;
nsCOMPtr<nsIRDFNode> kReadLiteral;
nsCOMPtr<nsIRDFNode> kTrueLiteral;
nsCOMPtr<nsIRDFNode> kFalseLiteral;
nsCOMPtr<nsISupportsArray> kThreadsArcsOutArray;
nsCOMPtr<nsISupportsArray> kNoThreadsArcsOutArray;

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

@ -348,24 +348,21 @@ nsMsgRDFDataSource::getRDFService()
nsresult nsMsgRDFDataSource::NotifyPropertyChanged(nsIRDFResource *resource,
nsIRDFResource *propertyResource,
const char *oldValue, const char *newValue)
const char *newValue)
{
nsCOMPtr<nsIRDFNode> oldValueNode, newValueNode;
nsString oldValueStr = oldValue;
nsCOMPtr<nsIRDFNode> newValueNode;
nsString newValueStr = newValue;
createNode(oldValueStr,getter_AddRefs(oldValueNode), getRDFService());
createNode(newValueStr, getter_AddRefs(newValueNode), getRDFService());
NotifyPropertyChanged(resource, propertyResource, oldValueNode, newValueNode);
NotifyPropertyChanged(resource, propertyResource, newValueNode);
return NS_OK;
}
nsresult nsMsgRDFDataSource::NotifyPropertyChanged(nsIRDFResource *resource,
nsIRDFResource *propertyResource,
nsIRDFNode *oldNode, nsIRDFNode *newNode)
nsIRDFNode *newNode)
{
NotifyObservers(resource, propertyResource, oldNode, PR_FALSE);
NotifyObservers(resource, propertyResource, newNode, PR_TRUE);
NotifyObservers(resource, propertyResource, newNode, PR_FALSE, PR_TRUE);
return NS_OK;
}
@ -373,12 +370,14 @@ nsresult nsMsgRDFDataSource::NotifyPropertyChanged(nsIRDFResource *resource,
nsresult nsMsgRDFDataSource::NotifyObservers(nsIRDFResource *subject,
nsIRDFResource *property,
nsIRDFNode *object,
PRBool assert)
PRBool assert, PRBool change)
{
if(mObservers)
{
nsMsgRDFNotification note = { subject, property, object };
if (assert)
if(change)
mObservers->EnumerateForwards(changeEnumFunc, &note);
else if (assert)
mObservers->EnumerateForwards(assertEnumFunc, &note);
else
mObservers->EnumerateForwards(unassertEnumFunc, &note);
@ -410,6 +409,17 @@ nsMsgRDFDataSource::unassertEnumFunc(nsISupports *aElement, void *aData)
return PR_TRUE;
}
PRBool
nsMsgRDFDataSource::changeEnumFunc(nsISupports *aElement, void *aData)
{
nsMsgRDFNotification* note = (nsMsgRDFNotification *)aData;
nsIRDFObserver* observer = (nsIRDFObserver *)aElement;
observer->OnChange(note->subject,
note->property,
nsnull, note->object);
return PR_TRUE;
}
nsresult
nsMsgRDFDataSource::GetTransactionManager(nsISupportsArray *aSources, nsITransactionManager **aTransactionManager)
{

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

@ -56,14 +56,15 @@ class nsMsgRDFDataSource : public nsIRDFDataSource,
nsIRDFService *getRDFService();
static PRBool assertEnumFunc(nsISupports *aElement, void *aData);
static PRBool unassertEnumFunc(nsISupports *aElement, void *aData);
static PRBool changeEnumFunc(nsISupports *aElement, void *aData);
nsresult NotifyObservers(nsIRDFResource *subject, nsIRDFResource *property,
nsIRDFNode *object, PRBool assert);
nsIRDFNode *object, PRBool assert, PRBool change);
nsresult NotifyPropertyChanged(nsIRDFResource *resource,
nsIRDFResource *propertyResource,
const char *oldValue, const char *newValue);
const char *newValue);
nsresult NotifyPropertyChanged(nsIRDFResource *resource,
nsIRDFResource *propertyResource,
nsIRDFNode *oldNode, nsIRDFNode *newNode);
nsIRDFNode *newNode);
nsresult GetTransactionManager(nsISupportsArray *sources, nsITransactionManager **aTransactionManager);
nsCOMPtr<nsIMsgWindow> mWindow;

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

@ -45,6 +45,7 @@ typedef struct _nsMsgRDFNotification {
#define NC_RDF_FLAGGED NC_NAMESPACE_URI "Flagged"
#define NC_RDF_PRIORITY NC_NAMESPACE_URI "Priority"
#define NC_RDF_SIZE NC_NAMESPACE_URI "Size"
#define NC_RDF_ISUNREAD NC_NAMESPACE_URI "IsUnread"
#define NC_RDF_CHILD NC_NAMESPACE_URI "child"
#define NC_RDF_MESSAGECHILD NC_NAMESPACE_URI "MessageChild"

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

@ -467,6 +467,11 @@ NS_IMETHODIMP nsMsgThread::MarkChildRead(PRBool bRead)
{
nsresult ret = NS_OK;
if(bRead)
ChangeUnreadChildCount(-1);
else
ChangeUnreadChildCount(1);
return ret;
}