X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fqtui%2Fchatitem.cpp;h=a087d6cd49b5578b31d2a031e608e8ce26862647;hp=e4580559c331e7fd8a9f5c8c317e2dbf2c2be89a;hb=600a710adeb06ed9dfbda52243255e11bbf811c5;hpb=148f1953967cdd1fc8febbdfd9bb103335dc8c91 diff --git a/src/qtui/chatitem.cpp b/src/qtui/chatitem.cpp index e4580559..a087d6cd 100644 --- a/src/qtui/chatitem.cpp +++ b/src/qtui/chatitem.cpp @@ -63,7 +63,6 @@ qreal ChatItem::setGeometry(qreal w, qreal h) { prepareGeometryChange(); _boundingRect.setWidth(w); if(h < 0) h = computeHeight(); - //if(h < 0) h = fontMetrics()->lineSpacing(); // only contents can be multi-line _boundingRect.setHeight(h); if(haveLayout()) updateLayout(); return h; @@ -296,7 +295,7 @@ void ContentsChatItem::updateLayout() { int col = finder.nextWrapColumn(); line.setNumColumns(col >= 0 ? col - line.textStart() : layout()->text().length()); line.setPosition(QPointF(0, h)); - h += line.height() + fontMetrics()->leading(); + h += fontMetrics()->lineSpacing(); } layout()->endLayout(); } @@ -305,11 +304,12 @@ void ContentsChatItem::updateLayout() { // (RegExps are not constant while matching, and they are static here for efficiency) QList ContentsChatItem::findClickables() { // For matching URLs - static QString urlEnd("(?:>|[,.;:]?\\s|\\b)"); + static QString urlEnd("(?:>|[,.;:\"]*\\s|\\b|$)"); static QString urlChars("(?:[\\w\\-~@/?&=+$()!%#]|[,.;:]\\w)"); static QRegExp regExp[] = { // URL + // QRegExp(QString("((?:https?://|s?ftp://|irc://|mailto:|www\\.)%1+|%1+\\.[a-z]{2,4}(?:?=/%1+|\\b))%2").arg(urlChars, urlEnd)), QRegExp(QString("((?:(?:https?://|s?ftp://|irc://|mailto:)|www)%1+)%2").arg(urlChars, urlEnd)), // Channel name @@ -335,18 +335,21 @@ QList ContentsChatItem::findClickables() { type = -1; minidx = str.length(); for(int i = 0; i < regExpCount; i++) { - if(matches[i] < 0 || idx < matchEnd[i] || matchEnd[i] >= str.length()) continue; - matches[i] = str.indexOf(regExp[i], qMax(matchEnd[i], idx)); - if(matches[i] >= 0) { - matchEnd[i] = matches[i] + regExp[i].cap(1).length(); - if(matches[i] < minidx) { - minidx = matches[i]; - type = i; - } + if(matches[i] < 0 || matchEnd[i] > str.length()) continue; + if(idx >= matchEnd[i]) { + matches[i] = str.indexOf(regExp[i], qMax(matchEnd[i], idx)); + if(matches[i] >= 0) matchEnd[i] = matches[i] + regExp[i].cap(1).length(); + } + if(matches[i] >= 0 && matches[i] < minidx) { + minidx = matches[i]; + type = i; } } if(type >= 0) { idx = matchEnd[type]; + if(type == Clickable::Url && str.at(idx-1) == ')') { // special case: closing paren only matches if we had an open one + if(!str.mid(matches[type], matchEnd[type]-matches[type]).contains('(')) matchEnd[type]--; + } result.append(Clickable((Clickable::Type)type, matches[type], matchEnd[type] - matches[type])); } } while(type >= 0); @@ -374,56 +377,76 @@ QVector ContentsChatItem::additionalFormats() const { return fmt; } -void ContentsChatItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { - // FIXME dirty and fast hack to make http:// urls klickable +void ContentsChatItem::endHoverMode() { + if(layoutData()->currentClickable.isValid()) { + setCursor(Qt::ArrowCursor); + layoutData()->currentClickable = Clickable(); + update(); + } +} + +void ContentsChatItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { + layoutData()->hasDragged = false; + ChatItem::mousePressEvent(event); +} - QRegExp regex("\\b([hf]t{1,2}ps?://[^\\s]+)\\b"); - QString str = data(ChatLineModel::DisplayRole).toString(); - int idx = posToCursor(event->pos()); - int mi = 0; - do { - mi = regex.indexIn(str, mi); - if(mi < 0) break; - if(idx >= mi && idx < mi + regex.matchedLength()) { - QDesktopServices::openUrl(QUrl(regex.capturedTexts()[1])); - break; +void ContentsChatItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + if(!event->buttons() && !layoutData()->hasDragged) { + // got a click + Clickable click = layoutData()->currentClickable; + if(click.isValid()) { + QString str = data(ChatLineModel::DisplayRole).toString().mid(click.start, click.length); + switch(click.type) { + case Clickable::Url: + QDesktopServices::openUrl(str); + break; + case Clickable::Channel: + // TODO join or whatever... + break; + default: + break; + } } - mi += regex.matchedLength(); - } while(mi >= 0); - event->accept(); + } + ChatItem::mouseReleaseEvent(event); } void ContentsChatItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { // mouse move events always mean we're not hovering anymore... - if(layoutData()->currentClickable.isValid()) { - layoutData()->currentClickable = Clickable(); - update(); - } + endHoverMode(); + // also, check if we have dragged the mouse + if(!layoutData()->hasDragged && event->buttons() & Qt::LeftButton + && (event->buttonDownScreenPos(Qt::LeftButton) - event->screenPos()).manhattanLength() >= QApplication::startDragDistance()) + layoutData()->hasDragged = true; ChatItem::mouseMoveEvent(event); } -void ContentsChatItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { - //layoutData()->currentClickable = event->pos(); - event->accept(); -} - void ContentsChatItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { - if(layoutData()->currentClickable.isValid()) { - layoutData()->currentClickable = Clickable(); - update(); - } + endHoverMode(); event->accept(); } void ContentsChatItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { + bool onClickable = false; qint16 idx = posToCursor(event->pos()); for(int i = 0; i < layoutData()->clickables.count(); i++) { Clickable click = layoutData()->clickables.at(i); if(idx >= click.start && idx < click.start + click.length) { - layoutData()->currentClickable = click; - update(); + if(click.type == Clickable::Url) + onClickable = true; + else if(click.type == Clickable::Channel) { + // TODO: don't make clickable if it's our own name + //onClickable = true; //FIXME disabled for now + } + if(onClickable) { + setCursor(Qt::PointingHandCursor); + layoutData()->currentClickable = click; + update(); + break; + } } } + if(!onClickable) endHoverMode(); event->accept(); }