Bug 200833 - chat view is left-to-right, even for RTL discussions
Summary: chat view is left-to-right, even for RTL discussions
Status: RESOLVED FIXED
Alias: None
Product: konversation
Classification: Applications
Component: general (show other bugs)
Version: 1.2-alpha4
Platform: Gentoo Packages Linux
: NOR normal
Target Milestone: ---
Assignee: Konversation Developers
URL:
Keywords:
Depends on:
Blocks: 192499
  Show dependency treegraph
 
Reported: 2009-07-20 08:58 UTC by Yuval Hager
Modified: 2009-09-20 01:37 UTC (History)
4 users (show)

See Also:
Latest Commit:
Version Fixed In:
Sentry Crash Report:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Yuval Hager 2009-07-20 08:58:54 UTC
Version:           1.2-alpha4 (using KDE 4.2.4)
Compiler:          gcc (GCC) 4.1.2 (Gentoo 4.1.2 p1.1)  
OS:                Linux
Installed from:    Gentoo Packages

The chat view in konversation for KDE3.5 used to display RTL chats correctly (I think it was based on the first letter in the message, like other KDE apps used to do it).

For KDE4, all chats are LTR, regardless of the message text.

I have the same issue for the inputline, but I guess this is another bug report.
Comment 1 Peter Simonsson 2009-09-15 18:47:44 UTC
SVN commit 1023945 by psn:

Resurrect RTL text support in ircview.


 M  +1 -0      ChangeLog
 M  +1 -1      src/commit.h
 M  +154 -17   src/viewer/ircview.cpp
 M  +2 -3      src/viewer/ircview.h


--- trunk/extragear/network/konversation/ChangeLog #1023944:1023945
@@ -54,6 +54,7 @@
 * The initial width of the nickname lists in channel tabs is now more sen-
  sible.
 * Added back the ability to drag links out of the chat view.
+* Resurrected the RTL text support in the chat view.


 Changes from 1.2-alpha5 to 1.2-alpha6:
--- trunk/extragear/network/konversation/src/commit.h #1023944:1023945
@@ -1,4 +1,4 @@
 // This COMMIT number is added to version string to be used as "patch level"
 #ifndef COMMIT
-#define COMMIT 3434
+#define COMMIT 3435
 #endif
--- trunk/extragear/network/konversation/src/viewer/ircview.cpp #1023944:1023945
@@ -36,6 +36,7 @@
 #include <QColor>
 #include <QMouseEvent>
 #include <QScrollBar>
+#include <QTextBlock>

 #include <KUrl>
 #include <KBookmarkManager>
@@ -280,12 +281,24 @@
    QString nickLine = createNickLine(nick, channelColor);

    QString line;
-    line = "<font color=\"" + channelColor + "\">%1" + nickLine + " %3</font>";
+    bool rtl = (basicDirection(message) == QChar::DirR);
+
+    if(rtl)
+    {
+        line = RLE;
+        line += LRE;
+        line += "<font color=\"" + channelColor + "\">" + nickLine +" %1" + PDF + RLM + " %3</font>";
+    }
+    else
+    {
+        line = "<font color=\"" + channelColor + "\">%1" + nickLine + " %3</font>";
+    }
+
    line = line.arg(timeStamp(), nick, filter(message, channelColor, nick, true));

    emit textToLog(QString("<%1>\t%2").arg(nick).arg(message));

-    doAppend(line);
+    doAppend(line, rtl);
 }

 void IRCView::appendRaw(const QString& message, bool suppressTimestamps, bool self)
@@ -299,7 +312,7 @@
    else
        line = QString(timeStamp() + " <font color=\"" + channelColor.name() + "\">" + message + "</font>");

-    doAppend(line, self);
+    doAppend(line, false, self);
 }

 void IRCView::appendLog(const QString & message)
@@ -309,7 +322,7 @@

    QString line("<font color=\"" + channelColor.name() + "\">" + message + "</font>");

-    doRawAppend(line);
+    doRawAppend(line, !QApplication::isLeftToRight());
 }

 void IRCView::appendQuery(const QString& nick, const QString& message, bool inChannel)
@@ -321,12 +334,24 @@
    QString nickLine = createNickLine(nick, queryColor, true, inChannel);

    QString line;
-    line = "<font color=\"" + queryColor + "\">%1 " + nickLine + " %3</font>";
+    bool rtl = (basicDirection(message) == QChar::DirR);
+
+    if(rtl)
+    {
+        line = RLE;
+        line += LRE;
+        line += "<font color=\"" + queryColor + "\">" + nickLine + " %1" + PDF + RLM + " %3</font>";
+    }
+    else
+    {
+        line = "<font color=\"" + queryColor + "\">%1 " + nickLine + " %3</font>";
+    }
+
    line = line.arg(timeStamp(), nick, filter(message, queryColor, nick, true));

    emit textToLog(QString("<%1>\t%2").arg(nick).arg(message));

-    doAppend(line);
+    doAppend(line, rtl);
 }

 void IRCView::appendChannelAction(const QString& nick, const QString& message)
@@ -348,12 +373,24 @@
    QString nickLine = createNickLine(nick, actionColor, false);

    QString line;
-    line = "<font color=\"" + actionColor + "\">%1 * " + nickLine + " %3</font>";
+    bool rtl = (basicDirection(message) == QChar::DirR);
+
+    if(rtl)
+    {
+        line = RLE;
+        line += LRE;
+        line += "<font color=\"" + actionColor + "\">" + nickLine + " * %1" + PDF + " %3</font>";
+    }
+    else
+    {
+        line = "<font color=\"" + actionColor + "\">%1 * " + nickLine + " %3</font>";
+    }
+
    line = line.arg(timeStamp(), nick, filter(message, actionColor, nick, true));

    emit textToLog(QString("\t * %1 %2").arg(nick).arg(message));

-    doAppend(line);
+    doAppend(line, rtl);
 }

 void IRCView::appendServerMessage(const QString& type, const QString& message, bool parseURL)
@@ -370,7 +407,19 @@
    }

    QString line;
-    line = "<font color=\"" + serverColor + "\"" + fixed + ">%1 <b>[</b>%2<b>]</b> %3</font>";
+    bool rtl = (basicDirection(message) == QChar::DirR);
+
+    if(rtl)
+    {
+        line = RLE;
+        line += LRE;
+        line += "<font color=\"" + serverColor + "\"" + fixed + "><b>[</b>%2<b>]</b> %1" + PDF + " %3</font>";
+    }
+    else
+    {
+        line = "<font color=\"" + serverColor + "\"" + fixed + ">%1 <b>[</b>%2<b>]</b> %3</font>";
+    }
+
    if(type != i18n("Notify"))
        line = line.arg(timeStamp(), type, filter(message, serverColor, 0 , true, parseURL));
    else
@@ -378,7 +427,7 @@

    emit textToLog(QString("%1\t%2").arg(type).arg(message));

-    doAppend(line);
+    doAppend(line, rtl);
 }

 void IRCView::appendCommandMessage(const QString& type,const QString& message, bool important, bool parseURL, bool self)
@@ -403,13 +452,24 @@
    prefix=Qt::escape(prefix);

    QString line;
-    line = "<font color=\"" + commandColor + "\">%1 %2 %3</font>";
+    bool rtl = (basicDirection(message) == QChar::DirR);

+    if(rtl)
+    {
+        line = RLE;
+        line += LRE;
+        line += "<font color=\"" + commandColor + "\">%2 %1" + PDF + " %3</font>";
+    }
+    else
+    {
+        line = "<font color=\"" + commandColor + "\">%1 %2 %3</font>";
+    }
+
    line = line.arg(timeStamp(), prefix, filter(message, commandColor, 0, true, parseURL, self));

    emit textToLog(QString("%1\t%2").arg(type).arg(message));

-    doAppend(line, self);
+    doAppend(line, rtl, self);
 }

 void IRCView::appendBacklogMessage(const QString& firstColumn,const QString& rawMessage)
@@ -433,14 +493,25 @@
    nick.replace('>',"&gt;");

    QString line;
+    bool rtl = (basicDirection(message) == QChar::DirR);

-    line = "<font color=\"" + backlogColor + "\">%1 %2 %3</font>";
+    if(rtl)
+    {
+        line = RLE;
+        line += LRE;
+        line += "<font color=\"" + backlogColor + "\">%2 %1" + PDF + " %3</font>";
+    }
+    else
+    {
+        line = "<font color=\"" + backlogColor + "\">%1 %2 %3</font>";
+    }
+
    line = line.arg(time, nick, filter(message, backlogColor, NULL, false, false));

-    doAppend(line);
+    doAppend(line, rtl);
 }

-void IRCView::doAppend(const QString& newLine, bool self)
+void IRCView::doAppend(const QString& newLine, bool rtl, bool self)
 {
    if (!self && m_chatWin)
        m_chatWin->activateTabNotification(m_tabNotification);
@@ -454,7 +525,7 @@
        //setMaximumBlockCount(atBottom ? scrollMax : maximumBlockCount() + 1);
    }

-    doRawAppend(newLine);
+    doRawAppend(newLine, rtl);

    //appendHtml(line);

@@ -478,7 +549,7 @@
        emit clearStatusBarTempText();
 }

-void IRCView::doRawAppend(const QString& newLine)
+void IRCView::doRawAppend(const QString& newLine, bool rtl)
 {
    QString line(newLine);

@@ -499,6 +570,11 @@

    KTextBrowser::append(line);

+    QTextCursor formatCursor(document()->lastBlock());
+    QTextBlockFormat format = formatCursor.blockFormat();
+    format.setAlignment(rtl ? Qt::AlignRight : Qt::AlignLeft);
+    formatCursor.setBlockFormat(format);
+
    if (checkSelection && selectionLength < (cursor.selectionEnd() - cursor.selectionStart()))
    {
        cursor.setPosition(cursor.selectionStart());
@@ -1244,6 +1320,67 @@
    emit popupCommand(action->data().toInt());
 }

+// for more information about these RTFM
+//    http://www.unicode.org/reports/tr9/
+//    http://www.w3.org/TR/unicode-xml/
+QChar IRCView::LRM = (ushort)0x200e; // Right-to-Left Mark
+QChar IRCView::RLM = (ushort)0x200f; // Left-to-Right Mark
+QChar IRCView::LRE = (ushort)0x202a; // Left-to-Right Embedding
+QChar IRCView::RLE = (ushort)0x202b; // Right-to-Left Embedding
+QChar IRCView::RLO = (ushort)0x202e; // Right-to-Left Override
+QChar IRCView::LRO = (ushort)0x202d; // Left-to-Right Override
+QChar IRCView::PDF = (ushort)0x202c; // Previously Defined Format
+
+QChar::Direction IRCView::basicDirection(const QString& string)
+{
+    // The following code decides between LTR or RTL direction for
+    // a line based on the amount of each type of characters pre-
+    // sent. It does so by counting, but stops when one of the two
+    // counters becomes higher than half of the string length to
+    // avoid unnecessary work.
+
+    unsigned int pos = 0;
+    unsigned int rtl_chars = 0;
+    unsigned int ltr_chars = 0;
+    unsigned int str_len = string.length();
+    unsigned int str_half_len = str_len/2;
+
+    for(pos=0; pos < str_len; pos++)
+    {
+        if (!(string[pos].isNumber() || string[pos].isSymbol() ||
+            string[pos].isSpace()  || string[pos].isPunct()  ||
+            string[pos].isMark()))
+        {
+            switch(string[pos].direction())
+            {
+                case QChar::DirL:
+                case QChar::DirLRO:
+                case QChar::DirLRE:
+                    ltr_chars++;
+                    break;
+                case QChar::DirR:
+                case QChar::DirAL:
+                case QChar::DirRLO:
+                case QChar::DirRLE:
+                    rtl_chars++;
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        if (ltr_chars > str_half_len)
+            return QChar::DirL;
+        else if (rtl_chars > str_half_len)
+            return QChar::DirR;
+    }
+
+    if (rtl_chars > ltr_chars)
+        return QChar::DirR;
+    else
+        return QChar::DirL;
+}
+
 // **WARNING** the selectionChange signal comes BEFORE the selection has actually been changed, hook cursorPositionChanged too

 //void IRCView::mouseDoubleClickEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos)
--- trunk/extragear/network/konversation/src/viewer/ircview.h #1023944:1023945
@@ -112,18 +112,17 @@
        void appendBacklogMessage(const QString& firstColumn, const QString& message);

    protected:
-        void doAppend(const QString& line, bool self=false);
+        void doAppend(const QString& line, bool rtl, bool self=false);
        /**
         * Appends a newLine without any scrollback or notification checks
         * @param newLine
         */
-        void doRawAppend(const QString& newLine);
+        void doRawAppend(const QString& newLine, bool rtl);
        void appendLine(const QString& color);
        void appendRememberLine();

        void updateNickMenuEntries(const QString& nickname);

-
    public slots:
        /// Emits the doSeach signal.
        void findText();
Comment 2 Peter Simonsson 2009-09-15 18:50:11 UTC
Would be nice if you could test trunk and see if it works as expected for you
Comment 3 Eike Hein 2009-09-15 18:53:43 UTC
Diego, I added you to the CC list on this one because we could use your feedback. Could you try Konvi SVN and check whether things work like in Konversation 1.1? Our goal here is to have parity with 1.1, since we're close to releasing 1.2 otherwise.
Comment 4 Eike Hein 2009-09-15 18:55:47 UTC
Youssef, I added you to the CC list on this one because we could use your
feedback. Could you try Konvi SVN and check whether things work like in
Konversation 1.1? Our goal here is to have parity with 1.1, since we're close
to releasing 1.2 otherwise.
Comment 5 Eike Hein 2009-09-15 19:08:33 UTC
We'd like to do beta1 this week, which will also signal feature and string freeze, and then release the final in early October.

BTW we know that RTL text in the input line is currently somewhat broken; that seems to be Qt's fault. So this is only about the chat text view for now ...

Thanks for taking a look!
Comment 6 Eike Hein 2009-09-15 19:10:07 UTC
To clarify, RTL in the input bar should work if the locale used makes the entire app RTL, but typing RTL text into an LTR Konvi input bar behaves wonky - text is not right-aligned - due to Qt.
Comment 7 Peter Simonsson 2009-09-15 20:14:38 UTC
SVN commit 1023971 by psn:

Fix text layout problems when run with --reverse
CCBUG: 200833


 M  +123 -115  config/generalbehavior_config.ui  
 M  +4 -0      config/konversation.kcfg  
 M  +28 -6     viewer/ircview.cpp  


WebSVN link: http://websvn.kde.org/?view=rev&revision=1023971
Comment 8 Eike Hein 2009-09-20 01:37:01 UTC
Fixed as of SVN revision 1023971.