diff --git a/qtox.pro b/qtox.pro index 2b0f79d19..14303d207 100644 --- a/qtox.pro +++ b/qtox.pro @@ -33,7 +33,8 @@ FORMS += \ src/widget/form/settings/privacysettings.ui \ src/widget/form/loadhistorydialog.ui \ src/widget/form/inputpassworddialog.ui \ - src/widget/form/setpassworddialog.ui + src/widget/form/setpassworddialog.ui \ + src/chatlog/content/filetransferwidget.ui CONFIG += c++11 @@ -118,17 +119,10 @@ HEADERS += src/widget/form/addfriendform.h \ src/widget/friendlistwidget.h \ src/widget/genericchatroomwidget.h \ src/widget/form/genericchatform.h \ - src/widget/tool/chatactions/chataction.h \ - src/widget/chatareawidget.h \ src/filetransferinstance.h \ src/corestructs.h \ src/coredefines.h \ src/coreav.h \ - src/widget/tool/chatactions/messageaction.h \ - src/widget/tool/chatactions/filetransferaction.h \ - src/widget/tool/chatactions/systemmessageaction.h \ - src/widget/tool/chatactions/actionaction.h \ - src/widget/tool/chatactions/alertaction.h \ src/widget/maskablepixmapwidget.h \ src/video/videosource.h \ src/video/cameraworker.h \ @@ -148,7 +142,15 @@ HEADERS += src/widget/form/addfriendform.h \ src/toxdns.h \ src/widget/toxsave.h \ src/autoupdate.h \ - src/misc/serialize.h + src/misc/serialize.h \ + src/chatlog/chatlog.h \ + src/chatlog/chatline.h \ + src/chatlog/chatlinecontent.h \ + src/chatlog/chatlinecontentproxy.h \ + src/chatlog/content/text.h \ + src/chatlog/content/spinner.h \ + src/chatlog/content/filetransferwidget.h \ + src/chatlog/chatmessage.h SOURCES += \ src/widget/form/addfriendform.cpp \ @@ -185,15 +187,8 @@ SOURCES += \ src/coreav.cpp \ src/widget/genericchatroomwidget.cpp \ src/widget/form/genericchatform.cpp \ - src/widget/tool/chatactions/chataction.cpp \ - src/widget/chatareawidget.cpp \ src/filetransferinstance.cpp \ src/corestructs.cpp \ - src/widget/tool/chatactions/messageaction.cpp \ - src/widget/tool/chatactions/filetransferaction.cpp \ - src/widget/tool/chatactions/systemmessageaction.cpp \ - src/widget/tool/chatactions/actionaction.cpp \ - src/widget/tool/chatactions/alertaction.cpp \ src/widget/maskablepixmapwidget.cpp \ src/video/cameraworker.cpp \ src/widget/videosurface.cpp \ @@ -213,4 +208,12 @@ SOURCES += \ src/ipc.cpp \ src/widget/toxsave.cpp \ src/autoupdate.cpp \ - src/misc/serialize.cpp + src/misc/serialize.cpp \ + src/chatlog/chatlog.cpp \ + src/chatlog/chatline.cpp \ + src/chatlog/chatlinecontent.cpp \ + src/chatlog/chatlinecontentproxy.cpp \ + src/chatlog/content/text.cpp \ + src/chatlog/content/spinner.cpp \ + src/chatlog/content/filetransferwidget.cpp \ + src/chatlog/chatmessage.cpp diff --git a/src/chatlog/chatline.cpp b/src/chatlog/chatline.cpp new file mode 100644 index 000000000..a531b42f4 --- /dev/null +++ b/src/chatlog/chatline.cpp @@ -0,0 +1,178 @@ +#include "chatline.h" +#include "chatlog.h" +#include "chatlinecontent.h" + +#include +#include +#include + +ChatLine::ChatLine(QGraphicsScene* grScene) + : scene(grScene) +{ + +} + +ChatLine::~ChatLine() +{ + for(ChatLineContent* c : content) + { + scene->removeItem(c); + delete c; + } +} + +void ChatLine::setRowIndex(int idx) +{ + rowIndex = idx; + + for(int c = 0; c < content.size(); ++c) + 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; +} + +void ChatLine::selectionCleared() +{ + for(ChatLineContent* c : content) + c->selectionCleared(); +} + +void ChatLine::selectionCleared(int col) +{ + if(col < content.size() && content[col]) + content[col]->selectionCleared(); +} + +void ChatLine::selectAll() +{ + for(ChatLineContent* c : content) + c->selectAll(); +} + +void ChatLine::selectAll(int col) +{ + if(col < content.size() && content[col]) + content[col]->selectAll(); +} + +int ChatLine::getColumnCount() +{ + return content.size(); +} + +void ChatLine::updateBBox() +{ + bbox = QRectF(); + bbox.setTop(pos.y()); + bbox.setLeft(pos.x()); + bbox.setWidth(width); + + for(ChatLineContent* c : content) + bbox.setHeight(qMax(c->sceneBoundingRect().height(), bbox.height())); +} + +QRectF ChatLine::boundingSceneRect() const +{ + return bbox; +} + +void ChatLine::addColumn(ChatLineContent* item, ColumnFormat fmt) +{ + if(!item) + return; + + item->setChatLine(this); + scene->addItem(item); + + format << fmt; + content << item; +} + +void ChatLine::layout(qreal w, QPointF scenePos) +{ + width = w; + pos = scenePos; + + qreal fixedWidth = 0.0; + qreal varWidth = 0.0; // used for normalisation + + for(int i = 0; i < format.size(); ++i) + { + 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); + + qreal xOffset = 0.0; + for(int i = 0; i < content.size(); ++i) + { + // 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; + + // set the width of the current column as + // firstLineVOffset() may depend on the current width + content[i]->setWidth(width); + + // calculate vertical alignment + qreal yOffset = 0.0; + if(format[i].vAlignCol >= 0 && format[i].vAlignCol < content.size()) + yOffset = content[format[i].vAlignCol]->firstLineVOffset() - content[i]->firstLineVOffset(); + + // calculate horizontal alignment + qreal xAlign = 0.0; + 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 + content[i]->setPos(pos.x() + xOffset + xAlign, pos.y() + yOffset); + + xOffset += width; + } + + updateBBox(); +} + +void ChatLine::layout(QPointF scenePos) +{ + // reposition only + QPointF offset = pos - scenePos; + for(ChatLineContent* c : content) + c->setPos(c->pos() - offset); + + pos = scenePos; + + updateBBox(); +} diff --git a/src/chatlog/chatline.h b/src/chatlog/chatline.h new file mode 100644 index 000000000..13038b434 --- /dev/null +++ b/src/chatlog/chatline.h @@ -0,0 +1,83 @@ +#ifndef CHATLINE_H +#define CHATLINE_H + +#include + +class ChatLog; +class ChatLineContent; +class QGraphicsScene; +class QStyleOptionGraphicsItem; + +struct ColumnFormat +{ + enum Policy { + FixedSize, + VariableSize, + }; + + enum Align { + Left, + Center, + Right, + }; + + ColumnFormat() {} + ColumnFormat(qreal s, Policy p, int valign = -1, Align halign = Left) + : size(s) + , policy(p) + , vAlignCol(valign) + , hAlign(halign) + {} + + qreal size = 1.0; + Policy policy = VariableSize; + int vAlignCol = -1; + Align hAlign = Left; +}; + +using ColumnFormats = QVector; + +class ChatLine +{ +public: + explicit ChatLine(QGraphicsScene* scene); + virtual ~ChatLine(); + + virtual QRectF boundingSceneRect() const; + + void addColumn(ChatLineContent* item, ColumnFormat fmt); + + void layout(qreal width, QPointF scenePos); + void layout(QPointF scenePos); + + void selectionCleared(); + void selectionCleared(int col); + void selectAll(); + void selectAll(int col); + + int getColumnCount(); + int getRowIndex() const; + + bool isOverSelection(QPointF scenePos); + +private: + QPointF mapToContent(ChatLineContent* c, QPointF pos); + void updateBBox(); + + friend class ChatLog; + void setRowIndex(int idx); + void visibilityChanged(bool visible); + +private: + int rowIndex = -1; + QGraphicsScene* scene = nullptr; + QVector content; // 3 columns + QVector format; + qreal width; + QRectF bbox; + QPointF pos; + bool isVisible = false; + +}; + +#endif // CHATLINE_H diff --git a/src/chatlog/chatlinecontent.cpp b/src/chatlog/chatlinecontent.cpp new file mode 100644 index 000000000..1cfc61dc6 --- /dev/null +++ b/src/chatlog/chatlinecontent.cpp @@ -0,0 +1,70 @@ +#include "chatlinecontent.h" + +void ChatLineContent::setChatLine(ChatLine* chatline) +{ + line = chatline; +} + +ChatLine* ChatLineContent::getChatLine() const +{ + return line; +} + +void ChatLineContent::setIndex(int r, int c) +{ + row = r; + col = c; +} + +int ChatLineContent::getColumn() const +{ + return col; +} + +int ChatLineContent::getRow() const +{ + return row; +} + +int ChatLineContent::type() const +{ + return GraphicsItemType::ChatLineContentType; +} + +void ChatLineContent::selectionMouseMove(QPointF) +{ + +} + +void ChatLineContent::selectionStarted(QPointF) +{ + +} + +void ChatLineContent::selectionCleared() +{ +} + +void ChatLineContent::selectAll() +{ +} + +bool ChatLineContent::isOverSelection(QPointF) const +{ + return false; +} + +QString ChatLineContent::getSelectedText() const +{ + return QString(); +} + +qreal ChatLineContent::firstLineVOffset() +{ + return 0.0; +} + +void ChatLineContent::visibilityChanged(bool) +{ + +} diff --git a/src/chatlog/chatlinecontent.h b/src/chatlog/chatlinecontent.h new file mode 100644 index 000000000..32d08d7c8 --- /dev/null +++ b/src/chatlog/chatlinecontent.h @@ -0,0 +1,51 @@ +#ifndef CHATLINECONTENT_H +#define CHATLINECONTENT_H + +#include + +class ChatLine; + +class ChatLineContent : public QGraphicsItem +{ +public: + enum GraphicsItemType + { + ChatLineContentType = QGraphicsItem::UserType + 1, + }; + + ChatLine* getChatLine() const; + + int getColumn() const; + int getRow() const; + + virtual void setWidth(qreal width) = 0; + virtual int type() const final; + + virtual void selectionMouseMove(QPointF scenePos); + virtual void selectionStarted(QPointF scenePos); + virtual void selectionCleared(); + virtual void selectAll(); + virtual bool isOverSelection(QPointF scenePos) const; + virtual QString getSelectedText() const; + + virtual qreal firstLineVOffset(); + + virtual QRectF boundingSceneRect() const = 0; + virtual QRectF boundingRect() const = 0; + virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) = 0; + + virtual void visibilityChanged(bool visible); + +private: + friend class ChatLine; + + void setIndex(int row, int col); + void setChatLine(ChatLine* chatline); + +private: + ChatLine* line = nullptr; + int row = -1; + int col = -1; +}; + +#endif // CHATLINECONTENT_H diff --git a/src/chatlog/chatlinecontentproxy.cpp b/src/chatlog/chatlinecontentproxy.cpp new file mode 100644 index 000000000..28eac44ef --- /dev/null +++ b/src/chatlog/chatlinecontentproxy.cpp @@ -0,0 +1,29 @@ +#include "chatlinecontentproxy.h" +#include +#include + +ChatLineContentProxy::ChatLineContentProxy(QWidget* widget) +{ + proxy = new QGraphicsProxyWidget(this); + proxy->setWidget(widget); +} + +QRectF ChatLineContentProxy::boundingRect() const +{ + return proxy->boundingRect(); +} + +QRectF ChatLineContentProxy::boundingSceneRect() const +{ + return proxy->boundingRect().translated(scenePos()); +} + +void ChatLineContentProxy::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + proxy->paint(painter, option, widget); +} + +void ChatLineContentProxy::setWidth(qreal width) +{ + proxy->widget()->setFixedWidth(qMax(width,0.0)); +} diff --git a/src/chatlog/chatlinecontentproxy.h b/src/chatlog/chatlinecontentproxy.h new file mode 100644 index 000000000..aa69fae36 --- /dev/null +++ b/src/chatlog/chatlinecontentproxy.h @@ -0,0 +1,21 @@ +#ifndef CHATLINECONTENTPROXY_H +#define CHATLINECONTENTPROXY_H + +#include +#include "chatlinecontent.h" + +class ChatLineContentProxy : public ChatLineContent +{ +public: + ChatLineContentProxy(QWidget* widget); + + virtual QRectF boundingRect() const; + virtual QRectF boundingSceneRect() const; + virtual void setWidth(qreal width); + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + +private: + QGraphicsProxyWidget* proxy; +}; + +#endif // CHATLINECONTENTPROXY_H diff --git a/src/chatlog/chatlog.cpp b/src/chatlog/chatlog.cpp new file mode 100644 index 000000000..e3f8c2d1f --- /dev/null +++ b/src/chatlog/chatlog.cpp @@ -0,0 +1,519 @@ +#include "chatlog.h" +#include "chatline.h" +#include "chatlinecontent.h" +#include "chatlinecontentproxy.h" +#include "content/text.h" +#include "content/filetransferwidget.h" +#include "content/spinner.h" + +#include +#include +#include +#include +#include + +template +T clamp(T x, T min, T max) +{ + if(x > max) + return max; + if(x < min) + return min; + return x; +} + +ChatLog::ChatLog(QWidget* parent) + : QGraphicsView(parent) +{ + scene = new QGraphicsScene(this); + scene->setItemIndexMethod(QGraphicsScene::NoIndex); + setScene(scene); + + setInteractive(true); + setAlignment(Qt::AlignTop | Qt::AlignLeft); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setDragMode(QGraphicsView::NoDrag); + setViewportUpdateMode(SmartViewportUpdate); + //setRenderHint(QPainter::TextAntialiasing); + + // copy action + copyAction = new QAction(this); + copyAction->setShortcut(QKeySequence::Copy); + addAction(copyAction); + connect(copyAction, &QAction::triggered, this, [ = ](bool) + { + copySelectedText(); + }); +} + +ChatLog::~ChatLog() +{ + for(ChatLine* line : lines) + delete line; +} + +void ChatLog::addTextLine(const QString& sender, const QString& text, QDateTime timestamp) +{ + ChatLine* line = new ChatLine(scene); + + line->addColumn(new Text(sender, true), ColumnFormat(75.0, ColumnFormat::FixedSize, 1, ColumnFormat::Right)); + line->addColumn(new Text(text), ColumnFormat(1.0, ColumnFormat::VariableSize)); + line->addColumn(new Text(timestamp.toString("hh:mm")), ColumnFormat(50.0, ColumnFormat::FixedSize, 1)); + + insertChatline(line); +} + +void ChatLog::addWidgetLine(const QString& sender, QDateTime timestamp) +{ + ChatLine* line = new ChatLine(scene); + + line->addColumn(new Text(sender, true), ColumnFormat(75.0, ColumnFormat::FixedSize, 1)); + line->addColumn(new ChatLineContentProxy(new FileTransferWidget()), ColumnFormat(1.0, ColumnFormat::VariableSize)); + line->addColumn(new Spinner(QSizeF(16, 16)), ColumnFormat(50.0, ColumnFormat::FixedSize, 1, ColumnFormat::Right)); + + insertChatline(line); +} + +void ChatLog::clearSelection() +{ + if(selStartRow >= 0) + for(int r = qMin(selStartRow, selLastRow); r <= qMax(selLastRow, selStartRow) && r < lines.size(); ++r) + lines[r]->selectionCleared(); + + selStartRow = -1; + selStartCol = -1; + selLastRow = -1; + selLastCol = -1; +} + +void ChatLog::dbgPopulate() +{ + for(int i = 0; i < 2000; i++) + addTextLine("Jemp longlong name foo moth", "Line " + QString::number(i) + + " Lorem ipsum Hello dolor sit amet, " + "consectetur adipisicing elit, sed do eiusmod " + "tempor incididunt ut labore et dolore magna " + "aliqua. Ut enim ad minim veniam, quis nostrud " + "exercitation ullamco laboris nisi ut aliquip ex " + "ea commodo consequat. "); +} + +QRect ChatLog::getVisibleRect() const +{ + return mapToScene(viewport()->rect()).boundingRect().toRect(); +} + +void ChatLog::updateSceneRect() +{ + setSceneRect(QRectF(0, 0, width(), lines.empty() ? 0.0 : lines.last()->boundingSceneRect().bottom())); +} + +bool ChatLog::layout(int start, int end, qreal width) +{ + //qDebug() << "layout " << start << end; + if(lines.empty()) + return false; + + start = clamp(start, 0, lines.size() - 1); + end = clamp(end + 1, 0, lines.size()); + + qreal h = lines[start]->boundingSceneRect().top(); + + bool needsReposition = false; + for(int i = start; i < end; ++i) + { + ChatLine* l = lines[i]; + + qreal oldHeight = l->boundingSceneRect().height(); + l->layout(width, QPointF(0, h)); + + if(oldHeight != l->boundingSceneRect().height()) + needsReposition = true; + + h += l->boundingSceneRect().height() + lineSpacing; + } + + // move up + if(needsReposition) + reposition(end-1, end+10); + + return needsReposition; +} + +void ChatLog::partialUpdate() +{ + checkVisibility(); + + if(visibleLines.empty()) + return; + + auto oldUpdateMode = viewportUpdateMode(); + setViewportUpdateMode(NoViewportUpdate); + + static int count = 0; + int count2 = 0; + int lastNonDirty = visibleLines.first()->getRowIndex(); + bool repos; + do + { + repos = false; + if(!visibleLines.empty()) + { + repos = layout(visibleLines.first()->getRowIndex(), visibleLines.last()->getRowIndex(), useableWidth()); + lastNonDirty = visibleLines.last()->getRowIndex(); + } + + checkVisibility(); + count2++; + } + while(repos); + + reposition(visibleLines.last()->getRowIndex(), lines.size()); + checkVisibility(); + + count = qMax(count, count2); + //qDebug() << "COUNT: " << count; + + setViewportUpdateMode(oldUpdateMode); + updateSceneRect(); +} + +void ChatLog::fullUpdate() +{ + layout(0, lines.size(), useableWidth()); + checkVisibility(); + updateSceneRect(); +} + +void ChatLog::mousePressEvent(QMouseEvent* ev) +{ + QGraphicsView::mousePressEvent(ev); + + QPointF scenePos = mapToScene(ev->pos()); + + if(ev->button() == Qt::LeftButton) + { + clickPos = ev->pos(); + clearSelection(); + } + + if(ev->button() == Qt::RightButton) + { + if(!isOverSelection(scenePos)) + clearSelection(); + + showContextMenu(ev->globalPos(), scenePos); + } +} + +void ChatLog::mouseReleaseEvent(QMouseEvent* ev) +{ + QGraphicsView::mouseReleaseEvent(ev); + + if(ev->button() == Qt::LeftButton) + selecting = false; +} + +void ChatLog::mouseMoveEvent(QMouseEvent* ev) +{ + QGraphicsView::mouseMoveEvent(ev); + + QPointF scenePos = mapToScene(ev->pos()); + + if(ev->buttons() & Qt::LeftButton) + { + if(!selecting && (clickPos - ev->pos()).manhattanLength() > QApplication::startDragDistance()) + { + QPointF sceneClickPos = mapToScene(clickPos.toPoint()); + + ChatLineContent* content = getContentFromPos(sceneClickPos); + if(content) + { + selStartRow = content->getRow(); + selStartCol = content->getColumn(); + selLastRow = selStartRow; + selLastCol = selStartCol; + + content->selectionStarted(sceneClickPos); + + selecting = true; + + // ungrab mouse grabber + if(scene->mouseGrabberItem()) + scene->mouseGrabberItem()->ungrabMouse(); + } + } + } + + if(selecting && ev->pos() != lastPos) + { + lastPos = ev->pos(); + + ChatLineContent* content = getContentFromPos(scenePos); + + if(content) + { + // TODO: turn this into a sane algo. + int row = content->getRow(); + int col = content->getColumn(); + int firstRow = selStartRow; + + // selection + for(int r = qMin(firstRow, row + 1); r < qMax(row, firstRow); r++) + lines[r]->selectAll(); + + if(row != selStartRow) + for(int c = 0; c < col; c++) + lines[selStartRow]->selectAll(); + + if(row == selStartRow) + content->selectionMouseMove(scenePos); + else + { + lines[row]->selectAll(); + selStartCol = 0; + selLastCol = lines[row]->getColumnCount(); + } + + // de-selection + if(row < selStartRow) + selLastRow = qMin(row, selLastRow); + else + selLastRow = qMax(row, selLastRow); + + if(col < selStartCol) + selLastCol = qMin(col, selLastCol); + else + selLastCol = qMax(col, selLastCol); + + for(int r = qMin(row, selLastRow); r < qMax(row, selLastRow + 1) && r < lines.size(); ++r) + if(r != row) + lines[r]->selectionCleared(); + + if(row == selStartRow) + for(int c = col + 1; c < lines[row]->getColumnCount() && c < selLastCol; ++c) + lines[row]->selectionCleared(c); + + } + } +} + +ChatLineContent* ChatLog::getContentFromPos(QPointF scenePos) const +{ + QGraphicsItem* item = scene->itemAt(scenePos, QTransform()); + + if(item && item->type() == ChatLineContent::ChatLineContentType) + return static_cast(item); + + return nullptr; +} + +bool ChatLog::isOverSelection(QPointF scenePos) +{ + ChatLineContent* content = getContentFromPos(scenePos); + + if(content) + return content->isOverSelection(scenePos); + + return false; +} + +int ChatLog::useableWidth() +{ + return width() - verticalScrollBar()->sizeHint().width(); +} + +void ChatLog::reposition(int start, int end) +{ + if(lines.isEmpty()) + return; + + start = clamp(start, 0, lines.size() - 1); + end = clamp(end + 1, 0, lines.size()); + + qreal h = lines[start]->boundingSceneRect().bottom() + lineSpacing; + + for(int i = start + 1; i < end; ++i) + { + ChatLine* l = lines[i]; + l->layout(QPointF(0, h)); + h += l->boundingSceneRect().height() + lineSpacing; + } +} + +void ChatLog::repositionDownTo(int start, qreal end) +{ + if(lines.isEmpty()) + return; + + start = clamp(start, 0, lines.size() - 1); + + qreal h = lines[start]->boundingSceneRect().bottom() + lineSpacing; + + for(int i = start + 1; i < lines.size(); ++i) + { + ChatLine* l = lines[i]; + l->layout(QPointF(0, h)); + h += l->boundingSceneRect().height() + lineSpacing; + + if(h > end) + break; + } +} + +void ChatLog::insertChatline(ChatLine* l) +{ + stickToBtm = stickToBottom(); + + l->setRowIndex(lines.size()); + lines.append(l); + + layout(lines.last()->getRowIndex() - 1, lines.size(), useableWidth()); + updateSceneRect(); + + if(stickToBtm) + scrollToBottom(); + + checkVisibility(); +} + +bool ChatLog::stickToBottom() +{ + return verticalScrollBar()->value() == verticalScrollBar()->maximum(); +} + +void ChatLog::scrollToBottom() +{ + verticalScrollBar()->setValue(verticalScrollBar()->maximum()); + updateGeometry(); + checkVisibility(); +} + +QString ChatLog::getSelectedText() const +{ + QString ret; + + const int rowStart = qMin(selStartRow, selLastRow); + const int rowLast = qMax(selStartRow, selLastRow); + + const int colStart = qMin(selStartCol, selLastCol); + const int colLast = qMax(selStartCol, selLastCol); + + for(int r = rowStart; r <= rowLast && r < lines.size(); ++r) + for(int c = colStart; c <= colLast && c < lines[r]->getColumnCount(); ++c) + ret.append(lines[r]->content[c]->getSelectedText() + '\n'); + + return ret; +} + +void ChatLog::showContextMenu(const QPoint& globalPos, const QPointF& scenePos) +{ + QMenu menu; + + // populate + QAction* copyAction = menu.addAction(QIcon::fromTheme("edit-copy"), "Copy"); + menu.addSeparator(); + QAction* clearAction = menu.addAction("Clear log"); + + if(!isOverSelection(scenePos)) + copyAction->setDisabled(true); + + // show + QAction* action = menu.exec(globalPos); + + if(action == copyAction) + copySelectedText(); + + if(action == clearAction) + clear(); +} + +void ChatLog::clear() +{ + visibleLines.clear(); + clearSelection(); + + for(ChatLine* line : lines) + delete line; + + lines.clear(); + updateSceneRect(); +} + +void ChatLog::copySelectedText() const +{ + QString text = getSelectedText(); + + QClipboard* clipboard = QApplication::clipboard(); + clipboard->setText(text); +} + +void ChatLog::checkVisibility() +{ + // find first visible row + QList::const_iterator upperBound; + upperBound = std::upper_bound(lines.cbegin(), lines.cend(), getVisibleRect().top(), [](const qreal lhs, const ChatLine* rhs) + { + return lhs < rhs->boundingSceneRect().bottom(); + }); + + if(upperBound == lines.end()) + upperBound = lines.begin(); + + // find last visible row + QList::const_iterator lowerBound; + lowerBound = std::lower_bound(lines.cbegin(), lines.cend(), getVisibleRect().bottom(), [](const ChatLine* lhs, const qreal rhs) + { + return lhs->boundingSceneRect().bottom() < rhs; + }); + + if(lowerBound == lines.end()) + lowerBound = lines.end(); + + // set visibilty + QList newVisibleLines; + for(auto itr = upperBound; itr <= lowerBound && itr != lines.end(); ++itr) + { + newVisibleLines.append(*itr); + + if(!visibleLines.contains(*itr)) + (*itr)->visibilityChanged(true); + + visibleLines.removeOne(*itr); + } + + for(ChatLine* line : visibleLines) + line->visibilityChanged(false); + + visibleLines = newVisibleLines; + + // assure order + std::sort(visibleLines.begin(), visibleLines.end(), [](const ChatLine* lhs, const ChatLine* rhs) + { + return lhs->getRowIndex() < rhs->getRowIndex(); + }); + + //if(!visibleLines.empty()) + // qDebug() << "visible from " << visibleLines.first()->getRowIndex() << "to " << visibleLines.last()->getRowIndex() << " total " << visibleLines.size(); +} + +void ChatLog::scrollContentsBy(int dx, int dy) +{ + QGraphicsView::scrollContentsBy(dx, dy); + partialUpdate(); +} + +void ChatLog::resizeEvent(QResizeEvent* ev) +{ + bool stb = stickToBottom(); + + QGraphicsView::resizeEvent(ev); + + if(lines.count() > 300) + partialUpdate(); + else + fullUpdate(); + + if(stb) + scrollToBottom(); +} diff --git a/src/chatlog/chatlog.h b/src/chatlog/chatlog.h new file mode 100644 index 000000000..5a9b31fb4 --- /dev/null +++ b/src/chatlog/chatlog.h @@ -0,0 +1,84 @@ +#ifndef CHATLOG_H +#define CHATLOG_H + +#include +#include + +class QGraphicsScene; +class ChatLine; +class ChatLineContent; + +class ChatLog : public QGraphicsView +{ + Q_OBJECT +public: + explicit ChatLog(QWidget* parent = 0); + virtual ~ChatLog(); + + void addTextLine(const QString& sender, const QString& text, QDateTime timestamp = QDateTime::currentDateTime()); + void addWidgetLine(const QString& sender, QDateTime timestamp = QDateTime::currentDateTime()); + void insertChatline(ChatLine* l); + + void clearSelection(); + void clear(); + void copySelectedText() const; + QString getSelectedText() const; + + void dbgPopulate(); + +signals: + +public slots: + +protected: + QRect getVisibleRect() const; + ChatLineContent* getContentFromPos(QPointF scenePos) const; + + bool layout(int start, int end, qreal width); + bool isOverSelection(QPointF scenePos); + bool stickToBottom(); + + int useableWidth(); + + void reposition(int start, int end); + void repositionDownTo(int start, qreal end); + void updateSceneRect(); + void partialUpdate(); + void fullUpdate(); + void checkVisibility(); + void scrollToBottom(); + void showContextMenu(const QPoint& globalPos, const QPointF& scenePos); + + virtual void mousePressEvent(QMouseEvent* ev); + virtual void mouseReleaseEvent(QMouseEvent* ev); + virtual void mouseMoveEvent(QMouseEvent* ev); + virtual void scrollContentsBy(int dx, int dy); + virtual void resizeEvent(QResizeEvent *ev); + +private: + QGraphicsScene* scene = nullptr; + QList lines; + QList visibleLines; + + bool multiLineInsert = false; + bool stickToBtm = false; + int insertStartIndex = -1; + + // selection + int selStartRow = -1; + int selStartCol = -1; + int selLastRow = -1; + int selLastCol = -1; + bool selecting = false; + QPointF clickPos; + QPointF lastPos; + + // actions + QAction* copyAction = nullptr; + + // layout + qreal lineSpacing = 10.0f; + +}; + +#endif // CHATLOG_H diff --git a/src/chatlog/chatmessage.cpp b/src/chatlog/chatmessage.cpp new file mode 100644 index 000000000..a6350843e --- /dev/null +++ b/src/chatlog/chatmessage.cpp @@ -0,0 +1,5 @@ +#include "chatmessage.h" + +ChatMessage::ChatMessage() +{ +} diff --git a/src/chatlog/chatmessage.h b/src/chatlog/chatmessage.h new file mode 100644 index 000000000..a0d487292 --- /dev/null +++ b/src/chatlog/chatmessage.h @@ -0,0 +1,12 @@ +#ifndef CHATMESSAGE_H +#define CHATMESSAGE_H + +#include "chatline.h" + +class ChatMessage : public ChatLine +{ +public: + ChatMessage(); +}; + +#endif // CHATMESSAGE_H diff --git a/src/chatlog/content/filetransferwidget.cpp b/src/chatlog/content/filetransferwidget.cpp new file mode 100644 index 000000000..fef501647 --- /dev/null +++ b/src/chatlog/content/filetransferwidget.cpp @@ -0,0 +1,34 @@ +#include "filetransferwidget.h" +#include "ui_filetransferwidget.h" + +#include +#include + +FileTransferWidget::FileTransferWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::FileTransferWidget) +{ + ui->setupUi(this); + + setFixedHeight(100); +} + +FileTransferWidget::~FileTransferWidget() +{ + delete ui; +} + +void FileTransferWidget::on_pushButton_2_clicked() +{ + qDebug() << "Button Cancel Clicked"; +} + +void FileTransferWidget::on_pushButton_clicked() +{ + qDebug() << "Button Resume Clicked"; +} + +void FileTransferWidget::on_pushButton_2_pressed() +{ + qDebug() << "Button Resume Clicked"; +} diff --git a/src/chatlog/content/filetransferwidget.h b/src/chatlog/content/filetransferwidget.h new file mode 100644 index 000000000..b09c09023 --- /dev/null +++ b/src/chatlog/content/filetransferwidget.h @@ -0,0 +1,29 @@ +#ifndef FILETRANSFERWIDGET_H +#define FILETRANSFERWIDGET_H + +#include +#include "../chatlinecontent.h" + +namespace Ui { +class FileTransferWidget; +} + +class FileTransferWidget : public QWidget +{ + Q_OBJECT + +public: + explicit FileTransferWidget(QWidget *parent = 0); + virtual ~FileTransferWidget(); + +private: + Ui::FileTransferWidget *ui; + +private slots: + void on_pushButton_2_clicked(); + void on_pushButton_clicked(); + void on_pushButton_2_pressed(); + +}; + +#endif // FILETRANSFERWIDGET_H diff --git a/src/chatlog/content/filetransferwidget.ui b/src/chatlog/content/filetransferwidget.ui new file mode 100644 index 000000000..4e2cca60d --- /dev/null +++ b/src/chatlog/content/filetransferwidget.ui @@ -0,0 +1,127 @@ + + + FileTransferWidget + + + + 0 + 0 + 729 + 124 + + + + Form + + + false + + + background-color:transparent; + + + + + + QFrame { +border-radius:10; +background-color:green; +} + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + color:white; + + + SomeRandomFile.7z + + + + + + + color:white; + + + 142/1742 YiB + + + + + + + color:white; + + + 24 + + + + + + + + + + + + 0 + 0 + + + + + 50 + 50 + + + + background-color:red; + + + Cancel + + + + + + + + 0 + 0 + + + + + 50 + 50 + + + + background-color:rgb(0, 255, 0); + + + Resume + + + + + + + + + + + + + diff --git a/src/chatlog/content/spinner.cpp b/src/chatlog/content/spinner.cpp new file mode 100644 index 000000000..67330f862 --- /dev/null +++ b/src/chatlog/content/spinner.cpp @@ -0,0 +1,61 @@ +#include "spinner.h" + +#include +#include + +Spinner::Spinner(QSizeF Size) + : size(Size) +{ + pmap.load(":/media/spinner.png"); + + timer.setInterval(33); // 30Hz + timer.setSingleShot(false); + timer.start(); + + QObject::connect(&timer, &QTimer::timeout, this, &Spinner::timeout); +} + +QRectF Spinner::boundingRect() const +{ + return QRectF(QPointF(-size.width() / 2.0, -size.height() / 2.0), size); +} + +QRectF Spinner::boundingSceneRect() const +{ + return QRectF(scenePos(), size); +} + +void Spinner::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) +{ + QTransform rotMat; + rotMat.translate(size.width() / 2.0, size.height() / 2.0); + rotMat.rotate(rot); + rotMat.translate(-size.width() / 2.0, -size.height() / 2.0); + + painter->translate(-size.width() / 2.0, -size.height() / 2.0); + painter->setTransform(rotMat, true); + painter->setRenderHint(QPainter::SmoothPixmapTransform); + painter->drawPixmap(0, 0, size.width(), size.height(), pmap); + + Q_UNUSED(option) + Q_UNUSED(widget) +} + +void Spinner::setWidth(qreal width) +{ + Q_UNUSED(width) +} + +void Spinner::visibilityChanged(bool visible) +{ + if(visible) + timer.start(); + else + timer.stop(); +} + +void Spinner::timeout() +{ + rot += 8; + update(); +} diff --git a/src/chatlog/content/spinner.h b/src/chatlog/content/spinner.h new file mode 100644 index 000000000..81dc6f835 --- /dev/null +++ b/src/chatlog/content/spinner.h @@ -0,0 +1,32 @@ +#ifndef SPINNER_H +#define SPINNER_H + +#include "../chatlinecontent.h" + +#include +#include + +class Spinner : public QObject, public ChatLineContent +{ + Q_OBJECT +public: + Spinner(QSizeF size); + + virtual QRectF boundingRect() const; + virtual QRectF boundingSceneRect() const; + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + virtual void setWidth(qreal width); + virtual void visibilityChanged(bool visible); + +private slots: + void timeout(); + +private: + QSizeF size; + QPixmap pmap; + qreal rot; + QTimer timer; + +}; + +#endif // SPINNER_H diff --git a/src/chatlog/content/text.cpp b/src/chatlog/content/text.cpp new file mode 100644 index 000000000..37e0ed74c --- /dev/null +++ b/src/chatlog/content/text.cpp @@ -0,0 +1,228 @@ +#include "text.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int Text::count = 0; + +Text::Text(const QString& txt, bool enableElide) + : ChatLineContent() + , elide(enableElide) +{ + setText(txt); + setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton); + //setCacheMode(QGraphicsItem::DeviceCoordinateCache); +} + +Text::~Text() +{ + delete doc; +} + +void Text::setText(const QString& txt) +{ + text = txt; + text.replace("\n", "
"); + + ensureIntegrity(); + freeResources(); +} + +void Text::setWidth(qreal w) +{ + if(w == width) + return; + + width = w; + + if(elide) + { + QFontMetrics metrics = QFontMetrics(QFont()); + elidedText = metrics.elidedText(text, Qt::ElideRight, width); + } + + ensureIntegrity(); + freeResources(); +} + +void Text::selectionMouseMove(QPointF scenePos) +{ + ensureIntegrity(); + int cur = cursorFromPos(scenePos); + if(cur >= 0) + cursor.setPosition(cur, QTextCursor::KeepAnchor); + + update(); +} + +void Text::selectionStarted(QPointF scenePos) +{ + ensureIntegrity(); + int cur = cursorFromPos(scenePos); + if(cur >= 0) + cursor.setPosition(cur); +} + +void Text::selectionCleared() +{ + ensureIntegrity(); + cursor.setPosition(0); + freeResources(); + + update(); +} + +void Text::selectAll() +{ + ensureIntegrity(); + cursor.select(QTextCursor::Document); + update(); +} + +bool Text::isOverSelection(QPointF scenePos) const +{ + int cur = cursorFromPos(scenePos); + if(cur >= 0 && cursor.selectionStart() < cur && cursor.selectionEnd() >= cur) + return true; + + return false; +} + +QString Text::getSelectedText() const +{ + return cursor.selectedText(); +} + +QRectF Text::boundingSceneRect() const +{ + return QRectF(scenePos(), size); +} + +QRectF Text::boundingRect() const +{ + return QRectF(QPointF(0, 0), size); +} + +void Text::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) +{ + if(doc) + { + // draw selection + QAbstractTextDocumentLayout::PaintContext ctx; + QAbstractTextDocumentLayout::Selection sel; + sel.cursor = cursor; + sel.format.setBackground(QApplication::palette().color(QPalette::Highlight)); + sel.format.setForeground(QApplication::palette().color(QPalette::HighlightedText)); + ctx.selections.append(sel); + + // draw text + doc->documentLayout()->draw(painter, ctx); + } + + Q_UNUSED(option) + Q_UNUSED(widget) +} + +void Text::visibilityChanged(bool visible) +{ + isVisible = visible; + + if(visible) + ensureIntegrity(); + else + freeResources(); +} + +qreal Text::firstLineVOffset() +{ + return vOffset; +} + +void Text::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + if(event->button() == Qt::LeftButton) + event->accept(); // grabber +} + +void Text::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + QString anchor = doc->documentLayout()->anchorAt(event->pos()); + + // open anchors in browser + if(!anchor.isEmpty()) + QDesktopServices::openUrl(anchor); +} + +void Text::ensureIntegrity() +{ + if(!doc) + { + doc = new QTextDocument(); + doc->setUndoRedoEnabled(false); + doc->setUseDesignMetrics(true); + + if(!elide) + { + doc->setHtml(text); + } + else + { + QTextOption opt; + opt.setWrapMode(QTextOption::NoWrap); + doc->setDefaultTextOption(opt); + doc->setPlainText(elidedText); + + } + + cursor = QTextCursor(doc); + count++; + } + + doc->setTextWidth(width); + doc->documentLayout()->update(); + + if(doc->firstBlock().layout()->lineCount() > 0) + vOffset = doc->firstBlock().layout()->lineAt(0).ascent(); + + if(size != idealSize()) + { + prepareGeometryChange(); + size = idealSize(); + } +} + +void Text::freeResources() +{ + if(doc && !isVisible && !cursor.hasSelection()) + { + delete doc; + doc = nullptr; + cursor = QTextCursor(); + + count--; + } +} + +QSizeF Text::idealSize() +{ + if(doc) + return QSizeF(doc->idealWidth(), doc->size().height()); + + return QSizeF(); +} + +int Text::cursorFromPos(QPointF scenePos) const +{ + if(doc) + return doc->documentLayout()->hitTest(mapFromScene(scenePos), Qt::ExactHit); + + return -1; +} diff --git a/src/chatlog/content/text.h b/src/chatlog/content/text.h new file mode 100644 index 000000000..edcdd486d --- /dev/null +++ b/src/chatlog/content/text.h @@ -0,0 +1,62 @@ +#ifndef TEXT_H +#define TEXT_H + +#include "../chatlinecontent.h" + +#include +#include + +class ChatLine; +class QTextLayout; + +class Text : public ChatLineContent +{ +public: + Text(const QString& txt = "", bool enableElide = false); + virtual ~Text(); + + void setText(const QString& txt); + + virtual void setWidth(qreal width); + + virtual void selectionMouseMove(QPointF scenePos); + virtual void selectionStarted(QPointF scenePos); + virtual void selectionCleared(); + virtual void selectAll(); + virtual bool isOverSelection(QPointF scenePos) const; + virtual QString getSelectedText() const; + + virtual QRectF boundingSceneRect() const; + virtual QRectF boundingRect() const; + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + + virtual void visibilityChanged(bool isVisible); + + virtual qreal firstLineVOffset(); + virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + + static int count; + +protected: + // dynamic resource management + void ensureIntegrity(); + void freeResources(); + QSizeF idealSize(); + + int cursorFromPos(QPointF scenePos) const; + +private: + QTextDocument* doc = nullptr; + QString text; + QString elidedText; + QSizeF size; + bool isVisible = false; + bool elide = false; + QTextCursor cursor; + qreal vOffset = 0.0; + qreal width = 0.0; + +}; + +#endif // TEXT_H diff --git a/src/widget/chatareawidget.cpp b/src/widget/chatareawidget.cpp deleted file mode 100644 index 393a01c0e..000000000 --- a/src/widget/chatareawidget.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - 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. -*/ - -#include "chatareawidget.h" -#include "tool/chatactions/chataction.h" -#include -#include -#include -#include -#include -#include -#include - -ChatAreaWidget::ChatAreaWidget(QWidget *parent) - : QTextBrowser(parent) - , tableFrmt(nullptr) - , nameWidth(75) - , empty{true} -{ - setReadOnly(true); - viewport()->setCursor(Qt::ArrowCursor); - setContextMenuPolicy(Qt::CustomContextMenu); - setUndoRedoEnabled(false); - - setOpenExternalLinks(false); - setOpenLinks(false); - setAcceptRichText(false); - setFrameStyle(QFrame::NoFrame); - - nameFormat.setAlignment(Qt::AlignRight); - nameFormat.setNonBreakableLines(true); - dateFormat.setAlignment(Qt::AlignLeft); - dateFormat.setNonBreakableLines(true); - - connect(this, &ChatAreaWidget::anchorClicked, this, &ChatAreaWidget::onAnchorClicked); - connect(verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(onSliderRangeChanged())); -} - -ChatAreaWidget::~ChatAreaWidget() -{ - if (tableFrmt) - delete tableFrmt; -} - -void ChatAreaWidget::mouseReleaseEvent(QMouseEvent * event) -{ - QTextEdit::mouseReleaseEvent(event); - QPointF documentHitPost(event->pos().x() + horizontalScrollBar()->value(), event->pos().y() + verticalScrollBar()->value()); - int pos = this->document()->documentLayout()->hitTest(documentHitPost, Qt::ExactHit); - if (pos > 0) - { - QTextCursor cursor(document()); - cursor.setPosition(pos); - - if(!cursor.atEnd()) - { - cursor.setPosition(pos+1); - - QTextFormat format = cursor.charFormat(); - if (format.isImageFormat()) - { - QString imageName = format.toImageFormat().name(); - if (QRegExp("^data:ftrans.*").exactMatch(imageName)) - { - QString data = imageName.right(imageName.length() - 12); - int endpos = data.indexOf("/png;base64"); - data = data.left(endpos); - int middlepos = data.indexOf("."); - QString widgetID = data.left(middlepos); - QString widgetBtn = data.right(data.length() - middlepos - 1); - qDebug() << "ChatAreaWidget::mouseReleaseEvent:" << widgetID << widgetBtn; - emit onFileTranfertInterract(widgetID, widgetBtn); - } - } - } - } -} - -void ChatAreaWidget::onAnchorClicked(const QUrl &url) -{ - QDesktopServices::openUrl(url); -} - -void ChatAreaWidget::insertMessage(ChatActionPtr msgAction, QTextCursor::MoveOperation pos) -{ - if (msgAction == nullptr) - return; - - checkSlider(); - - QTextTable *chatTextTable = getMsgTable(pos); - msgAction->assignPlace(chatTextTable, this); - msgAction->dispaly(); - - /* - QTextCursor cur = chatTextTable->cellAt(0, 2).firstCursorPosition(); - cur.clearSelection(); - cur.setKeepPositionOnInsert(true); - chatTextTable->cellAt(0, 0).firstCursorPosition().setBlockFormat(nameFormat); - chatTextTable->cellAt(0, 0).firstCursorPosition().insertHtml(msgAction->getName()); - chatTextTable->cellAt(0, 2).firstCursorPosition().insertHtml(msgAction->getMessage()); - chatTextTable->cellAt(0, 4).firstCursorPosition().setBlockFormat(dateFormat); - chatTextTable->cellAt(0, 4).firstCursorPosition().insertHtml(msgAction->getDate()); - msgAction->setup(cur, this); - */ - - if (msgAction->isInteractive()) - messages.append(msgAction); - - empty = false; -} - -bool ChatAreaWidget::isEmpty() -{ - return empty; -} - -void ChatAreaWidget::onSliderRangeChanged() -{ - QScrollBar* scroll = verticalScrollBar(); - if (lockSliderToBottom) - scroll->setValue(scroll->maximum()); -} - -void ChatAreaWidget::checkSlider() -{ - QScrollBar* scroll = verticalScrollBar(); - lockSliderToBottom = scroll && scroll->value() == scroll->maximum(); -} - -QTextTable *ChatAreaWidget::getMsgTable(QTextCursor::MoveOperation pos) -{ - if (tableFrmt == nullptr) - { - tableFrmt = new QTextTableFormat(); - tableFrmt->setCellSpacing(2); - tableFrmt->setBorderStyle(QTextFrameFormat::BorderStyle_None); - tableFrmt->setColumnWidthConstraints({QTextLength(QTextLength::FixedLength,nameWidth), - QTextLength(QTextLength::FixedLength,2), - QTextLength(QTextLength::PercentageLength,100), - QTextLength(QTextLength::FixedLength,2), - QTextLength(QTextLength::VariableLength,0)}); - } - - QTextCursor tc = textCursor(); - tc.movePosition(pos); - - QTextTable *chatTextTable = tc.insertTable(1, 5, *tableFrmt); - - return chatTextTable; -} - -void ChatAreaWidget::setNameColWidth(int w) -{ - if (tableFrmt != nullptr) - { - delete tableFrmt; - tableFrmt = nullptr; - } - - nameWidth = w; -} - -void ChatAreaWidget::clearChatArea() -{ - QList newMsgs; - for (ChatActionPtr message : messages) - { - if (message->isInteractive()) - { - newMsgs.append(message); - } - } - messages.clear(); - this->clear(); - empty = true; - - for (ChatActionPtr message : newMsgs) - { - insertMessage(message); - } -} - -void ChatAreaWidget::insertMessagesTop(QList &list) -{ - std::reverse(list.begin(), list.end()); - - for (ChatActionPtr it : list) - { - insertMessage(it, QTextCursor::Start); - } - - empty = false; -} diff --git a/src/widget/chatareawidget.h b/src/widget/chatareawidget.h deleted file mode 100644 index 2eda1aad4..000000000 --- a/src/widget/chatareawidget.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - 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. -*/ - -#ifndef CHATAREAWIDGET_H -#define CHATAREAWIDGET_H - -#include -#include -#include - -class QTextTable; - -class ChatAreaWidget : public QTextBrowser -{ - Q_OBJECT -public: - explicit ChatAreaWidget(QWidget *parent = 0); - virtual ~ChatAreaWidget(); - void insertMessage(ChatActionPtr msgAction, QTextCursor::MoveOperation pos = QTextCursor::End); - void insertMessagesTop(QList &list); - - int nameColWidth() {return nameWidth;} - void setNameColWidth(int w); - bool isEmpty(); - -public slots: - void clearChatArea(); - -signals: - void onFileTranfertInterract(QString widgetName, QString buttonName); - -protected: - void mouseReleaseEvent(QMouseEvent * event); - -private slots: - void onAnchorClicked(const QUrl& url); - void onSliderRangeChanged(); - -private: - void checkSlider(); - QTextTable* getMsgTable(QTextCursor::MoveOperation pos = QTextCursor::End); - - QTextTableFormat* tableFrmt; - QList messages; - bool lockSliderToBottom; - int sliderPosition; - int nameWidth; - QTextBlockFormat nameFormat, dateFormat; - bool empty; -}; - -#endif // CHATAREAWIDGET_H diff --git a/src/widget/form/chatform.cpp b/src/widget/form/chatform.cpp index 9850e4c36..23b8d9da7 100644 --- a/src/widget/form/chatform.cpp +++ b/src/widget/form/chatform.cpp @@ -29,9 +29,7 @@ #include "src/friend.h" #include "src/widget/friendwidget.h" #include "src/filetransferinstance.h" -#include "src/widget/tool/chatactions/filetransferaction.h" #include "src/widget/netcamview.h" -#include "src/widget/chatareawidget.h" #include "src/widget/tool/chattextedit.h" #include "src/core.h" #include "src/widget/widget.h" @@ -75,7 +73,7 @@ ChatForm::ChatForm(Friend* chatFriend) connect(msgEdit, &ChatTextEdit::enterPressed, this, &ChatForm::onSendTriggered); connect(micButton, SIGNAL(clicked()), this, SLOT(onMicMuteToggle())); connect(volButton, SIGNAL(clicked()), this, SLOT(onVolMuteToggle())); - connect(chatWidget, &ChatAreaWidget::onFileTranfertInterract, this, &ChatForm::onFileTansBtnClicked); + //TODO: connect(chatWidget, &ChatAreaWidget::onFileTranfertInterract, this, &ChatForm::onFileTansBtnClicked); connect(Core::getInstance(), &Core::fileSendFailed, this, &ChatForm::onFileSendFailed); connect(this, SIGNAL(chatAreaCleared()), this, SLOT(clearReciepts())); @@ -121,7 +119,7 @@ void ChatForm::onSendTriggered() int id = HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, qt_msg_hist, Core::getInstance()->getSelfId().publicKey, timestamp, status); - MessageActionPtr ma = addSelfMessage(msg, isAction, timestamp, false); + //MessageActionPtr ma = addSelfMessage(msg, isAction, timestamp, false); int rec; if (isAction) @@ -129,7 +127,7 @@ void ChatForm::onSendTriggered() else rec = Core::getInstance()->sendMessage(f->getFriendID(), msg); - registerReceipt(rec, id, ma); + //registerReceipt(rec, id, ma); } msgEdit->clear(); @@ -183,8 +181,9 @@ void ChatForm::startFileSend(ToxFile file) previousId = core->getSelfId(); } - chatWidget->insertMessage(ChatActionPtr(new FileTransferAction(fileTrans, getElidedName(name), - QTime::currentTime().toString("hh:mm"), true))); + //TODO: +// chatWidget->insertMessage(ChatActionPtr(new FileTransferAction(fileTrans, getElidedName(name), +// QTime::currentTime().toString("hh:mm"), true))); } void ChatForm::onFileRecvRequest(ToxFile file) @@ -219,8 +218,8 @@ void ChatForm::onFileRecvRequest(ToxFile file) previousId = friendId; } - chatWidget->insertMessage(ChatActionPtr(new FileTransferAction(fileTrans, getElidedName(name), - QTime::currentTime().toString("hh:mm"), false))); + //TODO: chatWidget->insertMessage(ChatActionPtr(new FileTransferAction(fileTrans, getElidedName(name), + // QTime::currentTime().toString("hh:mm"), false))); if (!Settings::getInstance().getAutoAcceptDir(Core::getInstance()->getFriendAddress(f->getFriendID())).isEmpty() || Settings::getInstance().getAutoSaveEnabled()) @@ -253,7 +252,7 @@ void ChatForm::onAvInvite(int FriendId, int CallId, bool video) connect(callButton, SIGNAL(clicked()), this, SLOT(onAnswerCallTriggered())); } - addSystemInfoMessage(tr("%1 calling").arg(f->getDisplayedName()), "white", QDateTime::currentDateTime()); + //TODO: addSystemInfoMessage(tr("%1 calling").arg(f->getDisplayedName()), "white", QDateTime::currentDateTime()); Widget* w = Widget::getInstance(); if (!w->isFriendWidgetCurActiveWidget(f)|| w->isMinimized() || !w->isActiveWindow()) @@ -322,7 +321,7 @@ void ChatForm::onAvCancel(int FriendId, int) netcam->hide(); - addSystemInfoMessage(tr("%1 stopped calling").arg(f->getDisplayedName()), "white", QDateTime::currentDateTime()); + //TODO: addSystemInfoMessage(tr("%1 stopped calling").arg(f->getDisplayedName()), "white", QDateTime::currentDateTime()); } void ChatForm::onAvEnd(int FriendId, int) @@ -378,7 +377,7 @@ void ChatForm::onAvRinging(int FriendId, int CallId, bool video) connect(callButton, SIGNAL(clicked()), this, SLOT(onCancelCallTriggered())); } - addSystemInfoMessage(tr("Calling to %1").arg(f->getDisplayedName()), "white", QDateTime::currentDateTime()); + //TODO: addSystemInfoMessage(tr("Calling to %1").arg(f->getDisplayedName()), "white", QDateTime::currentDateTime()); } void ChatForm::onAvStarting(int FriendId, int CallId, bool video) @@ -519,7 +518,7 @@ void ChatForm::onAvRejected(int FriendId, int) connect(callButton, SIGNAL(clicked()), this, SLOT(onCallTriggered())); connect(videoButton, SIGNAL(clicked()), this, SLOT(onVideoCallTriggered())); - addSystemInfoMessage(tr("Call rejected"), "white", QDateTime::currentDateTime()); + //TODO: addSystemInfoMessage(tr("Call rejected"), "white", QDateTime::currentDateTime()); netcam->hide(); } @@ -670,7 +669,7 @@ void ChatForm::onFileSendFailed(int FriendId, const QString &fname) if (FriendId != f->getFriendID()) return; - addSystemInfoMessage("File: \"" + fname + "\" failed to send.", "red", QDateTime::currentDateTime()); + //TODO: addSystemInfoMessage("File: \"" + fname + "\" failed to send.", "red", QDateTime::currentDateTime()); } void ChatForm::onAvatarChange(int FriendId, const QPixmap &pic) @@ -731,49 +730,49 @@ void ChatForm::loadHistory(QDateTime since, bool processUndelivered) ToxID storedPrevId; std::swap(storedPrevId, previousId); - QList historyMessages; + //QList historyMessages; - QDate lastDate(1,0,0); - for (const auto &it : msgs) - { - // Show the date every new day - QDateTime msgDateTime = it.timestamp.toLocalTime(); - QDate msgDate = msgDateTime.date(); - if (msgDate > lastDate) - { - lastDate = msgDate; - historyMessages.append(genSystemInfoAction(msgDate.toString(),"",QDateTime())); - } +// QDate lastDate(1,0,0); +// for (const auto &it : msgs) +// { +// // Show the date every new day +// QDateTime msgDateTime = it.timestamp.toLocalTime(); +// QDate msgDate = msgDateTime.date(); +// if (msgDate > lastDate) +// { +// lastDate = msgDate; +// historyMessages.append(genSystemInfoAction(msgDate.toString(),"",QDateTime())); +// } - // Show each messages - MessageActionPtr ca = genMessageActionAction(ToxID::fromString(it.sender), it.message, false, msgDateTime); - if (it.isSent) - { - ca->markAsSent(); - } else { - if (processUndelivered) - { - int rec; - if (ca->isAction()) - rec = Core::getInstance()->sendAction(f->getFriendID(), ca->getRawMessage()); - else - rec = Core::getInstance()->sendMessage(f->getFriendID(), ca->getRawMessage()); - registerReceipt(rec, it.id, ca); - } - } - historyMessages.append(ca); - } - std::swap(storedPrevId, previousId); +// // Show each messages +// MessageActionPtr ca = genMessageActionAction(ToxID::fromString(it.sender), it.message, false, msgDateTime); +// if (it.isSent) +// { +// ca->markAsSent(); +// } else { +// if (processUndelivered) +// { +// int rec; +// if (ca->isAction()) +// rec = Core::getInstance()->sendAction(f->getFriendID(), ca->getRawMessage()); +// else +// rec = Core::getInstance()->sendMessage(f->getFriendID(), ca->getRawMessage()); +// registerReceipt(rec, it.id, ca); +// } +// } +// historyMessages.append(ca); +// } +// std::swap(storedPrevId, previousId); - int savedSliderPos = chatWidget->verticalScrollBar()->maximum() - chatWidget->verticalScrollBar()->value(); +// int savedSliderPos = chatWidget->verticalScrollBar()->maximum() - chatWidget->verticalScrollBar()->value(); - if (earliestMessage != nullptr) - *earliestMessage = since; +// if (earliestMessage != nullptr) +// *earliestMessage = since; - chatWidget->insertMessagesTop(historyMessages); +// chatWidget->insertMessagesTop(historyMessages); - savedSliderPos = chatWidget->verticalScrollBar()->maximum() - savedSliderPos; - chatWidget->verticalScrollBar()->setValue(savedSliderPos); +// savedSliderPos = chatWidget->verticalScrollBar()->maximum() - savedSliderPos; +// chatWidget->verticalScrollBar()->setValue(savedSliderPos); } void ChatForm::onLoadHistory() @@ -803,9 +802,10 @@ void ChatForm::stopCounter() { if(timer) { - addSystemInfoMessage(tr("Call with %1 ended. %2").arg(f->getDisplayedName(), - secondsToDHMS(timeElapsed.elapsed()/1000)), - "white", QDateTime::currentDateTime()); + //TODO: +// addSystemInfoMessage(tr("Call with %1 ended. %2").arg(f->getDisplayedName(), +// secondsToDHMS(timeElapsed.elapsed()/1000)), +// "white", QDateTime::currentDateTime()); timer->stop(); callDuration->setText(""); callDuration->hide(); @@ -842,52 +842,52 @@ QString ChatForm::secondsToDHMS(quint32 duration) return cD + res.sprintf("%dd%02dh %02dm %02ds", days, hours, minutes, seconds); } -void ChatForm::registerReceipt(int receipt, int messageID, MessageActionPtr msg) -{ - receipts[receipt] = messageID; - undeliveredMsgs[messageID] = msg; -} +//void ChatForm::registerReceipt(int receipt, int messageID, MessageActionPtr msg) +//{ +// receipts[receipt] = messageID; +// undeliveredMsgs[messageID] = msg; +//} -void ChatForm::dischargeReceipt(int receipt) -{ - auto it = receipts.find(receipt); - if (it != receipts.end()) - { - int mID = it.value(); - auto msgIt = undeliveredMsgs.find(mID); - if (msgIt != undeliveredMsgs.end()) - { - HistoryKeeper::getInstance()->markAsSent(mID); - msgIt.value()->markAsSent(); - msgIt.value()->featureUpdate(); - undeliveredMsgs.erase(msgIt); - } - receipts.erase(it); - } -} +//void ChatForm::dischargeReceipt(int receipt) +//{ +// auto it = receipts.find(receipt); +// if (it != receipts.end()) +// { +// int mID = it.value(); +// auto msgIt = undeliveredMsgs.find(mID); +// if (msgIt != undeliveredMsgs.end()) +// { +// HistoryKeeper::getInstance()->markAsSent(mID); +// msgIt.value()->markAsSent(); +// msgIt.value()->featureUpdate(); +// undeliveredMsgs.erase(msgIt); +// } +// receipts.erase(it); +// } +//} void ChatForm::clearReciepts() { - receipts.clear(); - undeliveredMsgs.clear(); +// receipts.clear(); +// undeliveredMsgs.clear(); } void ChatForm::deliverOfflineMsgs() { - if (!Settings::getInstance().getFauxOfflineMessaging()) - return; +// if (!Settings::getInstance().getFauxOfflineMessaging()) +// return; - QMap msgs = undeliveredMsgs; - clearReciepts(); +// QMap msgs = undeliveredMsgs; +// clearReciepts(); - for (auto iter = msgs.begin(); iter != msgs.end(); iter++) - { - QString messageText = iter.value()->getRawMessage(); - int rec; - if (iter.value()->isAction()) - rec = Core::getInstance()->sendAction(f->getFriendID(), messageText); - else - rec = Core::getInstance()->sendMessage(f->getFriendID(), messageText); - registerReceipt(rec, iter.key(), iter.value()); - } +// for (auto iter = msgs.begin(); iter != msgs.end(); iter++) +// { +// QString messageText = iter.value()->getRawMessage(); +// int rec; +// if (iter.value()->isAction()) +// rec = Core::getInstance()->sendAction(f->getFriendID(), messageText); +// else +// rec = Core::getInstance()->sendMessage(f->getFriendID(), messageText); +// registerReceipt(rec, iter.key(), iter.value()); +// } } diff --git a/src/widget/form/chatform.h b/src/widget/form/chatform.h index 2a051f84e..faf1b5400 100644 --- a/src/widget/form/chatform.h +++ b/src/widget/form/chatform.h @@ -89,7 +89,7 @@ protected: // drag & drop void dragEnterEvent(QDragEnterEvent* ev); void dropEvent(QDropEvent* ev); - void registerReceipt(int receipt, int messageID, MessageActionPtr msg); + //TODO: void registerReceipt(int receipt, int messageID, MessageActionPtr msg); private: Friend* f; @@ -107,7 +107,7 @@ private: void stopCounter(); QString secondsToDHMS(quint32 duration); QHash receipts; - QMap undeliveredMsgs; + //TODO: QMap undeliveredMsgs; }; #endif // CHATFORM_H diff --git a/src/widget/form/genericchatform.cpp b/src/widget/form/genericchatform.cpp index ffe6f8ecb..785b63354 100644 --- a/src/widget/form/genericchatform.cpp +++ b/src/widget/form/genericchatform.cpp @@ -23,16 +23,12 @@ #include "src/misc/style.h" #include "src/widget/widget.h" #include "src/misc/settings.h" -#include "src/widget/tool/chatactions/messageaction.h" -#include "src/widget/tool/chatactions/systemmessageaction.h" -#include "src/widget/tool/chatactions/actionaction.h" -#include "src/widget/tool/chatactions/alertaction.h" -#include "src/widget/chatareawidget.h" #include "src/widget/tool/chattextedit.h" #include "src/widget/maskablepixmapwidget.h" #include "src/core.h" #include "src/friendlist.h" #include "src/friend.h" +#include "src/chatlog/chatlog.h" GenericChatForm::GenericChatForm(QWidget *parent) : QWidget(parent), @@ -52,7 +48,7 @@ GenericChatForm::GenericChatForm(QWidget *parent) : QVBoxLayout *mainLayout = new QVBoxLayout(); QVBoxLayout *footButtonsSmall = new QVBoxLayout(), *volMicLayout = new QVBoxLayout(); - chatWidget = new ChatAreaWidget(); + chatWidget = new ChatLog(this); msgEdit = new ChatTextEdit(); @@ -146,16 +142,16 @@ GenericChatForm::GenericChatForm(QWidget *parent) : connect(emoteButton, SIGNAL(clicked()), this, SLOT(onEmoteButtonClicked())); connect(chatWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onChatContextMenuRequested(QPoint))); - chatWidget->document()->setDefaultStyleSheet(Style::getStylesheet(":ui/chatArea/innerStyle.css")); - chatWidget->setStyleSheet(Style::getStylesheet(":/ui/chatArea/chatArea.css")); + //chatWidget->document()->setDefaultStyleSheet(Style::getStylesheet(":ui/chatArea/innerStyle.css")); + //chatWidget->setStyleSheet(Style::getStylesheet(":/ui/chatArea/chatArea.css")); headWidget->setStyleSheet(Style::getStylesheet(":/ui/chatArea/chatHead.css")); - ChatAction::setupFormat(); + //ChatAction::setupFormat(); } bool GenericChatForm::isEmpty() { - return chatWidget->isEmpty(); + //return chatWidget->isEmpty(); } void GenericChatForm::setName(const QString &newName) @@ -181,70 +177,70 @@ void GenericChatForm::onChatContextMenuRequested(QPoint pos) void GenericChatForm::onSaveLogClicked() { - QString path = QFileDialog::getSaveFileName(0, tr("Save chat log")); - if (path.isEmpty()) - return; +// QString path = QFileDialog::getSaveFileName(0, tr("Save chat log")); +// if (path.isEmpty()) +// return; - QFile file(path); - if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) - return; +// QFile file(path); +// if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) +// return; - QString log; - log = chatWidget->toPlainText(); +// QString log; +// log = chatWidget->toPlainText(); - file.write(log.toUtf8()); - file.close(); +// file.write(log.toUtf8()); +// file.close(); } /** * @deprecated The only reason it's still alive is because the groupchat API is a bit limited */ -void GenericChatForm::addMessage(const QString& author, const QString &message, bool isAction, const QDateTime &datetime) -{ - MessageActionPtr ca = genMessageActionAction(author, message, isAction, datetime); - ca->markAsSent(); - chatWidget->insertMessage(ca); -} +//void GenericChatForm::addMessage(const QString& author, const QString &message, bool isAction, const QDateTime &datetime) +//{ +// MessageActionPtr ca = genMessageActionAction(author, message, isAction, datetime); +// ca->markAsSent(); +// chatWidget->insertMessage(ca); +//} -MessageActionPtr GenericChatForm::addMessage(const ToxID& author, const QString &message, bool isAction, - const QDateTime &datetime, bool isSent) -{ - MessageActionPtr ca = genMessageActionAction(author, message, isAction, datetime); - if (isSent) - ca->markAsSent(); - chatWidget->insertMessage(ca); - return ca; -} +//MessageActionPtr GenericChatForm::addMessage(const ToxID& author, const QString &message, bool isAction, +// const QDateTime &datetime, bool isSent) +//{ +// MessageActionPtr ca = genMessageActionAction(author, message, isAction, datetime); +// if (isSent) +// ca->markAsSent(); +// chatWidget->insertMessage(ca); +// return ca; +//} -MessageActionPtr GenericChatForm::addSelfMessage(const QString &message, bool isAction, const QDateTime &datetime, bool isSent) -{ - MessageActionPtr ca = genSelfActionAction(message, isAction, datetime); - if (isSent) - ca->markAsSent(); - chatWidget->insertMessage(ca); - return ca; -} +//MessageActionPtr GenericChatForm::addSelfMessage(const QString &message, bool isAction, const QDateTime &datetime, bool isSent) +//{ +// MessageActionPtr ca = genSelfActionAction(message, isAction, datetime); +// if (isSent) +// ca->markAsSent(); +// chatWidget->insertMessage(ca); +// return ca; +//} /** * @deprecated The only reason it's still alive is because the groupchat API is a bit limited */ -void GenericChatForm::addAlertMessage(const QString& author, QString message, QDateTime datetime) -{ - QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); - AlertAction *alact = new AlertAction(author, message, date); - alact->markAsSent(); - chatWidget->insertMessage(ChatActionPtr(alact)); +//void GenericChatForm::addAlertMessage(const QString& author, QString message, QDateTime datetime) +//{ +// QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); +// AlertAction *alact = new AlertAction(author, message, date); +// alact->markAsSent(); +// chatWidget->insertMessage(ChatActionPtr(alact)); - previousId.publicKey = author; -} +// previousId.publicKey = author; +//} -void GenericChatForm::addAlertMessage(const ToxID &author, QString message, QDateTime datetime) -{ - QString authorStr = Core::getInstance()->getPeerName(author); - QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); - chatWidget->insertMessage(ChatActionPtr(new AlertAction(authorStr, message, date))); - previousId = author; -} +//void GenericChatForm::addAlertMessage(const ToxID &author, QString message, QDateTime datetime) +//{ +// QString authorStr = Core::getInstance()->getPeerName(author); +// QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); +// chatWidget->insertMessage(ChatActionPtr(new AlertAction(authorStr, message, date))); +// previousId = author; +//} void GenericChatForm::onEmoteButtonClicked() { @@ -278,158 +274,158 @@ void GenericChatForm::focusInput() msgEdit->setFocus(); } -void GenericChatForm::addSystemInfoMessage(const QString &message, const QString &type, const QDateTime &datetime) -{ - ChatActionPtr ca = genSystemInfoAction(message, type, datetime); - chatWidget->insertMessage(ca); -} +//void GenericChatForm::addSystemInfoMessage(const QString &message, const QString &type, const QDateTime &datetime) +//{ +// ChatActionPtr ca = genSystemInfoAction(message, type, datetime); +// chatWidget->insertMessage(ca); +//} -QString GenericChatForm::getElidedName(const QString& name) -{ - // update this whenever you change the font in innerStyle.css - QFontMetrics fm(Style::getFont(Style::BigBold)); +//QString GenericChatForm::getElidedName(const QString& name) +//{ +// // update this whenever you change the font in innerStyle.css +// QFontMetrics fm(Style::getFont(Style::BigBold)); - return fm.elidedText(name, Qt::ElideRight, chatWidget->nameColWidth()); -} +// return fm.elidedText(name, Qt::ElideRight, chatWidget->nameColWidth()); +//} void GenericChatForm::clearChatArea(bool notinform) { - chatWidget->clearChatArea(); - previousId = ToxID(); +// chatWidget->clearChatArea(); +// previousId = ToxID(); - if (!notinform) - addSystemInfoMessage(tr("Cleared"), "white", QDateTime::currentDateTime()); +// if (!notinform) +// addSystemInfoMessage(tr("Cleared"), "white", QDateTime::currentDateTime()); - if (earliestMessage) - { - delete earliestMessage; - earliestMessage = nullptr; - } +// if (earliestMessage) +// { +// delete earliestMessage; +// earliestMessage = nullptr; +// } - emit chatAreaCleared(); +// emit chatAreaCleared(); } /** * @deprecated The only reason it's still alive is because the groupchat API is a bit limited */ -MessageActionPtr GenericChatForm::genMessageActionAction(const QString &author, QString message, bool isAction, - const QDateTime &datetime) -{ - if (earliestMessage == nullptr) - { - earliestMessage = new QDateTime(datetime); - } +//MessageActionPtr GenericChatForm::genMessageActionAction(const QString &author, QString message, bool isAction, +// const QDateTime &datetime) +//{ +// if (earliestMessage == nullptr) +// { +// earliestMessage = new QDateTime(datetime); +// } - QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); - bool isMe = (author == Widget::getInstance()->getUsername()); +// QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); +// bool isMe = (author == Widget::getInstance()->getUsername()); - if (!isAction && message.startsWith("/me ")) - { // always render actions regardless of what core thinks - isAction = true; - message = message.right(message.length()-4); - } +// if (!isAction && message.startsWith("/me ")) +// { // always render actions regardless of what core thinks +// isAction = true; +// message = message.right(message.length()-4); +// } - if (isAction) - { - previousId = ToxID(); // next msg has a name regardless - return MessageActionPtr(new ActionAction (getElidedName(author), message, date, isMe)); - } +// if (isAction) +// { +// previousId = ToxID(); // next msg has a name regardless +// return MessageActionPtr(new ActionAction (getElidedName(author), message, date, isMe)); +// } - MessageActionPtr res; - if (previousId.publicKey == author) - res = MessageActionPtr(new MessageAction(QString(), message, date, isMe)); - else - res = MessageActionPtr(new MessageAction(getElidedName(author), message, date, isMe)); +// MessageActionPtr res; +// if (previousId.publicKey == author) +// res = MessageActionPtr(new MessageAction(QString(), message, date, isMe)); +// else +// res = MessageActionPtr(new MessageAction(getElidedName(author), message, date, isMe)); - previousId.publicKey = author; - return res; -} +// previousId.publicKey = author; +// return res; +//} -MessageActionPtr GenericChatForm::genMessageActionAction(const ToxID& author, QString message, bool isAction, const QDateTime &datetime) -{ - if (earliestMessage == nullptr) - { - earliestMessage = new QDateTime(datetime); - } +//MessageActionPtr GenericChatForm::genMessageActionAction(const ToxID& author, QString message, bool isAction, const QDateTime &datetime) +//{ +// if (earliestMessage == nullptr) +// { +// earliestMessage = new QDateTime(datetime); +// } - const Core* core = Core::getInstance(); +// const Core* core = Core::getInstance(); - QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); - bool isMe = (author == core->getSelfId()); - QString authorStr; - if (isMe) - authorStr = core->getUsername(); - else { - Friend *f = FriendList::findFriend(author.publicKey); - if (f) - authorStr = f->getDisplayedName(); - else - authorStr = core->getPeerName(author); - } +// QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); +// bool isMe = (author == core->getSelfId()); +// QString authorStr; +// if (isMe) +// authorStr = core->getUsername(); +// else { +// Friend *f = FriendList::findFriend(author.publicKey); +// if (f) +// authorStr = f->getDisplayedName(); +// else +// authorStr = core->getPeerName(author); +// } - if (authorStr.isEmpty()) // Fallback if we can't find a username - authorStr = author.toString(); +// if (authorStr.isEmpty()) // Fallback if we can't find a username +// authorStr = author.toString(); - if (!isAction && message.startsWith("/me ")) - { // always render actions regardless of what core thinks - isAction = true; - message = message.right(message.length()-4); - } +// if (!isAction && message.startsWith("/me ")) +// { // always render actions regardless of what core thinks +// isAction = true; +// message = message.right(message.length()-4); +// } - if (isAction) - { - previousId = ToxID(); // next msg has a name regardless - return MessageActionPtr(new ActionAction (getElidedName(authorStr), message, date, isMe)); - } +// if (isAction) +// { +// previousId = ToxID(); // next msg has a name regardless +// return MessageActionPtr(new ActionAction (getElidedName(authorStr), message, date, isMe)); +// } - MessageActionPtr res; - if (previousId == author) - res = MessageActionPtr(new MessageAction(QString(), message, date, isMe)); - else - res = MessageActionPtr(new MessageAction(getElidedName(authorStr), message, date, isMe)); +// MessageActionPtr res; +// if (previousId == author) +// res = MessageActionPtr(new MessageAction(QString(), message, date, isMe)); +// else +// res = MessageActionPtr(new MessageAction(getElidedName(authorStr), message, date, isMe)); - previousId = author; - return res; -} +// previousId = author; +// return res; +//} -MessageActionPtr GenericChatForm::genSelfActionAction(QString message, bool isAction, const QDateTime &datetime) -{ - if (earliestMessage == nullptr) - { - earliestMessage = new QDateTime(datetime); - } +//MessageActionPtr GenericChatForm::genSelfActionAction(QString message, bool isAction, const QDateTime &datetime) +//{ +// if (earliestMessage == nullptr) +// { +// earliestMessage = new QDateTime(datetime); +// } - const Core* core = Core::getInstance(); +// const Core* core = Core::getInstance(); - QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); - QString author = core->getUsername();; +// QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); +// QString author = core->getUsername();; - if (!isAction && message.startsWith("/me ")) - { // always render actions regardless of what core thinks - isAction = true; - message = message.right(message.length()-4); - } +// if (!isAction && message.startsWith("/me ")) +// { // always render actions regardless of what core thinks +// isAction = true; +// message = message.right(message.length()-4); +// } - if (isAction) - { - previousId = ToxID(); // next msg has a name regardless - return MessageActionPtr(new ActionAction (getElidedName(author), message, date, true)); - } +// if (isAction) +// { +// previousId = ToxID(); // next msg has a name regardless +// return MessageActionPtr(new ActionAction (getElidedName(author), message, date, true)); +// } - MessageActionPtr res; - if (previousId.isMine()) - res = MessageActionPtr(new MessageAction(QString(), message, date, true)); - else - res = MessageActionPtr(new MessageAction(getElidedName(author), message, date, true)); +// MessageActionPtr res; +// if (previousId.isMine()) +// res = MessageActionPtr(new MessageAction(QString(), message, date, true)); +// else +// res = MessageActionPtr(new MessageAction(getElidedName(author), message, date, true)); - previousId = Core::getInstance()->getSelfId(); - return res; -} +// previousId = Core::getInstance()->getSelfId(); +// return res; +//} -ChatActionPtr GenericChatForm::genSystemInfoAction(const QString &message, const QString &type, const QDateTime &datetime) -{ - previousId = ToxID(); - QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); +//ChatActionPtr GenericChatForm::genSystemInfoAction(const QString &message, const QString &type, const QDateTime &datetime) +//{ +// previousId = ToxID(); +// QString date = datetime.toString(Settings::getInstance().getTimestampFormat()); - return ChatActionPtr(new SystemMessageAction(message, type, date)); -} +// return ChatActionPtr(new SystemMessageAction(message, type, date)); +//} diff --git a/src/widget/form/genericchatform.h b/src/widget/form/genericchatform.h index ddd451ca7..9d967125a 100644 --- a/src/widget/form/genericchatform.h +++ b/src/widget/form/genericchatform.h @@ -21,7 +21,6 @@ #include #include #include -#include "src/widget/tool/chatactions/messageaction.h" #include "src/corestructs.h" // Spacing in px inserted when the author of the last message changes @@ -32,7 +31,7 @@ class QVBoxLayout; class QPushButton; class CroppingLabel; class ChatTextEdit; -class ChatAreaWidget; +class ChatLog; class MaskablePixmapWidget; struct ToxID; @@ -50,8 +49,8 @@ public: virtual void show(Ui::MainWindow &ui); void addMessage(const QString& author, const QString &message, bool isAction, const QDateTime &datetime); ///< Deprecated - MessageActionPtr addMessage(const ToxID& author, const QString &message, bool isAction, const QDateTime &datetime, bool isSent); - MessageActionPtr addSelfMessage(const QString &message, bool isAction, const QDateTime &datetime, bool isSent); +// TODO: MessageActionPtr addMessage(const ToxID& author, const QString &message, bool isAction, const QDateTime &datetime, bool isSent); +// MessageActionPtr addSelfMessage(const QString &message, bool isAction, const QDateTime &datetime, bool isSent); void addSystemInfoMessage(const QString &message, const QString &type, const QDateTime &datetime); void addAlertMessage(const QString& author, QString message, QDateTime datetime); ///< Deprecated void addAlertMessage(const ToxID& author, QString message, QDateTime datetime); @@ -74,10 +73,10 @@ protected slots: protected: QString getElidedName(const QString& name); - MessageActionPtr genMessageActionAction(const QString& author, QString message, bool isAction, const QDateTime &datetime); ///< Deprecated - MessageActionPtr genMessageActionAction(const ToxID& author, QString message, bool isAction, const QDateTime &datetime); - MessageActionPtr genSelfActionAction(QString message, bool isAction, const QDateTime &datetime); - ChatActionPtr genSystemInfoAction(const QString &message, const QString &type, const QDateTime &datetime); +//TODO: MessageActionPtr genMessageActionAction(const QString& author, QString message, bool isAction, const QDateTime &datetime); ///< Deprecated +// MessageActionPtr genMessageActionAction(const ToxID& author, QString message, bool isAction, const QDateTime &datetime); +// MessageActionPtr genSelfActionAction(QString message, bool isAction, const QDateTime &datetime); +// ChatActionPtr genSystemInfoAction(const QString &message, const QString &type, const QDateTime &datetime); ToxID previousId; QMenu menu; @@ -89,7 +88,7 @@ protected: QVBoxLayout *headTextLayout; ChatTextEdit *msgEdit; QPushButton *sendButton; - ChatAreaWidget *chatWidget; + ChatLog *chatWidget; QDateTime *earliestMessage; }; diff --git a/src/widget/tool/chatactions/actionaction.cpp b/src/widget/tool/chatactions/actionaction.cpp deleted file mode 100644 index 1063f070b..000000000 --- a/src/widget/tool/chatactions/actionaction.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - 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. -*/ - -#include "actionaction.h" -#include - -ActionAction::ActionAction(const QString &author, QString message, const QString &date, const bool& me) : - MessageAction(author, author+" "+message, date, me) -{ - rawMessage = message; -} - -QString ActionAction::getName() -{ - return QString("
*
"); -} - -QString ActionAction::getMessage() -{ - return MessageAction::getMessage("action"); -} - -QString ActionAction::getRawMessage() -{ - return rawMessage; -} diff --git a/src/widget/tool/chatactions/actionaction.h b/src/widget/tool/chatactions/actionaction.h deleted file mode 100644 index 62b101ef0..000000000 --- a/src/widget/tool/chatactions/actionaction.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - 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. -*/ - -#ifndef ACTIONACTION_H -#define ACTIONACTION_H - -#include "messageaction.h" - -class ActionAction : public MessageAction -{ -public: - ActionAction(const QString &author, QString message, const QString& date, const bool&); - virtual ~ActionAction(){;} - virtual QString getRawMessage(); - virtual bool isAction() {return true;} - -protected: - virtual QString getMessage(); - virtual QString getName(); - -private: - QString message, rawMessage; -}; - -#endif // MESSAGEACTION_H diff --git a/src/widget/tool/chatactions/alertaction.cpp b/src/widget/tool/chatactions/alertaction.cpp deleted file mode 100644 index 23179340d..000000000 --- a/src/widget/tool/chatactions/alertaction.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - 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. -*/ - -#include "alertaction.h" - -AlertAction::AlertAction(const QString &author, const QString &message, const QString &date) : - MessageAction(author, message, date, false) -{ -} - -QString AlertAction::getMessage() -{ - return MessageAction::getMessage("alert"); -} diff --git a/src/widget/tool/chatactions/alertaction.h b/src/widget/tool/chatactions/alertaction.h deleted file mode 100644 index d37f355bd..000000000 --- a/src/widget/tool/chatactions/alertaction.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - 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. -*/ - -#ifndef ALERTACTION_H -#define ALERTACTION_H - -#include "messageaction.h" - -class AlertAction : public MessageAction -{ -public: - AlertAction(const QString &author, const QString &message, const QString& date); - virtual ~AlertAction(){;} - -protected: - virtual QString getMessage(); - -private: - QString message; -}; - -#endif // MESSAGEACTION_H diff --git a/src/widget/tool/chatactions/chataction.cpp b/src/widget/tool/chatactions/chataction.cpp deleted file mode 100644 index a2aa3e140..000000000 --- a/src/widget/tool/chatactions/chataction.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - 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. -*/ - -#include "chataction.h" -#include -#include -#include -#include -#include - -QTextBlockFormat ChatAction::nameFormat, ChatAction::dateFormat; - -QString ChatAction::toHtmlChars(const QString &str) -{ - static QList> replaceList = {{"&","&"}, {">",">"}, {"<","<"}}; - QString res = str; - - for (auto &it : replaceList) - res = res.replace(it.first,it.second); - - return res; -} - -QString ChatAction::QImage2base64(const QImage &img) -{ - QByteArray ba; - QBuffer buffer(&ba); - buffer.open(QIODevice::WriteOnly); - img.save(&buffer, "PNG"); // writes image into ba in PNG format - return ba.toBase64(); -} - -QString ChatAction::getName() -{ - if (isMe) - return QString("
%2
").arg("name_me").arg(toHtmlChars(name)); - else - return QString("
%2
").arg("name").arg(toHtmlChars(name)); -} - -QString ChatAction::getDate() -{ - if (isMe) - return QString("
" + toHtmlChars(date) + "
"); - else - return QString("
" + toHtmlChars(date) + "
"); -} - -void ChatAction::assignPlace(QTextTable *position, QTextEdit *te) -{ - textTable = position; - cur = position->cellAt(0, 2).firstCursorPosition(); - cur.clearSelection(); - cur.setKeepPositionOnInsert(true); - textEdit = te; -} - -void ChatAction::dispaly() -{ - textTable->cellAt(0, 0).firstCursorPosition().setBlockFormat(nameFormat); - textTable->cellAt(0, 0).firstCursorPosition().insertHtml(getName()); - textTable->cellAt(0, 2).firstCursorPosition().insertHtml(getMessage()); - textTable->cellAt(0, 4).firstCursorPosition().setBlockFormat(dateFormat); - textTable->cellAt(0, 4).firstCursorPosition().insertHtml(getDate()); - - cur.setKeepPositionOnInsert(true); - int end=cur.selectionEnd(); - cur.setPosition(cur.position()); - cur.setPosition(end, QTextCursor::KeepAnchor); - - featureUpdate(); -} - -void ChatAction::setupFormat() -{ - nameFormat.setAlignment(Qt::AlignRight); - nameFormat.setNonBreakableLines(true); - dateFormat.setAlignment(Qt::AlignLeft); - dateFormat.setNonBreakableLines(true); -} - -void ChatAction::updateContent() -{ - if (cur.isNull() || !textEdit) - return; - - int vSliderVal = textEdit->verticalScrollBar()->value(); - - // update content - int pos = cur.selectionStart(); - cur.removeSelectedText(); - cur.setKeepPositionOnInsert(false); - cur.insertHtml(getMessage()); - cur.setKeepPositionOnInsert(true); - int end = cur.position(); - cur.setPosition(pos); - cur.setPosition(end, QTextCursor::KeepAnchor); - - // restore old slider value - textEdit->verticalScrollBar()->setValue(vSliderVal); - - featureUpdate(); -} diff --git a/src/widget/tool/chatactions/chataction.h b/src/widget/tool/chatactions/chataction.h deleted file mode 100644 index b007ecb60..000000000 --- a/src/widget/tool/chatactions/chataction.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - 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. -*/ - -#ifndef CHATACTION_H -#define CHATACTION_H - -#include -#include -#include - -class FileTransferInstance; -class QTextEdit; -class QTextTable; - -class ChatAction : public QObject -{ - Q_OBJECT -public: - ChatAction(const bool &me, const QString &author, const QString &date) : isMe(me), name(author), date(date) {;} - virtual ~ChatAction(){;} - - void assignPlace(QTextTable *position, QTextEdit* te); - virtual void dispaly(); - virtual bool isInteractive(){return false;} - virtual void featureUpdate() {;} - - static void setupFormat(); - -public slots: - void updateContent(); - -protected: - virtual QString getName(); - virtual QString getMessage() = 0; - virtual QString getDate(); - - QString toHtmlChars(const QString &str); - QString QImage2base64(const QImage &img); - -protected: - bool isMe; - QString name, date; - - QTextTable *textTable; - QTextEdit *textEdit; - QTextCursor cur; - - static QTextBlockFormat nameFormat, dateFormat; -}; - -typedef QSharedPointer ChatActionPtr; - -#endif // CHATACTION_H diff --git a/src/widget/tool/chatactions/filetransferaction.cpp b/src/widget/tool/chatactions/filetransferaction.cpp deleted file mode 100644 index 103e72f36..000000000 --- a/src/widget/tool/chatactions/filetransferaction.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - 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. -*/ - -#include "filetransferaction.h" -#include "src/filetransferinstance.h" - -#include -#include - -FileTransferAction::FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me) - : ChatAction(me, author, date) -{ - w = widget; - - connect(w, &FileTransferInstance::stateUpdated, this, &FileTransferAction::updateContent); -} - -FileTransferAction::~FileTransferAction() -{ -} - -QString FileTransferAction::getMessage() -{ - QString widgetHtml; - if (w != nullptr) - widgetHtml = w->getHtmlImage(); - else - widgetHtml = "
EMPTY CONTENT
"; - return widgetHtml; -} - -/* -void FileTransferAction::setup(QTextCursor cursor, QTextEdit *textEdit) -{ - cur = cursor; - cur.setKeepPositionOnInsert(true); - int end=cur.selectionEnd(); - cur.setPosition(cur.position()); - cur.setPosition(end, QTextCursor::KeepAnchor); - - edit = textEdit; -} -*/ -/* -void FileTransferAction::updateHtml() -{ - if (cur.isNull() || !edit) - return; - - // save old slider value - int vSliderVal = edit->verticalScrollBar()->value(); - - // update content - int pos = cur.selectionStart(); - cur.removeSelectedText(); - cur.setKeepPositionOnInsert(false); - cur.insertHtml(getMessage()); - cur.setKeepPositionOnInsert(true); - int end = cur.position(); - cur.setPosition(pos); - cur.setPosition(end, QTextCursor::KeepAnchor); - - // restore old slider value - edit->verticalScrollBar()->setValue(vSliderVal); -} -*/ -bool FileTransferAction::isInteractive() -{ - if (w->getState() == FileTransferInstance::TransfState::tsCanceled - || w->getState() == FileTransferInstance::TransfState::tsFinished) - { - return false; - } - - return true; -} diff --git a/src/widget/tool/chatactions/filetransferaction.h b/src/widget/tool/chatactions/filetransferaction.h deleted file mode 100644 index 696d4a5c0..000000000 --- a/src/widget/tool/chatactions/filetransferaction.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - 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. -*/ - -#ifndef FILETRANSFERACTION_H -#define FILETRANSFERACTION_H - -#include "chataction.h" - -class FileTransferAction : public ChatAction -{ - Q_OBJECT -public: - FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me); - virtual ~FileTransferAction(); - virtual bool isInteractive(); - -protected: - virtual QString getMessage(); - -private: - FileTransferInstance *w; -}; - -#endif // FILETRANSFERACTION_H diff --git a/src/widget/tool/chatactions/messageaction.cpp b/src/widget/tool/chatactions/messageaction.cpp deleted file mode 100644 index 42e46bc79..000000000 --- a/src/widget/tool/chatactions/messageaction.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - 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. -*/ - -#include "messageaction.h" -#include "src/misc/smileypack.h" -#include "src/misc/settings.h" -#include - -MessageAction::MessageAction(const QString &author, const QString &message, const QString &date, const bool &me) : - ChatAction(me, author, date), - message(message) -{ - isProcessed = false; -} - -QString MessageAction::getMessage(QString div) -{ - QString message_; - if(Settings::getInstance().getUseEmoticons()) - message_ = SmileyPack::getInstance().smileyfied(toHtmlChars(message)); - else - message_ = toHtmlChars(message); - - // detect urls - QRegExp exp("(?:\\b)(www\\.|http[s]?:\\/\\/|ftp:\\/\\/|tox:\\/\\/|tox:)\\S+"); - int offset = 0; - while ((offset = exp.indexIn(message_, offset)) != -1) - { - QString url = exp.cap(); - - // add scheme if not specified - if (exp.cap(1) == "www.") - url.prepend("http://"); - - QString htmledUrl = QString("%1").arg(url); - message_.replace(offset, exp.cap().length(), htmledUrl); - - offset += htmledUrl.length(); - } - - // detect text quotes - QStringList messageLines = message_.split("\n"); - message_ = ""; - for (QString& s : messageLines) - { - if (QRegExp("^[ ]*>.*").exactMatch(s)) - message_ += "" + s + "
"; - else - message_ += s + "
"; - } - message_ = message_.left(message_.length()-4); - - return QString(QString("
").arg(div) + message_ + "
"); -} - -QString MessageAction::getMessage() -{ - if (isMe) - return getMessage("message_me"); - else - return getMessage("message"); -} - -void MessageAction::featureUpdate() -{ - QTextTableCell cell = textTable->cellAt(0,3); - QTextTableCellFormat format; - if (!isProcessed) - format.setBackground(QColor(Qt::red)); - else - format.setBackground(QColor(Qt::white)); - cell.setFormat(format); -} - -void MessageAction::markAsSent() -{ - isProcessed = true; -} - -QString MessageAction::getRawMessage() -{ - return message; -} diff --git a/src/widget/tool/chatactions/messageaction.h b/src/widget/tool/chatactions/messageaction.h deleted file mode 100644 index 9c11bbda4..000000000 --- a/src/widget/tool/chatactions/messageaction.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - 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. -*/ - -#ifndef MESSAGEACTION_H -#define MESSAGEACTION_H - -#include "chataction.h" - -class MessageAction : public ChatAction -{ -public: - MessageAction(const QString &author, const QString &message, const QString &date, const bool &me); - virtual ~MessageAction(){;} - virtual void featureUpdate(); - void markAsSent(); - virtual QString getRawMessage(); - virtual bool isAction() {return false;} - -protected: - virtual QString getMessage(); - virtual QString getMessage(QString div); - -protected: - QString message; - bool isProcessed; -}; - -typedef QSharedPointer MessageActionPtr; - -#endif // MESSAGEACTION_H diff --git a/src/widget/tool/chatactions/systemmessageaction.cpp b/src/widget/tool/chatactions/systemmessageaction.cpp deleted file mode 100644 index 506370871..000000000 --- a/src/widget/tool/chatactions/systemmessageaction.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - 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. -*/ - -#include "systemmessageaction.h" - -SystemMessageAction::SystemMessageAction(const QString &message, const QString &type, const QString &date) : - ChatAction(false, QString(), date), - message(message), - type(type) -{ -} - -QString SystemMessageAction::getMessage() -{ - return QString("
" + message + "
"); -} diff --git a/src/widget/tool/chatactions/systemmessageaction.h b/src/widget/tool/chatactions/systemmessageaction.h deleted file mode 100644 index 99740cedc..000000000 --- a/src/widget/tool/chatactions/systemmessageaction.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (C) 2014 by Project Tox - - 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. -*/ - -#ifndef SYSTEMMESSAGEACTION_H -#define SYSTEMMESSAGEACTION_H - -#include "chataction.h" - -class SystemMessageAction : public ChatAction -{ -public: - SystemMessageAction(const QString &message, const QString& type, const QString &date); - virtual ~SystemMessageAction(){;} - -protected: - virtual QString getName() {return QString();} - virtual QString getMessage(); - -private: - QString message; - QString type; -}; - -#endif // SYSTEMMESSAGEACTION_H diff --git a/src/widget/widget.cpp b/src/widget/widget.cpp index a7802bba1..7623baa25 100644 --- a/src/widget/widget.cpp +++ b/src/widget/widget.cpp @@ -687,9 +687,10 @@ void Widget::onFriendStatusChanged(int friendId, Status status) default: fStatus = tr("online", "contact status"); break; } - if (isActualChange) - f->getChatForm()->addSystemInfoMessage(tr("%1 is now %2", "e.g. \"Dubslow is now online\"").arg(f->getDisplayedName()).arg(fStatus), - "white", QDateTime::currentDateTime()); + //TODO: +// if (isActualChange) +// f->getChatForm()->addSystemInfoMessage(tr("%1 is now %2", "e.g. \"Dubslow is now online\"").arg(f->getDisplayedName()).arg(fStatus), +// "white", QDateTime::currentDateTime()); } if (isActualChange && status != Status::Offline) @@ -742,7 +743,7 @@ void Widget::onFriendMessageReceived(int friendId, const QString& message, bool return; QDateTime timestamp = QDateTime::currentDateTime(); - f->getChatForm()->addMessage(f->getToxID(), message, isAction, timestamp, true); + //TODO: f->getChatForm()->addMessage(f->getToxID(), message, isAction, timestamp, true); if (isAction) HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, "/me " + message, f->getToxID().publicKey, timestamp, true); @@ -772,7 +773,7 @@ void Widget::onReceiptRecieved(int friendId, int receipt) if (!f) return; - f->getChatForm()->dischargeReceipt(receipt); + //TODO: f->getChatForm()->dischargeReceipt(receipt); } void Widget::newMessageAlert(GenericChatroomWidget* chat) @@ -900,9 +901,9 @@ void Widget::onGroupMessageReceived(int groupnumber, const QString& message, con bool targeted = (author != name) && message.contains(name, Qt::CaseInsensitive); if (targeted) - g->chatForm->addAlertMessage(author, message, QDateTime::currentDateTime()); + ;//TODO: g->chatForm->addAlertMessage(author, message, QDateTime::currentDateTime()); else - g->chatForm->addMessage(author, message, isAction, QDateTime::currentDateTime()); + ;//TODO: g->chatForm->addMessage(author, message, isAction, QDateTime::currentDateTime()); if ((static_cast(g->widget) != activeChatroomWidget) || isMinimized() || !isActiveWindow()) { @@ -1086,7 +1087,7 @@ void Widget::onGroupSendResult(int groupId, const QString& message, int result) return; if (result == -1) - g->chatForm->addSystemInfoMessage(tr("Message failed to send"), "red", QDateTime::currentDateTime()); + ;//TODO: g->chatForm->addSystemInfoMessage(tr("Message failed to send"), "red", QDateTime::currentDateTime()); } void Widget::getPassword(QString info, int passtype, uint8_t* salt) @@ -1158,6 +1159,6 @@ void Widget::clearAllReceipts() QList frnds = FriendList::getAllFriends(); for (Friend *f : frnds) { - f->getChatForm()->clearReciepts(); + //TODO: f->getChatForm()->clearReciepts(); } }