[SCM] ktp-text-ui packaging branch, master, updated. debian/15.12.1-1-1918-gdf4b0ec

Maximiliano Curia maxy at moszumanska.debian.org
Sat May 28 00:16:05 UTC 2016


Gitweb-URL: http://git.debian.org/?p=pkg-kde/applications/ktp-text-ui.git;a=commitdiff;h=8d6e871

The following commit has been merged in the master branch:
commit 8d6e871987936f4d462424c779f766fd6ebd96a3
Author: David Edmundson <kde at davidedmundson.co.uk>
Date:   Sun Aug 8 17:21:12 2010 +0000

    Switched to the Adium method of using JS for message insertion.
    
    This gives us:
      Faster insertion of multiple messages (due to DOM change buffering)
      Simpler code in ChatView
      Possible JS animations on insert
    
      A new feature - click an emoticon to convert it to text and back.
    
    
    
    svn path=/trunk/playground/network/telepathy-chat-handler/; revision=1160652
---
 CMakeLists.txt        |   3 +-
 config/mainwindow.cpp |  29 ++---
 config/mainwindow.h   |   3 +
 data/CMakeLists.txt   |   2 +
 data/template.html    | 341 ++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/chatview.cpp      | 130 ++++++++++++-------
 lib/chatview.h        |  10 +-
 lib/chatwindow.cpp    |  24 ++--
 lib/chatwindow.h      |   5 +-
 9 files changed, 478 insertions(+), 69 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 315c445..02adb26 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -25,4 +25,5 @@ include_directories (${KDE4_INCLUDES}
 
 
 add_subdirectory(app)
-add_subdirectory(config)
\ No newline at end of file
+add_subdirectory(config)
+add_subdirectory(data)
\ No newline at end of file
diff --git a/config/mainwindow.cpp b/config/mainwindow.cpp
index 888098c..281628a 100644
--- a/config/mainwindow.cpp
+++ b/config/mainwindow.cpp
@@ -30,20 +30,7 @@ MainWindow::MainWindow(QWidget *parent) :
 
     ui->chatView->initialise(info);
 
-
-    //add a fake message
-    //in my head Bob Marley is quite a chatty friendly guy...
-
-    TelepathyChatMessageInfo message(TelepathyChatMessageInfo::RemoteToLocal);
-    message.setMessage("Hello, how are things?");
-    message.setSenderDisplayName("BobMarley at yahoo.com");
-    message.setSenderScreenName("Bob Marley");
-    message.setService("Jabber");
-    message.setTime(QDateTime::currentDateTime());
-
-
-    ui->chatView->addMessage(message);
-
+    connect(ui->chatView,SIGNAL(loadFinished(bool)),SLOT(sendDemoMessages()));
 }
 
 MainWindow::~MainWindow()
@@ -67,3 +54,17 @@ void MainWindow::changeEvent(QEvent *e)
         break;
     }*/
 }
+
+void MainWindow::sendDemoMessages()
+{
+    //add a fake message
+    //in my head Bob Marley is quite a chatty friendly guy...
+
+    TelepathyChatMessageInfo message(TelepathyChatMessageInfo::RemoteToLocal);
+    message.setMessage("Hello, how are things?");
+    message.setSenderDisplayName("BobMarley at yahoo.com");
+    message.setSenderScreenName("Bob Marley");
+    message.setService("Jabber");
+    message.setTime(QDateTime::currentDateTime());
+    ui->chatView->addMessage(message);
+}
diff --git a/config/mainwindow.h b/config/mainwindow.h
index 008a510..f173144 100644
--- a/config/mainwindow.h
+++ b/config/mainwindow.h
@@ -23,6 +23,9 @@ public slots:
 
 private:
     Ui::ChatWindowConfig *ui;
+
+private slots:
+    void sendDemoMessages();
 };
 
 #endif // MAINWINDOW_H
diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt
new file mode 100644
index 0000000..d30e960
--- /dev/null
+++ b/data/CMakeLists.txt
@@ -0,0 +1,2 @@
+install(FILES template.html
+        DESTINATION ${DATA_INSTALL_DIR}/ktelepathy)
\ No newline at end of file
diff --git a/data/template.html b/data/template.html
new file mode 100644
index 0000000..fe7c4de
--- /dev/null
+++ b/data/template.html
@@ -0,0 +1,341 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+	<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+	<base href="file://%baseRef%" />
+	<script type="text/javascript" defer="defer">
+		
+		function appendHTML(html) {
+			var node = document.getElementById("Chat");
+			var range = document.createRange();
+			range.selectNode(node);
+			var documentFragment = range.createContextualFragment(html);
+			node.appendChild(documentFragment);
+		}
+		
+		// a coalesced HTML object buffers and outputs DOM objects en masse.
+		// saves A LOT of CSS recalculation time when loading many messages.
+		// (ex. a long twitter timeline)
+		function CoalescedHTML() {
+			var self = this;
+			this.fragment = document.createDocumentFragment();
+			this.timeoutID = 0;
+			this.coalesceRounds = 0;
+			this.isCoalescing = false;
+			this.isConsecutive = undefined;
+			this.shouldScroll = undefined;
+			
+			var appendElement = function (elem) {
+				document.getElementById("Chat").appendChild(elem);
+			};
+			
+			function outputHTML() {
+				var insert = document.getElementById("insert");
+				if(!!insert && self.isConsecutive) {
+					insert.parentNode.replaceChild(self.fragment, insert);
+				} else {
+					if(insert)
+						insert.parentNode.removeChild(insert);
+					// insert the documentFragment into the live DOM
+					appendElement(self.fragment);
+				}
+				alignChat(self.shouldScroll);
+				
+				// reset state to empty/non-coalescing
+				self.shouldScroll = undefined;
+				self.isConsecutive = undefined;
+				self.isCoalescing = false;
+				self.coalesceRounds = 0;
+			}
+			
+			// creates and returns a new documentFragment, containing all content nodes
+			// which can be inserted as a single node.
+			function createHTMLNode(html) {
+				var range = document.createRange();
+				range.selectNode(document.getElementById("Chat"));
+				return range.createContextualFragment(html);
+			}
+			
+			// removes first insert node from the internal fragment.
+			function rmInsertNode() {
+				var insert = self.fragment.querySelector("#insert");
+				if(insert)
+					insert.parentNode.removeChild(insert);
+			}
+			
+			function setShouldScroll(flag) {
+				if(flag && undefined === self.shouldScroll)
+					self.shouldScroll = flag;
+			}
+			
+			// hook in a custom method to append new data
+			// to the chat.
+			this.setAppendElementMethod = function (func) {
+				if(typeof func === 'function')
+					appendElement = func;
+			}
+						
+			// (re)start the coalescing timer.
+			//   we wait 25ms for a new message to come in.
+			//   If we get one, restart the timer and wait another 10ms.
+			//   If not, run outputHTML()
+			//  We do this a maximum of 400 times, for 10s max that can be spent
+			//  coalescing input, since this will block display.
+			this.coalesce = function() {
+				window.clearTimeout(self.timeoutID);
+				self.timeoutID = window.setTimeout(outputHTML, 25);
+				self.isCoalescing = true;
+				self.coalesceRounds += 1;
+				if(400 < self.coalesceRounds)
+					self.cancel();
+			}
+			
+			// if we need to append content into an insertion div,
+			// we need to clear the buffer and cancel the timeout.
+			this.cancel = function() {
+				if(self.isCoalescing) {
+					window.clearTimeout(self.timeoutID);
+					outputHTML();
+				}
+			}
+			
+			
+			// coalased analogs to the global functions
+			
+			this.append = function(html, shouldScroll) {
+				// if we started this fragment with a consecuative message,
+				// cancel and output before we continue
+				if(self.isConsecutive) {
+					self.cancel();
+				}
+				self.isConsecutive = false;
+				rmInsertNode();
+				var node = createHTMLNode(html);
+				self.fragment.appendChild(node);
+				
+				node = null;
+
+				setShouldScroll(shouldScroll);
+				self.coalesce();
+			}
+			
+			this.appendNext = function(html, shouldScroll) {
+				if(undefined === self.isConsecutive)
+					self.isConsecutive = true;
+				var node = createHTMLNode(html);
+				var insert = self.fragment.querySelector("#insert");
+				if(insert) {
+					insert.parentNode.replaceChild(node, insert);
+				} else {
+					self.fragment.appendChild(node);
+				}
+				node = null;
+				setShouldScroll(shouldScroll);
+				self.coalesce();
+			}
+			
+			this.replaceLast = function (html, shouldScroll) {
+				rmInsertNode();
+				var node = createHTMLNode(html);
+				var lastMessage = self.fragment.lastChild;
+				lastMessage.parentNode.replaceChild(node, lastMessage);
+				node = null;
+				setShouldScroll(shouldScroll);
+			}
+		}
+		var coalescedHTML;
+
+		//Appending new content to the message view
+		function appendMessage(html) {
+			var shouldScroll;
+			
+			// Only call nearBottom() if should scroll is undefined.
+			if(undefined === coalescedHTML.shouldScroll) {
+				shouldScroll = nearBottom();
+			} else {
+				shouldScroll = coalescedHTML.shouldScroll;
+			}
+			appendMessageNoScroll(html, shouldScroll);
+		}
+		
+		function appendMessageNoScroll(html, shouldScroll) {			
+			shouldScroll = shouldScroll || false;
+			// always try to coalesce new, non-griuped, messages
+			coalescedHTML.append(html, shouldScroll)
+		}
+		
+		function appendNextMessage(html){
+			var shouldScroll;
+			if(undefined === coalescedHTML.shouldScroll) {
+				shouldScroll = nearBottom();
+			} else {
+				shouldScroll = coalescedHTML.shouldScroll;
+			}
+			appendNextMessageNoScroll(html, shouldScroll);
+		}
+		
+		function appendNextMessageNoScroll(html, shouldScroll){
+			shouldScroll = shouldScroll || false;
+			// only group next messages if we're already coalescing input
+			coalescedHTML.appendNext(html, shouldScroll);
+		}
+
+		function replaceLastMessage(html){
+			var shouldScroll;
+			// only replace messages if we're already coalescing
+			if(coalescedHTML.isCoalescing){
+				if(undefined === coalescedHTML.shouldScroll) {
+					shouldScroll = nearBottom();
+				} else {
+					shouldScroll = coalescedHTML.shouldScroll;
+				}
+				coalescedHTML.replaceLast(html, shouldScroll);
+			} else {
+				shouldScroll = nearBottom();
+				//Retrieve the current insertion point, then remove it
+				//This requires that there have been an insertion point... is there a better way to retrieve the last element? -evands
+				var insert = document.getElementById("insert");
+				if(insert){
+					var parentNode = insert.parentNode;
+					parentNode.removeChild(insert);
+					var lastMessage = document.getElementById("Chat").lastChild;
+					document.getElementById("Chat").removeChild(lastMessage);
+				}
+
+				//Now append the message itself
+				appendHTML(html);
+
+				alignChat(shouldScroll);
+			}
+		}
+
+		//Auto-scroll to bottom.  Use nearBottom to determine if a scrollToBottom is desired.
+		function nearBottom() {
+			return ( document.body.scrollTop >= ( document.body.offsetHeight - ( window.innerHeight * 1.2 ) ) );
+		}
+		function scrollToBottom() {
+			document.body.scrollTop = document.body.offsetHeight;
+		}
+
+		//Dynamically exchange the active stylesheet
+		function setStylesheet( id, url ) {
+			var code = "<style id=\"" + id + "\" type=\"text/css\" media=\"screen,print\">";
+			if( url.length ) 
+				code += "@import url( \"" + url + "\" );";
+			code += "</style>";
+			var range = document.createRange();
+			var head = document.getElementsByTagName( "head" ).item(0);
+			range.selectNode( head );
+			var documentFragment = range.createContextualFragment( code );
+			head.removeChild( document.getElementById( id ) );
+			head.appendChild( documentFragment );
+		}
+
+		/* Converts emoticon images to textual emoticons; all emoticons in message if alt is held */
+		document.onclick = function imageCheck() {
+			var node = event.target;
+			if (node.tagName.toLowerCase() != 'img')
+				return;
+				
+			imageSwap(node, false);
+		}
+		
+		/* Converts textual emoticons to images if textToImagesFlag is true, otherwise vice versa */
+		function imageSwap(node, textToImagesFlag) {
+			var shouldScroll = nearBottom();
+			
+			var images = [node];
+			if (event.altKey) {
+				while (node.id != "Chat" && node.parentNode.id != "Chat")
+					node = node.parentNode;
+				images = node.querySelectorAll(textToImagesFlag ? "a" : "img");
+			}
+			
+			for (var i = 0; i < images.length; i++) {
+				textToImagesFlag ? textToImage(images[i]) : imageToText(images[i]);
+			}
+			
+			alignChat(shouldScroll);
+		}
+
+		function textToImage(node) {
+			if (!node.getAttribute("isEmoticon"))
+				return;
+			//Swap the image/text
+			var img = document.createElement('img');
+			img.setAttribute('src', node.getAttribute('src'));
+			img.setAttribute('alt', node.firstChild.nodeValue);
+			img.className = node.className;
+			node.parentNode.replaceChild(img, node);
+		}
+		
+		function imageToText(node)
+		{
+			if (!node.alt)
+				return;
+			var a = document.createElement('a');
+			a.setAttribute('onclick', 'imageSwap(this, true)');
+			a.setAttribute('src', node.getAttribute('src'));
+			a.setAttribute('isEmoticon', true);
+			a.className = node.className;
+			var text = document.createTextNode(node.alt);
+			a.appendChild(text);
+			node.parentNode.replaceChild(a, node);
+		}
+		
+		//Align our chat to the bottom of the window.  If true is passed, view will also be scrolled down
+		function alignChat(shouldScroll) {
+			var windowHeight = window.innerHeight;
+
+			if (windowHeight > 0) {
+				var contentElement = document.getElementById('Chat');
+				var contentHeight = contentElement.offsetHeight;
+				if (windowHeight - contentHeight > 0) {
+					contentElement.style.position = 'relative';
+					contentElement.style.top = (windowHeight - contentHeight) + 'px';
+				} else {
+					contentElement.style.position = 'static';
+				}
+			}
+
+			if (shouldScroll) scrollToBottom();
+		}
+
+		window.onresize = function windowDidResize(){
+			alignChat(true/*nearBottom()*/); //nearBottom buggy with inactive tabs
+		}
+		
+		function initStyle() {
+			alignChat(true);
+			if(!coalescedHTML)
+				coalescedHTML = new CoalescedHTML();
+		}
+	</script>
+
+	<style type="text/css">
+		.actionMessageUserName { display:none; }
+		.actionMessageBody:before { content:"*"; }
+		.actionMessageBody:after { content:"*"; }
+		* { word-wrap:break-word; text-rendering: optimizelegibility; }
+		img.scaledToFitImage { height: auto; max-width: 100%; }
+	</style>
+
+	<!-- This style is shared by all variants. !-->
+	<style id="baseStyle" type="text/css" media="screen,print">
+		%extraStyleCode%
+	</style>
+
+	<!-- Although we call this mainStyle for legacy reasons, it's actually the variant style !-->
+	<style id="mainStyle" type="text/css" media="screen,print">
+            @import url( "main.css" );
+            @import url( "%variant%" );
+	</style>
+
+</head>
+<body onload="initStyle();">
+%header%
+<div id="Chat">
+</div>
+%footer%
+</body>
+</html>
diff --git a/lib/chatview.cpp b/lib/chatview.cpp
index ac75630..89ac071 100644
--- a/lib/chatview.cpp
+++ b/lib/chatview.cpp
@@ -21,6 +21,9 @@
 #include <QDebug>
 #include <QWebFrame>
 #include <QWebElement>
+#include <QFile>
+#include <QTextCodec>
+#include <QTextDocument> //needed for Qt::escape
 
 #include <KDebug>
 #include <KEmoticonsTheme>
@@ -53,78 +56,107 @@ ChatView::ChatView(QWidget *parent) :
 
 void ChatView::initialise(const TelepathyChatInfo &chatInfo)
 {
-    //Stolen from Kopete code..took out some stuff we will need in future (variants and custom Kopete style)
-
-    QString headerHtml = replaceHeaderKeywords(m_chatStyle->getHeaderHtml(),chatInfo);
-
-
-    QString xhtmlBase;
-
-    xhtmlBase = QString("<?xml version=\"1.0\" encoding=\"utf-8\"?>
"
-                        "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
"
-                        "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
"
-                        "<html xmlns=\"http://www.w3.org/1999/xhtml\">
"
-                        "<head>
"
-                        "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8
\" />
"
-                        "<base href=\"file://%1\">
"
-                        "<style id=\"baseStyle\" type=\"text/css\" media=\"screen,print\">
"
-                        "	@import url(\"main.css\");
"
-                        "   @import url(\"%4\");
"
-                        "	*{ word-wrap:break-word; }
"
-                        "</style>
"
-                        "</head>
"
-                        "<body>
"
-                        "%2
"
-                        "<div id=\"Chat\">
</div>
"
-                        "%3
"
-                        "</body>"
-                        "</html>"
-                       ).arg(m_chatStyle->getStyleBaseHref()).arg(headerHtml).arg(m_chatStyle->getFooterHtml()).arg(m_variantPath);
-
-    setHtml(xhtmlBase);
+    QString templateHtml;
 
+
+    QString templateFileName( KGlobal::dirs()->findResource("data","ktelepathy/template.html"));
+
+    if (! templateFileName.isEmpty() && QFile::exists(templateFileName))
+    {
+        QFile fileAccess;
+
+        fileAccess.setFileName(templateFileName);
+        fileAccess.open(QIODevice::ReadOnly);
+        QTextStream headerStream(&fileAccess);
+        headerStream.setCodec(QTextCodec::codecForName("UTF-8"));
+        templateHtml = headerStream.readAll();
+        fileAccess.close();
+    }
+    else
+    {
+        KMessageBox::error(this,"Missing required file Template.html - check your installation.");
+    }
+
+    QString headerHtml;
+    if (m_showHeader)
+    {
+        headerHtml = replaceHeaderKeywords(m_chatStyle->getHeaderHtml(),chatInfo);
+    } //otherwise leave as blank.
+
+    templateHtml.replace("%baseRef%",m_chatStyle->getStyleBaseHref());
+    templateHtml.replace("%extraStyleCode%",""); // FIXME once we get some font from the config file, put it here
+    templateHtml.replace("%variant%",m_variantPath);
+    templateHtml.replace("%header%",headerHtml);
+    templateHtml.replace("%footer%",m_chatStyle->getFooterHtml());
+
+    setHtml(templateHtml);
 }
 
 
 
 void ChatView::addMessage(TelepathyChatMessageInfo & message)
 {
-    QWebElement chat = page()->mainFrame()->findFirstElement("#Chat");
-    if (chat.isNull())
+    QString styleHtml;
+    bool consecutiveMessage = false;
+
+    //FIXME "if group consecutive messages....{
+    if (lastSender == message.senderScreenName())
+    {
+        consecutiveMessage = true;
+    }
+    else
     {
-        kDebug() << "Cannot find #Chat element.";
-        return;
+        lastSender = message.senderScreenName();
     }
 
-    //Kopete added messages (manipulating the DOM) in a completely different way to how Adium does (via some JS)
-    //Gone with the Kopete way, but the Adium way is probably worth at least considering. (the latter allows for sexy theme animations)
-    QString styleHtml;
 
     switch(message.type())
     {
     case TelepathyChatMessageInfo::RemoteToLocal:
-        styleHtml= m_chatStyle->getIncomingHtml();
+        if(consecutiveMessage)
+        {
+            styleHtml = m_chatStyle->getNextIncomingHtml();
+        }
+        else
+        {
+            styleHtml= m_chatStyle->getIncomingHtml();
+        }
         break;
     case TelepathyChatMessageInfo::LocalToRemote:
-        styleHtml = m_chatStyle->getOutgoingHtml();
+        if(consecutiveMessage)
+        {
+            styleHtml = m_chatStyle->getNextOutgoingHtml();
+        }
+        else
+        {
+            styleHtml = m_chatStyle->getOutgoingHtml();
+        }
         break;
     case TelepathyChatMessageInfo::Status:
         styleHtml = m_chatStyle->getStatusHtml();
+        consecutiveMessage = false;
         break;
     }
 
-    QString messageHtml = m_emoticons.theme().parseEmoticons(message.message());
+    QString messageHtml = m_emoticons.theme().parseEmoticons(Qt::escape(message.message()));
+
     styleHtml.replace("%message%", messageHtml);
     styleHtml.replace("%messageDirection%",message.messageDirection());
     styleHtml.replace("%sender%", message.senderDisplayName()); // FIXME sender is complex: not always this
     styleHtml.replace("%time%", message.time().toString());
     styleHtml.replace("%userIconPath%", "Outgoing/buddy_icon.png");// this fallback should be done in the messageinfo
 
-    chat.appendInside(styleHtml);
+    if(consecutiveMessage)
+    {
+        appendNextMessage(styleHtml);
+    }
+    else
+    {
+        appendNewMessage(styleHtml);
+    }
 }
 
 
-/* FIXME? maybe this method should be in the telepathychatinfo class, then not have the getters in that class.? */
 QString ChatView::replaceHeaderKeywords(QString htmlTemplate, const TelepathyChatInfo & info)
 {
     htmlTemplate.replace("%chatName%", info.chatName());
@@ -136,7 +168,19 @@ QString ChatView::replaceHeaderKeywords(QString htmlTemplate, const TelepathyCha
     htmlTemplate.replace("%timeOpened%", info.timeOpened().toString()); //FIXME use KLocale to get format.
     //FIXME time fields - remember to do both, steal the complicated one from Kopete code.
 
-    qDebug() << htmlTemplate;
-
     return htmlTemplate;
 }
+
+void ChatView::appendNewMessage(QString html)
+{
+    //by making the JS return false evaluateJavaScript is a _lot_ faster, as it has nothing to convert to QVariant.
+    //escape quotes, and merge HTML onto one line.
+    QString js = QString("appendMessage(\"%1\");false;").arg(html.replace('"',"\\"").replace('
',""));
+    page()->mainFrame()->evaluateJavaScript(js);
+}
+
+void ChatView::appendNextMessage(QString html)
+{
+    QString js = QString("appendNextMessage(\"%1\");false;").arg(html.replace('"',"\\"").replace('
',""));
+    page()->mainFrame()->evaluateJavaScript(js);
+}
diff --git a/lib/chatview.h b/lib/chatview.h
index bfdcbaa..5446773 100644
--- a/lib/chatview.h
+++ b/lib/chatview.h
@@ -34,7 +34,6 @@ class ChatView : public QWebView
 public:
     explicit ChatView(QWidget *parent = 0);
     void initialise(const TelepathyChatInfo&);
-signals:
 
 public slots:
     void addMessage(TelepathyChatMessageInfo & message);
@@ -44,7 +43,14 @@ private:
     QString m_variantPath;
     KEmoticons m_emoticons;
     QString replaceHeaderKeywords(QString htmlTemplate, const TelepathyChatInfo&);
-//replaceMessageKeywords(QString htmlTemplate, const TelepathyChatMessageInfo&);
+    //QString replaceMessageKeywords(QString htmlTemplate, const TelepathyChatMessageInfo&);
+
+
+    QString lastSender;
+    bool m_showHeader;
+
+    void appendNewMessage(QString);
+    void appendNextMessage(QString);
 };
 
 #endif // CHATVIEW_H
diff --git a/lib/chatwindow.cpp b/lib/chatwindow.cpp
index 8bf76dd..7d915e5 100644
--- a/lib/chatwindow.cpp
+++ b/lib/chatwindow.cpp
@@ -28,7 +28,7 @@ ChatWindow::ChatWindow(ChatConnection* chat, QWidget *parent) :
         QWidget(parent),
         ui(new Ui::ChatWindow),
         m_chatConnection(chat),
-        m_channelInitialised(false)
+        m_chatviewlInitialised(false)
 {
     ui->setupUi(this);    
     ui->statusLabel->setText("");
@@ -43,6 +43,7 @@ ChatWindow::ChatWindow(ChatConnection* chat, QWidget *parent) :
     connect(m_chatConnection->channel().data(), SIGNAL(messageSent(Tp::Message, Tp::MessageSendingFlags, QString)), SLOT(handleMessageSent(Tp::Message, Tp::MessageSendingFlags, QString)));
     connect(m_chatConnection->channel().data(), SIGNAL(chatStateChanged(Tp::ContactPtr, ChannelChatState)), SLOT(updateChatStatus(Tp::ContactPtr, ChannelChatState)));
     connect(ui->sendMessageButton, SIGNAL(released()), SLOT(sendMessage()));
+    connect(ui->chatArea, SIGNAL(loadFinished(bool)),SLOT(chatViewReady()));
 
     messageBoxEventFilter = new MessageBoxEventFilter(this);
     ui->sendMessageBox->installEventFilter(messageBoxEventFilter);
@@ -72,7 +73,7 @@ void ChatWindow::changeEvent(QEvent *e)
 
 void ChatWindow::handleIncomingMessage(const Tp::ReceivedMessage &message)
 {
-    if(m_channelInitialised)
+    if(m_chatviewlInitialised)
     {
         TelepathyChatMessageInfo messageInfo(TelepathyChatMessageInfo::RemoteToLocal);
         messageInfo.setMessage(message.text());
@@ -95,6 +96,18 @@ void ChatWindow::handleMessageSent(const Tp::Message &message, Tp::MessageSendin
     ui->chatArea->addMessage(messageInfo);
 }
 
+void ChatWindow::chatViewReady()
+{
+    m_chatviewlInitialised = true;
+
+    //process any messages we've 'missed' whilst initialising.
+    foreach(Tp::ReceivedMessage message, m_chatConnection->channel()->messageQueue())
+    {
+        handleIncomingMessage(message);
+    }
+}
+
+
 void ChatWindow::sendMessage()
 {
     if(!ui->sendMessageBox->toPlainText().isEmpty()) {
@@ -171,16 +184,11 @@ void ChatWindow::updateEnabledState(bool enable)
         info.setTimeOpened(QDateTime::currentDateTime()); //FIXME how do I know when the channel opened? Using current time for now.
 
         ui->chatArea->initialise(info);
-        m_channelInitialised = true;
 
         //inform anyone using the class of the new name for this chat.
         Q_EMIT titleChanged(info.chatName());
 
-        //process any messages we've 'missed' whilst initialising.
-        foreach(Tp::ReceivedMessage message, m_chatConnection->channel()->messageQueue())
-        {
-            handleIncomingMessage(message);
-        }
+
     }
 }
 
diff --git a/lib/chatwindow.h b/lib/chatwindow.h
index d7908a8..954fa4e 100644
--- a/lib/chatwindow.h
+++ b/lib/chatwindow.h
@@ -68,6 +68,9 @@ protected slots:
 
     void updateChatStatus(Tp::ContactPtr contact, ChannelChatState state);
 
+
+    void chatViewReady();
+
 signals:
     void titleChanged(QString title);
 
@@ -76,7 +79,7 @@ private:
     ChatConnection* m_chatConnection;
 
     /** Stores whether the channel is ready with all contacts upgraded*/
-    bool m_channelInitialised;
+    bool m_chatviewlInitialised;
 
 
     MessageBoxEventFilter* messageBoxEventFilter;

-- 
ktp-text-ui packaging



More information about the pkg-kde-commits mailing list