|
|
@ -57,6 +57,12 @@ ChatLog::ChatLog(QWidget* parent) |
|
|
|
setViewportUpdateMode(SmartViewportUpdate); |
|
|
|
setViewportUpdateMode(SmartViewportUpdate); |
|
|
|
//setRenderHint(QPainter::TextAntialiasing);
|
|
|
|
//setRenderHint(QPainter::TextAntialiasing);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
selGraphItem = new QGraphicsRectItem(); |
|
|
|
|
|
|
|
selGraphItem->setZValue(-10.0); //behind all items
|
|
|
|
|
|
|
|
selGraphItem->setBrush(QBrush(QColor(166,225,255))); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
scene->addItem(selGraphItem); |
|
|
|
|
|
|
|
|
|
|
|
// copy action
|
|
|
|
// copy action
|
|
|
|
copyAction = new QAction(this); |
|
|
|
copyAction = new QAction(this); |
|
|
|
copyAction->setShortcut(QKeySequence::Copy); |
|
|
|
copyAction->setShortcut(QKeySequence::Copy); |
|
|
@ -116,14 +122,17 @@ ChatMessage *ChatLog::addFileTransferMessage(const QString &sender, const ToxFil |
|
|
|
|
|
|
|
|
|
|
|
void ChatLog::clearSelection() |
|
|
|
void ChatLog::clearSelection() |
|
|
|
{ |
|
|
|
{ |
|
|
|
if(selStartRow >= 0) |
|
|
|
for(int i=selFirstRow; i<=selLastRow && i<lines.size() && i >= 0; ++i) |
|
|
|
for(int r = qMin(selStartRow, selLastRow); r <= qMax(selLastRow, selStartRow) && r < lines.size(); ++r) |
|
|
|
lines[i]->selectionCleared(); |
|
|
|
lines[r]->selectionCleared(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
selStartRow = -1; |
|
|
|
selGraphItem->hide(); |
|
|
|
selStartCol = -1; |
|
|
|
|
|
|
|
|
|
|
|
selFirstRow = -1; |
|
|
|
selLastRow = -1; |
|
|
|
selLastRow = -1; |
|
|
|
selLastCol = -1; |
|
|
|
selClickedCol = -1; |
|
|
|
|
|
|
|
selClickedRow = -1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
selectionMode = None; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
QRect ChatLog::getVisibleRect() const |
|
|
|
QRect ChatLog::getVisibleRect() const |
|
|
@ -229,9 +238,6 @@ void ChatLog::mousePressEvent(QMouseEvent* ev) |
|
|
|
void ChatLog::mouseReleaseEvent(QMouseEvent* ev) |
|
|
|
void ChatLog::mouseReleaseEvent(QMouseEvent* ev) |
|
|
|
{ |
|
|
|
{ |
|
|
|
QGraphicsView::mouseReleaseEvent(ev); |
|
|
|
QGraphicsView::mouseReleaseEvent(ev); |
|
|
|
|
|
|
|
|
|
|
|
if(ev->button() == Qt::LeftButton) |
|
|
|
|
|
|
|
selecting = false; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void ChatLog::mouseMoveEvent(QMouseEvent* ev) |
|
|
|
void ChatLog::mouseMoveEvent(QMouseEvent* ev) |
|
|
@ -242,21 +248,21 @@ void ChatLog::mouseMoveEvent(QMouseEvent* ev) |
|
|
|
|
|
|
|
|
|
|
|
if(ev->buttons() & Qt::LeftButton) |
|
|
|
if(ev->buttons() & Qt::LeftButton) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if(!selecting && (clickPos - ev->pos()).manhattanLength() > QApplication::startDragDistance()) |
|
|
|
if(selectionMode == None && (clickPos - ev->pos()).manhattanLength() > QApplication::startDragDistance()) |
|
|
|
{ |
|
|
|
{ |
|
|
|
QPointF sceneClickPos = mapToScene(clickPos.toPoint()); |
|
|
|
QPointF sceneClickPos = mapToScene(clickPos.toPoint()); |
|
|
|
|
|
|
|
|
|
|
|
ChatLineContent* content = getContentFromPos(sceneClickPos); |
|
|
|
ChatLineContent* content = getContentFromPos(sceneClickPos); |
|
|
|
if(content) |
|
|
|
if(content) |
|
|
|
{ |
|
|
|
{ |
|
|
|
selStartRow = content->getRow(); |
|
|
|
selClickedRow = content->getRow(); |
|
|
|
selStartCol = content->getColumn(); |
|
|
|
selClickedCol = content->getColumn(); |
|
|
|
selLastRow = selStartRow; |
|
|
|
selFirstRow = content->getRow(); |
|
|
|
selLastCol = selStartCol; |
|
|
|
selLastRow = content->getRow(); |
|
|
|
|
|
|
|
|
|
|
|
content->selectionStarted(sceneClickPos); |
|
|
|
content->selectionStarted(sceneClickPos); |
|
|
|
|
|
|
|
|
|
|
|
selecting = true; |
|
|
|
selectionMode = Precise; |
|
|
|
|
|
|
|
|
|
|
|
// ungrab mouse grabber
|
|
|
|
// ungrab mouse grabber
|
|
|
|
if(scene->mouseGrabberItem()) |
|
|
|
if(scene->mouseGrabberItem()) |
|
|
@ -265,7 +271,7 @@ void ChatLog::mouseMoveEvent(QMouseEvent* ev) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if(selecting && ev->pos() != lastPos) |
|
|
|
if(selectionMode != None && ev->pos() != lastPos) |
|
|
|
{ |
|
|
|
{ |
|
|
|
lastPos = ev->pos(); |
|
|
|
lastPos = ev->pos(); |
|
|
|
|
|
|
|
|
|
|
@ -273,47 +279,35 @@ void ChatLog::mouseMoveEvent(QMouseEvent* ev) |
|
|
|
|
|
|
|
|
|
|
|
if(content) |
|
|
|
if(content) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// TODO: turn this into a sane algo.
|
|
|
|
|
|
|
|
int row = content->getRow(); |
|
|
|
int row = content->getRow(); |
|
|
|
int col = content->getColumn(); |
|
|
|
int col = content->getColumn(); |
|
|
|
int firstRow = selStartRow; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// selection
|
|
|
|
if(row >= selClickedRow) |
|
|
|
for(int r = qMin(firstRow, row + 1); r < qMax(row, firstRow); r++) |
|
|
|
selLastRow = row; |
|
|
|
lines[r]->selectAll(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(row != selStartRow) |
|
|
|
if(row <= selClickedRow) |
|
|
|
for(int c = 0; c < col; c++) |
|
|
|
selFirstRow = row; |
|
|
|
lines[selStartRow]->selectAll(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(row == selStartRow) |
|
|
|
if(row == selClickedRow && col == selClickedCol) |
|
|
|
content->selectionMouseMove(scenePos); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
lines[row]->selectAll(); |
|
|
|
selectionMode = Precise; |
|
|
|
selStartCol = 0; |
|
|
|
|
|
|
|
selLastCol = lines[row]->getColumnCount(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// de-selection
|
|
|
|
|
|
|
|
if(row < selStartRow) |
|
|
|
|
|
|
|
selLastRow = qMin(row, selLastRow); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
selLastRow = qMax(row, selLastRow); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(col < selStartCol) |
|
|
|
content->selectionMouseMove(scenePos); |
|
|
|
selLastCol = qMin(col, selLastCol); |
|
|
|
selGraphItem->hide(); |
|
|
|
|
|
|
|
} |
|
|
|
else |
|
|
|
else |
|
|
|
selLastCol = qMax(col, selLastCol); |
|
|
|
{ |
|
|
|
|
|
|
|
selectionMode = Multi; |
|
|
|
|
|
|
|
|
|
|
|
for(int r = qMin(row, selLastRow); r < qMax(row, selLastRow + 1) && r < lines.size(); ++r) |
|
|
|
lines[selClickedRow]->selectionCleared(); |
|
|
|
if(r != row) |
|
|
|
|
|
|
|
lines[r]->selectionCleared(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(row == selStartRow) |
|
|
|
QRectF selBBox; |
|
|
|
for(int c = col + 1; c < lines[row]->getColumnCount() && c < selLastCol; ++c) |
|
|
|
selBBox = selBBox.united(lines[selFirstRow]->boundingSceneRect()); |
|
|
|
lines[row]->selectionCleared(c); |
|
|
|
selBBox = selBBox.united(lines[selLastRow]->boundingSceneRect()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
selGraphItem->setRect(selBBox); |
|
|
|
|
|
|
|
selGraphItem->show(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -329,18 +323,26 @@ ChatLineContent* ChatLog::getContentFromPos(QPointF scenePos) const |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool ChatLog::isOverSelection(QPointF scenePos) |
|
|
|
bool ChatLog::isOverSelection(QPointF scenePos) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if(selectionMode == Precise) |
|
|
|
{ |
|
|
|
{ |
|
|
|
ChatLineContent* content = getContentFromPos(scenePos); |
|
|
|
ChatLineContent* content = getContentFromPos(scenePos); |
|
|
|
|
|
|
|
|
|
|
|
if(content) |
|
|
|
if(content) |
|
|
|
return content->isOverSelection(scenePos); |
|
|
|
return content->isOverSelection(scenePos); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if(selectionMode == Multi) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if(selGraphItem->rect().contains(scenePos)) |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int ChatLog::useableWidth() |
|
|
|
int ChatLog::useableWidth() |
|
|
|
{ |
|
|
|
{ |
|
|
|
return width() - verticalScrollBar()->sizeHint().width(); |
|
|
|
return width() - verticalScrollBar()->sizeHint().width() - 10.0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void ChatLog::reposition(int start, int end) |
|
|
|
void ChatLog::reposition(int start, int end) |
|
|
@ -411,19 +413,33 @@ void ChatLog::scrollToBottom() |
|
|
|
|
|
|
|
|
|
|
|
QString ChatLog::getSelectedText() const |
|
|
|
QString ChatLog::getSelectedText() const |
|
|
|
{ |
|
|
|
{ |
|
|
|
QString ret; |
|
|
|
if(selectionMode == Precise) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return lines[selClickedRow]->content[selClickedCol]->getSelectedText(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if(selectionMode == Multi) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// build a nicely formatted message
|
|
|
|
|
|
|
|
QString out; |
|
|
|
|
|
|
|
|
|
|
|
const int rowStart = qMin(selStartRow, selLastRow); |
|
|
|
QString lastSender; |
|
|
|
const int rowLast = qMax(selStartRow, selLastRow); |
|
|
|
for(int i=selFirstRow; i<=selLastRow && i>=0 && i<lines.size(); ++i) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if(lastSender != lines[i]->content[0]->getText() && !lines[i]->content[0]->getText().isEmpty()) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
//author changed
|
|
|
|
|
|
|
|
out += lines[i]->content[0]->getText() + ":\n"; |
|
|
|
|
|
|
|
lastSender = lines[i]->content[0]->getText(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const int colStart = qMin(selStartCol, selLastCol); |
|
|
|
out += lines[i]->content[1]->getText(); |
|
|
|
const int colLast = qMax(selStartCol, selLastCol); |
|
|
|
out += "\n\n"; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for(int r = rowStart; r <= rowLast && r < lines.size(); ++r) |
|
|
|
return out; |
|
|
|
for(int c = colStart; c <= colLast && c < lines[r]->getColumnCount(); ++c) |
|
|
|
} |
|
|
|
ret.append(lines[r]->content[c]->getSelectedText() + '\n'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
return QString(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void ChatLog::showContextMenu(const QPoint& globalPos, const QPointF& scenePos) |
|
|
|
void ChatLog::showContextMenu(const QPoint& globalPos, const QPointF& scenePos) |
|
|
|