RetroShare/retroshare-gui/src/gui/GxsForumsDialog.cpp

2516 lines
75 KiB
C++
Raw Normal View History

/****************************************************************
* RetroShare is distributed under the following license:
*
* Copyright (C) 2008 Robert Fernie
*
* This program is free 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 2
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
****************************************************************/
#include <QMenu>
#include <QFile>
#include <QDateTime>
#include <QMessageBox>
#include <QKeyEvent>
#include <QProgressBar>
#include "GxsForumsDialog.h"
#include "gxs/GxsForumGroupDialog.h"
#include "gxsforums/CreateGxsForumMsg.h"
#include "msgs/MessageComposer.h"
#include "settings/rsharesettings.h"
#include "common/Emoticons.h"
#include "common/RSItemDelegate.h"
#include "common/PopularityDefs.h"
#include "RetroShareLink.h"
#include "channels/ShareKey.h"
#include "notifyqt.h"
#include "util/HandleRichText.h"
#include <retroshare/rspeers.h>
#include <retroshare/rsgxsforums.h>
// These should be in retroshare/ folder.
#include "gxs/rsgxsflags.h"
#include <algorithm>
//#define DEBUG_FORUMS
/* Images for context menu icons */
#define IMAGE_MESSAGE ":/images/folder-draft.png"
#define IMAGE_MESSAGEREPLY ":/images/mail_reply.png"
#define IMAGE_MESSAGEREMOVE ":/images/mail_delete.png"
#define IMAGE_DOWNLOAD ":/images/start.png"
#define IMAGE_DOWNLOADALL ":/images/startall.png"
/* Images for TreeWidget */
#define IMAGE_FOLDER ":/images/folder16.png"
#define IMAGE_FOLDERGREEN ":/images/folder_green.png"
#define IMAGE_FOLDERRED ":/images/folder_red.png"
#define IMAGE_FOLDERYELLOW ":/images/folder_yellow.png"
#define IMAGE_FORUM ":/images/konversation.png"
#define IMAGE_SUBSCRIBE ":/images/edit_add24.png"
#define IMAGE_UNSUBSCRIBE ":/images/cancel.png"
#define IMAGE_INFO ":/images/info16.png"
#define IMAGE_NEWFORUM ":/images/new_forum16.png"
#define IMAGE_FORUMAUTHD ":/images/konv_message2.png"
#define IMAGE_COPYLINK ":/images/copyrslink.png"
#define VIEW_LAST_POST 0
#define VIEW_THREADED 1
#define VIEW_FLAT 2
/* Thread constants */
#define COLUMN_THREAD_COUNT 6
#define COLUMN_THREAD_TITLE 0
#define COLUMN_THREAD_READ 1
#define COLUMN_THREAD_DATE 2
#define COLUMN_THREAD_AUTHOR 3
#define COLUMN_THREAD_SIGNED 4
#define COLUMN_THREAD_CONTENT 5
#define COLUMN_THREAD_DATA 0 // column for storing the userdata like msgid and parentid
#define ROLE_THREAD_MSGID Qt::UserRole
#define ROLE_THREAD_STATUS Qt::UserRole + 1
#define ROLE_THREAD_MISSING Qt::UserRole + 2
// no need to copy, don't count in ROLE_THREAD_COUNT
#define ROLE_THREAD_READCHILDREN Qt::UserRole + 3
#define ROLE_THREAD_UNREADCHILDREN Qt::UserRole + 4
#define ROLE_THREAD_COUNT 3
static int FilterColumnFromComboBox(int nIndex)
{
switch (nIndex) {
case 0:
return COLUMN_THREAD_DATE;
case 1:
return COLUMN_THREAD_TITLE;
case 2:
return COLUMN_THREAD_AUTHOR;
case 3:
return COLUMN_THREAD_CONTENT;
}
return COLUMN_THREAD_TITLE;
}
static int FilterColumnToComboBox(int nIndex)
{
switch (nIndex) {
case COLUMN_THREAD_DATE:
return 0;
case COLUMN_THREAD_TITLE:
return 1;
case COLUMN_THREAD_AUTHOR:
return 2;
case COLUMN_THREAD_CONTENT:
return 3;
}
return FilterColumnToComboBox(COLUMN_THREAD_TITLE);
}
/*
* Transformation Notes:
* there are still a couple of things that the new forums differ from Old version.
* these will need to be addressed in the future.
* -> Missing Messages are not handled yet.
* -> Child TS (for sorting) is not handled by GXS, this will probably have to be done in the GUI.
* -> Need to handle IDs properly.
* -> Popularity not handled in GXS yet.
* -> Much more to do.
*/
/** Constructor */
GxsForumsDialog::GxsForumsDialog(QWidget *parent)
: RsAutoUpdatePage(1000,parent)
{
/* Invoke the Qt Designer generated object setup routine */
ui.setupUi(this);
m_bProcessSettings = false;
subscribeFlags = 0;
inMsgAsReadUnread = false;
/* Setup Queue */
mForumQueue = new TokenQueue(rsGxsForums->getTokenService(), this);
connect( ui.forumTreeWidget, SIGNAL( treeCustomContextMenuRequested( QPoint ) ), this, SLOT( forumListCustomPopupMenu( QPoint ) ) );
connect( ui.threadTreeWidget, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( threadListCustomPopupMenu( QPoint ) ) );
connect(ui.newForumButton, SIGNAL(clicked()), this, SLOT(newforum()));
connect(ui.newmessageButton, SIGNAL(clicked()), this, SLOT(createmessage()));
connect(ui.newthreadButton, SIGNAL(clicked()), this, SLOT(createthread()));
connect( ui.forumTreeWidget, SIGNAL( treeCurrentItemChanged(QString) ), this, SLOT( changedForum(QString) ) );
connect( ui.threadTreeWidget, SIGNAL( itemSelectionChanged() ), this, SLOT( changedThread () ) );
connect( ui.threadTreeWidget, SIGNAL( itemClicked(QTreeWidgetItem*,int)), this, SLOT( clickedThread (QTreeWidgetItem*,int) ) );
connect( ui.viewBox, SIGNAL( currentIndexChanged ( int ) ), this, SLOT( changedViewBox () ) );
connect(ui.expandButton, SIGNAL(clicked()), this, SLOT(togglethreadview()));
connect(ui.previousButton, SIGNAL(clicked()), this, SLOT(previousMessage()));
connect(ui.nextButton, SIGNAL(clicked()), this, SLOT(nextMessage()));
// HACK - TEMPORARY HIJACKING THIS BUTTON FOR REFRESH.
//connect(ui.nextUnreadButton, SIGNAL(clicked()), this, SLOT(nextUnreadMessage()));
connect(ui.nextUnreadButton, SIGNAL(clicked()), this, SLOT(forceUpdateDisplay()));
connect(ui.downloadButton, SIGNAL(clicked()), this, SLOT(downloadAllFiles()));
connect(ui.filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterItems(QString)));
connect(ui.filterColumnComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterColumnChanged()));
connect(NotifyQt::getInstance(), SIGNAL(forumMsgReadSatusChanged(QString,QString,int)), this, SLOT(forumMsgReadSatusChanged(QString,QString,int)));
/* Set initial size the splitter */
QList<int> sizes;
sizes << 300 << width(); // Qt calculates the right sizes
//ui.splitter->setSizes(sizes);
/* Set own item delegate */
RSItemDelegate *itemDelegate = new RSItemDelegate(this);
itemDelegate->setSpacing(QSize(0, 2));
ui.threadTreeWidget->setItemDelegate(itemDelegate);
/* Set header resize modes and initial section sizes */
QHeaderView * ttheader = ui.threadTreeWidget->header () ;
ttheader->setResizeMode (COLUMN_THREAD_TITLE, QHeaderView::Interactive);
ttheader->resizeSection (COLUMN_THREAD_DATE, 140);
ttheader->resizeSection (COLUMN_THREAD_TITLE, 290);
ui.threadTreeWidget->sortItems( COLUMN_THREAD_DATE, Qt::DescendingOrder );
/* Set text of column "Read" to empty - without this the column has a number as header text */
QTreeWidgetItem *headerItem = ui.threadTreeWidget->headerItem();
headerItem->setText(COLUMN_THREAD_READ, "");
m_ForumNameFont = QFont("Times", 12, QFont::Bold);
ui.forumName->setFont(m_ForumNameFont);
ui.threadTitle->setFont(m_ForumNameFont);
/* Initialize group tree */
ui.forumTreeWidget->initDisplayMenu(ui.displayButton);
/* create forum tree */
yourForums = ui.forumTreeWidget->addCategoryItem(tr("Your Forums"), QIcon(IMAGE_FOLDER), true);
subscribedForums = ui.forumTreeWidget->addCategoryItem(tr("Subscribed Forums"), QIcon(IMAGE_FOLDERRED), true);
popularForums = ui.forumTreeWidget->addCategoryItem(tr("Popular Forums"), QIcon(IMAGE_FOLDERGREEN), false);
otherForums = ui.forumTreeWidget->addCategoryItem(tr("Other Forums"), QIcon(IMAGE_FOLDERYELLOW), false);
lastViewType = -1;
// load settings
processSettings(true);
/* Set header sizes for the fixed columns and resize modes, must be set after processSettings */
ttheader->resizeSection (COLUMN_THREAD_READ, 24);
ttheader->setResizeMode (COLUMN_THREAD_READ, QHeaderView::Fixed);
ttheader->hideSection (COLUMN_THREAD_CONTENT);
ui.progressBar->hide();
ui.progLayOutTxt->hide();
ui.progressBarLayOut->setEnabled(false);
mThreadLoading = false;
insertThreads();
ui.threadTreeWidget->installEventFilter(this);
rsGxsForums->generateDummyData();
/* Hide platform specific features */
#ifdef Q_WS_WIN
#endif
}
GxsForumsDialog::~GxsForumsDialog()
{
// save settings
processSettings(false);
}
void GxsForumsDialog::processSettings(bool bLoad)
{
m_bProcessSettings = true;
QHeaderView *pHeader = ui.threadTreeWidget->header () ;
Settings->beginGroup(QString("GxsForumsDialog"));
if (bLoad) {
// load settings
// expandFiles
bool bValue = Settings->value("expandButton", true).toBool();
ui.expandButton->setChecked(bValue);
togglethreadview_internal();
// filterColumn
int nValue = FilterColumnToComboBox(Settings->value("filterColumn", COLUMN_THREAD_TITLE).toInt());
ui.filterColumnComboBox->setCurrentIndex(nValue);
// index of viewBox
ui.viewBox->setCurrentIndex(Settings->value("viewBox", VIEW_THREADED).toInt());
// state of thread tree
pHeader->restoreState(Settings->value("ThreadTree").toByteArray());
// state of splitter
ui.splitter->restoreState(Settings->value("Splitter").toByteArray());
ui.threadSplitter->restoreState(Settings->value("threadSplitter").toByteArray());
} else {
// save settings
// state of thread tree
Settings->setValue("ThreadTree", pHeader->saveState());
// state of splitter
Settings->setValue("Splitter", ui.splitter->saveState());
Settings->setValue("threadSplitter", ui.threadSplitter->saveState());
}
ui.forumTreeWidget->processSettings(Settings, bLoad);
Settings->endGroup();
m_bProcessSettings = false;
}
void GxsForumsDialog::forumListCustomPopupMenu( QPoint /*point*/ )
{
QMenu contextMnu( this );
QAction *action = contextMnu.addAction(QIcon(IMAGE_SUBSCRIBE), tr("Subscribe to Forum"), this, SLOT(subscribeToForum()));
action->setDisabled (mCurrForumId.empty() || IS_GROUP_SUBSCRIBED(subscribeFlags));
action = contextMnu.addAction(QIcon(IMAGE_UNSUBSCRIBE), tr("Unsubscribe to Forum"), this, SLOT(unsubscribeToForum()));
action->setEnabled (!mCurrForumId.empty() && IS_GROUP_SUBSCRIBED(subscribeFlags));
contextMnu.addSeparator();
contextMnu.addAction(QIcon(IMAGE_NEWFORUM), tr("New Forum"), this, SLOT(newforum()));
action = contextMnu.addAction(QIcon(IMAGE_INFO), tr("Show Forum Details"), this, SLOT(showForumDetails()));
action->setEnabled (!mCurrForumId.empty ());
action = contextMnu.addAction(QIcon(":/images/settings16.png"), tr("Edit Forum Details"), this, SLOT(editForumDetails()));
action->setEnabled (!mCurrForumId.empty () && IS_GROUP_ADMIN(subscribeFlags));
QAction *shareKeyAct = new QAction(QIcon(":/images/gpgp_key_generate.png"), tr("Share Forum"), &contextMnu);
connect( shareKeyAct, SIGNAL( triggered() ), this, SLOT( shareKey() ) );
shareKeyAct->setEnabled(!mCurrForumId.empty() && IS_GROUP_ADMIN(subscribeFlags));
contextMnu.addAction( shareKeyAct);
QAction *restoreKeysAct = new QAction(QIcon(":/images/settings16.png"), tr("Restore Publish Rights for Forum" ), &contextMnu);
connect( restoreKeysAct , SIGNAL( triggered() ), this, SLOT( restoreForumKeys() ) );
restoreKeysAct->setEnabled(!mCurrForumId.empty() && !IS_GROUP_ADMIN(subscribeFlags));
contextMnu.addAction( restoreKeysAct);
action = contextMnu.addAction(QIcon(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyForumLink()));
action->setEnabled(!mCurrForumId.empty());
contextMnu.addSeparator();
action = contextMnu.addAction(QIcon(":/images/message-mail-read.png"), tr("Mark all as read"), this, SLOT(markMsgAsReadAll()));
action->setEnabled (!mCurrForumId.empty () && IS_GROUP_SUBSCRIBED(subscribeFlags));
action = contextMnu.addAction(QIcon(":/images/message-mail.png"), tr("Mark all as unread"), this, SLOT(markMsgAsUnreadAll()));
action->setEnabled (!mCurrForumId.empty () && IS_GROUP_SUBSCRIBED(subscribeFlags));
#ifdef DEBUG_FORUMS
contextMnu.addSeparator();
action = contextMnu.addAction("Generate mass data", this, SLOT(generateMassData()));
action->setEnabled (!mCurrForumId.empty() && IS_GROUP_SUBSCRIBED(subscribeFlags));
#endif
contextMnu.exec(QCursor::pos());
}
void GxsForumsDialog::threadListCustomPopupMenu( QPoint /*point*/ )
{
if (mThreadLoading) {
return;
}
QMenu contextMnu( this );
QAction *replyAct = new QAction(QIcon(IMAGE_MESSAGEREPLY), tr( "Reply" ), &contextMnu );
connect( replyAct , SIGNAL( triggered() ), this, SLOT( createmessage() ) );
QAction *newthreadAct = new QAction(QIcon(IMAGE_DOWNLOADALL), tr( "Start New Thread" ), &contextMnu );
newthreadAct->setEnabled (IS_GROUP_SUBSCRIBED(subscribeFlags));
connect( newthreadAct , SIGNAL( triggered() ), this, SLOT( createthread() ) );
QAction *replyauthorAct = new QAction(QIcon(IMAGE_MESSAGEREPLY), tr( "Reply to Author" ), &contextMnu );
connect( replyauthorAct , SIGNAL( triggered() ), this, SLOT( replytomessage() ) );
QAction* expandAll = new QAction(tr( "Expand all" ), &contextMnu );
connect( expandAll , SIGNAL( triggered() ), ui.threadTreeWidget, SLOT (expandAll()) );
QAction* collapseAll = new QAction(tr( "Collapse all" ), &contextMnu );
connect( collapseAll , SIGNAL( triggered() ), ui.threadTreeWidget, SLOT(collapseAll()) );
QAction *markMsgAsRead = new QAction(QIcon(":/images/message-mail-read.png"), tr("Mark as read"), &contextMnu);
connect(markMsgAsRead , SIGNAL(triggered()), this, SLOT(markMsgAsRead()));
QAction *markMsgAsReadChildren = new QAction(QIcon(":/images/message-mail-read.png"), tr("Mark as read") + " (" + tr ("with children") + ")", &contextMnu);
connect(markMsgAsReadChildren, SIGNAL(triggered()), this, SLOT(markMsgAsReadChildren()));
QAction *markMsgAsUnread = new QAction(QIcon(":/images/message-mail.png"), tr("Mark as unread"), &contextMnu);
connect(markMsgAsUnread , SIGNAL(triggered()), this, SLOT(markMsgAsUnread()));
QAction *markMsgAsUnreadChildren = new QAction(QIcon(":/images/message-mail.png"), tr("Mark as unread") + " (" + tr ("with children") + ")", &contextMnu);
connect(markMsgAsUnreadChildren , SIGNAL(triggered()), this, SLOT(markMsgAsUnreadChildren()));
if (IS_GROUP_SUBSCRIBED(subscribeFlags)) {
QList<QTreeWidgetItem*> Rows;
QList<QTreeWidgetItem*> RowsRead;
QList<QTreeWidgetItem*> RowsUnread;
int nCount = getSelectedMsgCount (&Rows, &RowsRead, &RowsUnread);
if (RowsUnread.size() == 0) {
markMsgAsRead->setDisabled(true);
}
if (RowsRead.size() == 0) {
markMsgAsUnread->setDisabled(true);
}
bool bHasUnreadChildren = false;
bool bHasReadChildren = false;
int nRowCount = Rows.count();
for (int i = 0; i < nRowCount; i++) {
if (bHasUnreadChildren || Rows[i]->data(COLUMN_THREAD_DATA, ROLE_THREAD_UNREADCHILDREN).toBool()) {
bHasUnreadChildren = true;
}
if (bHasReadChildren || Rows[i]->data(COLUMN_THREAD_DATA, ROLE_THREAD_READCHILDREN).toBool()) {
bHasReadChildren = true;
}
}
markMsgAsReadChildren->setEnabled(bHasUnreadChildren);
markMsgAsUnreadChildren->setEnabled(bHasReadChildren);
if (nCount == 1) {
replyAct->setEnabled (true);
replyauthorAct->setEnabled (true);
} else {
replyAct->setDisabled (true);
replyauthorAct->setDisabled (true);
}
} else {
markMsgAsRead->setDisabled(true);
markMsgAsReadChildren->setDisabled(true);
markMsgAsUnread->setDisabled(true);
markMsgAsUnreadChildren->setDisabled(true);
replyAct->setDisabled (true);
replyauthorAct->setDisabled (true);
}
contextMnu.addAction( replyAct);
contextMnu.addAction( newthreadAct);
contextMnu.addAction( replyauthorAct);
QAction* action = contextMnu.addAction(QIcon(IMAGE_COPYLINK), tr( "Copy RetroShare Link"), this, SLOT(copyMessageLink()));
action->setEnabled(!mCurrForumId.empty() && !mCurrThreadId.empty());
contextMnu.addSeparator();
contextMnu.addAction(markMsgAsRead);
contextMnu.addAction(markMsgAsReadChildren);
contextMnu.addAction(markMsgAsUnread);
contextMnu.addAction(markMsgAsUnreadChildren);
contextMnu.addSeparator();
contextMnu.addAction( expandAll);
contextMnu.addAction( collapseAll);
contextMnu.exec(QCursor::pos());
}
bool GxsForumsDialog::eventFilter(QObject *obj, QEvent *event)
{
if (obj == ui.threadTreeWidget) {
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent && keyEvent->key() == Qt::Key_Space) {
// Space pressed
QTreeWidgetItem *item = ui.threadTreeWidget->currentItem ();
clickedThread (item, COLUMN_THREAD_READ);
return true; // eat event
}
}
}
// pass the event on to the parent class
return RsAutoUpdatePage::eventFilter(obj, event);
}
void GxsForumsDialog::restoreForumKeys(void)
{
#ifdef TOGXS
rsGxsForums->groupRestoreKeys(mCurrForumId);
#endif
}
void GxsForumsDialog::togglethreadview()
{
// save state of button
Settings->setValueToGroup("GxsForumsDialog", "expandButton", ui.expandButton->isChecked());
togglethreadview_internal();
}
void GxsForumsDialog::togglethreadview_internal()
{
if (ui.expandButton->isChecked()) {
ui.postText->setVisible(true);
ui.expandButton->setIcon(QIcon(QString(":/images/edit_remove24.png")));
ui.expandButton->setToolTip(tr("Hide"));
} else {
ui.postText->setVisible(false);
ui.expandButton->setIcon(QIcon(QString(":/images/edit_add24.png")));
ui.expandButton->setToolTip(tr("Expand"));
}
}
void GxsForumsDialog::updateDisplay()
{
std::list<std::string> forumIds;
std::list<std::string>::iterator it;
if (!rsGxsForums)
return;
#if 0
// TODO groupsChanged... HACK XXX.
if ((rsGxsForums->groupsChanged(forumIds)) || (rsGxsForums->updated()))
{
/* update Forums List */
insertForums();
it = std::find(forumIds.begin(), forumIds.end(), mCurrForumId);
if (it != forumIds.end())
{
/* update threads as well */
insertThreads();
}
}
#endif
/* The proper version (above) can be done with a data request -> TODO */
if (rsGxsForums->updated())
{
/* update Forums List */
insertForums();
/* update threads as well */
insertThreads();
}
}
// HACK until update works.
void GxsForumsDialog::forceUpdateDisplay()
{
std::cerr << "GxsForumsDialog::forceUpdateDisplay()";
std::cerr << std::endl;
/* update Forums List */
insertForums();
/* update threads as well */
insertThreads();
}
static void CleanupItems (QList<QTreeWidgetItem *> &items)
{
QList<QTreeWidgetItem *>::iterator item;
for (item = items.begin (); item != items.end (); item++) {
if (*item) {
delete (*item);
}
}
items.clear();
}
void GxsForumsDialog::forumInfoToGroupItemInfo(const RsGroupMetaData &forumInfo, GroupItemInfo &groupItemInfo)
//void GxsForumsDialog::forumInfoToGroupItemInfo(const ForumInfo &forumInfo, GroupItemInfo &groupItemInfo)
{
groupItemInfo.id = QString::fromStdString(forumInfo.mGroupId);
groupItemInfo.name = QString::fromUtf8(forumInfo.mGroupName.c_str());
//groupItemInfo.description = QString::fromUtf8(forumInfo.forumDesc);
groupItemInfo.popularity = forumInfo.mPop;
groupItemInfo.lastpost = QDateTime::fromTime_t(forumInfo.mLastPost);
#if TOGXS
if (forumInfo.mGroupFlags & RS_DISTRIB_AUTHEN_REQ) {
groupItemInfo.name += " (" + tr("AUTHD") + ")";
groupItemInfo.icon = QIcon(IMAGE_FORUMAUTHD);
}
else
#endif
{
groupItemInfo.icon = QIcon(IMAGE_FORUM);
}
// groupItemInfo.id = QString::fromStdString(forumInfo.forumId);
// groupItemInfo.name = QString::fromStdWString(forumInfo.forumName);
// groupItemInfo.description = QString::fromStdWString(forumInfo.forumDesc);
// groupItemInfo.popularity = forumInfo.pop;
// groupItemInfo.lastpost = QDateTime::fromTime_t(forumInfo.lastPost);
//
// if (forumInfo.forumFlags & RS_DISTRIB_AUTHEN_REQ) {
// groupItemInfo.name += " (" + tr("AUTHD") + ")";
// groupItemInfo.icon = QIcon(IMAGE_FORUMAUTHD);
// } else {
// groupItemInfo.icon = QIcon(IMAGE_FORUM);
// }
}
/***** INSERT FORUM LISTS *****/
void GxsForumsDialog::insertForumsData(const std::list<RsGroupMetaData> &forumList)
{
std::list<RsGroupMetaData>::const_iterator it;
QList<GroupItemInfo> adminList;
QList<GroupItemInfo> subList;
QList<GroupItemInfo> popList;
QList<GroupItemInfo> otherList;
std::multimap<uint32_t, GroupItemInfo> popMap;
for (it = forumList.begin(); it != forumList.end(); it++) {
/* sort it into Publish (Own), Subscribed, Popular and Other */
uint32_t flags = it->mSubscribeFlags;
GroupItemInfo groupItemInfo;
forumInfoToGroupItemInfo(*it, groupItemInfo);
if (IS_GROUP_ADMIN(flags)) {
adminList.push_back(groupItemInfo);
} else if (IS_GROUP_SUBSCRIBED(flags)) {
/* subscribed forum */
subList.push_back(groupItemInfo);
} else {
/* rate the others by popularity */
popMap.insert(std::make_pair(it->mPop, groupItemInfo));
}
}
/* iterate backwards through popMap - take the top 5 or 10% of list */
uint32_t popCount = 5;
if (popCount < popMap.size() / 10)
{
popCount = popMap.size() / 10;
}
uint32_t i = 0;
uint32_t popLimit = 0;
std::multimap<uint32_t, GroupItemInfo>::reverse_iterator rit;
for(rit = popMap.rbegin(); ((rit != popMap.rend()) && (i < popCount)); rit++, i++) ;
if (rit != popMap.rend()) {
popLimit = rit->first;
}
for (rit = popMap.rbegin(); rit != popMap.rend(); rit++) {
if (rit->second.popularity < (int) popLimit) {
otherList.append(rit->second);
} else {
popList.append(rit->second);
}
}
/* now we can add them in as a tree! */
ui.forumTreeWidget->fillGroupItems(yourForums, adminList);
ui.forumTreeWidget->fillGroupItems(subscribedForums, subList);
ui.forumTreeWidget->fillGroupItems(popularForums, popList);
ui.forumTreeWidget->fillGroupItems(otherForums, otherList);
updateMessageSummaryList("");
}
void GxsForumsDialog::changedForum(const QString &id)
{
mCurrForumId = id.toStdString();
insertThreads();
}
void GxsForumsDialog::changedThread ()
{
if (mThreadLoading) {
return;
}
/* just grab the ids of the current item */
QTreeWidgetItem *curr = ui.threadTreeWidget->currentItem();
if ((!curr) || (!curr->isSelected())) {
mCurrThreadId = "";
} else {
mCurrThreadId = curr->data(COLUMN_THREAD_DATA, ROLE_THREAD_MSGID).toString().toStdString();
}
insertPost();
}
void GxsForumsDialog::clickedThread (QTreeWidgetItem *item, int column)
{
if (mCurrForumId.empty() || !IS_GROUP_SUBSCRIBED(subscribeFlags)) {
return;
}
if (item == NULL) {
return;
}
if (column == COLUMN_THREAD_READ) {
QList<QTreeWidgetItem*> Rows;
Rows.append(item);
uint32_t status = item->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt();
setMsgReadStatus(Rows, IS_MSG_UNREAD(status));
return;
}
}
void GxsForumsDialog::forumMsgReadStatusChanged(const QString &forumId, const QString &msgId, int status)
{
if (inMsgAsReadUnread) {
return;
}
if (forumId.toStdString() == mCurrForumId) {
/* Search exisiting item */
QTreeWidgetItemIterator itemIterator(ui.threadTreeWidget);
QTreeWidgetItem *item = NULL;
while ((item = *itemIterator) != NULL) {
itemIterator++;
if (item->data(COLUMN_THREAD_DATA, ROLE_THREAD_MSGID).toString() == msgId) {
// update status
item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS, status);
QTreeWidgetItem *parentItem = item;
while (parentItem->parent()) {
parentItem = parentItem->parent();
}
CalculateIconsAndFonts(parentItem);
break;
}
}
}
updateMessageSummaryList(forumId.toStdString());
}
void GxsForumsDialog::CalculateIconsAndFonts(QTreeWidgetItem *pItem, bool &bHasReadChilddren, bool &bHasUnreadChilddren)
{
uint32_t status = pItem->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt();
bool bUnread = IS_MSG_UNREAD(status);
bool missing = pItem->data(COLUMN_THREAD_DATA, ROLE_THREAD_MISSING).toBool();
// set icon
if (missing) {
pItem->setIcon(COLUMN_THREAD_READ, QIcon());
pItem->setIcon(COLUMN_THREAD_TITLE, QIcon());
} else {
if (bUnread) {
pItem->setIcon(COLUMN_THREAD_READ, QIcon(":/images/message-state-unread.png"));
} else {
pItem->setIcon(COLUMN_THREAD_READ, QIcon(":/images/message-state-read.png"));
}
if (IS_MSG_UNREAD(status)) {
pItem->setIcon(COLUMN_THREAD_TITLE, QIcon(":/images/message-state-new.png"));
} else {
pItem->setIcon(COLUMN_THREAD_TITLE, QIcon());
}
}
int nItem;
int nItemCount = pItem->childCount();
bool bMyReadChilddren = false;
bool bMyUnreadChilddren = false;
for (nItem = 0; nItem < nItemCount; nItem++) {
CalculateIconsAndFonts(pItem->child(nItem), bMyReadChilddren, bMyUnreadChilddren);
}
// set font
for (int i = 0; i < COLUMN_THREAD_COUNT; i++) {
QFont qf = pItem->font(i);
if (!IS_GROUP_SUBSCRIBED(subscribeFlags)) {
qf.setBold(false);
pItem->setTextColor(i, Qt::black);
} else if (bUnread) {
qf.setBold(true);
pItem->setTextColor(i, Qt::black);
} else if (bMyUnreadChilddren) {
qf.setBold(true);
pItem->setTextColor(i, Qt::gray);
} else {
qf.setBold(false);
pItem->setTextColor(i, Qt::gray);
}
if (missing) {
/* Missing message */
pItem->setTextColor(i, Qt::darkRed);
}
pItem->setFont(i, qf);
}
pItem->setData(COLUMN_THREAD_DATA, ROLE_THREAD_READCHILDREN, bHasReadChilddren || bMyReadChilddren);
pItem->setData(COLUMN_THREAD_DATA, ROLE_THREAD_UNREADCHILDREN, bHasUnreadChilddren || bMyUnreadChilddren);
bHasReadChilddren = bHasReadChilddren || bMyReadChilddren || !bUnread;
bHasUnreadChilddren = bHasUnreadChilddren || bMyUnreadChilddren || bUnread;
}
void GxsForumsDialog::CalculateIconsAndFonts(QTreeWidgetItem *pItem /*= NULL*/)
{
bool bDummy1 = false;
bool bDummy2 = false;
if (pItem) {
CalculateIconsAndFonts(pItem, bDummy1, bDummy2);
return;
}
int nItem;
int nItemCount = ui.threadTreeWidget->topLevelItemCount();
for (nItem = 0; nItem < nItemCount; nItem++) {
bDummy1 = false;
bDummy2 = false;
CalculateIconsAndFonts(ui.threadTreeWidget->topLevelItem(nItem), bDummy1, bDummy2);
}
}
void GxsForumsDialog::fillThreadFinished()
{
#ifdef DEBUG_FORUMS
std::cerr << "GxsForumsDialog::fillThreadFinished" << std::endl;
#endif
// This is now only called with a successful Load.
// cleanup of incomplete is handled elsewhere.
// current thread has finished, hide progressbar and release thread
ui.progressBar->hide();
ui.progLayOutTxt->hide();
ui.progressBarLayOut->setEnabled(false);
#ifdef DEBUG_FORUMS
std::cerr << "GxsForumsDialog::fillThreadFinished Add messages" << std::endl;
#endif
ui.threadTreeWidget->setSortingEnabled(false);
/* add all messages in! */
if (lastViewType != mThreadLoad.ViewType || lastForumID != mCurrForumId)
{
ui.threadTreeWidget->clear();
lastViewType = mThreadLoad.ViewType;
lastForumID = mCurrForumId;
ui.threadTreeWidget->insertTopLevelItems(0, mThreadLoad.Items);
// clear list
mThreadLoad.Items.clear();
}
else
{
FillThreads (mThreadLoad.Items, mThreadLoad.ExpandNewMessages, mThreadLoad.ItemToExpand);
// cleanup list
CleanupItems (mThreadLoad.Items);
}
ui.threadTreeWidget->setSortingEnabled(true);
if (mThreadLoad.FocusMsgId.empty() == false)
{
/* Search exisiting item */
QTreeWidgetItemIterator itemIterator(ui.threadTreeWidget);
QTreeWidgetItem *item = NULL;
while ((item = *itemIterator) != NULL)
{
itemIterator++;
if (item->data(COLUMN_THREAD_DATA, ROLE_THREAD_MSGID).toString().toStdString() == mThreadLoad.FocusMsgId)
{
ui.threadTreeWidget->setCurrentItem(item);
ui.threadTreeWidget->setFocus();
break;
}
}
}
QList<QTreeWidgetItem*>::iterator Item;
for (Item = mThreadLoad.ItemToExpand.begin(); Item != mThreadLoad.ItemToExpand.end(); Item++)
{
if ((*Item)->isHidden() == false)
{
(*Item)->setExpanded(true);
}
}
mThreadLoad.ItemToExpand.clear();
if (ui.filterLineEdit->text().isEmpty() == false) {
filterItems(ui.filterLineEdit->text());
}
insertPost ();
CalculateIconsAndFonts();
ui.newthreadButton->setEnabled (IS_GROUP_SUBSCRIBED(subscribeFlags));
mThreadLoading = false;
#ifdef DEBUG_FORUMS
std::cerr << "GxsForumsDialog::fillThreadFinished done" << std::endl;
#endif
}
void GxsForumsDialog::fillThreadProgress(int current, int count)
{
// show fill progress
if (count) {
ui.progressBar->setValue(current * ui.progressBar->maximum() / count);
}
}
void GxsForumsDialog::insertThreads()
{
#ifdef DEBUG_FORUMS
/* get the current Forum */
std::cerr << "GxsForumsDialog::insertThreads()" << std::endl;
#endif
subscribeFlags = 0;
ui.newmessageButton->setEnabled (false);
ui.newthreadButton->setEnabled (false);
ui.postText->clear();
ui.threadTitle->clear();
if (mCurrForumId.empty())
{
/* not an actual forum - clear */
ui.threadTreeWidget->clear();
/* when no Thread selected - clear */
ui.forumName->clear();
/* clear last stored forumID */
mCurrForumId.erase();
lastForumID.erase();
#ifdef DEBUG_FORUMS
std::cerr << "GxsForumsDialog::insertThreads() Current Thread Invalid" << std::endl;
#endif
return;
}
// Get Current Forum Info... then complete insertForumThreads().
requestGroupSummary_CurrentForum(mCurrForumId);
}
void GxsForumsDialog::insertForumThreads(const RsGroupMetaData &fi)
{
subscribeFlags = fi.mSubscribeFlags;
ui.forumName->setText(QString::fromUtf8(fi.mGroupName.c_str()));
ui.progressBarLayOut->setEnabled(true);
ui.progLayOutTxt->show();
ui.progressBar->reset();
ui.progressBar->show();
#ifdef DEBUG_FORUMS
std::cerr << "GxsForumsDialog::insertThreads() Start filling Forum threads" << std::endl;
#endif
loadCurrentForumThreads(fi.mGroupId);
}
void GxsForumsDialog::FillThreads(QList<QTreeWidgetItem *> &ThreadList, bool expandNewMessages, QList<QTreeWidgetItem*> &itemToExpand)
{
#ifdef DEBUG_FORUMS
std::cerr << "GxsForumsDialog::FillThreads()" << std::endl;
#endif
int Index = 0;
QTreeWidgetItem *Thread;
QList<QTreeWidgetItem *>::iterator NewThread;
// delete not existing
while (Index < ui.threadTreeWidget->topLevelItemCount ()) {
Thread = ui.threadTreeWidget->topLevelItem (Index);
// search existing new thread
int Found = -1;
for (NewThread = ThreadList.begin (); NewThread != ThreadList.end (); NewThread++) {
if (Thread->data (COLUMN_THREAD_DATA, ROLE_THREAD_MSGID) == (*NewThread)->data (COLUMN_THREAD_DATA, ROLE_THREAD_MSGID)) {
// found it
Found = Index;
break;
}
}
if (Found >= 0) {
Index++;
} else {
delete (ui.threadTreeWidget->takeTopLevelItem (Index));
}
}
// iterate all new threads
for (NewThread = ThreadList.begin (); NewThread != ThreadList.end (); NewThread++) {
// search existing thread
int Found = -1;
int Count = ui.threadTreeWidget->topLevelItemCount ();
for (Index = 0; Index < Count; Index++) {
Thread = ui.threadTreeWidget->topLevelItem (Index);
if (Thread->data (COLUMN_THREAD_DATA, ROLE_THREAD_MSGID) == (*NewThread)->data (COLUMN_THREAD_DATA, ROLE_THREAD_MSGID)) {
// found it
Found = Index;
break;
}
}
if (Found >= 0) {
// set child data
int i;
for (i = 0; i < COLUMN_THREAD_COUNT; i++) {
Thread->setText (i, (*NewThread)->text (i));
}
for (i = 0; i < ROLE_THREAD_COUNT; i++) {
Thread->setData (COLUMN_THREAD_DATA, Qt::UserRole + i, (*NewThread)->data (COLUMN_THREAD_DATA, Qt::UserRole + i));
}
// fill recursive
FillChildren (Thread, *NewThread, expandNewMessages, itemToExpand);
} else {
// add new thread
ui.threadTreeWidget->addTopLevelItem (*NewThread);
Thread = *NewThread;
*NewThread = NULL;
}
uint32_t status = Thread->data (COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt();
if (expandNewMessages && IS_MSG_UNREAD(status)) {
QTreeWidgetItem *pParent = Thread;
while ((pParent = pParent->parent()) != NULL) {
if (std::find(itemToExpand.begin(), itemToExpand.end(), pParent) == itemToExpand.end()) {
itemToExpand.push_back(pParent);
}
}
}
}
#ifdef DEBUG_FORUMS
std::cerr << "GxsForumsDialog::FillThreads() done" << std::endl;
#endif
}
void GxsForumsDialog::FillChildren(QTreeWidgetItem *Parent, QTreeWidgetItem *NewParent, bool expandNewMessages, QList<QTreeWidgetItem*> &itemToExpand)
{
int Index = 0;
int NewIndex;
int NewCount = NewParent->childCount();
QTreeWidgetItem *Child;
QTreeWidgetItem *NewChild;
// delete not existing
while (Index < Parent->childCount ()) {
Child = Parent->child (Index);
// search existing new child
int Found = -1;
int Count = NewParent->childCount();
for (NewIndex = 0; NewIndex < Count; NewIndex++) {
NewChild = NewParent->child (NewIndex);
if (NewChild->data (COLUMN_THREAD_DATA, ROLE_THREAD_MSGID) == Child->data (COLUMN_THREAD_DATA, ROLE_THREAD_MSGID)) {
// found it
Found = Index;
break;
}
}
if (Found >= 0) {
Index++;
} else {
delete (Parent->takeChild (Index));
}
}
// iterate all new children
for (NewIndex = 0; NewIndex < NewCount; NewIndex++) {
NewChild = NewParent->child (NewIndex);
// search existing child
int Found = -1;
int Count = Parent->childCount();
for (Index = 0; Index < Count; Index++) {
Child = Parent->child (Index);
if (Child->data (COLUMN_THREAD_DATA, ROLE_THREAD_MSGID) == NewChild->data (COLUMN_THREAD_DATA, ROLE_THREAD_MSGID)) {
// found it
Found = Index;
break;
}
}
if (Found >= 0) {
// set child data
int i;
for (i = 0; i < COLUMN_THREAD_COUNT; i++) {
Child->setText (i, NewChild->text (i));
}
for (i = 0; i < ROLE_THREAD_COUNT; i++) {
Child->setData (COLUMN_THREAD_DATA, Qt::UserRole + i, NewChild->data (COLUMN_THREAD_DATA, Qt::UserRole + i));
}
// fill recursive
FillChildren (Child, NewChild, expandNewMessages, itemToExpand);
} else {
// add new child
Child = NewParent->takeChild(NewIndex);
Parent->addChild (Child);
NewIndex--;
NewCount--;
}
uint32_t status = Child->data (COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt();
if (expandNewMessages && IS_MSG_UNREAD(status)) {
QTreeWidgetItem *pParent = Child;
while ((pParent = pParent->parent()) != NULL) {
if (std::find(itemToExpand.begin(), itemToExpand.end(), pParent) == itemToExpand.end()) {
itemToExpand.push_back(pParent);
}
}
}
}
}
QString GxsForumsDialog::titleFromInfo(const RsMsgMetaData &meta)
{
// NOTE - NOTE SURE HOW THIS WILL WORK!
#ifdef TOGXS
if (meta.mMsgStatus & RS_DISTRIB_MISSING_MSG) {
return QApplication::translate("GxsForumsDialog", "[ ... Missing Message ... ]");
}
#endif
return QString::fromUtf8(meta.mMsgName.c_str());
}
QString GxsForumsDialog::messageFromInfo(const RsGxsForumMsg &msg)
{
#ifdef TOGXS
if (msg.mMeta.mMsgStatus & RS_DISTRIB_MISSING_MSG) {
return QApplication::translate("GxsForumsDialog", "Placeholder for missing Message");
}
#endif
return QString::fromUtf8(msg.mMsg.c_str());
}
void GxsForumsDialog::insertPost()
{
if ((mCurrForumId == "") || (mCurrThreadId == ""))
{
ui.postText->setText("");
ui.threadTitle->setText("");
ui.previousButton->setEnabled(false);
ui.nextButton->setEnabled(false);
ui.newmessageButton->setEnabled (false);
return;
}
QTreeWidgetItem *curr = ui.threadTreeWidget->currentItem();
if (curr) {
QTreeWidgetItem *Parent = curr->parent ();
int Index = Parent ? Parent->indexOfChild (curr) : ui.threadTreeWidget->indexOfTopLevelItem (curr);
int Count = Parent ? Parent->childCount () : ui.threadTreeWidget->topLevelItemCount ();
ui.previousButton->setEnabled (Index > 0);
ui.nextButton->setEnabled (Index < Count - 1);
} else {
// there is something wrong
ui.previousButton->setEnabled(false);
ui.nextButton->setEnabled(false);
return;
}
ui.newmessageButton->setEnabled (IS_GROUP_SUBSCRIBED(subscribeFlags) && mCurrThreadId.empty() == false);
/* blank text, incase we get nothing */
ui.postText->setText("");
/* request Post */
RsGxsGrpMsgIdPair postId = std::make_pair(mCurrForumId, mCurrThreadId);
requestMsgData_InsertPost(postId);
}
void GxsForumsDialog::insertPostData(const RsGxsForumMsg &msg)
{
/* As some time has elapsed since request - check that this is still the current msg.
* otherwise, another request will fill the data
*/
if ((msg.mMeta.mGroupId != mCurrForumId) || (msg.mMeta.mMsgId != mCurrThreadId))
{
std::cerr << "GxsForumsDialog::insertPostData() Ignoring Invalid Data....";
std::cerr << std::endl;
std::cerr << "\t CurrForumId: " << mCurrForumId << " != msg.GroupId: " << msg.mMeta.mGroupId;
std::cerr << std::endl;
std::cerr << "\t or CurrThdId: " << mCurrThreadId << " != msg.MsgId: " << msg.mMeta.mMsgId;
std::cerr << std::endl;
std::cerr << std::endl;
return;
}
QTreeWidgetItem *curr = ui.threadTreeWidget->currentItem();
bool bSetToReadOnActive = Settings->getForumMsgSetToReadOnActivate();
uint32_t status = curr->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt();
QList<QTreeWidgetItem*> Row;
Row.append(curr);
if (bSetToReadOnActive && IS_MSG_UNREAD(status))
{
setMsgReadStatus(Row, true);
}
QString text;
{
QDateTime qtime;
qtime.setTime_t(msg.mMeta.mPublishTs);
text = qtime.toString("yyyy-MM-dd hh:mm:ss");
ui.time_label->setText(text);
}
std::string authorName = rsPeers->getPeerName(msg.mMeta.mAuthorId);
text = QString::fromUtf8(authorName.c_str());
if (text.isEmpty())
{
ui.by_label->setText( tr("By") + " " + tr("Anonymous"));
}
else
{
ui.by_label->setText( tr("By") + " " + text );
}
QString extraTxt = RsHtml().formatText(ui.postText->document(), messageFromInfo(msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS);
ui.postText->setHtml(extraTxt);
ui.threadTitle->setText(titleFromInfo(msg.mMeta));
}
void GxsForumsDialog::previousMessage ()
{
QTreeWidgetItem *Item = ui.threadTreeWidget->currentItem ();
if (Item == NULL) {
return;
}
QTreeWidgetItem *Parent = Item->parent ();
int Index = Parent ? Parent->indexOfChild (Item) : ui.threadTreeWidget->indexOfTopLevelItem (Item);
if (Index > 0) {
QTreeWidgetItem *Previous = Parent ? Parent->child (Index - 1) : ui.threadTreeWidget->topLevelItem (Index - 1);
if (Previous) {
ui.threadTreeWidget->setCurrentItem (Previous);
}
}
}
void GxsForumsDialog::nextMessage ()
{
QTreeWidgetItem *Item = ui.threadTreeWidget->currentItem ();
if (Item == NULL) {
return;
}
QTreeWidgetItem *Parent = Item->parent ();
int Index = Parent ? Parent->indexOfChild (Item) : ui.threadTreeWidget->indexOfTopLevelItem (Item);
int Count = Parent ? Parent->childCount () : ui.threadTreeWidget->topLevelItemCount ();
if (Index < Count - 1) {
QTreeWidgetItem *Next = Parent ? Parent->child (Index + 1) : ui.threadTreeWidget->topLevelItem (Index + 1);
if (Next) {
ui.threadTreeWidget->setCurrentItem (Next);
}
}
}
void GxsForumsDialog::downloadAllFiles()
{
QStringList urls;
if (RsHtml::findAnchors(ui.postText->toHtml(), urls) == false) {
return;
}
if (urls.count() == 0) {
return;
}
RetroShareLink::process(urls, RetroShareLink::TYPE_FILE/*, true*/);
}
void GxsForumsDialog::nextUnreadMessage()
{
QTreeWidgetItem* currentItem = ui.threadTreeWidget->currentItem();
if( !currentItem )
{
currentItem = ui.threadTreeWidget->topLevelItem(0);
if( !currentItem )
return;
}
do
{
uint32_t status = currentItem->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt();
if( IS_MSG_UNREAD(status) )
{
ui.threadTreeWidget->setCurrentItem(currentItem);
return;
}
} while( (currentItem = ui.threadTreeWidget->itemBelow(currentItem)) != NULL );
}
// TODO
#if 0
void GxsForumsDialog::removemessage()
{
//std::cerr << "GxsForumsDialog::removemessage()" << std::endl;
std::string cid, mid;
if (!getCurrentMsg(cid, mid))
{
//std::cerr << "GxsForumsDialog::removemessage()";
//std::cerr << " No Message selected" << std::endl;
return;
}
rsMsgs -> MessageDelete(mid);
}
#endif
/* get selected messages
the messages tree is single selected, but who knows ... */
int GxsForumsDialog::getSelectedMsgCount(QList<QTreeWidgetItem*> *pRows, QList<QTreeWidgetItem*> *pRowsRead, QList<QTreeWidgetItem*> *pRowsUnread)
{
if (pRowsRead) pRowsRead->clear();
if (pRowsUnread) pRowsUnread->clear();
QList<QTreeWidgetItem*> selectedItems = ui.threadTreeWidget->selectedItems();
for(QList<QTreeWidgetItem*>::iterator it = selectedItems.begin(); it != selectedItems.end(); it++) {
if (pRows) pRows->append(*it);
if (pRowsRead || pRowsUnread) {
uint32_t status = (*it)->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt();
if (IS_MSG_UNREAD(status)) {
if (pRowsUnread) pRowsUnread->append(*it);
} else {
if (pRowsRead) pRowsRead->append(*it);
}
}
}
return selectedItems.size();
}
void GxsForumsDialog::setMsgReadStatus(QList<QTreeWidgetItem*> &Rows, bool bRead)
{
QList<QTreeWidgetItem*>::iterator Row;
std::list<QTreeWidgetItem*> changedItems;
inMsgAsReadUnread = true;
for (Row = Rows.begin(); Row != Rows.end(); Row++) {
if ((*Row)->data(COLUMN_THREAD_DATA, ROLE_THREAD_MISSING).toBool()) {
/* Missing message */
continue;
}
uint32_t status = (*Row)->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt();
uint32_t statusNew = (status & ~GXS_SERV::GXS_MSG_STATUS_UNREAD); // orig status, without UNREAD.
if (!bRead) {
statusNew |= GXS_SERV::GXS_MSG_STATUS_UNREAD;
}
if (IS_MSG_UNREAD(status) == bRead) // is it different?
{
std::string msgId = (*Row)->data(COLUMN_THREAD_DATA, ROLE_THREAD_MSGID).toString().toStdString();
// NB: MUST BE PART OF ACTIVE THREAD--- OR ELSE WE MUST STORE GROUPID SOMEWHERE!.
// LIKE THIS BELOW...
//std::string grpId = (*Row)->data(COLUMN_THREAD_DATA, ROLE_THREAD_GROUPID).toString().toStdString();
RsGxsGrpMsgIdPair msgPair = std::make_pair(mCurrForumId, msgId);
uint32_t token;
rsGxsForums->setMessageReadStatus(token, msgPair, bRead);
(*Row)->setData(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS, statusNew);
QTreeWidgetItem *parentItem = *Row;
while (parentItem->parent()) {
parentItem = parentItem->parent();
}
if (std::find(changedItems.begin(), changedItems.end(), parentItem) == changedItems.end()) {
changedItems.push_back(parentItem);
}
}
}
inMsgAsReadUnread = false;
if (changedItems.size()) {
for (std::list<QTreeWidgetItem*>::iterator it = changedItems.begin(); it != changedItems.end(); it++) {
CalculateIconsAndFonts(*it);
}
updateMessageSummaryList(mCurrForumId);
}
}
void GxsForumsDialog::markMsgAsReadUnread (bool bRead, bool bChildren, bool bForum)
{
if (mCurrForumId.empty() || !IS_GROUP_SUBSCRIBED(subscribeFlags)) {
return;
}
/* get selected messages */
QList<QTreeWidgetItem*> Rows;
if (bForum) {
int itemCount = ui.threadTreeWidget->topLevelItemCount();
for (int item = 0; item < itemCount; item++) {
Rows.push_back(ui.threadTreeWidget->topLevelItem(item));
}
} else {
getSelectedMsgCount (&Rows, NULL, NULL);
}
if (bChildren) {
/* add children */
QList<QTreeWidgetItem*> AllRows;
while (Rows.isEmpty() == false) {
QTreeWidgetItem *pRow = Rows.takeFirst();
/* add only items with the right state or with not RSGXS_MSG_STATUS_READ */
uint32_t status = pRow->data(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS).toUInt();
if (IS_MSG_UNREAD(status) == bRead) {
AllRows.append(pRow);
}
for (int i = 0; i < pRow->childCount(); i++) {
/* add child to main list and let the main loop do the work */
Rows.append(pRow->child(i));
}
}
if (AllRows.isEmpty()) {
/* nothing to do */
return;
}
setMsgReadStatus(AllRows, bRead);
return;
}
setMsgReadStatus(Rows, bRead);
}
void GxsForumsDialog::markMsgAsRead()
{
markMsgAsReadUnread(true, false, false);
}
void GxsForumsDialog::markMsgAsReadChildren()
{
markMsgAsReadUnread(true, true, false);
}
void GxsForumsDialog::markMsgAsReadAll()
{
markMsgAsReadUnread(true, true, true);
}
void GxsForumsDialog::markMsgAsUnread()
{
markMsgAsReadUnread(false, false, false);
}
void GxsForumsDialog::markMsgAsUnreadChildren()
{
markMsgAsReadUnread(false, true, false);
}
void GxsForumsDialog::markMsgAsUnreadAll()
{
markMsgAsReadUnread(false, true, true);
}
void GxsForumsDialog::copyForumLink()
{
if (mCurrForumId.empty()) {
return;
}
// THIS CODE CALLS getForumInfo() to verify that the Ids are valid.
// As we are switching to Request/Response this is now harder to do...
// So not bothering any more - shouldn't be necessary.
// IF we get errors - fix them, rather than patching here.
#if 0
ForumInfo fi;
if (rsGxsForums->getForumInfo(mCurrForumId, fi)) {
RetroShareLink link;
if (link.createForum(fi.forumId, "")) {
QList<RetroShareLink> urls;
urls.push_back(link);
RSLinkClipboard::copyLinks(urls);
}
}
#endif
{
RetroShareLink link;
if (link.createForum(mCurrForumId, ""))
{
QList<RetroShareLink> urls;
urls.push_back(link);
RSLinkClipboard::copyLinks(urls);
}
}
}
void GxsForumsDialog::copyMessageLink()
{
if (mCurrForumId.empty() || mCurrThreadId.empty()) {
return;
}
// SEE NOTE In fn above.
#if 0
ForumInfo fi;
if (rsGxsForums->getForumInfo(mCurrForumId, fi)) {
RetroShareLink link;
if (link.createForum(mCurrForumId, mCurrThreadId)) {
QList<RetroShareLink> urls;
urls.push_back(link);
RSLinkClipboard::copyLinks(urls);
}
}
#endif
{
RetroShareLink link;
if (link.createForum(mCurrForumId, mCurrThreadId))
{
QList<RetroShareLink> urls;
urls.push_back(link);
RSLinkClipboard::copyLinks(urls);
}
}
}
void GxsForumsDialog::newforum()
{
GxsForumGroupDialog cf (mForumQueue, this);
//cf.newGroup();
cf.exec ();
}
void GxsForumsDialog::createmessage()
{
if (mCurrForumId.empty () || !IS_GROUP_SUBSCRIBED(subscribeFlags)) {
return;
}
CreateGxsForumMsg *cfm = new CreateGxsForumMsg(mCurrForumId, mCurrThreadId);
cfm->show();
/* window will destroy itself! */
}
void GxsForumsDialog::createthread()
{
if (mCurrForumId.empty ()) {
QMessageBox::information(this, tr("RetroShare"), tr("No Forum Selected!"));
return;
}
CreateGxsForumMsg *cfm = new CreateGxsForumMsg(mCurrForumId, "");
cfm->setWindowTitle(tr("Start New Thread"));
cfm->show();
/* window will destroy itself! */
}
void GxsForumsDialog::subscribeToForum()
{
forumSubscribe(true);
}
void GxsForumsDialog::unsubscribeToForum()
{
forumSubscribe(false);
}
void GxsForumsDialog::forumSubscribe(bool subscribe)
{
if (mCurrForumId.empty()) {
return;
}
uint32_t token;
rsGxsForums->subscribeToGroup(token, mCurrForumId, subscribe);
}
void GxsForumsDialog::showForumDetails()
{
if (mCurrForumId.empty()) {
return;
}
RsGxsForumGroup grp;
grp.mMeta.mGroupId = mCurrForumId;
GxsForumGroupDialog cf(grp, this);
cf.exec ();
}
void GxsForumsDialog::editForumDetails()
{
if (mCurrForumId.empty()) {
return;
}
RsGxsForumGroup grp;
grp.mMeta.mGroupId = mCurrForumId;
GxsForumGroupDialog cf(grp, this);
//GxsForumGroupDialog cf (mForumQueue, this, mCurrForumId, GXS_GROUP_DIALOG_EDIT_MODE);
cf.exec ();
}
static QString buildReplyHeader(const RsMsgMetaData &meta)
{
RetroShareLink link;
link.createMessage(meta.mAuthorId, "");
QString from = link.toHtml();
QDateTime qtime;
qtime.setTime_t(meta.mPublishTs);
QString header = QString("<span>-----%1-----").arg(QApplication::translate("GxsForumsDialog", "Original Message"));
header += QString("<br><font size='3'><strong>%1: </strong>%2</font><br>").arg(QApplication::translate("GxsForumsDialog", "From"), from);
header += QString("<br><font size='3'><strong>%1: </strong>%2</font><br>").arg(QApplication::translate("GxsForumsDialog", "Sent"), qtime.toString(Qt::SystemLocaleLongDate));
header += QString("<font size='3'><strong>%1: </strong>%2</font></span><br>").arg(QApplication::translate("GxsForumsDialog", "Subject"), QString::fromUtf8(meta.mMsgName.c_str()));
header += "<br>";
header += QApplication::translate("GxsForumsDialog", "On %1, %2 wrote:").arg(qtime.toString(Qt::SystemLocaleShortDate), from);
return header;
}
void GxsForumsDialog::replytomessage()
{
if (mCurrForumId.empty() || mCurrThreadId.empty()) {
QMessageBox::information(this, tr("RetroShare"),tr("You cant reply to a non-existant Message"));
return;
}
RsGxsGrpMsgIdPair postId = std::make_pair(mCurrForumId, mCurrThreadId);
requestMsgData_ReplyMessage(postId);
}
void GxsForumsDialog::replyMessageData(const RsGxsForumMsg &msg)
{
if ((msg.mMeta.mGroupId != mCurrForumId) || (msg.mMeta.mMsgId != mCurrThreadId))
{
std::cerr << "GxsForumsDialog::replyMessageData() ERROR Message Ids have changed!";
std::cerr << std::endl;
return;
}
// NB: TODO REMOVE rsPeers references.
if (rsPeers->getPeerName(msg.mMeta.mAuthorId) !="")
{
MessageComposer *nMsgDialog = MessageComposer::newMsg();
nMsgDialog->setTitleText(QString::fromUtf8(msg.mMeta.mMsgName.c_str()), MessageComposer::REPLY);
nMsgDialog->setQuotedMsg(QString::fromUtf8(msg.mMsg.c_str()), buildReplyHeader(msg.mMeta));
nMsgDialog->addRecipient(MessageComposer::TO, msg.mMeta.mAuthorId, false);
nMsgDialog->show();
nMsgDialog->activateWindow();
/* window will destroy itself! */
}
else
{
QMessageBox::information(this, tr("RetroShare"),tr("You cant reply to an Anonymous Author"));
}
}
void GxsForumsDialog::changedViewBox()
{
if (m_bProcessSettings) {
return;
}
// save index
Settings->setValueToGroup("GxsForumsDialog", "viewBox", ui.viewBox->currentIndex());
insertThreads();
}
void GxsForumsDialog::filterColumnChanged()
{
if (m_bProcessSettings) {
return;
}
int filterColumn = FilterColumnFromComboBox(ui.filterColumnComboBox->currentIndex());
if (filterColumn == COLUMN_THREAD_CONTENT) {
// need content ... refill
insertThreads();
} else {
filterItems(ui.filterLineEdit->text());
}
// save index
Settings->setValueToGroup("GxsForumsDialog", "filterColumn", filterColumn);
}
void GxsForumsDialog::filterItems(const QString& text)
{
int filterColumn = FilterColumnFromComboBox(ui.filterColumnComboBox->currentIndex());
int nCount = ui.threadTreeWidget->topLevelItemCount ();
for (int nIndex = 0; nIndex < nCount; nIndex++) {
filterItem(ui.threadTreeWidget->topLevelItem(nIndex), text, filterColumn);
}
}
void GxsForumsDialog::shareKey()
{
ShareKey shareUi(this, 0, mCurrForumId, FORUM_KEY_SHARE);
shareUi.exec();
}
bool GxsForumsDialog::filterItem(QTreeWidgetItem *pItem, const QString &text, int filterColumn)
{
bool bVisible = true;
if (text.isEmpty() == false) {
if (pItem->text(filterColumn).contains(text, Qt::CaseInsensitive) == false) {
bVisible = false;
}
}
int nVisibleChildCount = 0;
int nCount = pItem->childCount();
for (int nIndex = 0; nIndex < nCount; nIndex++) {
if (filterItem(pItem->child(nIndex), text, filterColumn)) {
nVisibleChildCount++;
}
}
if (bVisible || nVisibleChildCount) {
pItem->setHidden(false);
} else {
pItem->setHidden(true);
}
return (bVisible || nVisibleChildCount);
}
void GxsForumsDialog::updateMessageSummaryList(std::string forumId)
{
QTreeWidgetItem *items[2] = { yourForums, subscribedForums };
for (int item = 0; item < 2; item++) {
int child;
int childCount = items[item]->childCount();
for (child = 0; child < childCount; child++) {
QTreeWidgetItem *childItem = items[item]->child(child);
std::string childId = ui.forumTreeWidget->itemId(childItem).toStdString();
if (childId.empty()) {
continue;
}
if (forumId.empty() || childId == forumId) {
/* calculate unread messages */
unsigned int newMessageCount = 0;
unsigned int unreadMessageCount = 0;
//rsGxsForums->getMessageCount(childId, newMessageCount, unreadMessageCount);
std::cerr << "IMPLEMENT rsGxsForums->getMessageCount()";
std::cerr << std::endl;
ui.forumTreeWidget->setUnreadCount(childItem, unreadMessageCount);
if (forumId.empty() == false) {
/* Calculate only this forum */
break;
}
}
}
}
}
bool GxsForumsDialog::navigate(const std::string& forumId, const std::string& msgId)
{
if (forumId.empty()) {
return false;
}
if (ui.forumTreeWidget->activateId(QString::fromStdString(forumId), msgId.empty()) == NULL) {
return false;
}
/* Threads are filled in changedForum */
if (mCurrForumId != forumId) {
return false;
}
if (msgId.empty()) {
return true;
}
if (mThreadLoading) {
mThreadLoad.FocusMsgId = msgId;
return true;
}
/* Search exisiting item */
QTreeWidgetItemIterator itemIterator(ui.threadTreeWidget);
QTreeWidgetItem *item = NULL;
while ((item = *itemIterator) != NULL) {
itemIterator++;
if (item->data(COLUMN_THREAD_DATA, ROLE_THREAD_MSGID).toString().toStdString() == msgId) {
ui.threadTreeWidget->setCurrentItem(item);
ui.threadTreeWidget->setFocus();
return true;
}
}
return false;
}
void GxsForumsDialog::generateMassData()
{
#ifdef DEBUG_FORUMS
if (mCurrForumId.empty ()) {
return;
}
if (QMessageBox::question(this, "Generate mass data", "Do you really want to generate mass data ?", QMessageBox::Yes|QMessageBox::No, QMessageBox::No) == QMessageBox::No) {
return;
}
for (int thread = 1; thread < 1000; thread++) {
ForumMsgInfo threadInfo;
threadInfo.forumId = mCurrForumId;
threadInfo.title = QString("Test %1").arg(thread, 3, 10, QChar('0')).toStdWString();
threadInfo.msg = QString("That is only a test").toStdWString();
if (rsGxsForums->ForumMessageSend(threadInfo) == false) {
return;
}
for (int msg = 1; msg < 3; msg++) {
ForumMsgInfo msgInfo;
msgInfo.forumId = mCurrForumId;
msgInfo.threadId = threadInfo.msgId;
msgInfo.parentId = threadInfo.msgId;
msgInfo.title = threadInfo.title;
msgInfo.msg = threadInfo.msg;
if (rsGxsForums->ForumMessageSend(msgInfo) == false) {
return;
}
}
}
#endif
}
/*********************** **** **** **** ***********************/
/** Request / Response of Data ********************************/
/*********************** **** **** **** ***********************/
#define FORUMSV2DIALOG_LISTING 1
#define FORUMSV2DIALOG_CURRENTFORUM 2
#define FORUMSV2DIALOG_INSERTTHREADS 3
#define FORUMSV2DIALOG_INSERTCHILD 4
#define FORUMV2DIALOG_INSERT_POST 5
#define FORUMV2DIALOG_REPLY_MESSAGE 6
void GxsForumsDialog::insertForums()
{
requestGroupSummary();
}
void GxsForumsDialog::requestGroupSummary()
{
std::cerr << "GxsForumsDialog::requestGroupSummary()";
std::cerr << std::endl;
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_GROUP_META;
uint32_t token;
mForumQueue->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_SUMMARY, opts, FORUMSV2DIALOG_LISTING);
}
void GxsForumsDialog::loadGroupSummary(const uint32_t &token)
{
std::cerr << "GxsForumsDialog::loadGroupSummary()";
std::cerr << std::endl;
std::list<RsGroupMetaData> groupInfo;
rsGxsForums->getGroupSummary(token, groupInfo);
if (groupInfo.size() > 0)
{
insertForumsData(groupInfo);
}
else
{
std::cerr << "GxsForumsDialog::loadGroupSummary() ERROR No Groups...";
std::cerr << std::endl;
}
}
/*********************** **** **** **** ***********************/
/*********************** **** **** **** ***********************/
void GxsForumsDialog::requestGroupSummary_CurrentForum(const std::string &forumId)
{
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_GROUP_META;
std::list<std::string> grpIds;
grpIds.push_back(forumId);
std::cerr << "GxsForumsDialog::requestGroupSummary_CurrentForum(" << forumId << ")";
std::cerr << std::endl;
uint32_t token;
mForumQueue->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_SUMMARY, opts, grpIds, FORUMSV2DIALOG_CURRENTFORUM);
}
void GxsForumsDialog::loadGroupSummary_CurrentForum(const uint32_t &token)
{
std::cerr << "GxsForumsDialog::loadGroupSummary_CurrentForum()";
std::cerr << std::endl;
std::list<RsGroupMetaData> groupInfo;
rsGxsForums->getGroupSummary(token, groupInfo);
if (groupInfo.size() == 1)
{
RsGroupMetaData fi = groupInfo.front();
insertForumThreads(fi);
}
else
{
std::cerr << "GxsForumsDialog::loadGroupSummary_CurrentForum() ERROR Invalid Number of Groups...";
std::cerr << std::endl;
}
}
/*********************** **** **** **** ***********************/
/*********************** **** **** **** ***********************/
/*********************** **** **** **** ***********************/
/*********************** **** **** **** ***********************/
void GxsForumsDialog::loadCurrentForumThreads(const std::string &forumId)
{
std::cerr << "GxsForumsDialog::loadCurrentForumThreads(" << forumId << ")";
std::cerr << std::endl;
/* if already active -> kill current loading */
if (mThreadLoading)
{
/* Cleanup */
std::cerr << "GxsForumsDialog::loadCurrentForumThreads() Cleanup old Threads";
std::cerr << std::endl;
/* Wipe Widget Tree */
mThreadLoad.Items.clear();
/* Stop all active requests */
std::map<uint32_t, QTreeWidgetItem *>::iterator it;
for(it = mThreadLoad.MsgTokens.begin(); it != mThreadLoad.MsgTokens.end(); it++)
{
std::cerr << "GxsForumsDialog::loadCurrentForumThreads() Canceling Request: " << it->first;
std::cerr << std::endl;
mForumQueue->cancelRequest(it->first);
}
mThreadLoad.MsgTokens.clear();
mThreadLoad.ItemToExpand.clear();
}
/* initiate loading */
std::cerr << "GxsForumsDialog::loadCurrentForumThreads() Initiating Loading";
std::cerr << std::endl;
mThreadLoading = true;
mThreadLoad.ForumId = mCurrForumId;
mThreadLoad.FilterColumn = FilterColumnFromComboBox(ui.filterColumnComboBox->currentIndex());
mThreadLoad.ViewType = ui.viewBox->currentIndex();
mThreadLoad.FillComplete = false;
if (lastViewType != mThreadLoad.ViewType || lastForumID != mCurrForumId) {
mThreadLoad.FillComplete = true;
}
mThreadLoad.FlatView = false;
mThreadLoad.UseChildTS = false;
mThreadLoad.ExpandNewMessages = Settings->getExpandNewMessages();
mThreadLoad.SubscribeFlags = subscribeFlags;
if (mThreadLoad.ViewType == VIEW_FLAT) {
ui.threadTreeWidget->setRootIsDecorated(false);
} else {
ui.threadTreeWidget->setRootIsDecorated(true);
}
switch(mThreadLoad.ViewType)
{
case VIEW_LAST_POST:
mThreadLoad.UseChildTS = true;
break;
case VIEW_FLAT:
mThreadLoad.FlatView = true;
break;
case VIEW_THREADED:
break;
}
requestGroupThreadData_InsertThreads(forumId);
}
void GxsForumsDialog::requestGroupThreadData_InsertThreads(const std::string &forumId)
{
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA;
opts.mOptions = RS_TOKREQOPT_MSG_THREAD | RS_TOKREQOPT_MSG_LATEST;
std::list<std::string> grpIds;
grpIds.push_back(forumId);
std::cerr << "GxsForumsDialog::requestGroupThreadData_InsertThreads(" << forumId << ")";
std::cerr << std::endl;
uint32_t token;
mForumQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, grpIds, FORUMSV2DIALOG_INSERTTHREADS);
}
void GxsForumsDialog::loadGroupThreadData_InsertThreads(const uint32_t &token)
{
std::cerr << "GxsForumsDialog::loadGroupThreadData_InsertThreads()";
std::cerr << std::endl;
bool someData = false;
std::vector<RsGxsForumMsg> msgs;
std::vector<RsGxsForumMsg>::iterator vit;
if (rsGxsForums->getMsgData(token, msgs))
{
for(vit = msgs.begin(); vit != msgs.end(); vit++)
{
std::cerr << "GxsForumsDialog::loadGroupThreadData_InsertThreads() MsgId: " << vit->mMeta.mMsgId;
std::cerr << std::endl;
loadForumBaseThread(*vit);
someData = true;
}
}
/* completed with no data */
if (!someData)
{
fillThreadFinished();
}
}
bool GxsForumsDialog::convertMsgToThreadWidget(const RsGxsForumMsg &msgInfo, std::string authorName,
bool useChildTS, uint32_t filterColumn, QTreeWidgetItem *item)
{
QString text;
{
QDateTime qtime;
if (useChildTS)
qtime.setTime_t(msgInfo.mMeta.mChildTs);
else
qtime.setTime_t(msgInfo.mMeta.mPublishTs);
text = qtime.toString("yyyy-MM-dd hh:mm:ss");
if (useChildTS)
{
QDateTime qtime2;
qtime2.setTime_t(msgInfo.mMeta.mPublishTs);
QString timestamp2 = qtime2.toString("yyyy-MM-dd hh:mm:ss");
text += " / ";
text += timestamp2;
}
item->setText(COLUMN_THREAD_DATE, text);
}
item->setText(COLUMN_THREAD_TITLE, GxsForumsDialog::titleFromInfo(msgInfo.mMeta));
text = QString::fromUtf8(authorName.c_str());
if (text.isEmpty())
{
item->setText(COLUMN_THREAD_AUTHOR, tr("Anonymous"));
}
else
{
item->setText(COLUMN_THREAD_AUTHOR, text);
}
#ifdef TOGXS
if (msgInfo.mMeta.mMsgFlags & RS_DISTRIB_AUTHEN_REQ)
{
item->setText(COLUMN_THREAD_SIGNED, tr("signed"));
item->setIcon(COLUMN_THREAD_SIGNED, QIcon(":/images/mail-signed.png"));
}
else
{
item->setText(COLUMN_THREAD_SIGNED, tr("none"));
item->setIcon(COLUMN_THREAD_SIGNED, QIcon(":/images/mail-signature-unknown.png"));
}
#endif
if (filterColumn == COLUMN_THREAD_CONTENT) {
// need content for filter
QTextDocument doc;
doc.setHtml(QString::fromUtf8(msgInfo.mMsg.c_str()));
item->setText(COLUMN_THREAD_CONTENT, doc.toPlainText().replace(QString("\n"), QString(" ")));
}
item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_MSGID, QString::fromStdString(msgInfo.mMeta.mMsgId));
#if 0
if (IS_GROUP_SUBSCRIBED(subscribeFlags) && !(msginfo.mMsgFlags & RS_DISTRIB_MISSING_MSG)) {
rsGxsForums->getMessageStatus(msginfo.forumId, msginfo.msgId, status);
} else {
// show message as read
status = RSGXS_MSG_STATUS_READ;
}
#endif
item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_STATUS, msgInfo.mMeta.mMsgStatus);
#ifdef TOGXS
item->setData(COLUMN_THREAD_DATA, ROLE_THREAD_MISSING, (msgInfo.mMeta.mMsgFlags & RS_DISTRIB_MISSING_MSG) ? true : false);
#endif
return true;
}
void GxsForumsDialog::loadForumBaseThread(const RsGxsForumMsg &msg)
{
std::string authorName = rsPeers->getPeerName(msg.mMeta.mAuthorId);
QTreeWidgetItem *item = new QTreeWidgetItem(); // no Parent.
convertMsgToThreadWidget(msg, authorName, mThreadLoad.UseChildTS, mThreadLoad.FilterColumn, item);
/* request Children Data */
uint32_t token;
RsGxsGrpMsgIdPair parentId = std::make_pair(msg.mMeta.mGroupId, msg.mMeta.mMsgId);
requestChildData_InsertThreads(token, parentId);
/* store pair of (token, item) */
mThreadLoad.MsgTokens[token] = item;
/* add item to final tree */
mThreadLoad.Items.append(item);
}
/*********************** **** **** **** ***********************/
void GxsForumsDialog::requestChildData_InsertThreads(uint32_t &token, const RsGxsGrpMsgIdPair &parentId)
{
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_MSG_RELATED_DATA;
opts.mOptions = RS_TOKREQOPT_MSG_PARENT | RS_TOKREQOPT_MSG_LATEST;
std::cerr << "GxsForumsDialog::requestChildData_InsertThreads(" << parentId.first << "," << parentId.second << ")";
std::cerr << std::endl;
std::vector<RsGxsGrpMsgIdPair> msgIds;
msgIds.push_back(parentId);
mForumQueue->requestMsgRelatedInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, FORUMSV2DIALOG_INSERTCHILD);
}
void GxsForumsDialog::loadChildData_InsertThreads(const uint32_t &token)
{
std::cerr << "GxsForumsDialog::loadChildData_InsertThreads()";
std::cerr << std::endl;
/* find the matching *item */
std::map<uint32_t, QTreeWidgetItem *>::iterator it;
it = mThreadLoad.MsgTokens.find(token);
if (it == mThreadLoad.MsgTokens.end())
{
std::cerr << "GxsForumsDialog::loadChildData_InsertThreads() ERROR Missing Token->Parent in Map";
std::cerr << std::endl;
/* finished with this one */
return;
}
QTreeWidgetItem *parent = it->second;
// cleanup map.
mThreadLoad.MsgTokens.erase(it);
std::cerr << "GxsForumsDialog::loadChildData_InsertThreads()";
std::cerr << std::endl;
std::vector<RsGxsForumMsg> msgs;
std::vector<RsGxsForumMsg>::iterator vit;
if (rsGxsForums->getRelatedMessages(token, msgs))
{
for(vit = msgs.begin(); vit != msgs.end(); vit++)
{
std::cerr << "GxsForumsDialog::loadChildData_InsertThreads() MsgId: " << vit->mMeta.mMsgId;
std::cerr << std::endl;
loadForumChildMsg(*vit, parent);
}
}
else
{
std::cerr << "GxsForumsDialog::loadChildData_InsertThreads() Error getting MsgData";
std::cerr << std::endl;
}
/* check for completion */
if (mThreadLoad.MsgTokens.size() == 0)
{
/* finished */
/* push data into GUI */
fillThreadFinished();
}
}
void GxsForumsDialog::loadForumChildMsg(const RsGxsForumMsg &msg, QTreeWidgetItem *parent)
{
std::string authorName = rsPeers->getPeerName(msg.mMeta.mAuthorId);
QTreeWidgetItem *child = NULL;
if (mThreadLoad.FlatView)
{
child = new QTreeWidgetItem(); // no Parent.
}
else
{
child = new QTreeWidgetItem(parent);
}
convertMsgToThreadWidget(msg, authorName, mThreadLoad.UseChildTS, mThreadLoad.FilterColumn, child);
/* request Children Data */
uint32_t token;
RsGxsGrpMsgIdPair parentId = std::make_pair(msg.mMeta.mGroupId, msg.mMeta.mMsgId);
requestChildData_InsertThreads(token, parentId);
/* store pair of (token, item) */
mThreadLoad.MsgTokens[token] = child;
// Leave this here... BUT IT WILL NEED TO BE FIXED.
if (mThreadLoad.FillComplete && mThreadLoad.ExpandNewMessages && IS_MSG_UNREAD(msg.mMeta.mMsgStatus))
{
QTreeWidgetItem *pParent = child;
while ((pParent = pParent->parent()) != NULL)
{
if (std::find(mThreadLoad.ItemToExpand.begin(), mThreadLoad.ItemToExpand.end(), pParent) == mThreadLoad.ItemToExpand.end())
{
mThreadLoad.ItemToExpand.push_back(pParent);
}
}
}
if (mThreadLoad.FlatView)
{
/* add item to final tree */
mThreadLoad.Items.append(child);
}
}
/*********************** **** **** **** ***********************/
/*********************** **** **** **** ***********************/
void GxsForumsDialog::requestMsgData_InsertPost(const RsGxsGrpMsgIdPair &msgId)
{
#if 0
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_MSG_RELATED_DATA;
std::cerr << "GxsForumsDialog::requestMsgData_InsertPost(" << msgId.first << "," << msgId.second << ")";
std::cerr << std::endl;
std::vector<RsGxsGrpMsgIdPair> msgIds;
msgIds.push_back(msgId);
uint32_t token;
mForumQueue->requestMsgRelatedInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, FORUMV2DIALOG_INSERT_POST);
#else
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA;
std::cerr << "GxsForumsDialog::requestMsgData_InsertPost(" << msgId.first << "," << msgId.second << ")";
std::cerr << std::endl;
GxsMsgReq msgIds;
std::vector<RsGxsMessageId> &vect = msgIds[msgId.first];
vect.push_back(msgId.second);
uint32_t token;
mForumQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, FORUMV2DIALOG_INSERT_POST);
#endif
}
void GxsForumsDialog::loadMsgData_InsertPost(const uint32_t &token)
{
std::cerr << "GxsForumsDialog::loadMsgData_InsertPost()";
std::cerr << std::endl;
std::vector<RsGxsForumMsg> msgs;
#if 0
if (rsGxsForums->getRelatedMessages(token, msgs))
#else
if (rsGxsForums->getMsgData(token, msgs))
#endif
{
if (msgs.size() != 1)
{
std::cerr << "GxsForumsDialog::loadMsgData_InsertPost() ERROR Wrong number of answers";
std::cerr << std::endl;
return;
}
insertPostData(msgs[0]);
}
else
{
std::cerr << "GxsForumsDialog::loadMsgData_InsertPost() ERROR Missing Message Data...";
std::cerr << std::endl;
}
}
/*********************** **** **** **** ***********************/
/*********************** **** **** **** ***********************/
void GxsForumsDialog::requestMsgData_ReplyMessage(const RsGxsGrpMsgIdPair &msgId)
{
#if 0
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_MSG_RELATED_DATA;
std::cerr << "GxsForumsDialog::requestMsgData_ReplyMessage(" << msgId.first << "," << msgId.second << ")";
std::cerr << std::endl;
std::vector<RsGxsGrpMsgIdPair> msgIds;
msgIds.push_back(msgId);
uint32_t token;
mForumQueue->requestMsgRelatedInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, FORUMV2DIALOG_REPLY_MESSAGE);
#else
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA;
std::cerr << "GxsForumsDialog::requestMsgData_ReplyMessage(" << msgId.first << "," << msgId.second << ")";
std::cerr << std::endl;
GxsMsgReq msgIds;
std::vector<RsGxsMessageId> &vect = msgIds[msgId.first];
vect.push_back(msgId.second);
uint32_t token;
mForumQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, msgIds, FORUMV2DIALOG_REPLY_MESSAGE);
#endif
}
void GxsForumsDialog::loadMsgData_ReplyMessage(const uint32_t &token)
{
std::cerr << "GxsForumsDialog::loadMsgData_ReplyMessage()";
std::cerr << std::endl;
std::vector<RsGxsForumMsg> msgs;
#if 0
if (rsGxsForums->getRelatedMessages(token, msgs))
#else
if (rsGxsForums->getMsgData(token, msgs))
#endif
{
if (msgs.size() != 1)
{
std::cerr << "GxsForumsDialog::loadMsgData_ReplyMessage() ERROR Wrong number of answers";
std::cerr << std::endl;
return;
}
replyMessageData(msgs[0]);
}
else
{
std::cerr << "GxsForumsDialog::loadMsgData_ReplyMessage() ERROR Missing Message Data...";
std::cerr << std::endl;
}
}
/*********************** **** **** **** ***********************/
/*********************** **** **** **** ***********************/
/*********************** **** **** **** ***********************/
/*********************** **** **** **** ***********************/
/*********************** **** **** **** ***********************/
/*********************** **** **** **** ***********************/
void GxsForumsDialog::loadRequest(const TokenQueue *queue, const TokenRequest &req)
{
std::cerr << "GxsForumsDialog::loadRequest() UserType: " << req.mUserType;
std::cerr << std::endl;
if (queue == mForumQueue)
{
/* now switch on req */
switch(req.mUserType)
{
case FORUMSV2DIALOG_LISTING:
loadGroupSummary(req.mToken);
break;
case FORUMSV2DIALOG_CURRENTFORUM:
loadGroupSummary_CurrentForum(req.mToken);
break;
case FORUMSV2DIALOG_INSERTTHREADS:
loadGroupThreadData_InsertThreads(req.mToken);
break;
case FORUMSV2DIALOG_INSERTCHILD:
loadChildData_InsertThreads(req.mToken);
break;
case FORUMV2DIALOG_INSERT_POST:
loadMsgData_InsertPost(req.mToken);
break;
case FORUMV2DIALOG_REPLY_MESSAGE:
loadMsgData_ReplyMessage(req.mToken);
break;
default:
std::cerr << "GxsForumsDialog::loadRequest() ERROR: INVALID TYPE";
std::cerr << std::endl;
break;
}
}
}