Move generated binaries back in the root directory
[quassel.git] / src / qtui / chatitem.cpp
index 13cae26..072ae1b 100644 (file)
 #include <QPainter>
 #include <QPalette>
 #include <QTextLayout>
+#ifdef HAVE_WEBKIT
+#include <QWebView>
+#endif
+#include <QGraphicsProxyWidget>
 
 #include "chatitem.h"
 #include "chatlinemodel.h"
@@ -274,9 +278,7 @@ qreal ContentsChatItem::setGeometryByWidth(qreal w) {
 
 void ContentsChatItem::updateLayout() {
   if(!privateData()) {
-    ContentsChatItemPrivate *data = new ContentsChatItemPrivate(createLayout(QTextOption::WrapAnywhere),
-                                                               findClickables());
-    // data->clickables = findClickables();
+    ContentsChatItemPrivate *data = new ContentsChatItemPrivate(createLayout(QTextOption::WrapAnywhere), findClickables(), this);
     setPrivateData(data);
   }
 
@@ -378,9 +380,14 @@ QVector<QTextLayout::FormatRange> ContentsChatItem::additionalFormats() const {
 }
 
 void ContentsChatItem::endHoverMode() {
-  if(privateData()->currentClickable.isValid()) {
-    setCursor(Qt::ArrowCursor);
-    privateData()->currentClickable = Clickable();
+  if(hasLayout()) {
+    if(privateData()->currentClickable.isValid()) {
+      setCursor(Qt::ArrowCursor);
+      privateData()->currentClickable = Clickable();
+    }
+#ifdef HAVE_WEBKIT
+    clearWebPreview();
+#endif
     update();
   }
 }
@@ -398,6 +405,8 @@ void ContentsChatItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
       QString str = data(ChatLineModel::DisplayRole).toString().mid(click.start, click.length);
       switch(click.type) {
         case Clickable::Url:
+         if(!str.contains("://"))
+           str = "http://" + str;
           QDesktopServices::openUrl(str);
           break;
         case Clickable::Channel:
@@ -415,7 +424,7 @@ void ContentsChatItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
   // mouse move events always mean we're not hovering anymore...
   endHoverMode();
   // also, check if we have dragged the mouse
-  if(!privateData()->hasDragged && event->buttons() & Qt::LeftButton
+  if(hasLayout() && !privateData()->hasDragged && event->buttons() & Qt::LeftButton
     && (event->buttonDownScreenPos(Qt::LeftButton) - event->screenPos()).manhattanLength() >= QApplication::startDragDistance())
     privateData()->hasDragged = true;
   ChatItem::mouseMoveEvent(event);
@@ -432,9 +441,12 @@ void ContentsChatItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
   for(int i = 0; i < privateData()->clickables.count(); i++) {
     Clickable click = privateData()->clickables.at(i);
     if(idx >= click.start && idx < click.start + click.length) {
-      if(click.type == Clickable::Url)
+      if(click.type == Clickable::Url) {
         onClickable = true;
-      else if(click.type == Clickable::Channel) {
+#ifdef HAVE_WEBKIT
+       showWebPreview(click);
+#endif
+      } else if(click.type == Clickable::Channel) {
         // TODO: don't make clickable if it's our own name
         //onClickable = true; //FIXME disabled for now
       }
@@ -450,6 +462,107 @@ void ContentsChatItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
   event->accept();
 }
 
+#ifdef HAVE_WEBKIT
+void ContentsChatItem::showWebPreview(const Clickable &click) {
+  if(!hasLayout())
+    updateLayout();
+
+  QTextLine line = layout()->lineForTextPosition(click.start);
+  qreal x = line.cursorToX(click.start);
+  qreal width = line.cursorToX(click.start + click.length) - x;
+  qreal height = line.height();
+  qreal y = height * line.lineNumber();
+  QRectF urlRect(x, y, width, height);
+  QString url = data(ChatLineModel::DisplayRole).toString().mid(click.start, click.length);
+  if(!url.contains("://"))
+    url = "http://" + url;
+  privateData()->loadWebPreview(url, urlRect);
+}
+
+void ContentsChatItem::clearWebPreview() {
+  if(hasLayout())
+    privateData()->clearWebPreview();
+}
+#endif
+
+// ****************************************
+// ContentsChatItemPrivate
+// ****************************************
+#ifdef HAVE_WEBKIT
+ContentsChatItemPrivate::~ContentsChatItemPrivate() {
+  clearWebPreview();
+}
+
+void ContentsChatItemPrivate::loadWebPreview(const QString &url, const QRectF &urlRect) {
+  if(url != previewUrl) {
+    previewUrl = url;
+    // load a new web view and delete the old one (if exists)
+    if(previewItem) {
+      contentsItem->scene()->removeItem(previewItem);
+      delete previewItem;
+    }
+    QWebView *view = new QWebView;
+    view->load(url);
+    previewItem = new ContentsChatItemPrivate::PreviewItem(view);
+    contentsItem->scene()->addItem(previewItem);
+  }
+  if(urlRect != previewUrlRect) {
+    previewUrlRect = urlRect;
+    QPointF sPos = contentsItem->scenePos();
+    qreal previewY = sPos.y() + urlRect.y() + urlRect.height(); // bottom of url;
+    qreal previewX = sPos.x() + urlRect.x();
+    if(previewY + previewItem->boundingRect().height() > contentsItem->scene()->sceneRect().bottom())
+      previewY = sPos.y() + urlRect.y() - previewItem->boundingRect().height();
+    
+    if(previewX + previewItem->boundingRect().width() > contentsItem->scene()->sceneRect().width())
+      previewX = contentsItem->scene()->sceneRect().right() - previewItem->boundingRect().width();
+  
+    previewItem->setPos(previewX, previewY);
+  }
+}
+
+void ContentsChatItemPrivate::clearWebPreview() {
+  if(previewItem) {
+    contentsItem->scene()->removeItem(previewItem);
+    delete previewItem;
+    previewItem = 0;
+  }
+  previewUrl = QString();
+  previewUrlRect = QRectF();
+}
+
+ContentsChatItemPrivate::PreviewItem::PreviewItem(QWebView *webView)
+  : QGraphicsItem(0), // needs to be a top level item as we otherwise cannot guarantee that it's on top of other chatlines
+    _boundingRect(0, 0, 400, 300)
+{
+  qreal frameWidth = 5;
+  webView->resize(1000, 750);
+  QGraphicsProxyWidget *proxyItem = new QGraphicsProxyWidget(this);
+  proxyItem->setWidget(webView);
+  proxyItem->setAcceptHoverEvents(false);
+
+  qreal xScale = (_boundingRect.width() - 2 * frameWidth) / webView->width();
+  qreal yScale = (_boundingRect.height() - 2 * frameWidth) / webView->height();
+  proxyItem->scale(xScale, yScale);
+  proxyItem->setPos(frameWidth, frameWidth);
+
+  setZValue(30);
+}
+
+void ContentsChatItemPrivate::PreviewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
+  Q_UNUSED(option); Q_UNUSED(widget);
+  painter->setClipRect(boundingRect());
+  painter->setPen(QPen(Qt::black, 5));
+  painter->setBrush(Qt::black);
+  painter->setRenderHints(QPainter::Antialiasing);
+  painter->drawRoundedRect(boundingRect(), 10, 10);
+
+  painter->setPen(QPen(Qt::green));
+  QString text = QString::number(zValue());
+  painter->drawText(_boundingRect.center(), text);
+}
+#endif // #ifdef HAVE_WEBKIT
+
 /*************************************************************************************************/
 
 ContentsChatItem::WrapColumnFinder::WrapColumnFinder(ChatItem *_item)