mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-12-27 00:19:25 -05:00
1044 lines
31 KiB
C++
1044 lines
31 KiB
C++
/*******************************************************************************
|
|
* plugins/FeedReader/gui/FeedReaderMessageWidget.cpp *
|
|
* *
|
|
* Copyright (C) 2012 by RetroShare Team <retroshare.project@gmail.com> *
|
|
* *
|
|
* This program is free software: you can redistribute it and/or modify *
|
|
* it under the terms of the GNU Affero 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 *
|
|
* GNU Affero General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Affero General Public License *
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
|
* *
|
|
*******************************************************************************/
|
|
|
|
#include <QDateTime>
|
|
#include <QMenu>
|
|
#include <QKeyEvent>
|
|
#include <QClipboard>
|
|
#include <QDesktopServices>
|
|
#include <QTimer>
|
|
#include <QPainter>
|
|
#include <QMimeData>
|
|
|
|
#include "FeedReaderMessageWidget.h"
|
|
#include "ui_FeedReaderMessageWidget.h"
|
|
#include "FeedReaderNotify.h"
|
|
#include "FeedReaderConfig.h"
|
|
#include "FeedReaderDialog.h"
|
|
|
|
#include "gui/common/RSTreeWidgetItem.h"
|
|
#include "gui/settings/rsharesettings.h"
|
|
#include "util/HandleRichText.h"
|
|
#include "util/QtVersion.h"
|
|
#include "gui/Posted/PostedCreatePostDialog.h"
|
|
#include "gui/gxsforums/CreateGxsForumMsg.h"
|
|
#include "gui/common/FilesDefs.h"
|
|
#include "util/imageutil.h"
|
|
|
|
#include "retroshare/rsiface.h"
|
|
#include "retroshare/rsgxsforums.h"
|
|
#include "retroshare/rsposted.h"
|
|
|
|
#define COLUMN_MSG_COUNT 4
|
|
#define COLUMN_MSG_TITLE 0
|
|
#define COLUMN_MSG_READ 1
|
|
#define COLUMN_MSG_PUBDATE 2
|
|
#define COLUMN_MSG_AUTHOR 3
|
|
#define COLUMN_MSG_DATA 0
|
|
|
|
#define ROLE_MSG_ID Qt::UserRole
|
|
#define ROLE_MSG_SORT Qt::UserRole + 1
|
|
#define ROLE_MSG_NEW Qt::UserRole + 2
|
|
#define ROLE_MSG_READ Qt::UserRole + 3
|
|
#define ROLE_MSG_LINK Qt::UserRole + 4
|
|
|
|
FeedReaderMessageWidget::FeedReaderMessageWidget(uint32_t feedId, RsFeedReader *feedReader, FeedReaderNotify *notify, QWidget *parent) :
|
|
QWidget(parent), mFeedReader(feedReader), mNotify(notify), ui(new Ui::FeedReaderMessageWidget)
|
|
{
|
|
ui->setupUi(this);
|
|
|
|
mFeedId = 0;
|
|
mProcessSettings = false;
|
|
mUnreadCount = 0;
|
|
mNewCount = 0;
|
|
|
|
/* connect signals */
|
|
connect(mNotify, &FeedReaderNotify::feedChanged, this, &FeedReaderMessageWidget::feedChanged, Qt::QueuedConnection);
|
|
connect(mNotify, &FeedReaderNotify::msgChanged, this, &FeedReaderMessageWidget::msgChanged, Qt::QueuedConnection);
|
|
|
|
connect(ui->msgTreeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(msgItemChanged()));
|
|
connect(ui->msgTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(msgItemClicked(QTreeWidgetItem*,int)));
|
|
|
|
connect(ui->msgTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(msgTreeCustomPopupMenu(QPoint)));
|
|
|
|
connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterItems(QString)));
|
|
connect(ui->filterLineEdit, SIGNAL(filterChanged(int)), this, SLOT(filterColumnChanged(int)));
|
|
|
|
connect(ui->linkButton, SIGNAL(clicked()), this, SLOT(openLinkMsg()));
|
|
connect(ui->expandButton, SIGNAL(clicked()), this, SLOT(toggleMsgText()));
|
|
|
|
connect(ui->msgReadButton, SIGNAL(clicked()), this, SLOT(markAsReadMsg()));
|
|
connect(ui->msgUnreadButton, SIGNAL(clicked()), this, SLOT(markAsUnreadMsg()));
|
|
connect(ui->msgReadAllButton, SIGNAL(clicked()), this, SLOT(markAllAsReadMsg()));
|
|
connect(ui->msgRemoveButton, SIGNAL(clicked()), this, SLOT(removeMsg()));
|
|
connect(ui->feedProcessButton, SIGNAL(clicked()), this, SLOT(processFeed()));
|
|
|
|
/* Set initial size the splitter */
|
|
QList<int> sizes;
|
|
sizes << 250 << width(); // Qt calculates the right sizes
|
|
ui->pictureSplitter->setSizes(sizes);
|
|
ui->pictureSplitter->hide();
|
|
|
|
// create timer for navigation
|
|
mTimer = new QTimer(this);
|
|
mTimer->setInterval(300);
|
|
mTimer->setSingleShot(true);
|
|
connect(mTimer, SIGNAL(timeout()), this, SLOT(updateCurrentMessage()));
|
|
|
|
mMsgCompareRole = new RSTreeWidgetItemCompareRole;
|
|
mMsgCompareRole->setRole(COLUMN_MSG_TITLE, ROLE_MSG_SORT);
|
|
mMsgCompareRole->setRole(COLUMN_MSG_READ, ROLE_MSG_SORT);
|
|
mMsgCompareRole->setRole(COLUMN_MSG_PUBDATE, ROLE_MSG_SORT);
|
|
mMsgCompareRole->setRole(COLUMN_MSG_AUTHOR, ROLE_MSG_SORT);
|
|
|
|
/* initialize msg list */
|
|
ui->msgTreeWidget->sortItems(COLUMN_MSG_PUBDATE, Qt::DescendingOrder);
|
|
|
|
/* set header resize modes and initial section sizes */
|
|
QHeaderView *header = ui->msgTreeWidget->header();
|
|
QHeaderView_setSectionResizeModeColumn(header, COLUMN_MSG_TITLE, QHeaderView::Interactive);
|
|
header->resizeSection(COLUMN_MSG_TITLE, 350);
|
|
header->resizeSection(COLUMN_MSG_PUBDATE, 140);
|
|
header->resizeSection(COLUMN_MSG_AUTHOR, 150);
|
|
|
|
/* set text of column "Read" to empty - without this the column has a number as header text */
|
|
QTreeWidgetItem *headerItem = ui->msgTreeWidget->headerItem();
|
|
headerItem->setText(COLUMN_MSG_READ, "");
|
|
|
|
/* add filter actions */
|
|
ui->filterLineEdit->addFilter(QIcon(), tr("Title"), COLUMN_MSG_TITLE, tr("Search Title"));
|
|
ui->filterLineEdit->addFilter(QIcon(), tr("Date"), COLUMN_MSG_PUBDATE, tr("Search Date"));
|
|
ui->filterLineEdit->addFilter(QIcon(), tr("Author"), COLUMN_MSG_AUTHOR, tr("Search Author"));
|
|
ui->filterLineEdit->setCurrentFilter(COLUMN_MSG_TITLE);
|
|
|
|
/* add image actions */
|
|
ui->attachmentLabel->addContextMenuAction(ui->actionAttachmentCopyLinkLocation);
|
|
connect(ui->actionAttachmentCopyLinkLocation, &QAction::triggered, this, &FeedReaderMessageWidget::attachmentCopyLinkLocation);
|
|
|
|
/* load settings */
|
|
processSettings(true);
|
|
|
|
/* Set header sizes for the fixed columns and resize modes, must be set after processSettings */
|
|
header->resizeSection(COLUMN_MSG_READ, 24);
|
|
QHeaderView_setSectionResizeModeColumn(header, COLUMN_MSG_READ, QHeaderView::Fixed);
|
|
|
|
/* build menu for link button */
|
|
QMenu *menu = new QMenu(this);
|
|
QAction *action = menu->addAction(tr("Open link in browser"), this, SLOT(openLinkMsg()));
|
|
menu->addAction(tr("Copy link to clipboard"), this, SLOT(copyLinkMsg()));
|
|
|
|
QFont font = action->font();
|
|
font.setBold(true);
|
|
action->setFont(font);
|
|
|
|
ui->linkButton->setMenu(menu);
|
|
ui->linkButton->setEnabled(false);
|
|
|
|
ui->msgTreeWidget->installEventFilter(this);
|
|
|
|
setFeedId(feedId);
|
|
}
|
|
|
|
FeedReaderMessageWidget::~FeedReaderMessageWidget()
|
|
{
|
|
// stop and delete timer
|
|
mTimer->stop();
|
|
delete(mTimer);
|
|
|
|
/* save settings */
|
|
processSettings(false);
|
|
|
|
delete(mMsgCompareRole);
|
|
delete ui;
|
|
}
|
|
|
|
void FeedReaderMessageWidget::processSettings(bool load)
|
|
{
|
|
mProcessSettings = true;
|
|
Settings->beginGroup(QString("FeedReaderDialog"));
|
|
|
|
QHeaderView *header = ui->msgTreeWidget->header ();
|
|
|
|
if (load) {
|
|
// load settings
|
|
|
|
// expandButton
|
|
bool value = Settings->value("expandButton", true).toBool();
|
|
ui->expandButton->setChecked(value);
|
|
toggleMsgText_internal();
|
|
|
|
// filterColumn
|
|
ui->filterLineEdit->setCurrentFilter(Settings->value("filterColumn", COLUMN_MSG_TITLE).toInt());
|
|
|
|
// state of thread tree
|
|
header->restoreState(Settings->value("msgTree").toByteArray());
|
|
|
|
// state of splitter
|
|
ui->msgSplitter->restoreState(Settings->value("msgSplitter").toByteArray());
|
|
ui->pictureSplitter->restoreState(Settings->value("pictureSplitter").toByteArray());
|
|
} else {
|
|
// save settings
|
|
|
|
// state of thread tree
|
|
Settings->setValue("msgTree", header->saveState());
|
|
|
|
// state of splitter
|
|
Settings->setValue("msgSplitter", ui->msgSplitter->saveState());
|
|
Settings->setValue("pictureSplitter", ui->pictureSplitter->saveState());
|
|
}
|
|
|
|
Settings->endGroup();
|
|
mProcessSettings = false;
|
|
}
|
|
|
|
void FeedReaderMessageWidget::showEvent(QShowEvent */*event*/)
|
|
{
|
|
updateMsgs();
|
|
}
|
|
|
|
bool FeedReaderMessageWidget::eventFilter(QObject *obj, QEvent *event)
|
|
{
|
|
if (obj == ui->msgTreeWidget) {
|
|
if (event->type() == QEvent::KeyPress) {
|
|
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
|
|
if (keyEvent) {
|
|
if (keyEvent->key() == Qt::Key_Space) {
|
|
/* Space pressed */
|
|
QTreeWidgetItem *item = ui->msgTreeWidget->currentItem();
|
|
msgItemClicked(item, COLUMN_MSG_READ);
|
|
return true; // eat event
|
|
}
|
|
if (keyEvent->key() == Qt::Key_Delete) {
|
|
/* Delete pressed */
|
|
removeMsg();
|
|
return true; // eat event
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* pass the event on to the parent class */
|
|
return QWidget::eventFilter(obj, event);
|
|
}
|
|
|
|
void FeedReaderMessageWidget::setFeedId(uint32_t feedId)
|
|
{
|
|
if (mFeedId == feedId) {
|
|
if (feedId) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
mFeedId = feedId;
|
|
|
|
ui->feedProcessButton->setEnabled(mFeedId);
|
|
|
|
if (mFeedId) {
|
|
if (mFeedReader->getFeedInfo(mFeedId, mFeedInfo)) {
|
|
mFeedReader->getMessageCount(mFeedId, NULL, &mNewCount, &mUnreadCount);
|
|
} else {
|
|
mFeedId = 0;
|
|
mFeedInfo = FeedInfo();
|
|
}
|
|
} else {
|
|
mFeedInfo = FeedInfo();
|
|
}
|
|
|
|
if (mFeedId == 0) {
|
|
ui->msgReadAllButton->setEnabled(false);
|
|
ui->msgTreeWidget->setPlaceholderText("");
|
|
} else {
|
|
if (mFeedInfo.flag.forum || mFeedInfo.flag.posted) {
|
|
ui->msgReadAllButton->setEnabled(false);
|
|
|
|
if (mFeedInfo.flag.forum && mFeedInfo.flag.posted) {
|
|
ui->msgTreeWidget->setPlaceholderText(tr("The messages will be added to the forum and the board"));
|
|
} else {
|
|
if (mFeedInfo.flag.forum) {
|
|
ui->msgTreeWidget->setPlaceholderText(tr("The messages will be added to the forum"));
|
|
}
|
|
if (mFeedInfo.flag.posted) {
|
|
ui->msgTreeWidget->setPlaceholderText(tr("The messages will be added to the board"));
|
|
}
|
|
}
|
|
} else {
|
|
ui->msgReadAllButton->setEnabled(true);
|
|
ui->msgTreeWidget->setPlaceholderText("");
|
|
}
|
|
}
|
|
|
|
updateMsgs();
|
|
updateCurrentMessage();
|
|
|
|
emit feedMessageChanged(this);
|
|
}
|
|
|
|
QString FeedReaderMessageWidget::feedName(bool withUnreadCount)
|
|
{
|
|
QString name = mFeedInfo.name.empty() ? tr("No name") : QString::fromUtf8(mFeedInfo.name.c_str());
|
|
|
|
if (withUnreadCount && mUnreadCount) {
|
|
name += QString(" (%1)").arg(mUnreadCount);
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
QIcon FeedReaderMessageWidget::feedIcon()
|
|
{
|
|
QIcon icon = FeedReaderDialog::iconFromFeed(mFeedInfo);
|
|
|
|
if (mFeedInfo.flag.deactivated) {
|
|
/* create disabled icon */
|
|
icon = icon.pixmap(QSize(16, 16), QIcon::Disabled);
|
|
}
|
|
|
|
if (mFeedId) {
|
|
QImage overlayIcon;
|
|
|
|
if (mFeedInfo.workstate != FeedInfo::WAITING) {
|
|
/* overlaying icon */
|
|
overlayIcon = QImage(":/images/FeedProcessOverlay.png");
|
|
} else if (mFeedInfo.errorState != RS_FEED_ERRORSTATE_OK) {
|
|
overlayIcon = QImage(":/images/FeedErrorOverlay.png");
|
|
} else if (mNewCount) {
|
|
overlayIcon = QImage(":/images/FeedNewOverlay.png");
|
|
}
|
|
if (!overlayIcon.isNull()) {
|
|
if (icon.isNull()) {
|
|
icon = QPixmap::fromImage(overlayIcon);
|
|
} else {
|
|
QPixmap pixmap = icon.pixmap(QSize(16, 16));
|
|
QPainter painter(&pixmap);
|
|
painter.drawImage(0, 0, overlayIcon.scaled(pixmap.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
|
painter.end();
|
|
icon = pixmap;
|
|
}
|
|
}
|
|
}
|
|
|
|
return icon;
|
|
}
|
|
|
|
std::string FeedReaderMessageWidget::currentMsgId()
|
|
{
|
|
QTreeWidgetItem *item = ui->msgTreeWidget->currentItem();
|
|
if (!item) {
|
|
return "";
|
|
}
|
|
|
|
return item->data(COLUMN_MSG_DATA, ROLE_MSG_ID).toString().toStdString();
|
|
}
|
|
|
|
void FeedReaderMessageWidget::msgTreeCustomPopupMenu(QPoint /*point*/)
|
|
{
|
|
QMenu contextMnu(this);
|
|
|
|
QList<QTreeWidgetItem*> selectedItems = ui->msgTreeWidget->selectedItems();
|
|
|
|
QAction *action = contextMnu.addAction(QIcon(""), tr("Mark as read"), this, SLOT(markAsReadMsg()));
|
|
action->setEnabled(!selectedItems.empty());
|
|
|
|
action = contextMnu.addAction(QIcon(""), tr("Mark as unread"), this, SLOT(markAsUnreadMsg()));
|
|
action->setEnabled(!selectedItems.empty());
|
|
|
|
action = contextMnu.addAction(QIcon(""), tr("Mark all as read"), this, SLOT(markAllAsReadMsg()));
|
|
action->setEnabled(mFeedId);
|
|
|
|
contextMnu.addSeparator();
|
|
|
|
action = contextMnu.addAction(QIcon(""), tr("Copy link"), this, SLOT(copySelectedLinksMsg()));
|
|
action->setEnabled(!selectedItems.empty());
|
|
|
|
action = contextMnu.addAction(QIcon(""), tr("Remove"), this, SLOT(removeMsg()));
|
|
action->setEnabled(!selectedItems.empty());
|
|
|
|
if (selectedItems.size() == 1 && (mFeedReader->forums() || mFeedReader->posted())) {
|
|
contextMnu.addSeparator();
|
|
|
|
if (mFeedReader->forums()) {
|
|
QMenu *menu = contextMnu.addMenu(tr("Add to forum"));
|
|
connect(menu, SIGNAL(aboutToShow()), this, SLOT(fillForumMenu()));
|
|
}
|
|
|
|
if (mFeedReader->posted()) {
|
|
QMenu *menu = contextMnu.addMenu(tr("Add to board"));
|
|
connect(menu, SIGNAL(aboutToShow()), this, SLOT(fillPostedMenu()));
|
|
}
|
|
}
|
|
|
|
contextMnu.addSeparator();
|
|
|
|
action = contextMnu.addAction(QIcon(""), tr("Retransform"), this, SLOT(retransformMsg()));
|
|
action->setEnabled((mFeedInfo.transformationType != RS_FEED_TRANSFORMATION_TYPE_NONE) && !selectedItems.empty());
|
|
|
|
contextMnu.exec(QCursor::pos());
|
|
}
|
|
|
|
void FeedReaderMessageWidget::updateMsgs()
|
|
{
|
|
if (mFeedId == 0) {
|
|
ui->msgTreeWidget->clear();
|
|
return;
|
|
}
|
|
|
|
std::list<FeedMsgInfo> msgInfos;
|
|
if (!mFeedReader->getFeedMsgList(mFeedId, msgInfos)) {
|
|
ui->msgTreeWidget->clear();
|
|
return;
|
|
}
|
|
|
|
int index = 0;
|
|
QTreeWidgetItem *item;
|
|
std::list<FeedMsgInfo>::iterator msgIt;
|
|
|
|
/* update existing and delete not existing msgs */
|
|
while (index < ui->msgTreeWidget->topLevelItemCount()) {
|
|
item = ui->msgTreeWidget->topLevelItem(index);
|
|
std::string msgId = item->data(COLUMN_MSG_DATA, ROLE_MSG_ID).toString().toStdString();
|
|
|
|
/* search existing msg */
|
|
int found = -1;
|
|
for (msgIt = msgInfos.begin (); msgIt != msgInfos.end (); ++msgIt) {
|
|
if (msgIt->msgId == msgId) {
|
|
/* found it, update it */
|
|
updateMsgItem(item, *msgIt);
|
|
|
|
msgInfos.erase(msgIt);
|
|
found = index;
|
|
break;
|
|
}
|
|
}
|
|
if (found >= 0) {
|
|
++index;
|
|
} else {
|
|
delete(ui->msgTreeWidget->takeTopLevelItem(index));
|
|
}
|
|
}
|
|
|
|
/* add new msgs */
|
|
for (msgIt = msgInfos.begin (); msgIt != msgInfos.end (); ++msgIt) {
|
|
item = new RSTreeWidgetItem(mMsgCompareRole);
|
|
updateMsgItem(item, *msgIt);
|
|
ui->msgTreeWidget->addTopLevelItem(item);
|
|
}
|
|
|
|
filterItems(ui->filterLineEdit->text());
|
|
}
|
|
|
|
void FeedReaderMessageWidget::calculateMsgIconsAndFonts(QTreeWidgetItem *item)
|
|
{
|
|
if (!item) {
|
|
return;
|
|
}
|
|
|
|
bool isnew = item->data(COLUMN_MSG_DATA, ROLE_MSG_NEW).toBool();
|
|
bool read = item->data(COLUMN_MSG_DATA, ROLE_MSG_READ).toBool();
|
|
|
|
if (read) {
|
|
item->setIcon(COLUMN_MSG_READ, QIcon(":/images/message-state-read.png"));
|
|
} else {
|
|
item->setIcon(COLUMN_MSG_READ, QIcon(":/images/message-state-unread.png"));
|
|
}
|
|
if (isnew) {
|
|
item->setIcon(COLUMN_MSG_TITLE, QIcon(":/images/message-state-new.png"));
|
|
} else {
|
|
item->setIcon(COLUMN_MSG_TITLE, QIcon());
|
|
}
|
|
|
|
for (int i = 0; i < COLUMN_MSG_COUNT; i++) {
|
|
QFont font = item->font(i);
|
|
font.setBold(isnew || !read);
|
|
item->setFont(i, font);
|
|
}
|
|
|
|
item->setData(COLUMN_MSG_READ, ROLE_MSG_SORT, QString("%1_%2_%3").arg(QString(isnew ? "1" : "0"), QString(read ? "0" : "1"), item->data(COLUMN_MSG_TITLE, ROLE_MSG_SORT).toString()));
|
|
}
|
|
|
|
void FeedReaderMessageWidget::updateMsgItem(QTreeWidgetItem *item, FeedMsgInfo &info)
|
|
{
|
|
QString title = QString::fromUtf8(info.title.c_str());
|
|
QDateTime qdatetime;
|
|
qdatetime.setTime_t(info.pubDate);
|
|
|
|
/* add string to all data */
|
|
QString sort = QString("%1_%2_%3").arg(title, qdatetime.toString("yyyyMMdd_hhmmss")).arg(info.feedId);
|
|
|
|
item->setText(COLUMN_MSG_TITLE, title);
|
|
item->setData(COLUMN_MSG_TITLE, ROLE_MSG_SORT, sort);
|
|
|
|
QString author = QString::fromUtf8(info.author.c_str());
|
|
item->setText(COLUMN_MSG_AUTHOR, author);
|
|
item->setData(COLUMN_MSG_AUTHOR, ROLE_MSG_SORT, author + "_" + sort);
|
|
|
|
/* if the message is on same date show only time */
|
|
if (qdatetime.daysTo(QDateTime::currentDateTime()) == 0) {
|
|
item->setData(COLUMN_MSG_PUBDATE, Qt::DisplayRole, qdatetime.time());
|
|
} else {
|
|
item->setData(COLUMN_MSG_PUBDATE, Qt::DisplayRole, qdatetime);
|
|
}
|
|
item->setData(COLUMN_MSG_PUBDATE, ROLE_MSG_SORT, QString("%1_%2_%3").arg(qdatetime.toString("yyyyMMdd_hhmmss"), title, QString::fromStdString(info.msgId)));
|
|
|
|
item->setData(COLUMN_MSG_DATA, ROLE_MSG_ID, QString::fromStdString(info.msgId));
|
|
item->setData(COLUMN_MSG_DATA, ROLE_MSG_LINK, QString::fromUtf8(info.link.c_str()));
|
|
item->setData(COLUMN_MSG_DATA, ROLE_MSG_READ, info.flag.read);
|
|
item->setData(COLUMN_MSG_DATA, ROLE_MSG_NEW, info.flag.isnew);
|
|
|
|
calculateMsgIconsAndFonts(item);
|
|
}
|
|
|
|
void FeedReaderMessageWidget::feedChanged(uint32_t feedId, int type)
|
|
{
|
|
if (feedId == 0) {
|
|
return;
|
|
}
|
|
|
|
if (feedId != mFeedId) {
|
|
return;
|
|
}
|
|
|
|
if (type == NOTIFY_TYPE_DEL) {
|
|
setFeedId(0);
|
|
return;
|
|
}
|
|
|
|
if (type == NOTIFY_TYPE_MOD) {
|
|
if (!mFeedReader->getFeedInfo(mFeedId, mFeedInfo)) {
|
|
setFeedId(0);
|
|
return;
|
|
}
|
|
|
|
emit feedMessageChanged(this);
|
|
}
|
|
}
|
|
|
|
void FeedReaderMessageWidget::msgChanged(uint32_t feedId, const QString &msgId, int type)
|
|
{
|
|
if (feedId == 0 || msgId.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
if (feedId != mFeedId) {
|
|
return;
|
|
}
|
|
|
|
uint32_t unreadCount;
|
|
uint32_t newCount;
|
|
mFeedReader->getMessageCount(mFeedId, NULL, &newCount, &unreadCount);
|
|
if (unreadCount != mUnreadCount || newCount || mNewCount) {
|
|
mUnreadCount = unreadCount;
|
|
mNewCount = newCount;
|
|
emit feedMessageChanged(this);
|
|
}
|
|
|
|
if (!isVisible()) {
|
|
/* complete update in showEvent */
|
|
return;
|
|
}
|
|
|
|
FeedMsgInfo msgInfo;
|
|
if (type != NOTIFY_TYPE_DEL) {
|
|
if (!mFeedReader->getMsgInfo(feedId, msgId.toStdString(), msgInfo)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (type == NOTIFY_TYPE_MOD || type == NOTIFY_TYPE_DEL) {
|
|
QTreeWidgetItemIterator it(ui->msgTreeWidget);
|
|
QTreeWidgetItem *item;
|
|
while ((item = *it) != NULL) {
|
|
if (item->data(COLUMN_MSG_DATA, ROLE_MSG_ID).toString() == msgId) {
|
|
if (type == NOTIFY_TYPE_MOD) {
|
|
updateMsgItem(item, msgInfo);
|
|
filterItem(item);
|
|
} else {
|
|
delete(item);
|
|
}
|
|
break;
|
|
}
|
|
++it;
|
|
}
|
|
}
|
|
|
|
if (type == NOTIFY_TYPE_MOD) {
|
|
if (msgId.toStdString() == currentMsgId()) {
|
|
updateCurrentMessage();
|
|
}
|
|
}
|
|
|
|
if (type == NOTIFY_TYPE_ADD) {
|
|
QTreeWidgetItem *item = new RSTreeWidgetItem(mMsgCompareRole);
|
|
updateMsgItem(item, msgInfo);
|
|
ui->msgTreeWidget->addTopLevelItem(item);
|
|
filterItem(item);
|
|
}
|
|
}
|
|
|
|
void FeedReaderMessageWidget::msgItemClicked(QTreeWidgetItem *item, int column)
|
|
{
|
|
if (item == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (column == COLUMN_MSG_READ) {
|
|
QList<QTreeWidgetItem*> rows;
|
|
rows.append(item);
|
|
bool read = item->data(COLUMN_MSG_DATA, ROLE_MSG_READ).toBool();
|
|
setMsgAsReadUnread(rows, !read);
|
|
return;
|
|
}
|
|
|
|
// show current message directly
|
|
updateCurrentMessage();
|
|
}
|
|
|
|
void FeedReaderMessageWidget::msgItemChanged()
|
|
{
|
|
mTimer->stop();
|
|
mTimer->start();
|
|
}
|
|
|
|
void FeedReaderMessageWidget::clearMessage()
|
|
{
|
|
ui->msgTitle->clear();
|
|
// ui->msgLink->clear();
|
|
ui->msgText->clear();
|
|
ui->msgTextSplitter->clear();
|
|
ui->attachmentLabel->clear();
|
|
ui->linkButton->setEnabled(false);
|
|
ui->msgText->show();
|
|
ui->pictureSplitter->hide();
|
|
|
|
ui->actionAttachmentCopyLinkLocation->setData(QVariant());
|
|
ui->actionAttachmentCopyLinkLocation->setEnabled(false);
|
|
}
|
|
|
|
void FeedReaderMessageWidget::updateCurrentMessage()
|
|
{
|
|
mTimer->stop();
|
|
|
|
#warning FeedReaderMessageWidget.cpp TODO thunder2: show link somewhere
|
|
|
|
std::string msgId = currentMsgId();
|
|
|
|
if (mFeedId == 0 || msgId.empty()) {
|
|
clearMessage();
|
|
|
|
ui->msgReadButton->setEnabled(false);
|
|
ui->msgUnreadButton->setEnabled(false);
|
|
ui->msgRemoveButton->setEnabled(false);
|
|
return;
|
|
}
|
|
|
|
QTreeWidgetItem *item = ui->msgTreeWidget->currentItem();
|
|
if (!item) {
|
|
/* there is something wrong */
|
|
clearMessage();
|
|
|
|
ui->msgReadButton->setEnabled(false);
|
|
ui->msgUnreadButton->setEnabled(false);
|
|
ui->msgRemoveButton->setEnabled(false);
|
|
return;
|
|
}
|
|
|
|
ui->msgReadButton->setEnabled(true);
|
|
ui->msgUnreadButton->setEnabled(true);
|
|
ui->msgRemoveButton->setEnabled(true);
|
|
|
|
/* get msg */
|
|
FeedMsgInfo msgInfo;
|
|
if (!mFeedReader->getMsgInfo(mFeedId, msgId, msgInfo)) {
|
|
clearMessage();
|
|
return;
|
|
}
|
|
|
|
bool setToReadOnActive = FeedReaderSetting_SetMsgToReadOnActivate();
|
|
bool isnew = item->data(COLUMN_MSG_DATA, ROLE_MSG_NEW).toBool();
|
|
bool read = item->data(COLUMN_MSG_DATA, ROLE_MSG_READ).toBool();
|
|
|
|
QList<QTreeWidgetItem*> row;
|
|
row.append(item);
|
|
if (read) {
|
|
if (isnew) {
|
|
/* something wrong, but set as read again to clear the new flag */
|
|
setMsgAsReadUnread(row, true);
|
|
}
|
|
} else {
|
|
/* set to read/unread */
|
|
setMsgAsReadUnread(row, setToReadOnActive);
|
|
}
|
|
|
|
ui->actionAttachmentCopyLinkLocation->setData(QVariant());
|
|
ui->actionAttachmentCopyLinkLocation->setEnabled(false);
|
|
|
|
if (!msgInfo.attachment.empty()) {
|
|
QByteArray imageData((char*) msgInfo.attachment.data(), msgInfo.attachment.size());
|
|
QPixmap pixmap;
|
|
if (pixmap.loadFromData(imageData)) {
|
|
ui->attachmentLabel->setPixmap(pixmap);
|
|
ui->pictureSplitter->show();
|
|
ui->msgText->hide();
|
|
} else {
|
|
ui->pictureSplitter->hide();
|
|
ui->msgText->show();
|
|
}
|
|
|
|
if (!msgInfo.attachmentLink.empty()) {
|
|
ui->actionAttachmentCopyLinkLocation->setData(QString::fromUtf8(msgInfo.attachmentLink.c_str()));
|
|
ui->actionAttachmentCopyLinkLocation->setEnabled(true);
|
|
}
|
|
} else {
|
|
ui->pictureSplitter->hide();
|
|
ui->msgText->show();
|
|
}
|
|
|
|
QString msgTxt = RsHtml().formatText(ui->msgText->document(), QString::fromUtf8((msgInfo.descriptionTransformed.empty() ? msgInfo.description : msgInfo.descriptionTransformed).c_str()), RSHTML_FORMATTEXT_EMBED_LINKS);
|
|
|
|
if (ui->pictureSplitter->isVisible()) {
|
|
ui->msgTextSplitter->setHtml(msgTxt);
|
|
ui->msgText->clear();
|
|
} else {
|
|
ui->msgText->setHtml(msgTxt);
|
|
ui->msgTextSplitter->clear();
|
|
ui->attachmentLabel->clear();
|
|
}
|
|
|
|
ui->msgTitle->setText(QString::fromUtf8(msgInfo.title.c_str()));
|
|
|
|
ui->linkButton->setEnabled(!msgInfo.link.empty());
|
|
}
|
|
|
|
void FeedReaderMessageWidget::setMsgAsReadUnread(QList<QTreeWidgetItem *> &rows, bool read)
|
|
{
|
|
QList<QTreeWidgetItem*>::iterator rowIt;
|
|
|
|
if (mFeedId == 0) {
|
|
return;
|
|
}
|
|
|
|
for (rowIt = rows.begin(); rowIt != rows.end(); rowIt++) {
|
|
QTreeWidgetItem *item = *rowIt;
|
|
bool rowRead = item->data(COLUMN_MSG_DATA, ROLE_MSG_READ).toBool();
|
|
bool rowNew = item->data(COLUMN_MSG_DATA, ROLE_MSG_NEW).toBool();
|
|
|
|
if (rowNew || read != rowRead) {
|
|
std::string msgId = item->data(COLUMN_MSG_DATA, ROLE_MSG_ID).toString().toStdString();
|
|
mFeedReader->setMessageRead(mFeedId, msgId, read);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FeedReaderMessageWidget::filterColumnChanged(int column)
|
|
{
|
|
if (mProcessSettings) {
|
|
return;
|
|
}
|
|
|
|
filterItems(ui->filterLineEdit->text());
|
|
|
|
// save index
|
|
Settings->setValueToGroup("FeedReaderDialog", "filterColumn", column);
|
|
}
|
|
|
|
void FeedReaderMessageWidget::filterItems(const QString& text)
|
|
{
|
|
int filterColumn = ui->filterLineEdit->currentFilter();
|
|
|
|
int count = ui->msgTreeWidget->topLevelItemCount();
|
|
for (int index = 0; index < count; ++index) {
|
|
filterItem(ui->msgTreeWidget->topLevelItem(index), text, filterColumn);
|
|
}
|
|
}
|
|
|
|
void FeedReaderMessageWidget::filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn)
|
|
{
|
|
if (text.isEmpty() == false) {
|
|
if (item->text(filterColumn).contains(text, Qt::CaseInsensitive)) {
|
|
item->setHidden(false);
|
|
} else {
|
|
item->setHidden(true);
|
|
}
|
|
} else {
|
|
item->setHidden(false);
|
|
}
|
|
}
|
|
|
|
void FeedReaderMessageWidget::filterItem(QTreeWidgetItem *item)
|
|
{
|
|
filterItem(item, ui->filterLineEdit->text(), ui->filterLineEdit->currentFilter());
|
|
}
|
|
|
|
void FeedReaderMessageWidget::toggleMsgText()
|
|
{
|
|
// save state of button
|
|
Settings->setValueToGroup("FeedReaderDialog", "expandButton", ui->expandButton->isChecked());
|
|
|
|
toggleMsgText_internal();
|
|
}
|
|
|
|
void FeedReaderMessageWidget::toggleMsgText_internal()
|
|
{
|
|
if (ui->expandButton->isChecked()) {
|
|
ui->horizontalLayoutWidget->setVisible(true);
|
|
ui->expandButton->setIcon(QIcon(QString(":/images/edit_remove24.png")));
|
|
ui->expandButton->setToolTip(tr("Hide"));
|
|
} else {
|
|
ui->horizontalLayoutWidget->setVisible(false);
|
|
ui->expandButton->setIcon(QIcon(QString(":/images/edit_add24.png")));
|
|
ui->expandButton->setToolTip(tr("Expand"));
|
|
}
|
|
}
|
|
|
|
void FeedReaderMessageWidget::markAsReadMsg()
|
|
{
|
|
QList<QTreeWidgetItem*> selectedItems = ui->msgTreeWidget->selectedItems();
|
|
setMsgAsReadUnread(selectedItems, true);
|
|
}
|
|
|
|
void FeedReaderMessageWidget::markAsUnreadMsg()
|
|
{
|
|
QList<QTreeWidgetItem*> selectedItems = ui->msgTreeWidget->selectedItems();
|
|
setMsgAsReadUnread(selectedItems, false);
|
|
}
|
|
|
|
void FeedReaderMessageWidget::markAllAsReadMsg()
|
|
{
|
|
QList<QTreeWidgetItem*> items;
|
|
|
|
QTreeWidgetItemIterator it(ui->msgTreeWidget);
|
|
QTreeWidgetItem *item;
|
|
while ((item = *it) != NULL) {
|
|
if (!item->isHidden()) {
|
|
items.push_back(item);
|
|
}
|
|
++it;
|
|
}
|
|
setMsgAsReadUnread(items, true);
|
|
}
|
|
|
|
void FeedReaderMessageWidget::copySelectedLinksMsg()
|
|
{
|
|
QString links;
|
|
|
|
QTreeWidgetItemIterator it(ui->msgTreeWidget, QTreeWidgetItemIterator::Selected);
|
|
QTreeWidgetItem *item;
|
|
while ((item = *it) != NULL) {
|
|
QString link = item->data(COLUMN_MSG_DATA, ROLE_MSG_LINK).toString();
|
|
if (!link.isEmpty()) {
|
|
links += link + "\n";
|
|
}
|
|
++it;
|
|
}
|
|
|
|
if (links.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
QApplication::clipboard()->setText(links);
|
|
}
|
|
|
|
void FeedReaderMessageWidget::removeMsg()
|
|
{
|
|
if (mFeedId == 0) {
|
|
return;
|
|
}
|
|
|
|
QList<QTreeWidgetItem*> selectedItems = ui->msgTreeWidget->selectedItems();
|
|
QList<QTreeWidgetItem*>::iterator it;
|
|
std::list<std::string> msgIds;
|
|
|
|
for (it = selectedItems.begin(); it != selectedItems.end(); ++it) {
|
|
msgIds.push_back((*it)->data(COLUMN_MSG_DATA, ROLE_MSG_ID).toString().toStdString());
|
|
}
|
|
mFeedReader->removeMsgs(mFeedId, msgIds);
|
|
}
|
|
|
|
void FeedReaderMessageWidget::retransformMsg()
|
|
{
|
|
if (mFeedId == 0) {
|
|
return;
|
|
}
|
|
|
|
QList<QTreeWidgetItem*> selectedItems = ui->msgTreeWidget->selectedItems();
|
|
QList<QTreeWidgetItem*>::iterator it;
|
|
|
|
for (it = selectedItems.begin(); it != selectedItems.end(); ++it) {
|
|
mFeedReader->retransformMsg(mFeedId, (*it)->data(COLUMN_MSG_DATA, ROLE_MSG_ID).toString().toStdString());
|
|
}
|
|
}
|
|
|
|
void FeedReaderMessageWidget::processFeed()
|
|
{
|
|
if (mFeedId == 0) {
|
|
return;
|
|
}
|
|
|
|
mFeedReader->processFeed(mFeedId);
|
|
}
|
|
|
|
void FeedReaderMessageWidget::copyLinkMsg()
|
|
{
|
|
QTreeWidgetItem *item = ui->msgTreeWidget->currentItem();
|
|
if (!item) {
|
|
return;
|
|
}
|
|
|
|
QString link = item->data(COLUMN_MSG_DATA, ROLE_MSG_LINK).toString();
|
|
if (link.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
QApplication::clipboard()->setText(link);
|
|
}
|
|
|
|
void FeedReaderMessageWidget::openLinkMsg()
|
|
{
|
|
QTreeWidgetItem *item = ui->msgTreeWidget->currentItem();
|
|
if (!item) {
|
|
return;
|
|
}
|
|
|
|
QString link = item->data(COLUMN_MSG_DATA, ROLE_MSG_LINK).toString();
|
|
if (link.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
QDesktopServices::openUrl(QUrl(link));
|
|
}
|
|
|
|
void FeedReaderMessageWidget::fillForumMenu()
|
|
{
|
|
QMenu *menu = dynamic_cast<QMenu*>(sender()) ;
|
|
if (!menu) {
|
|
return;
|
|
}
|
|
|
|
disconnect(menu, SIGNAL(aboutToShow()), this, SLOT(fillForumMenu()));
|
|
|
|
std::vector<RsGxsForumGroup> groups;
|
|
if (mFeedReader->getForumGroups(groups, true)) {
|
|
for (std::vector<RsGxsForumGroup>::iterator it = groups.begin(); it != groups.end(); ++it) {
|
|
const RsGxsForumGroup &group = *it;
|
|
QAction *action = menu->addAction(QString::fromUtf8(group.mMeta.mGroupName.c_str()), this, SLOT(addToForum()));
|
|
action->setData(QString::fromUtf8(group.mMeta.mGroupId.toStdString().c_str()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void FeedReaderMessageWidget::fillPostedMenu()
|
|
{
|
|
QMenu *menu = dynamic_cast<QMenu*>(sender()) ;
|
|
if (!menu) {
|
|
return;
|
|
}
|
|
|
|
disconnect(menu, SIGNAL(aboutToShow()), this, SLOT(fillPostedMenu()));
|
|
|
|
std::vector<RsPostedGroup> groups;
|
|
if (mFeedReader->getPostedGroups(groups, true)) {
|
|
for (std::vector<RsPostedGroup>::iterator it = groups.begin(); it != groups.end(); ++it) {
|
|
const RsPostedGroup &group = *it;
|
|
QAction *action = menu->addAction(QString::fromUtf8(group.mMeta.mGroupName.c_str()), this, SLOT(addToPosted()));
|
|
action->setData(QString::fromUtf8(group.mMeta.mGroupId.toStdString().c_str()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void FeedReaderMessageWidget::addToForum()
|
|
{
|
|
QAction *action = dynamic_cast<QAction*>(sender()) ;
|
|
if (!action) {
|
|
return;
|
|
}
|
|
|
|
QString id = action->data().toString();
|
|
if (id.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
QList<QTreeWidgetItem*> selectedItems = ui->msgTreeWidget->selectedItems();
|
|
if (selectedItems.size() != 1) {
|
|
return;
|
|
}
|
|
|
|
std::string msgId = selectedItems[0]->data(COLUMN_MSG_DATA, ROLE_MSG_ID).toString().toStdString();
|
|
FeedMsgInfo msgInfo;
|
|
if (!mFeedReader->getMsgInfo(mFeedId, msgId, msgInfo)) {
|
|
return;
|
|
}
|
|
|
|
RsGxsGroupId forumId(id.toStdString());
|
|
|
|
CreateGxsForumMsg *msgDialog = new CreateGxsForumMsg(forumId, RsGxsMessageId(), RsGxsMessageId(), RsGxsId()) ;
|
|
msgDialog->setSubject(QString::fromUtf8(msgInfo.title.c_str()));
|
|
msgDialog->insertPastedText(QString::fromUtf8(msgInfo.description.c_str()));
|
|
msgDialog->show();
|
|
}
|
|
|
|
void FeedReaderMessageWidget::addToPosted()
|
|
{
|
|
QAction *action = dynamic_cast<QAction*>(sender()) ;
|
|
if (!action) {
|
|
return;
|
|
}
|
|
|
|
QString id = action->data().toString();
|
|
if (id.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
QList<QTreeWidgetItem*> selectedItems = ui->msgTreeWidget->selectedItems();
|
|
if (selectedItems.size() != 1) {
|
|
return;
|
|
}
|
|
|
|
std::string msgId = selectedItems[0]->data(COLUMN_MSG_DATA, ROLE_MSG_ID).toString().toStdString();
|
|
FeedMsgInfo msgInfo;
|
|
if (!mFeedReader->getMsgInfo(mFeedId, msgId, msgInfo)) {
|
|
return;
|
|
}
|
|
|
|
RsGxsGroupId postedId(id.toStdString());
|
|
|
|
PostedCreatePostDialog *msgDialog = new PostedCreatePostDialog(mFeedReader->posted(), postedId);
|
|
msgDialog->setTitle(QString::fromUtf8(msgInfo.title.c_str()));
|
|
msgDialog->setNotes(QString::fromUtf8(msgInfo.description.c_str()));
|
|
msgDialog->setLink(QString::fromUtf8(msgInfo.link.c_str()));
|
|
msgDialog->show();
|
|
}
|
|
|
|
void FeedReaderMessageWidget::attachmentCopyLinkLocation()
|
|
{
|
|
QAction *action = dynamic_cast<QAction*>(sender()) ;
|
|
if (!action) {
|
|
return;
|
|
}
|
|
|
|
QVariant data = action->data();
|
|
if (!data.isValid()) {
|
|
return;
|
|
}
|
|
|
|
if (data.type() != QVariant::String) {
|
|
return;
|
|
}
|
|
|
|
QApplication::clipboard()->setText(data.toString());
|
|
}
|