Rewrite instant messaging screen

- HyperLink activated - YAY
- No more bubble size problem
- Username and date are now in an italic footer
- Username and date display are now saved in user preferences
- Remove sender avatar from right message as it's kind of
unnecessary

* Need LRC patch connecting message engine stuff : 4059 *

Change-Id: Id1adb1e96d99eb02a2c1e85a066dbbdc3e87cdc0
Tuleap: #601
Tuleap: #290
diff --git a/imdelegate.cpp b/imdelegate.cpp
index f18cf1d..054f4fc 100644
--- a/imdelegate.cpp
+++ b/imdelegate.cpp
@@ -19,36 +19,41 @@
 #include "imdelegate.h"
 
 #include <QApplication>
+#include <QTextDocument>
+#include <QSettings>
+#include <QDateTime>
 
 #include "media/text.h"
 #include "media/textrecording.h"
 
 #include "ringthemeutils.h"
+#include "settingskey.h"
 
 ImDelegate::ImDelegate(QObject *parent)
-    : QStyledItemDelegate(parent), showDate_(false), showAuthor_(false)
-{}
-
-void ImDelegate::setDisplayOptions(ImDelegate::DisplayOptions opt)
+    : QStyledItemDelegate(parent)
 {
-    showAuthor_ = opt & DisplayOptions::AUTHOR;
-    showDate_ = opt & DisplayOptions::DATE;
-    emit sizeHintChanged(QModelIndex());
 }
 
 void
 ImDelegate::formatMsg(const QModelIndex& index, QString& msg) const
 {
-    if (showAuthor_) {
-        auto author = index.data(
+    QSettings settings;
+    QStringList meta;
+    if (settings.value(SettingsKey::imShowAuthor).toBool()) {
+        meta << index.data(
                     static_cast<int>(Media::TextRecording::Role::AuthorDisplayname)).toString();
-        msg = QString("(%1)\n%2").arg(author, msg);
     }
-    if (showDate_) {
-        auto formattedDate = index.data(
-                    static_cast<int>(Media::TextRecording::Role::FormattedDate)).toString();
-        msg = QString("%2\n%1").arg(formattedDate, msg);
+    if (settings.value(SettingsKey::imShowDate).toBool()) {
+        auto timeStamp = index.data(
+                    static_cast<int>(Media::TextRecording::Role::Timestamp)).value<uint>();
+        auto date = QDateTime::fromTime_t(timeStamp);
+        auto now = QDateTime::currentDateTime();
+        if (now.date() == date.date())
+            meta << date.time().toString();
+        else
+            meta << date.toString();
     }
+    msg = QString("%2<footer><i>%1</i></footer>").arg(meta.join(" - "), msg);
 }
 
 void
@@ -64,7 +69,7 @@
     painter->setFont(fontMsg_);
 
     if (index.isValid()) {
-        auto msg = index.data(Qt::DisplayRole).toString();
+        auto msg = index.data(static_cast<int>(Media::TextRecording::Role::FormattedHtml)).toString();
         opt.text.clear();
         QStyle* style = opt.widget ? opt.widget->style() : QApplication::style();
 
@@ -76,53 +81,73 @@
 
         QRect textRect = getBoundingRect(dir, msg, opt);
 
-        QRect bubbleRect(textRect.left() - padding_,
-                         textRect.top() - padding_,
-                         textRect.width() + 2 * padding_,
-                         textRect.height() + 2 * padding_ );
-
-        opt.decorationSize = iconSize_;
-        opt.decorationPosition = (dir == Qt::AlignRight ?
-                                      QStyleOptionViewItem::Right : QStyleOptionViewItem::Left);
-        opt.decorationAlignment = Qt::AlignTop | Qt::AlignHCenter;
+        if (dir == Qt::AlignLeft) {
+            opt.decorationSize = iconSize_;
+            opt.decorationPosition = (dir == Qt::AlignRight ?
+                                          QStyleOptionViewItem::Right : QStyleOptionViewItem::Left);
+            opt.decorationAlignment = Qt::AlignTop | Qt::AlignHCenter;
+        } else
+            opt.decorationSize = QSize();
         style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, opt.widget);
 
         QPainterPath path;
-        path.addRoundedRect(bubbleRect, padding_, padding_);
+        path.addRoundedRect(textRect, padding_, padding_);
 
         if (dir == Qt::AlignRight) {
             painter->fillPath(path, RingTheme::blue_);
-            painter->setPen(Qt::white);
         }
         else {
             painter->fillPath(path, Qt::white);
-            painter->setPen(Qt::black);
         }
 
-        painter->drawText(textRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, msg);
+        painter->save();
+
+        QTextDocument document;
+        document.setDefaultFont(fontMsg_);
+
+        if (dir == Qt::AlignRight)
+            document.setDefaultStyleSheet("body { color : white; } i { opacity: 100; font-size : 11px; text-align : right; }");
+        else
+            document.setDefaultStyleSheet("body { color : black; } i { opacity: 100; font-size : 11px; text-align : right; }");
+
+        document.setHtml(msg);
+
+        auto textOptions = QTextOption(Qt::AlignLeft);
+        textOptions.setWrapMode(QTextOption::WrapMode::WordWrap);
+        document.setDefaultTextOption(textOptions);
+        document.setTextWidth(textRect.width());
+
+        painter->translate(textRect.topLeft());
+        document.drawContents(painter);
+        painter->restore();
     }
 }
 
-QRect ImDelegate::getBoundingRect(const Qt::AlignmentFlag& dir, const QString& msg, const QStyleOptionViewItem &option) const
+QRect ImDelegate::getBoundingRect(const Qt::AlignmentFlag& dir,
+                                  const QString& msg,
+                                  const QStyleOptionViewItem &option) const
 {
-    QFont textFont = option.font;
-    QFontMetrics textFontMetrics(textFont);
     QRect textRect;
 
-    if (dir == Qt::AlignRight) {
-        textRect = textFontMetrics.boundingRect(option.rect.left() + 2 * padding_,
-                                                option.rect.top() + 2 * padding_,
-                                                option.rect.width() - iconSize_.width() - 4 * padding_,
-                                                0,
-                                                dir|Qt::AlignTop|Qt::TextWordWrap,
-                                                msg);
+    QTextDocument txtDoc;
+    txtDoc.setDefaultFont(fontMsg_);
+    txtDoc.setHtml(msg);
+    auto textOptions = QTextOption(Qt::AlignLeft);
+    textOptions.setWrapMode(QTextOption::WrapMode::WordWrap);
+    txtDoc.setDefaultTextOption(textOptions);
+
+    if (dir == Qt::AlignLeft) {
+        txtDoc.setTextWidth(option.rect.width() - iconSize_.width() - padding_);
+        textRect.setRect(option.rect.left() + iconSize_.width() + padding_,
+                         option.rect.top() + padding_,
+                         txtDoc.idealWidth(),
+                         txtDoc.size().height());
     } else {
-        textRect = textFontMetrics.boundingRect(option.rect.left() + iconSize_.width() + 2 * padding_,
-                                                option.rect.top() + 2 * padding_,
-                                                option.rect.width() - iconSize_.width() - 4 * padding_ ,
-                                                0,
-                                                dir|Qt::AlignTop|Qt::TextWordWrap,
-                                                msg);
+        txtDoc.setTextWidth(option.rect.width() - padding_);
+        textRect.setRect(option.rect.right() - padding_ - txtDoc.idealWidth(),
+                         option.rect.top() + padding_,
+                         txtDoc.idealWidth(),
+                         txtDoc.size().height());
     }
     return textRect;
 }
@@ -134,7 +159,7 @@
     QStyleOptionViewItem opt = option;
     opt.font = fontMsg_;
 
-    QString msg = index.data(Qt::DisplayRole).toString();
+    QString msg = index.data(static_cast<int>(Media::TextRecording::Role::FormattedHtml)).toString();
 
     auto dir = index.data(
                 static_cast<int>(Media::TextRecording::Role::Direction))
@@ -145,11 +170,13 @@
 
     QRect boundingRect = getBoundingRect(dir, msg, opt);
 
-    QSize size(option.rect.width(), boundingRect.height() + padding_);
+    QSize size(option.rect.width(), boundingRect.height());
 
     /* Keep the minimum height needed. */
     if(size.height() < iconSize_.height())
-        size.setHeight(iconSize_.height() + padding_);
+        size.setHeight(iconSize_.height());
+
+    size.setHeight(size.height() + 2 * padding_);
 
     return size;
 }