giving the chatscene more control over the webpreview thus making it less crashy
authorMarcus Eggenberger <egs@quassel-irc.org>
Sun, 28 Sep 2008 14:28:07 +0000 (16:28 +0200)
committerMarcus Eggenberger <egs@quassel-irc.org>
Sun, 28 Sep 2008 14:28:07 +0000 (16:28 +0200)
src/qtui/CMakeLists.txt
src/qtui/chatitem.cpp
src/qtui/chatitem.h
src/qtui/chatscene.cpp
src/qtui/chatscene.h

index 253268e..c02fd2e 100644 (file)
@@ -41,7 +41,8 @@ set(SOURCES
     titlesetter.cpp
     topiclabel.cpp
     topicwidget.cpp
-    verticaldock.cpp)
+    verticaldock.cpp
+    webpreviewitem.cpp)
 
 set(MOC_HDRS
     aboutdlg.h
@@ -80,7 +81,8 @@ set(HEADERS
     chatlinemodelitem.h
     chatviewsettings.h
     qtuisettings.h
-    qtuistyle.h)
+    qtuistyle.h
+    webpreviewitem.h)
 
 set(FORMS
     aboutdlg.ui
index 072ae1b..df093d7 100644 (file)
 #include <QPainter>
 #include <QPalette>
 #include <QTextLayout>
-#ifdef HAVE_WEBKIT
-#include <QWebView>
-#endif
-#include <QGraphicsProxyWidget>
 
 #include "chatitem.h"
 #include "chatlinemodel.h"
@@ -385,9 +381,7 @@ void ContentsChatItem::endHoverMode() {
       setCursor(Qt::ArrowCursor);
       privateData()->currentClickable = Clickable();
     }
-#ifdef HAVE_WEBKIT
     clearWebPreview();
-#endif
     update();
   }
 }
@@ -443,9 +437,7 @@ void ContentsChatItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
     if(idx >= click.start && idx < click.start + click.length) {
       if(click.type == Clickable::Url) {
         onClickable = true;
-#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
@@ -462,8 +454,8 @@ void ContentsChatItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
   event->accept();
 }
 
-#ifdef HAVE_WEBKIT
 void ContentsChatItem::showWebPreview(const Clickable &click) {
+#ifdef HAVE_WEBKIT
   if(!hasLayout())
     updateLayout();
 
@@ -472,96 +464,22 @@ void ContentsChatItem::showWebPreview(const Clickable &click) {
   qreal width = line.cursorToX(click.start + click.length) - x;
   qreal height = line.height();
   qreal y = height * line.lineNumber();
-  QRectF urlRect(x, y, width, height);
+
+  QPointF topLeft = scenePos() + QPointF(x, y);
+  QRectF urlRect = QRectF(topLeft.x(), topLeft.y(), width, height);
+
   QString url = data(ChatLineModel::DisplayRole).toString().mid(click.start, click.length);
   if(!url.contains("://"))
     url = "http://" + url;
-  privateData()->loadWebPreview(url, urlRect);
+  chatScene()->loadWebPreview(this, url, urlRect);
+#endif
 }
 
 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);
+  chatScene()->clearWebPreview(this);
+#endif
 }
-#endif // #ifdef HAVE_WEBKIT
 
 /*************************************************************************************************/
 
index dd926bb..c2cb4ee 100644 (file)
@@ -169,7 +169,7 @@ private:
   void showWebPreview(const Clickable &click);
   void clearWebPreview();
 
-  
+
   // WARNING: setGeometry and setHeight should not be used without either:
   //  a) calling prepareGeometryChange() immediately before setColumns()
   //  b) calling Chatline::setPos() immediately afterwards
@@ -205,35 +205,9 @@ struct ContentsChatItemPrivate : ChatItemPrivate {
   ContentsChatItem::Clickable currentClickable;
   bool hasDragged;
 
-#ifndef HAVE_WEBKIT
   ContentsChatItemPrivate(QTextLayout *l, const QList<ContentsChatItem::Clickable> &c, ContentsChatItem *parent) : ChatItemPrivate(l), contentsItem(parent), clickables(c), hasDragged(false) {}
-#else
-  ContentsChatItemPrivate(QTextLayout *l, const QList<ContentsChatItem::Clickable> &c, ContentsChatItem *parent) : ChatItemPrivate(l), contentsItem(parent), clickables(c), hasDragged(false), previewItem(0) {}
-  ~ContentsChatItemPrivate();
-
-  void loadWebPreview(const QString &url, const QRectF &urlRect);
-  void clearWebPreview();
-
-private:
-  class PreviewItem;
-  PreviewItem *previewItem;
-  QString previewUrl;
-  QRectF previewUrlRect;
-#endif //#ifndef HAVE_WEBKIT
 };
 
-#ifdef HAVE_WEBKIT
-class QWebView;
-class ContentsChatItemPrivate::PreviewItem : public QGraphicsItem {
-public:
-  PreviewItem(QWebView *webView);
-  virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
-  virtual inline QRectF boundingRect() const { return _boundingRect; }
-
-private:
-  QRectF _boundingRect;
-};
-#endif //#ifdef HAVE_WEBKIT
 
 //inlines regarding ContentsChatItemPrivate
 ContentsChatItemPrivate *ContentsChatItem::privateData() const { return (ContentsChatItemPrivate *)ChatItem::privateData(); }
index ed8e68d..cab42c6 100644 (file)
@@ -34,6 +34,7 @@
 #include "qtui.h"
 #include "qtuistyle.h"
 #include "chatviewsettings.h"
+#include "webpreviewitem.h"
 
 const qreal minContentsWidth = 200;
 
@@ -90,6 +91,9 @@ ChatScene::~ChatScene() {
 
 void ChatScene::rowsInserted(const QModelIndex &index, int start, int end) {
   Q_UNUSED(index);
+
+  clearWebPreview();
+
   qreal h = 0;
   qreal y = _sceneRect.y();
   qreal width = _sceneRect.width();
@@ -175,6 +179,8 @@ void ChatScene::rowsInserted(const QModelIndex &index, int start, int end) {
 void ChatScene::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) {
   Q_UNUSED(parent);
 
+  clearWebPreview();
+
   qreal h = 0; // total height of removed items;
 
   bool atTop = (start == 0);
@@ -474,3 +480,45 @@ void ChatScene::updateSceneRect(const QRectF &rect) {
   _sceneRect = rect;
   setSceneRect(rect);
 }
+
+
+void ChatScene::loadWebPreview(ChatItem *parentItem, const QString &url, const QRectF &urlRect) {
+  if(webPreview.parentItem != parentItem)
+    webPreview.parentItem = parentItem;
+
+  if(webPreview.url != url) {
+    webPreview.url = url;
+    // load a new web view and delete the old one (if exists)
+    if(webPreview.previewItem) {
+      removeItem(webPreview.previewItem);
+      delete webPreview.previewItem;
+    }
+    webPreview.previewItem = new WebPreviewItem(url);
+    addItem(webPreview.previewItem);
+  }
+  if(webPreview.urlRect != urlRect) {
+    webPreview.urlRect = urlRect;
+    qreal previewY = urlRect.bottom();
+    qreal previewX = urlRect.x();
+    if(previewY + webPreview.previewItem->boundingRect().height() > sceneRect().bottom())
+      previewY = urlRect.y() - webPreview.previewItem->boundingRect().height();
+
+    if(previewX + webPreview.previewItem->boundingRect().width() > sceneRect().width())
+      previewX = sceneRect().right() - webPreview.previewItem->boundingRect().width();
+
+    webPreview.previewItem->setPos(previewX, previewY);
+  }
+}
+
+void ChatScene::clearWebPreview(ChatItem *parentItem) {
+  if(parentItem == 0 || webPreview.parentItem == parentItem) {
+    if(webPreview.previewItem) {
+      removeItem(webPreview.previewItem);
+      delete webPreview.previewItem;
+      webPreview.previewItem = 0;
+    }
+    webPreview.parentItem = 0;
+    webPreview.url = QString();
+    webPreview.urlRect = QRectF();
+  }
+}
index e0aaa50..aa741cb 100644 (file)
@@ -31,6 +31,7 @@
 class AbstractUiMsg;
 class ChatItem;
 class ChatLine;
+class WebPreviewItem;
 
 class QGraphicsSceneMouseEvent;
 
@@ -65,6 +66,9 @@ public slots:
 
   void requestBacklog();
 
+  void loadWebPreview(ChatItem *parentItem, const QString &url, const QRectF &urlRect);
+  void clearWebPreview(ChatItem *parentItem = 0);
+
 signals:
   void lastLineChanged(QGraphicsItem *);
 
@@ -107,6 +111,15 @@ private:
   bool _isSelecting;
 
   int _lastBacklogSize;
+
+  struct WebPreview {
+    ChatItem *parentItem;
+    WebPreviewItem *previewItem;
+    QString url;
+    QRectF urlRect;
+    WebPreview() : parentItem(0), previewItem(0) {}
+  };
+  WebPreview webPreview;
 };
 
 bool ChatScene::containsBuffer(const BufferId &id) const {