Bug 920801 - Port chat/ changes from Instantbird to comm-central - 6 - Bio 2163 - Displaying a large conversation log freezes the UI for a while before the first messages get displayed, r=aleth.
This commit is contained in:
Родитель
8e90321999
Коммит
b38ea21845
|
@ -32,6 +32,11 @@ interface imILogConversation: nsISupports {
|
|||
|
||||
void getMessages([optional] out unsigned long messageCount,
|
||||
[retval, array, size_is(messageCount)] out prplIMessage messages);
|
||||
|
||||
// Callers that process the messages asynchronously should use the enumerator
|
||||
// instead of the array version of the getMessages* methods to avoid paying
|
||||
// up front the cost of xpconnect wrapping all message objects.
|
||||
nsISimpleEnumerator getMessagesEnumerator([optional] out unsigned long messageCount);
|
||||
};
|
||||
|
||||
[scriptable, uuid(164ff6c3-ca64-4880-b8f3-67eb1817955f)]
|
||||
|
|
|
@ -351,10 +351,10 @@ function LogConversation(aLineInputStreams)
|
|||
sessionMsg.text = bundle.formatStringFromName("badLogfile",
|
||||
[inputStream.filename], 1);
|
||||
sessionMsg.flags.push("error", "system");
|
||||
this._messages.push(new LogMessage(sessionMsg, this));
|
||||
this._messages.push(sessionMsg);
|
||||
continue;
|
||||
}
|
||||
this._messages.push(new LogMessage(sessionMsg, this));
|
||||
this._messages.push(sessionMsg);
|
||||
|
||||
if (firstFile) {
|
||||
let data = JSON.parse(line.value);
|
||||
|
@ -372,8 +372,7 @@ function LogConversation(aLineInputStreams)
|
|||
if (!line.value)
|
||||
break;
|
||||
try {
|
||||
let data = JSON.parse(line.value);
|
||||
this._messages.push(new LogMessage(data, this));
|
||||
this._messages.push(JSON.parse(line.value));
|
||||
} catch (e) {
|
||||
// if a message line contains junk, just ignore the error and
|
||||
// continue reading the conversation.
|
||||
|
@ -398,7 +397,20 @@ LogConversation.prototype = {
|
|||
getMessages: function(aMessageCount) {
|
||||
if (aMessageCount)
|
||||
aMessageCount.value = this._messages.length;
|
||||
return this._messages;
|
||||
return this._messages.map(function(m) new LogMessage(m, this), this);
|
||||
},
|
||||
getMessagesEnumerator: function(aMessageCount) {
|
||||
if (aMessageCount)
|
||||
aMessageCount.value = this._messages.length;
|
||||
let enumerator = {
|
||||
_index: 0,
|
||||
_conv: this,
|
||||
_messages: this._messages,
|
||||
hasMoreElements: function() this._index < this._messages.length,
|
||||
getNext: function() new LogMessage(this._messages[this._index++], this._conv),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator])
|
||||
};
|
||||
return enumerator;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -316,6 +316,14 @@
|
|||
<![CDATA[
|
||||
this._pendingMessages.push({msg: aMsg, context: aContext,
|
||||
firstUnread: aFirstUnread});
|
||||
this.delayedDisplayPendingMessages();
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="delayedDisplayPendingMessages">
|
||||
<body>
|
||||
<![CDATA[
|
||||
if (this._messageDisplayPending)
|
||||
return;
|
||||
this._messageDisplayPending = true;
|
||||
|
@ -327,8 +335,38 @@
|
|||
</method>
|
||||
|
||||
<field name="progressBar">null</field>
|
||||
<!-- These variables are reset in onStateChange. -->
|
||||
|
||||
<!-- getNextPendingMessage and getPendingMessagesCount are the
|
||||
only 2 methods accessing the this._pendingMessages array
|
||||
directly during the chunked display of messages. It is
|
||||
possible to override these 2 methods to replace the array
|
||||
with something else. The log viewer for example uses an
|
||||
enumerator that creates message objects lazily to avoid
|
||||
jank when displaying lots of messages. -->
|
||||
<!-- This variable is reset in onStateChange. -->
|
||||
<field name="_nextPendingMessageIndex">0</field>
|
||||
<method name="getNextPendingMessage">
|
||||
<body>
|
||||
<![CDATA[
|
||||
if (this._nextPendingMessageIndex == this._pendingMessages.length) {
|
||||
this._pendingMessages = [];
|
||||
this._nextPendingMessageIndex = 0;
|
||||
return null;
|
||||
}
|
||||
return this._pendingMessages[this._nextPendingMessageIndex++];
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
<method name="getPendingMessagesCount">
|
||||
<body>
|
||||
<![CDATA[
|
||||
return this._pendingMessages.length;
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<!-- These variables are reset in onStateChange. -->
|
||||
<field name="_pendingMessagesDisplayed">0</field>
|
||||
<field name="_displayPendingMessagesCalls">0</field>
|
||||
<method name="displayPendingMessages">
|
||||
<body>
|
||||
|
@ -336,29 +374,27 @@
|
|||
if (!this._messageDisplayPending)
|
||||
return;
|
||||
|
||||
let max = this._pendingMessages.length;
|
||||
let begin = Date.now();
|
||||
let i;
|
||||
for (i = this._nextPendingMessageIndex; i < max; ++i) {
|
||||
let msg = this._pendingMessages[i];
|
||||
this.displayMessage(msg.msg, msg.context, i + 1 < max,
|
||||
msg.firstUnread);
|
||||
if (Date.now() - begin > 40)
|
||||
let max = this.getPendingMessagesCount();
|
||||
for (let begin = Date.now(); Date.now() - begin < 40; ) {
|
||||
let msg = this.getNextPendingMessage();
|
||||
if (!msg)
|
||||
break;
|
||||
this.displayMessage(msg.msg, msg.context,
|
||||
++this._pendingMessagesDisplayed < max,
|
||||
msg.firstUnread);
|
||||
}
|
||||
let event = document.createEvent("UIEvents");
|
||||
event.initUIEvent("MessagesDisplayed", false, false, window, 0);
|
||||
this.dispatchEvent(event);
|
||||
if (i < max - 1) {
|
||||
this._nextPendingMessageIndex = i + 1;
|
||||
if (this._pendingMessagesDisplayed < max) {
|
||||
if (this.progressBar) {
|
||||
// Show progress bar if after the third call (ca. 120ms)
|
||||
// less than half the messages have been displayed.
|
||||
if (++this._displayPendingMessagesCalls > 2 &&
|
||||
max > 2 * this._nextPendingMessageIndex)
|
||||
max > 2 * this._pendingMessagesDisplayed)
|
||||
this.progressBar.hidden = false;
|
||||
this.progressBar.max = max;
|
||||
this.progressBar.value = this._nextPendingMessageIndex;
|
||||
this.progressBar.value = this._pendingMessagesDisplayed;
|
||||
}
|
||||
Services.tm.mainThread.dispatch(this.displayPendingMessages.bind(this),
|
||||
Ci.nsIEventTarget.DISPATCH_NORMAL);
|
||||
|
@ -366,8 +402,7 @@
|
|||
}
|
||||
this.contentWindow.messageInsertPending = false;
|
||||
this._messageDisplayPending = false;
|
||||
this._pendingMessages = [];
|
||||
this._nextPendingMessageIndex = 0;
|
||||
this._pendingMessagesDisplayed = 0;
|
||||
this._displayPendingMessagesCalls = 0;
|
||||
if (this.progressBar)
|
||||
this.progressBar.hidden = true;
|
||||
|
@ -841,8 +876,11 @@
|
|||
this._messageDisplayPending = false;
|
||||
this._pendingMessages = [];
|
||||
this._nextPendingMessageIndex = 0;
|
||||
this._pendingMessagesDisplayed = 0;
|
||||
this._displayPendingMessagesCalls = 0;
|
||||
this._sessions = [];
|
||||
if (this.progressBar)
|
||||
this.progressBar.hidden = true;
|
||||
|
||||
Services.obs.notifyObservers(this, "conversation-loaded", null);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче