#include "chatview.h" #include "messagedelegate.h" #include #include #include #include #include #include ChatView::ChatView(QWidget *parent) : QListView(parent) { setMouseTracking(true); } void ChatView::setBackgroundImage(const QString &path) { if (!m_background.load(path)) { qWarning() << "ChatView: failed to load background" << path; return; } viewport()->update(); } void ChatView::resizeEvent(QResizeEvent *event) { QListView::resizeEvent(event); scheduleDelayedItemsLayout(); } void ChatView::scrollContentsBy(int dx, int dy) { QListView::scrollContentsBy(dx, dy); viewport()->update(); } void ChatView::paintEvent(QPaintEvent *event) { if (!m_background.isNull()) { QPainter p(viewport()); p.drawTiledPixmap(viewport()->rect(), m_background); } QListView::paintEvent(event); } bool ChatView::isRowSelected(const QModelIndex &idx) const { if (!m_selStart.isValid() || !m_selEnd.isValid() || !idx.isValid()) return false; int r = idx.row(); int a = m_selStart.row(); int b = m_selEnd.row(); if (a > b) qSwap(a, b); return r >= a && r <= b; } void ChatView::mousePressEvent(QMouseEvent *event) { if (event->button() != Qt::LeftButton) { QListView::mousePressEvent(event); return; } if (hasSelection()) { m_selStart = QPersistentModelIndex(); m_selEnd = QPersistentModelIndex(); m_textSel = ChatTextSelection{}; m_selecting = false; viewport()->update(); } QModelIndex idx = indexAt(viewport()->mapFrom(this, event->pos())); m_pressIndex = QPersistentModelIndex(idx); m_pressPos = event->pos(); event->accept(); } void ChatView::mouseMoveEvent(QMouseEvent *event) { if (!m_selecting && m_pressIndex.isValid()) { int dx = event->pos().x() - m_pressPos.x(); int dy = event->pos().y() - m_pressPos.y(); if (dx * dx + dy * dy >= 25) { m_selStart = m_pressIndex; m_selEnd = m_pressIndex; m_selecting = true; QRect r = visualRect(QModelIndex(m_pressIndex)); m_textSel.index = m_pressIndex; m_textSel.clickPos = m_pressPos - r.topLeft(); m_textSel.dragPos = m_textSel.clickPos; m_textSel.active = true; viewport()->update(); } } if (!m_selecting) { QModelIndex idx = indexAt(viewport()->mapFrom(this, event->pos())); if (idx != QModelIndex(m_lastHovered)) { m_lastHovered = idx; emit hoveredIndexChanged(idx); } } if (!m_selecting) { QListView::mouseMoveEvent(event); return; } QModelIndex idx = indexAt(viewport()->mapFrom(this, event->pos())); if (idx.isValid()) { m_selEnd = idx; } if (m_textSel.active) { QRect r = visualRect(QModelIndex(m_textSel.index)); m_textSel.dragPos = event->pos() - r.topLeft(); } viewport()->update(); event->accept(); } void ChatView::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton && m_selecting) { m_selecting = false; viewport()->update(); } m_pressIndex = QPersistentModelIndex(); QListView::mouseReleaseEvent(event); } void ChatView::keyPressEvent(QKeyEvent *event) { if (event == QKeySequence::Copy) { copySelection(); return; } QListView::keyPressEvent(event); } void ChatView::copySelection() { if (!hasSelection()) return; auto *m = model(); if (!m) return; if (selStart() == selEnd()) { QModelIndex idx(selStart()); QString text = idx.data(MsgTextRole).toString(); if (m_textSel.startChar >= 0 && m_textSel.endChar > m_textSel.startChar) text = text.mid(m_textSel.startChar, m_textSel.endChar - m_textSel.startChar); QApplication::clipboard()->setText(text); } else { QString r; int a = selStart().row(), b = selEnd().row(); if (a > b) qSwap(a, b); for (int i = a; i <= b; ++i) { QModelIndex idx = m->index(i, 0); if (!r.isEmpty()) r += '\n'; r += '[' + idx.data(MsgTimeRole).toString() + "] "; r += idx.data(MsgAuthorRole).toString() + ": "; r += idx.data(MsgTextRole).toString(); } QApplication::clipboard()->setText(r); } }