File indexing completed on 2024-12-08 04:34:23
0001 /* 0002 SPDX-FileCopyrightText: 2022-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "messagelistviewbase.h" 0008 #include "model/messagesmodel.h" 0009 #include "room/plugins/plugintext.h" 0010 #include "room/plugins/plugintextinterface.h" 0011 #include "room/textpluginmanager.h" 0012 #include <QAbstractItemModel> 0013 #include <QApplication> 0014 #include <QClipboard> 0015 #include <QMouseEvent> 0016 #include <QScrollBar> 0017 0018 MessageListViewBase::MessageListViewBase(QWidget *parent) 0019 : QListView(parent) 0020 { 0021 setProperty("_breeze_borders_sides", QVariant::fromValue(QFlags{Qt::BottomEdge})); 0022 setSelectionMode(QAbstractItemView::NoSelection); 0023 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0024 setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); // nicer in case of huge messages 0025 setWordWrap(true); // so that the delegate sizeHint is called again when the width changes 0026 // only the lineedit takes focus 0027 setFocusPolicy(Qt::NoFocus); 0028 scrollToBottom(); 0029 setMouseTracking(true); 0030 0031 const QVector<PluginText *> plugins = TextPluginManager::self()->pluginsList(); 0032 for (PluginText *plugin : plugins) { 0033 connect(plugin, &PluginText::errorMessage, this, &MessageListViewBase::errorMessage); 0034 connect(plugin, &PluginText::successMessage, this, &MessageListViewBase::successMessage); 0035 mPluginTextInterface.append(plugin->createInterface(this)); 0036 } 0037 } 0038 0039 MessageListViewBase::~MessageListViewBase() 0040 { 0041 qDeleteAll(mPluginTextInterface); 0042 } 0043 0044 void MessageListViewBase::resizeEvent(QResizeEvent *ev) 0045 { 0046 QListView::resizeEvent(ev); 0047 0048 // Fix not being really at bottom when the view gets reduced by the header widget becoming taller 0049 checkIfAtBottom(); 0050 maybeScrollToBottom(); // this forces a layout in QAIV, which then changes the vbar max value 0051 updateVerticalPageStep(); 0052 Q_EMIT needToClearSizeHintCache(); 0053 } 0054 0055 void MessageListViewBase::checkIfAtBottom() 0056 { 0057 auto *vbar = verticalScrollBar(); 0058 mAtBottom = vbar->value() == vbar->maximum(); 0059 } 0060 0061 void MessageListViewBase::maybeScrollToBottom() 0062 { 0063 if (mAtBottom) { 0064 scrollToBottom(); 0065 } 0066 } 0067 0068 void MessageListViewBase::updateVerticalPageStep() 0069 { 0070 verticalScrollBar()->setPageStep(viewport()->height() * 3 / 4); 0071 } 0072 0073 void MessageListViewBase::handleMouseEvent(QMouseEvent *event) 0074 { 0075 const QPersistentModelIndex index = indexAt(event->pos()); 0076 if (index.isValid()) { 0077 // When the cursor hovers another message, hide/show the reaction icon accordingly 0078 if (mCurrentIndex != index) { 0079 if (mCurrentIndex.isValid()) { 0080 auto lastModel = const_cast<QAbstractItemModel *>(mCurrentIndex.model()); 0081 lastModel->setData(mCurrentIndex, false, MessagesModel::HoverHighLight); 0082 } 0083 mCurrentIndex = index; 0084 auto model = const_cast<QAbstractItemModel *>(mCurrentIndex.model()); 0085 model->setData(mCurrentIndex, true, MessagesModel::HoverHighLight); 0086 } 0087 0088 QStyleOptionViewItem options = listViewOptions(); 0089 options.rect = visualRect(mCurrentIndex); 0090 if (mouseEvent(event, options, mCurrentIndex)) { 0091 update(mCurrentIndex); 0092 } 0093 } 0094 } 0095 0096 void MessageListViewBase::mouseReleaseEvent(QMouseEvent *event) 0097 { 0098 handleMouseEvent(event); 0099 } 0100 0101 void MessageListViewBase::mouseDoubleClickEvent(QMouseEvent *event) 0102 { 0103 handleMouseEvent(event); 0104 } 0105 0106 void MessageListViewBase::mousePressEvent(QMouseEvent *event) 0107 { 0108 mPressedPosition = event->pos(); 0109 handleMouseEvent(event); 0110 } 0111 0112 void MessageListViewBase::mouseMoveEvent(QMouseEvent *event) 0113 { 0114 // Drag support 0115 const int distance = (event->pos() - mPressedPosition).manhattanLength(); 0116 if (distance > QApplication::startDragDistance()) { 0117 mPressedPosition = {}; 0118 const QPersistentModelIndex index = indexAt(event->pos()); 0119 if (index.isValid()) { 0120 QStyleOptionViewItem options = listViewOptions(); 0121 options.rect = visualRect(index); 0122 if (maybeStartDrag(event, options, index)) { 0123 return; 0124 } 0125 } 0126 } 0127 handleMouseEvent(event); 0128 } 0129 0130 void MessageListViewBase::leaveEvent(QEvent *event) 0131 { 0132 if (mCurrentIndex.isValid()) { 0133 auto lastModel = const_cast<QAbstractItemModel *>(mCurrentIndex.model()); 0134 lastModel->setData(mCurrentIndex, false, MessagesModel::HoverHighLight); 0135 mCurrentIndex = QPersistentModelIndex(); 0136 } 0137 QListView::leaveEvent(event); 0138 } 0139 0140 QStyleOptionViewItem MessageListViewBase::listViewOptions() const 0141 { 0142 QStyleOptionViewItem option; 0143 initViewItemOption(&option); 0144 return option; 0145 } 0146 0147 bool MessageListViewBase::maybeStartDrag(QMouseEvent *event, const QStyleOptionViewItem &option, const QModelIndex &index) 0148 { 0149 Q_UNUSED(event); 0150 Q_UNUSED(option); 0151 Q_UNUSED(index); 0152 return false; 0153 } 0154 0155 bool MessageListViewBase::mouseEvent(QMouseEvent *event, const QStyleOptionViewItem &option, const QModelIndex &index) 0156 { 0157 Q_UNUSED(event); 0158 Q_UNUSED(option); 0159 Q_UNUSED(index); 0160 return false; 0161 } 0162 0163 void MessageListViewBase::addTextPlugins(QMenu *menu, const QString &selectedText) 0164 { 0165 for (PluginTextInterface *interface : std::as_const(mPluginTextInterface)) { 0166 interface->setSelectedText(selectedText); 0167 interface->addAction(menu); 0168 } 0169 } 0170 0171 QString MessageListViewBase::selectedText(const QModelIndex &index) 0172 { 0173 Q_UNUSED(index); 0174 return {}; 0175 } 0176 0177 void MessageListViewBase::copyMessageToClipboard(const QModelIndex &index) 0178 { 0179 const QString messageText = selectedText(index); 0180 if (messageText.isEmpty()) { 0181 return; 0182 } 0183 QClipboard *clip = QApplication::clipboard(); 0184 clip->setText(messageText, QClipboard::Clipboard); 0185 clip->setText(messageText, QClipboard::Selection); 0186 } 0187 0188 #include "moc_messagelistviewbase.cpp"