Put selections in both clipboard and X selection buffer on Linux again.
[quassel.git] / src / qtui / chatwidget.cpp
index b44e90c..cf897b6 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-07 by the Quassel IRC Team                         *
+ *   Copyright (C) 2005-08 by the Quassel Project                          *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 #include "chatline-old.h"
 #include "qtui.h"
 #include "uisettings.h"
-
-ChatWidget::ChatWidget(QWidget *parent) : QAbstractScrollArea(parent) {
+#include "client.h"
+#include "buffer.h"
+#include "clientbacklogmanager.h"
+
+ChatWidget::ChatWidget(BufferId bufid, QWidget *parent) : QAbstractScrollArea(parent), AbstractChatView(),
+    lastBacklogOffset(0),
+    lastBacklogSize(0)
+{
   //setAutoFillBackground(false);
   //QPalette palette;
   //palette.setColor(backgroundRole(), QColor(0, 0, 0, 50));
@@ -32,9 +38,9 @@ ChatWidget::ChatWidget(QWidget *parent) : QAbstractScrollArea(parent) {
   scrollTimer = new QTimer(this);
   scrollTimer->setSingleShot(false);
   scrollTimer->setInterval(100);
+  // setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
   setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
-  setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
-  setMinimumSize(QSize(400,400));
+  setMinimumSize(QSize(20,20));
   setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
   setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
   bottomLine = -1;
@@ -43,18 +49,19 @@ ChatWidget::ChatWidget(QWidget *parent) : QAbstractScrollArea(parent) {
   pointerPosition = QPoint(0,0);
   connect(verticalScrollBar(), SIGNAL(actionTriggered(int)), this, SLOT(scrollBarAction(int)));
   connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(scrollBarValChanged(int)));
+
+  init(bufid);
 }
 
-void ChatWidget::init(QString netname, QString bufname) {
-  networkName = netname;
-  bufferName = bufname;
+void ChatWidget::init(BufferId id) {
+  bufferId = id;
   setBackgroundRole(QPalette::Base);
   setFont(QFont("Fixed"));
   UiSettings s;
   QVariant tsDef = s.value("DefaultTimestampColumnWidth", 90);
   QVariant senderDef = s.value("DefaultSenderColumnWidth", 100);
-  tsWidth = s.value(QString("%1/%2/TimestampColumnWidth").arg(netname, bufname), tsDef).toInt();
-  senderWidth = s.value(QString("%1/%2/SenderColumnWidth").arg(netname, bufname), senderDef).toInt();
+  tsWidth = s.value(QString("%1/TimestampColumnWidth").arg(bufferId.toInt()), tsDef).toInt();
+  senderWidth = s.value(QString("%1/SenderColumnWidth").arg(bufferId.toInt()), senderDef).toInt();
   computePositions();
   adjustScrollBar();
   verticalScrollBar()->setValue(verticalScrollBar()->maximum());
@@ -63,30 +70,41 @@ void ChatWidget::init(QString netname, QString bufname) {
   //verticalScrollBar()->setMinimum(0);
   //verticalScrollBar()->setMaximum((int)height - verticalScrollBar()->pageStep());
 
-  setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+  // setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
   setMouseTracking(true);
   mouseMode = Normal;
   selectionMode = NoSelection;
   connect(scrollTimer, SIGNAL(timeout()), this, SLOT(handleScrollTimer()));
+
+  if(bufferId.isValid())
+    connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(viewportChanged(int)));
 }
 
 ChatWidget::~ChatWidget() {
   //qDebug() << "destroying chatwidget" << bufferName;
-  //foreach(ChatLine *l, lines) {
+  //foreach(ChatLineOld *l, lines) {
   //  delete l;
   //}
   UiSettings s;
   s.setValue("DefaultTimestampColumnWidth", tsWidth);  // FIXME stupid dirty quicky
   s.setValue("DefaultSenderColumnWidth", senderWidth);
-  s.setValue(QString("%1/%2/TimestampColumnWidth").arg(networkName, bufferName), tsWidth);
-  s.setValue(QString("%1/%2/SenderColumnWidth").arg(networkName, bufferName), senderWidth);
+  s.setValue(QString("%1/TimestampColumnWidth").arg(bufferId.toInt()), tsWidth);
+  s.setValue(QString("%1/SenderColumnWidth").arg(bufferId.toInt()), senderWidth);
+}
+
+QSize ChatWidget::minimumSizeHint() const {
+  return QSize(20, 20);
 }
 
 QSize ChatWidget::sizeHint() const {
-  //qDebug() << size();
-  return size();
+  return QSize(400, 100);
 }
 
+// QSize ChatWidget::sizeHint() const {
+//   //qDebug() << size();
+//   return size();
+// }
+
 void ChatWidget::adjustScrollBar() {
   verticalScrollBar()->setPageStep(viewport()->height());
   verticalScrollBar()->setSingleStep(20);
@@ -154,12 +172,12 @@ void ChatWidget::clear() {
 }
 
 void ChatWidget::prependMsg(AbstractUiMsg *msg) {
-  ChatLine *line = dynamic_cast<ChatLine*>(msg);
+  ChatLineOld *line = dynamic_cast<ChatLineOld*>(msg);
   Q_ASSERT(line);
   prependChatLine(line);
 }
 
-void ChatWidget::prependChatLine(ChatLine *line) {
+void ChatWidget::prependChatLine(ChatLineOld *line) {
   qreal h = line->layout(tsWidth, senderWidth, textWidth);
   for(int i = 1; i < ycoords.count(); i++) ycoords[i] += h;
   ycoords.insert(1, h);
@@ -174,10 +192,10 @@ void ChatWidget::prependChatLine(ChatLine *line) {
   viewport()->update();
 }
 
-void ChatWidget::prependChatLines(QList<ChatLine *> clist) {
+void ChatWidget::prependChatLines(QList<ChatLineOld *> clist) {
   QList<qreal> tmpy; tmpy.append(0);
   qreal h = 0;
-  foreach(ChatLine *l, clist) {
+  foreach(ChatLineOld *l, clist) {
     h += l->layout(tsWidth, senderWidth, textWidth);
     tmpy.append(h);
   }
@@ -201,12 +219,12 @@ void ChatWidget::prependChatLines(QList<ChatLine *> clist) {
 }
 
 void ChatWidget::appendMsg(AbstractUiMsg *msg) {
-  ChatLine *line = dynamic_cast<ChatLine*>(msg);
+  ChatLineOld *line = dynamic_cast<ChatLineOld*>(msg);
   Q_ASSERT(line);
   appendChatLine(line);
 }
 
-void ChatWidget::appendChatLine(ChatLine *line) {
+void ChatWidget::appendChatLine(ChatLineOld *line) {
   qreal h = line->layout(tsWidth, senderWidth, textWidth);
   ycoords.append(h + ycoords[ycoords.count() - 1]);
   height += h;
@@ -218,8 +236,8 @@ void ChatWidget::appendChatLine(ChatLine *line) {
 }
 
 
-void ChatWidget::appendChatLines(QList<ChatLine *> list) {
-  foreach(ChatLine *line, list) {
+void ChatWidget::appendChatLines(QList<ChatLineOld *> list) {
+  foreach(ChatLineOld *line, list) {
     qreal h = line->layout(tsWidth, senderWidth, textWidth);
     ycoords.append(h + ycoords[ycoords.count() - 1]);
     height += h;
@@ -231,12 +249,14 @@ void ChatWidget::appendChatLines(QList<ChatLine *> list) {
   viewport()->update();
 }
 
-void ChatWidget::setContents(QList<ChatLine *> list) {
+void ChatWidget::setContents(const QList<AbstractUiMsg *> &list) {
   ycoords.clear();
   ycoords.append(0);
   height = 0;
   lines.clear();
-  appendChatLines(list);
+  QList<ChatLineOld *> cl;
+  foreach(AbstractUiMsg *msg, list) cl << dynamic_cast<ChatLineOld *>(msg);
+  appendChatLines(cl);
 }
 
 //!\brief Computes the different x position vars for given tsWidth and senderWidth.
@@ -253,7 +273,7 @@ void ChatWidget::resizeEvent(QResizeEvent *event) {
   /*if(event->oldSize().isValid())*/
   //contents->setWidth(event->size().width());
   //setAlignment(Qt::AlignBottom);
-  if(event->size().width() != event->oldSize().width()) {
+  if(event->size() != event->oldSize()) {
     computePositions();
     layout();
   }
@@ -332,10 +352,43 @@ void ChatWidget::mousePressEvent(QMouseEvent *event) {
   }
 }
 
-void ChatWidget::mouseDoubleClickEvent(QMouseEvent * /*event*/) {
-
+void ChatWidget::mouseDoubleClickEvent(QMouseEvent *event) {
+  // dirty and fast hack to make http:// urls klickable
+  if(lines.isEmpty())
+    return;
 
+  QPoint pos = event->pos() + QPoint(0, verticalScrollBar()->value());
+  int x = pos.x();
+  int y = pos.y();
+  int l = yToLineIdx(y);
+  if(lines.count() <= l)
+    return;
+
+  ChatLineOld *line = lines[l];
+  QString text = line->text();
+  int cursorAt = qMax(0, line->posToCursor(QPointF(x, y - ycoords[l])) - 1);
+
+  int start = 0;
+  if(cursorAt > 0) {
+    for(int i = cursorAt; i > 0; i--) {
+      if(text[i] == ' ') {
+       start = i + 1;
+       break;
+      }
+    }
+  }
 
+  int end = text.indexOf(" ", start);
+  int len = -1;
+  if(end != -1) {
+    len = end - start;
+  }
+  QString word = text.mid(start, len);
+  QRegExp regex("^(h|f)t{1,2}ps?:\\/\\/");
+  if(regex.indexIn(word) != -1) {
+    QDesktopServices::openUrl(QUrl(word));
+  }
+  
 }
 
 void ChatWidget::mouseReleaseEvent(QMouseEvent *event) {
@@ -358,7 +411,11 @@ void ChatWidget::mouseReleaseEvent(QMouseEvent *event) {
         selectionStart = qMin(dragStartCursor, curCursor);
         selectionEnd = qMax(dragStartCursor, curCursor);
         // TODO Make X11SelectionMode configurable!
+#ifdef Q_WS_X11
+        QApplication::clipboard()->setText(selectionToString(), QClipboard::Selection);
+#else
         QApplication::clipboard()->setText(selectionToString());
+#endif
         break;
       case MarkLines:
         mouseMode = Normal;
@@ -366,7 +423,12 @@ void ChatWidget::mouseReleaseEvent(QMouseEvent *event) {
         selectionStart = qMin(dragStartLine, curLine);
         selectionEnd = qMax(dragStartLine, curLine);
         // TODO Make X11SelectionMode configurable!
+#ifdef Q_WS_X11
+        QApplication::clipboard()->setText(selectionToString(), QClipboard::Selection);
+#endif
+//#else
         QApplication::clipboard()->setText(selectionToString());
+//#endif
         break;
       default:
         mouseMode = Normal;
@@ -487,13 +549,13 @@ void ChatWidget::handleMouseMoveEvent(const QPoint &_pos) {
     if(curLine == dragStartLine && c >= 0) {
       if(c != curCursor) {
         curCursor = c;
-        lines[curLine]->setSelection(ChatLine::Partial, dragStartCursor, c);
+        lines[curLine]->setSelection(ChatLineOld::Partial, dragStartCursor, c);
         viewport()->update();
       }
     } else {
       mouseMode = MarkLines;
       selectionStart = qMin(curLine, dragStartLine); selectionEnd = qMax(curLine, dragStartLine);
-      for(int i = selectionStart; i <= selectionEnd; i++) lines[i]->setSelection(ChatLine::Full);
+      for(int i = selectionStart; i <= selectionEnd; i++) lines[i]->setSelection(ChatLineOld::Full);
       viewport()->update();
     }
   } else if(mouseMode == MarkLines) {
@@ -503,16 +565,16 @@ void ChatWidget::handleMouseMoveEvent(const QPoint &_pos) {
       selectionStart = qMin(l, dragStartLine); selectionEnd = qMax(l, dragStartLine);
       if(curLine < 0) {
         Q_ASSERT(selectionStart == selectionEnd);
-        lines[l]->setSelection(ChatLine::Full);
+        lines[l]->setSelection(ChatLineOld::Full);
       } else {
         if(curLine < selectionStart) {
-          for(int i = curLine; i < selectionStart; i++) lines[i]->setSelection(ChatLine::None);
+          for(int i = curLine; i < selectionStart; i++) lines[i]->setSelection(ChatLineOld::None);
         } else if(curLine > selectionEnd) {
-          for(int i = selectionEnd+1; i <= curLine; i++) lines[i]->setSelection(ChatLine::None);
+          for(int i = selectionEnd+1; i <= curLine; i++) lines[i]->setSelection(ChatLineOld::None);
         } else if(selectionStart < curLine && l < curLine) {
-          for(int i = selectionStart; i < curLine; i++) lines[i]->setSelection(ChatLine::Full);
+          for(int i = selectionStart; i < curLine; i++) lines[i]->setSelection(ChatLineOld::Full);
         } else if(curLine < selectionEnd && l > curLine) {
-          for(int i = curLine+1; i <= selectionEnd; i++) lines[i]->setSelection(ChatLine::Full);
+          for(int i = curLine+1; i <= selectionEnd; i++) lines[i]->setSelection(ChatLineOld::Full);
         }
       }
       curLine = l;
@@ -525,10 +587,10 @@ void ChatWidget::handleMouseMoveEvent(const QPoint &_pos) {
 //!\brief Clear current text selection.
 void ChatWidget::clearSelection() {
   if(selectionMode == TextSelected) {
-    lines[selectionLine]->setSelection(ChatLine::None);
+    lines[selectionLine]->setSelection(ChatLineOld::None);
   } else if(selectionMode == LinesSelected) {
     for(int i = selectionStart; i <= selectionEnd; i++) {
-      lines[i]->setSelection(ChatLine::None);
+      lines[i]->setSelection(ChatLineOld::None);
     }
   }
   selectionMode = NoSelection;
@@ -551,3 +613,26 @@ QString ChatWidget::selectionToString() {
   return lines[selectionLine]->text().mid(selectionStart, selectionEnd - selectionStart);
 }
 
+void ChatWidget::viewportChanged(int newPos) {
+  const int REQUEST_COUNT = 50;
+  QAbstractSlider *vbar = verticalScrollBar();
+  if(!vbar)
+    return;
+
+  int relativePos = 100;
+  if(vbar->maximum() - vbar->minimum() != 0)
+    relativePos = (newPos - vbar->minimum()) * 100 / (vbar->maximum() - vbar->minimum());
+
+  if(relativePos < 20) {
+    Buffer *buffer = Client::buffer(bufferId);
+    Q_CHECK_PTR(buffer);
+    if(buffer->contents().isEmpty())
+      return;
+    MsgId msgId = buffer->contents().first()->msgId();
+    if(!lastBacklogOffset.isValid() || (msgId < lastBacklogOffset && lastBacklogSize + REQUEST_COUNT <= buffer->contents().count())) {
+      Client::backlogManager()->requestBacklog(bufferId, REQUEST_COUNT, msgId.toInt());
+      lastBacklogOffset = msgId;
+      lastBacklogSize = buffer->contents().size();
+    }
+  }
+}