2014-11-16 19:58:43 +08:00
|
|
|
/*
|
|
|
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
|
|
|
|
|
|
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
|
|
|
|
|
|
|
This program is libre software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the COPYING file for more details.
|
|
|
|
*/
|
|
|
|
|
2014-11-12 21:11:25 +08:00
|
|
|
#include "chatline.h"
|
|
|
|
#include "chatlog.h"
|
|
|
|
#include "chatlinecontent.h"
|
|
|
|
|
|
|
|
#include <QTextLine>
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QGraphicsScene>
|
|
|
|
|
2015-01-04 03:37:40 +08:00
|
|
|
#define CELL_SPACING 15
|
|
|
|
|
2015-01-05 01:21:35 +08:00
|
|
|
ChatLine::ChatLine()
|
2014-11-12 21:11:25 +08:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ChatLine::~ChatLine()
|
|
|
|
{
|
|
|
|
for(ChatLineContent* c : content)
|
|
|
|
{
|
2015-01-04 20:29:14 +08:00
|
|
|
if(c->scene())
|
2015-01-05 01:21:35 +08:00
|
|
|
c->scene()->removeItem(c);
|
2015-01-04 20:29:14 +08:00
|
|
|
|
2014-11-12 21:11:25 +08:00
|
|
|
delete c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChatLine::setRowIndex(int idx)
|
|
|
|
{
|
|
|
|
rowIndex = idx;
|
|
|
|
|
2015-01-06 22:10:37 +08:00
|
|
|
for(int c = 0; c < static_cast<int>(content.size()); ++c)
|
2014-11-12 21:11:25 +08:00
|
|
|
content[c]->setIndex(rowIndex, c);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChatLine::visibilityChanged(bool visible)
|
|
|
|
{
|
|
|
|
if(isVisible != visible)
|
|
|
|
{
|
|
|
|
for(ChatLineContent* c : content)
|
|
|
|
c->visibilityChanged(visible);
|
|
|
|
}
|
|
|
|
|
|
|
|
isVisible = visible;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ChatLine::getRowIndex() const
|
|
|
|
{
|
|
|
|
return rowIndex;
|
|
|
|
}
|
|
|
|
|
2014-12-14 04:11:03 +08:00
|
|
|
ChatLineContent *ChatLine::getContent(int col) const
|
|
|
|
{
|
2015-01-06 22:10:37 +08:00
|
|
|
if(col < static_cast<int>(content.size()) && col >= 0)
|
2014-12-14 04:11:03 +08:00
|
|
|
return content[col];
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-01-07 00:47:57 +08:00
|
|
|
ChatLineContent *ChatLine::getContent(QPointF scenePos) const
|
|
|
|
{
|
|
|
|
for(ChatLineContent* c: content)
|
|
|
|
{
|
|
|
|
if(c->sceneBoundingRect().contains(scenePos))
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-01-04 20:29:14 +08:00
|
|
|
void ChatLine::removeFromScene()
|
|
|
|
{
|
|
|
|
for(ChatLineContent* c : content)
|
|
|
|
{
|
|
|
|
if(c->scene())
|
2015-01-05 01:21:35 +08:00
|
|
|
c->scene()->removeItem(c);
|
2015-01-04 20:29:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-05 01:21:35 +08:00
|
|
|
void ChatLine::addToScene(QGraphicsScene *scene)
|
|
|
|
{
|
|
|
|
if(!scene)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for(ChatLineContent* c : content)
|
|
|
|
scene->addItem(c);
|
|
|
|
}
|
|
|
|
|
2014-11-12 21:11:25 +08:00
|
|
|
void ChatLine::selectionCleared()
|
|
|
|
{
|
|
|
|
for(ChatLineContent* c : content)
|
|
|
|
c->selectionCleared();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChatLine::selectionCleared(int col)
|
|
|
|
{
|
2015-01-06 22:10:37 +08:00
|
|
|
if(col < static_cast<int>(content.size()) && content[col])
|
2014-11-12 21:11:25 +08:00
|
|
|
content[col]->selectionCleared();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChatLine::selectAll()
|
|
|
|
{
|
|
|
|
for(ChatLineContent* c : content)
|
|
|
|
c->selectAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChatLine::selectAll(int col)
|
|
|
|
{
|
2015-01-06 22:10:37 +08:00
|
|
|
if(col < static_cast<int>(content.size()) && content[col])
|
2014-11-12 21:11:25 +08:00
|
|
|
content[col]->selectAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
int ChatLine::getColumnCount()
|
|
|
|
{
|
|
|
|
return content.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChatLine::updateBBox()
|
|
|
|
{
|
2015-01-06 21:58:50 +08:00
|
|
|
bbox.setHeight(0);
|
2014-11-12 21:11:25 +08:00
|
|
|
bbox.setWidth(width);
|
|
|
|
|
|
|
|
for(ChatLineContent* c : content)
|
2015-01-06 21:58:50 +08:00
|
|
|
bbox.setHeight(qMax(c->sceneBoundingRect().height(), bbox.height()));
|
2014-11-12 21:11:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
QRectF ChatLine::boundingSceneRect() const
|
|
|
|
{
|
|
|
|
return bbox;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChatLine::addColumn(ChatLineContent* item, ColumnFormat fmt)
|
|
|
|
{
|
|
|
|
if(!item)
|
|
|
|
return;
|
|
|
|
|
2015-01-06 22:10:37 +08:00
|
|
|
format.push_back(fmt);
|
|
|
|
content.push_back(item);
|
2014-11-12 21:11:25 +08:00
|
|
|
}
|
|
|
|
|
2014-11-12 23:45:24 +08:00
|
|
|
void ChatLine::replaceContent(int col, ChatLineContent *lineContent)
|
|
|
|
{
|
2015-01-06 22:10:37 +08:00
|
|
|
if(col >= 0 && col < static_cast<int>(content.size()) && lineContent)
|
2014-11-12 23:45:24 +08:00
|
|
|
{
|
2015-01-05 01:21:35 +08:00
|
|
|
QGraphicsScene* scene = content[col]->scene();
|
2014-11-12 23:45:24 +08:00
|
|
|
delete content[col];
|
|
|
|
|
|
|
|
content[col] = lineContent;
|
2015-01-02 19:04:32 +08:00
|
|
|
lineContent->setIndex(rowIndex, col);
|
2015-01-05 01:21:35 +08:00
|
|
|
|
|
|
|
if(scene)
|
|
|
|
scene->addItem(content[col]);
|
2014-11-14 01:27:32 +08:00
|
|
|
|
2015-01-06 21:58:50 +08:00
|
|
|
layout(width, bbox.topLeft());
|
2014-11-14 01:27:32 +08:00
|
|
|
content[col]->visibilityChanged(isVisible);
|
|
|
|
content[col]->update();
|
2014-11-12 23:45:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-12 21:11:25 +08:00
|
|
|
void ChatLine::layout(qreal w, QPointF scenePos)
|
|
|
|
{
|
|
|
|
width = w;
|
2015-01-06 21:58:50 +08:00
|
|
|
bbox.setTopLeft(scenePos);
|
2014-11-12 21:11:25 +08:00
|
|
|
|
2015-01-04 03:37:40 +08:00
|
|
|
qreal fixedWidth = (content.size()-1) * CELL_SPACING;
|
2014-11-12 21:11:25 +08:00
|
|
|
qreal varWidth = 0.0; // used for normalisation
|
|
|
|
|
2015-01-06 22:10:37 +08:00
|
|
|
for(int i = 0; i < static_cast<int>(format.size()); ++i)
|
2014-11-12 21:11:25 +08:00
|
|
|
{
|
|
|
|
if(format[i].policy == ColumnFormat::FixedSize)
|
|
|
|
fixedWidth += format[i].size;
|
|
|
|
else
|
|
|
|
varWidth += format[i].size;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(varWidth == 0.0)
|
|
|
|
varWidth = 1.0;
|
|
|
|
|
|
|
|
qreal leftover = qMax(0.0, width - fixedWidth);
|
|
|
|
|
2014-12-09 05:08:23 +08:00
|
|
|
qreal maxVOffset = 0.0;
|
2014-11-12 21:11:25 +08:00
|
|
|
qreal xOffset = 0.0;
|
2014-12-09 05:08:23 +08:00
|
|
|
|
2015-01-06 22:10:37 +08:00
|
|
|
for(int i = 0; i < static_cast<int>(content.size()); ++i)
|
2014-11-12 21:11:25 +08:00
|
|
|
{
|
2014-12-10 23:45:12 +08:00
|
|
|
maxVOffset = qMax(maxVOffset, content[i]->getAscent());
|
2014-12-09 05:08:23 +08:00
|
|
|
|
2014-11-12 21:11:25 +08:00
|
|
|
// calculate the effective width of the current column
|
|
|
|
qreal width;
|
|
|
|
if(format[i].policy == ColumnFormat::FixedSize)
|
|
|
|
width = format[i].size;
|
|
|
|
else
|
|
|
|
width = format[i].size / varWidth * leftover;
|
|
|
|
|
2014-11-14 01:27:32 +08:00
|
|
|
// set the width of the current column
|
2014-11-12 21:11:25 +08:00
|
|
|
content[i]->setWidth(width);
|
|
|
|
|
|
|
|
// calculate horizontal alignment
|
|
|
|
qreal xAlign = 0.0;
|
2015-01-04 03:37:40 +08:00
|
|
|
|
2014-11-12 21:11:25 +08:00
|
|
|
switch(format[i].hAlign)
|
|
|
|
{
|
|
|
|
case ColumnFormat::Right:
|
|
|
|
xAlign = width - content[i]->boundingRect().width();
|
|
|
|
break;
|
|
|
|
case ColumnFormat::Center:
|
|
|
|
xAlign = (width - content[i]->boundingRect().width()) / 2.0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// reposition
|
2015-01-06 21:58:50 +08:00
|
|
|
content[i]->setPos(scenePos.x() + xOffset + xAlign, scenePos.y());
|
2014-11-12 21:11:25 +08:00
|
|
|
|
2015-01-04 03:37:40 +08:00
|
|
|
xOffset += width + CELL_SPACING;
|
2014-11-12 21:11:25 +08:00
|
|
|
}
|
|
|
|
|
2015-01-06 22:10:37 +08:00
|
|
|
for(int i = 0; i < static_cast<int>(content.size()); ++i)
|
2014-11-14 01:27:32 +08:00
|
|
|
{
|
|
|
|
// calculate vertical alignment
|
|
|
|
// vertical alignment may depend on width, so we do it in a second pass
|
|
|
|
qreal yOffset = 0.0;
|
2014-12-09 05:08:23 +08:00
|
|
|
|
2014-12-10 23:45:12 +08:00
|
|
|
yOffset = maxVOffset - content[i]->getAscent();
|
2014-11-14 01:27:32 +08:00
|
|
|
|
|
|
|
// reposition
|
|
|
|
content[i]->setPos(content[i]->pos().x(), content[i]->pos().y() + yOffset);
|
|
|
|
}
|
|
|
|
|
2014-11-12 21:11:25 +08:00
|
|
|
updateBBox();
|
|
|
|
}
|
|
|
|
|
2015-01-05 21:06:14 +08:00
|
|
|
void ChatLine::moveBy(qreal deltaY)
|
2014-11-12 21:11:25 +08:00
|
|
|
{
|
|
|
|
// reposition only
|
|
|
|
for(ChatLineContent* c : content)
|
2015-01-05 21:06:14 +08:00
|
|
|
c->moveBy(0, deltaY);
|
2014-11-12 21:11:25 +08:00
|
|
|
|
2015-01-06 21:58:50 +08:00
|
|
|
bbox.moveTop(bbox.top() + deltaY);
|
2014-11-12 21:11:25 +08:00
|
|
|
}
|