mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-10-01 02:35:48 -04:00
Merge branch 'v0.6.5' of github.com:RetroShare/RetroShare into v0.6.5
This commit is contained in:
commit
9264ef821f
@ -1714,10 +1714,11 @@ void RsGxsDataAccess::filterMsgList(
|
|||||||
|
|
||||||
MsgMetaFilter::const_iterator cit = msgMetas.find(groupId);
|
MsgMetaFilter::const_iterator cit = msgMetas.find(groupId);
|
||||||
if(cit == msgMetas.end()) continue;
|
if(cit == msgMetas.end()) continue;
|
||||||
|
#ifdef DATA_DEBUG
|
||||||
std::cerr << __PRETTY_FUNCTION__ << " " << msgsIdSet.size()
|
std::cerr << __PRETTY_FUNCTION__ << " " << msgsIdSet.size()
|
||||||
<< " for group: " << groupId << " before filtering"
|
<< " for group: " << groupId << " before filtering"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
for( std::set<RsGxsMessageId>::iterator msgIdIt = msgsIdSet.begin();
|
for( std::set<RsGxsMessageId>::iterator msgIdIt = msgsIdSet.begin();
|
||||||
msgIdIt != msgsIdSet.end(); )
|
msgIdIt != msgsIdSet.end(); )
|
||||||
@ -1738,9 +1739,11 @@ void RsGxsDataAccess::filterMsgList(
|
|||||||
else msgIdIt = msgsIdSet.erase(msgIdIt);
|
else msgIdIt = msgsIdSet.erase(msgIdIt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DATA_DEBUG
|
||||||
std::cerr << __PRETTY_FUNCTION__ << " " << msgsIdSet.size()
|
std::cerr << __PRETTY_FUNCTION__ << " " << msgsIdSet.size()
|
||||||
<< " for group: " << groupId << " after filtering"
|
<< " for group: " << groupId << " after filtering"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@ static const uint32_t RS_GXS_FORUM_MSG_FLAGS_MODERATED = 0x00000001;
|
|||||||
|
|
||||||
struct RsGxsForumGroup : RsSerializable
|
struct RsGxsForumGroup : RsSerializable
|
||||||
{
|
{
|
||||||
|
virtual ~RsGxsForumGroup() {}
|
||||||
|
|
||||||
RsGroupMetaData mMeta;
|
RsGroupMetaData mMeta;
|
||||||
std::string mDescription;
|
std::string mDescription;
|
||||||
|
|
||||||
@ -76,6 +78,8 @@ struct RsGxsForumGroup : RsSerializable
|
|||||||
|
|
||||||
struct RsGxsForumMsg : RsSerializable
|
struct RsGxsForumMsg : RsSerializable
|
||||||
{
|
{
|
||||||
|
virtual ~RsGxsForumMsg() {}
|
||||||
|
|
||||||
RsMsgMetaData mMeta;
|
RsMsgMetaData mMeta;
|
||||||
std::string mMsg;
|
std::string mMsg;
|
||||||
|
|
||||||
@ -139,10 +143,11 @@ public:
|
|||||||
const std::list<RsGxsGroupId>& forumIds,
|
const std::list<RsGxsGroupId>& forumIds,
|
||||||
std::vector<RsGxsForumGroup>& forumsInfo ) = 0;
|
std::vector<RsGxsForumGroup>& forumsInfo ) = 0;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get content of specified forums. Blocking API
|
* @brief Get content of specified forums. Blocking API
|
||||||
* @jsonapi{development}
|
* @jsonapi{development}
|
||||||
* @param[in] forumIds id of the channels of which the content is requested
|
* @param[in] forumIds id of the forum of which the content is requested
|
||||||
* @param[out] messages storage for the forum messages
|
* @param[out] messages storage for the forum messages
|
||||||
* @return false if something failed, true otherwhise
|
* @return false if something failed, true otherwhise
|
||||||
*/
|
*/
|
||||||
@ -150,6 +155,29 @@ public:
|
|||||||
const std::list<RsGxsGroupId>& forumIds,
|
const std::list<RsGxsGroupId>& forumIds,
|
||||||
std::vector<RsGxsForumMsg>& messages ) = 0;
|
std::vector<RsGxsForumMsg>& messages ) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get message metadatas for some messages of a specific forum. Blocking API
|
||||||
|
* @jsonapi{development}
|
||||||
|
* @param[in] forumIds id of the forum of which the content is requested
|
||||||
|
* @param[out] msg_metas storage for the forum messages meta data
|
||||||
|
* @return false if something failed, true otherwhise
|
||||||
|
*/
|
||||||
|
virtual bool getForumMsgMetaData( const RsGxsGroupId& forumId,
|
||||||
|
std::vector<RsMsgMetaData>& msg_metas) =0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get specific list of messages from a single forums. Blocking API
|
||||||
|
* @jsonapi{development}
|
||||||
|
* @param[in] forumId id of the forum of which the content is requested
|
||||||
|
* @param[in] msgs_to_request list of message ids to request
|
||||||
|
* @param[out] msgs storage for the forum messages
|
||||||
|
* @return false if something failed, true otherwhise
|
||||||
|
*/
|
||||||
|
virtual bool getForumsContent(
|
||||||
|
const RsGxsGroupId& forumId,
|
||||||
|
std::set<RsGxsMessageId>& msgs_to_request,
|
||||||
|
std::vector<RsGxsForumMsg>& msgs) =0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Toggle message read status. Blocking API.
|
* @brief Toggle message read status. Blocking API.
|
||||||
* @jsonapi{development}
|
* @jsonapi{development}
|
||||||
|
@ -61,6 +61,8 @@ struct RsGroupMetaData : RsSerializable
|
|||||||
mCircleType(0x0001), mAuthenFlags(0), mSubscribeFlags(0), mPop(0),
|
mCircleType(0x0001), mAuthenFlags(0), mSubscribeFlags(0), mPop(0),
|
||||||
mVisibleMsgCount(0), mLastPost(0), mGroupStatus(0) {}
|
mVisibleMsgCount(0), mLastPost(0), mGroupStatus(0) {}
|
||||||
|
|
||||||
|
virtual ~RsGroupMetaData() {}
|
||||||
|
|
||||||
void operator =(const RsGxsGrpMetaData& rGxsMeta);
|
void operator =(const RsGxsGrpMetaData& rGxsMeta);
|
||||||
|
|
||||||
RsGxsGroupId mGroupId;
|
RsGxsGroupId mGroupId;
|
||||||
@ -124,9 +126,9 @@ struct RsMsgMetaData : RsSerializable
|
|||||||
{
|
{
|
||||||
RsMsgMetaData() : mPublishTs(0), mMsgFlags(0), mMsgStatus(0), mChildTs(0) {}
|
RsMsgMetaData() : mPublishTs(0), mMsgFlags(0), mMsgStatus(0), mChildTs(0) {}
|
||||||
|
|
||||||
|
virtual ~RsMsgMetaData() {}
|
||||||
void operator =(const RsGxsMsgMetaData& rGxsMeta);
|
void operator =(const RsGxsMsgMetaData& rGxsMeta);
|
||||||
|
|
||||||
|
|
||||||
RsGxsGroupId mGroupId;
|
RsGxsGroupId mGroupId;
|
||||||
RsGxsMessageId mMsgId;
|
RsGxsMessageId mMsgId;
|
||||||
|
|
||||||
|
@ -297,6 +297,11 @@ bool p3GxsForums::getGroupData(const uint32_t &token, std::vector<RsGxsForumGrou
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool p3GxsForums::getMsgMetaData(const uint32_t &token, GxsMsgMetaMap& msg_metas)
|
||||||
|
{
|
||||||
|
return RsGenExchange::getMsgMeta(token, msg_metas);
|
||||||
|
}
|
||||||
|
|
||||||
/* Okay - chris is not going to be happy with this...
|
/* Okay - chris is not going to be happy with this...
|
||||||
* but I can't be bothered with crazy data structures
|
* but I can't be bothered with crazy data structures
|
||||||
* at the moment - fix it up later
|
* at the moment - fix it up later
|
||||||
@ -389,7 +394,7 @@ bool p3GxsForums::createForum(RsGxsForumGroup& forum)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(waitToken(token) != RsTokenService::COMPLETE)
|
if(waitToken(token,std::chrono::milliseconds(5000)) != RsTokenService::COMPLETE)
|
||||||
{
|
{
|
||||||
std::cerr << __PRETTY_FUNCTION__ << "Error! GXS operation failed."
|
std::cerr << __PRETTY_FUNCTION__ << "Error! GXS operation failed."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
@ -416,7 +421,7 @@ bool p3GxsForums::editForum(RsGxsForumGroup& forum)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(waitToken(token) != RsTokenService::COMPLETE)
|
if(waitToken(token,std::chrono::milliseconds(5000)) != RsTokenService::COMPLETE)
|
||||||
{
|
{
|
||||||
std::cerr << __PRETTY_FUNCTION__ << "Error! GXS operation failed."
|
std::cerr << __PRETTY_FUNCTION__ << "Error! GXS operation failed."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
@ -433,14 +438,13 @@ bool p3GxsForums::editForum(RsGxsForumGroup& forum)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool p3GxsForums::getForumsSummaries(
|
bool p3GxsForums::getForumsSummaries( std::list<RsGroupMetaData>& forums )
|
||||||
std::list<RsGroupMetaData>& forums )
|
|
||||||
{
|
{
|
||||||
uint32_t token;
|
uint32_t token;
|
||||||
RsTokReqOptions opts;
|
RsTokReqOptions opts;
|
||||||
opts.mReqType = GXS_REQUEST_TYPE_GROUP_META;
|
opts.mReqType = GXS_REQUEST_TYPE_GROUP_META;
|
||||||
if( !requestGroupInfo(token, opts)
|
if( !requestGroupInfo(token, opts)
|
||||||
|| waitToken(token) != RsTokenService::COMPLETE ) return false;
|
|| waitToken(token,std::chrono::milliseconds(5000)) != RsTokenService::COMPLETE ) return false;
|
||||||
return getGroupSummary(token, forums);
|
return getGroupSummary(token, forums);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,10 +456,24 @@ bool p3GxsForums::getForumsInfo(
|
|||||||
RsTokReqOptions opts;
|
RsTokReqOptions opts;
|
||||||
opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA;
|
opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA;
|
||||||
if( !requestGroupInfo(token, opts, forumIds)
|
if( !requestGroupInfo(token, opts, forumIds)
|
||||||
|| waitToken(token) != RsTokenService::COMPLETE ) return false;
|
|| waitToken(token,std::chrono::milliseconds(5000)) != RsTokenService::COMPLETE ) return false;
|
||||||
return getGroupData(token, forumsInfo);
|
return getGroupData(token, forumsInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool p3GxsForums::getForumsContent( const RsGxsGroupId& forumId, std::set<RsGxsMessageId>& msgs_to_request,std::vector<RsGxsForumMsg>& msgs)
|
||||||
|
{
|
||||||
|
uint32_t token;
|
||||||
|
RsTokReqOptions opts;
|
||||||
|
opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA;
|
||||||
|
|
||||||
|
GxsMsgReq msgIds;
|
||||||
|
msgIds[forumId] = msgs_to_request;
|
||||||
|
|
||||||
|
if( !requestMsgInfo(token, opts, msgIds) || waitToken(token,std::chrono::milliseconds(5000)) != RsTokenService::COMPLETE ) return false;
|
||||||
|
|
||||||
|
return getMsgData(token, msgs) ;
|
||||||
|
}
|
||||||
|
|
||||||
bool p3GxsForums::getForumsContent(
|
bool p3GxsForums::getForumsContent(
|
||||||
const std::list<RsGxsGroupId>& forumIds,
|
const std::list<RsGxsGroupId>& forumIds,
|
||||||
std::vector<RsGxsForumMsg>& messages )
|
std::vector<RsGxsForumMsg>& messages )
|
||||||
@ -464,15 +482,35 @@ bool p3GxsForums::getForumsContent(
|
|||||||
RsTokReqOptions opts;
|
RsTokReqOptions opts;
|
||||||
opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA;
|
opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA;
|
||||||
if( !requestMsgInfo(token, opts, forumIds)
|
if( !requestMsgInfo(token, opts, forumIds)
|
||||||
|| waitToken(token) != RsTokenService::COMPLETE ) return false;
|
|| waitToken(token,std::chrono::milliseconds(5000)) != RsTokenService::COMPLETE ) return false;
|
||||||
return getMsgData(token, messages);
|
return getMsgData(token, messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool p3GxsForums::getForumMsgMetaData(const RsGxsGroupId& forumId, std::vector<RsMsgMetaData>& msg_metas)
|
||||||
|
{
|
||||||
|
uint32_t token;
|
||||||
|
RsTokReqOptions opts;
|
||||||
|
opts.mReqType = GXS_REQUEST_TYPE_MSG_META;
|
||||||
|
|
||||||
|
GxsMsgMetaMap meta_map;
|
||||||
|
std::list<RsGxsGroupId> forumIds;
|
||||||
|
forumIds.push_back(forumId);
|
||||||
|
|
||||||
|
if( !requestMsgInfo(token, opts, forumIds) || waitToken(token,std::chrono::milliseconds(5000)) != RsTokenService::COMPLETE ) return false;
|
||||||
|
|
||||||
|
bool res = getMsgMetaData(token, meta_map);
|
||||||
|
|
||||||
|
msg_metas = meta_map[forumId];
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
bool p3GxsForums::markRead(const RsGxsGrpMsgIdPair& msgId, bool read)
|
bool p3GxsForums::markRead(const RsGxsGrpMsgIdPair& msgId, bool read)
|
||||||
{
|
{
|
||||||
uint32_t token;
|
uint32_t token;
|
||||||
setMessageReadStatus(token, msgId, read);
|
setMessageReadStatus(token, msgId, read);
|
||||||
if(waitToken(token) != RsTokenService::COMPLETE ) return false;
|
if(waitToken(token,std::chrono::milliseconds(5000)) != RsTokenService::COMPLETE ) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -517,7 +555,7 @@ bool p3GxsForums::createMessage(RsGxsForumMsg& message)
|
|||||||
{
|
{
|
||||||
uint32_t token;
|
uint32_t token;
|
||||||
if( !createMsg(token, message)
|
if( !createMsg(token, message)
|
||||||
|| waitToken(token) != RsTokenService::COMPLETE ) return false;
|
|| waitToken(token,std::chrono::milliseconds(5000)) != RsTokenService::COMPLETE ) return false;
|
||||||
|
|
||||||
if(RsGenExchange::getPublishedMsgMeta(token, message.mMeta)) return true;
|
if(RsGenExchange::getPublishedMsgMeta(token, message.mMeta)) return true;
|
||||||
|
|
||||||
|
@ -77,6 +77,12 @@ public:
|
|||||||
const std::list<RsGxsGroupId>& forumIds,
|
const std::list<RsGxsGroupId>& forumIds,
|
||||||
std::vector<RsGxsForumMsg>& messages );
|
std::vector<RsGxsForumMsg>& messages );
|
||||||
|
|
||||||
|
/// @see RsGxsForums::getForumMsgMetaData
|
||||||
|
virtual bool getForumMsgMetaData(const RsGxsGroupId& forumId, std::vector<RsMsgMetaData>& msg_metas) ;
|
||||||
|
|
||||||
|
/// @see RsGxsForums::getForumsContent
|
||||||
|
virtual bool getForumsContent( const RsGxsGroupId& forumId, std::set<RsGxsMessageId>& msgs_to_request,std::vector<RsGxsForumMsg>& msgs) ;
|
||||||
|
|
||||||
/// @see RsGxsForums::markRead
|
/// @see RsGxsForums::markRead
|
||||||
virtual bool markRead(const RsGxsGrpMsgIdPair& messageId, bool read);
|
virtual bool markRead(const RsGxsGrpMsgIdPair& messageId, bool read);
|
||||||
|
|
||||||
@ -86,6 +92,7 @@ public:
|
|||||||
|
|
||||||
virtual bool getGroupData(const uint32_t &token, std::vector<RsGxsForumGroup> &groups);
|
virtual bool getGroupData(const uint32_t &token, std::vector<RsGxsForumGroup> &groups);
|
||||||
virtual bool getMsgData(const uint32_t &token, std::vector<RsGxsForumMsg> &msgs);
|
virtual bool getMsgData(const uint32_t &token, std::vector<RsGxsForumMsg> &msgs);
|
||||||
|
virtual bool getMsgMetaData(const uint32_t &token, GxsMsgMetaMap& msg_metas);
|
||||||
virtual void setMessageReadStatus(uint32_t& token, const RsGxsGrpMsgIdPair& msgId, bool read);
|
virtual void setMessageReadStatus(uint32_t& token, const RsGxsGrpMsgIdPair& msgId, bool read);
|
||||||
virtual bool createGroup(uint32_t &token, RsGxsForumGroup &group);
|
virtual bool createGroup(uint32_t &token, RsGxsForumGroup &group);
|
||||||
virtual bool createMsg(uint32_t &token, RsGxsForumMsg &msg);
|
virtual bool createMsg(uint32_t &token, RsGxsForumMsg &msg);
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
#define IMAGE_PGPKNOWN ":/images/contact.png"
|
#define IMAGE_PGPKNOWN ":/images/contact.png"
|
||||||
#define IMAGE_PGPUNKNOWN ":/images/tags/pgp-unknown.png"
|
#define IMAGE_PGPUNKNOWN ":/images/tags/pgp-unknown.png"
|
||||||
#define IMAGE_ANON ":/images/tags/anon.png"
|
#define IMAGE_ANON ":/images/tags/anon.png"
|
||||||
#define IMAGE_BANNED ":/icons/yellow_biohazard64.png"
|
#define IMAGE_BANNED ":/icons/biohazard_red.png"
|
||||||
|
|
||||||
#define IMAGE_DEV_AMBASSADOR ":/images/tags/dev-ambassador.png"
|
#define IMAGE_DEV_AMBASSADOR ":/images/tags/dev-ambassador.png"
|
||||||
#define IMAGE_DEV_CONTRIBUTOR ":/images/tags/vote_down.png"
|
#define IMAGE_DEV_CONTRIBUTOR ":/images/tags/vote_down.png"
|
||||||
@ -897,7 +897,7 @@ QIcon GxsIdDetails::getLoadingIcon(const RsGxsId &/*id*/)
|
|||||||
return QIcon(IMAGE_LOADING);
|
return QIcon(IMAGE_LOADING);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GxsIdDetails::MakeIdDesc(const RsGxsId &id, bool doIcons, QString &str, QList<QIcon> &icons, QString& comment)
|
bool GxsIdDetails::MakeIdDesc(const RsGxsId &id, bool doIcons, QString &str, QList<QIcon> &icons, QString& comment,uint32_t icon_types)
|
||||||
{
|
{
|
||||||
RsIdentityDetails details;
|
RsIdentityDetails details;
|
||||||
|
|
||||||
@ -921,7 +921,7 @@ bool GxsIdDetails::MakeIdDesc(const RsGxsId &id, bool doIcons, QString &str, QLi
|
|||||||
comment += getComment(details);
|
comment += getComment(details);
|
||||||
|
|
||||||
if (doIcons)
|
if (doIcons)
|
||||||
getIcons(details, icons);
|
getIcons(details, icons,icon_types);
|
||||||
|
|
||||||
// Cyril: I disabled these three which I believe to have been put for testing purposes.
|
// Cyril: I disabled these three which I believe to have been put for testing purposes.
|
||||||
//
|
//
|
||||||
@ -973,7 +973,7 @@ QString nickname ;
|
|||||||
|
|
||||||
if (details.mFlags & RS_IDENTITY_FLAGS_PGP_LINKED)
|
if (details.mFlags & RS_IDENTITY_FLAGS_PGP_LINKED)
|
||||||
{
|
{
|
||||||
comment += QString("<br/>%1:%2 ").arg(QApplication::translate("GxsIdDetails", "Authentication"), QApplication::translate("GxsIdDetails", "Signed by"));
|
comment += QString("<br/>%1: ").arg(QApplication::translate("GxsIdDetails", "Node"));
|
||||||
|
|
||||||
if (details.mFlags & RS_IDENTITY_FLAGS_PGP_KNOWN)
|
if (details.mFlags & RS_IDENTITY_FLAGS_PGP_KNOWN)
|
||||||
{
|
{
|
||||||
@ -985,8 +985,8 @@ QString nickname ;
|
|||||||
else
|
else
|
||||||
comment += QApplication::translate("GxsIdDetails", "unknown Key");
|
comment += QApplication::translate("GxsIdDetails", "unknown Key");
|
||||||
}
|
}
|
||||||
else
|
//else
|
||||||
comment += QString("<br/>%1: %2").arg(QApplication::translate("GxsIdDetails", "Authentication"), QApplication::translate("GxsIdDetails", "anonymous"));
|
// comment += QString("<br/>%1: %2").arg(QApplication::translate("GxsIdDetails", "Node:"), QApplication::translate("GxsIdDetails", "anonymous"));
|
||||||
|
|
||||||
if(details.mReputation.mFriendsPositiveVotes || details.mReputation.mFriendsNegativeVotes)
|
if(details.mReputation.mFriendsPositiveVotes || details.mReputation.mFriendsNegativeVotes)
|
||||||
{
|
{
|
||||||
|
@ -63,6 +63,7 @@ class GxsIdDetails : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
static const int ICON_TYPE_NONE = 0x0000 ;
|
||||||
static const int ICON_TYPE_AVATAR = 0x0001 ;
|
static const int ICON_TYPE_AVATAR = 0x0001 ;
|
||||||
static const int ICON_TYPE_PGP = 0x0002 ;
|
static const int ICON_TYPE_PGP = 0x0002 ;
|
||||||
static const int ICON_TYPE_RECOGN = 0x0004 ;
|
static const int ICON_TYPE_RECOGN = 0x0004 ;
|
||||||
@ -76,7 +77,7 @@ public:
|
|||||||
static void cleanup();
|
static void cleanup();
|
||||||
|
|
||||||
/* Information */
|
/* Information */
|
||||||
static bool MakeIdDesc(const RsGxsId &id, bool doIcons, QString &desc, QList<QIcon> &icons, QString& comment);
|
static bool MakeIdDesc(const RsGxsId &id, bool doIcons, QString &desc, QList<QIcon> &icons, QString& comment, uint32_t icon_types=ICON_TYPE_ALL);
|
||||||
|
|
||||||
static QString getName(const RsIdentityDetails &details);
|
static QString getName(const RsIdentityDetails &details);
|
||||||
static QString getComment(const RsIdentityDetails &details);
|
static QString getComment(const RsIdentityDetails &details);
|
||||||
|
1320
retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp
Normal file
1320
retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp
Normal file
File diff suppressed because it is too large
Load Diff
207
retroshare-gui/src/gui/gxsforums/GxsForumModel.h
Normal file
207
retroshare-gui/src/gui/gxsforums/GxsForumModel.h
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* retroshare-gui/src/gui/gxsforums/GxsForumModel.h *
|
||||||
|
* *
|
||||||
|
* Copyright 2018 by Cyril Soler <csoler@users.sourceforge.net> *
|
||||||
|
* *
|
||||||
|
* 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 "retroshare/rsgxsforums.h"
|
||||||
|
#include "retroshare/rsgxsifacetypes.h"
|
||||||
|
#include <QModelIndex>
|
||||||
|
#include <QColor>
|
||||||
|
|
||||||
|
// This class holds the actual hierarchy of posts, represented by identifiers
|
||||||
|
// It is responsible for auto-updating when necessary and holds a mutex to allow the Model to
|
||||||
|
// safely access the data.
|
||||||
|
|
||||||
|
// The model contains a post in place 0 that is the parent of all posts.
|
||||||
|
|
||||||
|
typedef uint32_t ForumModelIndex;
|
||||||
|
|
||||||
|
struct ForumModelPostEntry
|
||||||
|
{
|
||||||
|
ForumModelPostEntry() : mPublishTs(0),mMostRecentTsInThread(0),mPostFlags(0),mReputationWarningLevel(0),mMsgStatus(0),prow(0) {}
|
||||||
|
|
||||||
|
enum { // flags for display of posts. To be used in mPostFlags
|
||||||
|
FLAG_POST_IS_PINNED = 0x0001,
|
||||||
|
FLAG_POST_IS_MISSING = 0x0002,
|
||||||
|
FLAG_POST_IS_REDACTED = 0x0004,
|
||||||
|
FLAG_POST_HAS_UNREAD_CHILDREN = 0x0008,
|
||||||
|
FLAG_POST_HAS_READ_CHILDREN = 0x0010,
|
||||||
|
FLAG_POST_PASSES_FILTER = 0x0020,
|
||||||
|
FLAG_POST_CHILDREN_PASSES_FILTER = 0x0040,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string mTitle ;
|
||||||
|
RsGxsId mAuthorId ;
|
||||||
|
RsGxsMessageId mMsgId;
|
||||||
|
uint32_t mPublishTs;
|
||||||
|
uint32_t mMostRecentTsInThread;
|
||||||
|
uint32_t mPostFlags;
|
||||||
|
int mReputationWarningLevel;
|
||||||
|
int mMsgStatus;
|
||||||
|
|
||||||
|
std::vector<ForumModelIndex> mChildren;
|
||||||
|
ForumModelIndex mParent;
|
||||||
|
int prow ; // parent row
|
||||||
|
};
|
||||||
|
|
||||||
|
// This class is the item model used by Qt to display the information
|
||||||
|
|
||||||
|
class RsGxsForumModel : public QAbstractItemModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit RsGxsForumModel(QObject *parent = NULL);
|
||||||
|
~RsGxsForumModel(){}
|
||||||
|
|
||||||
|
enum Columns {
|
||||||
|
COLUMN_THREAD_TITLE =0x00,
|
||||||
|
COLUMN_THREAD_READ =0x01,
|
||||||
|
COLUMN_THREAD_DATE =0x02,
|
||||||
|
COLUMN_THREAD_DISTRIBUTION =0x03,
|
||||||
|
COLUMN_THREAD_AUTHOR =0x04,
|
||||||
|
COLUMN_THREAD_CONTENT =0x05,
|
||||||
|
COLUMN_THREAD_MSGID =0x06,
|
||||||
|
COLUMN_THREAD_DATA =0x07,
|
||||||
|
COLUMN_THREAD_NB_COLUMNS =0x08,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Roles{ SortRole = Qt::UserRole+1,
|
||||||
|
ThreadPinnedRole = Qt::UserRole+2,
|
||||||
|
MissingRole = Qt::UserRole+3,
|
||||||
|
StatusRole = Qt::UserRole+4,
|
||||||
|
UnreadChildrenRole = Qt::UserRole+5,
|
||||||
|
FilterRole = Qt::UserRole+6,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TreeMode{ TREE_MODE_FLAT = 0x00,
|
||||||
|
TREE_MODE_TREE = 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SortMode{ SORT_MODE_PUBLISH_TS = 0x00,
|
||||||
|
SORT_MODE_CHILDREN_PUBLISH_TS = 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
|
QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;}
|
||||||
|
QModelIndex getIndexOfMessage(const RsGxsMessageId& mid) const;
|
||||||
|
|
||||||
|
static const QString FilterString ;
|
||||||
|
|
||||||
|
std::vector<std::pair<time_t,RsGxsMessageId> > getPostVersions(const RsGxsMessageId& mid) const;
|
||||||
|
|
||||||
|
// This method will asynchroneously update the data
|
||||||
|
void updateForum(const RsGxsGroupId& forumGroup);
|
||||||
|
const RsGxsGroupId& currentGroupId() const;
|
||||||
|
|
||||||
|
void setTreeMode(TreeMode mode) ;
|
||||||
|
void setSortMode(SortMode mode) ;
|
||||||
|
|
||||||
|
void setTextColorRead (QColor color) { mTextColorRead = color;}
|
||||||
|
void setTextColorUnread (QColor color) { mTextColorUnread = color;}
|
||||||
|
void setTextColorUnreadChildren(QColor color) { mTextColorUnreadChildren = color;}
|
||||||
|
void setTextColorNotSubscribed (QColor color) { mTextColorNotSubscribed = color;}
|
||||||
|
void setTextColorMissing (QColor color) { mTextColorMissing = color;}
|
||||||
|
|
||||||
|
void setMsgReadStatus(const QModelIndex &i, bool read_status, bool with_children);
|
||||||
|
void setFilter(int column, const QStringList &strings, uint32_t &count) ;
|
||||||
|
void setAuthorOpinion(const QModelIndex& indx,RsReputations::Opinion op);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||||
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
|
bool getPostData(const QModelIndex& i,ForumModelPostEntry& fmpe) const ;
|
||||||
|
|
||||||
|
QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override;
|
||||||
|
QModelIndex parent(const QModelIndex& child) const override;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||||
|
|
||||||
|
void clear() ;
|
||||||
|
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||||
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
QVariant sizeHintRole (int col) const;
|
||||||
|
QVariant displayRole (const ForumModelPostEntry& fmpe, int col) const;
|
||||||
|
QVariant decorationRole(const ForumModelPostEntry& fmpe, int col) const;
|
||||||
|
QVariant toolTipRole (const ForumModelPostEntry& fmpe, int col) const;
|
||||||
|
QVariant userRole (const ForumModelPostEntry& fmpe, int col) const;
|
||||||
|
QVariant pinnedRole (const ForumModelPostEntry& fmpe, int col) const;
|
||||||
|
QVariant missingRole (const ForumModelPostEntry& fmpe, int col) const;
|
||||||
|
QVariant statusRole (const ForumModelPostEntry& fmpe, int col) const;
|
||||||
|
QVariant authorRole (const ForumModelPostEntry& fmpe, int col) const;
|
||||||
|
QVariant sortRole (const ForumModelPostEntry& fmpe, int col) const;
|
||||||
|
QVariant fontRole (const ForumModelPostEntry& fmpe, int col) const;
|
||||||
|
QVariant filterRole (const ForumModelPostEntry& fmpe, int col) const;
|
||||||
|
QVariant textColorRole (const ForumModelPostEntry& fmpe, int col) const;
|
||||||
|
QVariant backgroundRole(const ForumModelPostEntry& fmpe, int col) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief debug_dump
|
||||||
|
* Dumps the hierarchy of posts in the terminal, to allow checking whether the internal representation is correct.
|
||||||
|
*/
|
||||||
|
void debug_dump();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void forumLoaded(); // emitted after the posts have been set. Can be used to updated the UI.
|
||||||
|
|
||||||
|
private:
|
||||||
|
RsGxsForumGroup mForumGroup;
|
||||||
|
|
||||||
|
bool mUseChildTS;
|
||||||
|
bool mFilteringEnabled;
|
||||||
|
TreeMode mTreeMode;
|
||||||
|
SortMode mSortMode;
|
||||||
|
|
||||||
|
void preMods() ;
|
||||||
|
void postMods() ;
|
||||||
|
|
||||||
|
void *getParentRef(void *ref,int& row) const;
|
||||||
|
void *getChildRef(void *ref,int row) const;
|
||||||
|
//bool hasIndex(int row,int column,const QModelIndex& parent)const;
|
||||||
|
int getChildrenCount(void *ref) const;
|
||||||
|
|
||||||
|
static bool convertTabEntryToRefPointer(uint32_t entry,void *& ref);
|
||||||
|
static bool convertRefPointerToTabEntry(void *ref,uint32_t& entry);
|
||||||
|
static void computeReputationLevel(uint32_t forum_sign_flags, ForumModelPostEntry& entry);
|
||||||
|
|
||||||
|
void update_posts(const RsGxsGroupId &group_id);
|
||||||
|
void setForumMessageSummary(const std::vector<RsGxsForumMsg>& messages);
|
||||||
|
void recursUpdateReadStatusAndTimes(ForumModelIndex i,bool& has_unread_below,bool& has_read_below);
|
||||||
|
uint32_t recursUpdateFilterStatus(ForumModelIndex i,int column,const QStringList& strings);
|
||||||
|
void recursSetMsgReadStatus(ForumModelIndex i,bool read_status,bool with_children);
|
||||||
|
|
||||||
|
static void generateMissingItem(const RsGxsMessageId &msgId,ForumModelPostEntry& entry);
|
||||||
|
static ForumModelIndex addEntry(std::vector<ForumModelPostEntry>& posts,const ForumModelPostEntry& entry,ForumModelIndex parent);
|
||||||
|
static void convertMsgToPostEntry(const RsGxsForumGroup &mForumGroup, const RsMsgMetaData &msg, bool useChildTS, ForumModelPostEntry& fentry);
|
||||||
|
|
||||||
|
void computeMessagesHierarchy(const RsGxsForumGroup& forum_group, const std::vector<RsMsgMetaData> &msgs_array, std::vector<ForumModelPostEntry>& posts, std::map<RsGxsMessageId, std::vector<std::pair<time_t, RsGxsMessageId> > > &mPostVersions);
|
||||||
|
void setPosts(const RsGxsForumGroup& group, const std::vector<ForumModelPostEntry>& posts,const std::map<RsGxsMessageId,std::vector<std::pair<time_t,RsGxsMessageId> > >& post_versions);
|
||||||
|
void initEmptyHierarchy(std::vector<ForumModelPostEntry>& posts);
|
||||||
|
|
||||||
|
std::vector<ForumModelPostEntry> mPosts ; // store the list of posts updated from rsForums.
|
||||||
|
std::map<RsGxsMessageId,std::vector<std::pair<time_t,RsGxsMessageId> > > mPostVersions;
|
||||||
|
|
||||||
|
QColor mTextColorRead ;
|
||||||
|
QColor mTextColorUnread ;
|
||||||
|
QColor mTextColorUnreadChildren;
|
||||||
|
QColor mTextColorNotSubscribed ;
|
||||||
|
QColor mTextColorMissing ;
|
||||||
|
|
||||||
|
friend class const_iterator;
|
||||||
|
};
|
File diff suppressed because it is too large
Load Diff
@ -27,11 +27,16 @@
|
|||||||
#include <retroshare/rsgxsforums.h>
|
#include <retroshare/rsgxsforums.h>
|
||||||
#include "gui/gxs/GxsIdDetails.h"
|
#include "gui/gxs/GxsIdDetails.h"
|
||||||
|
|
||||||
|
class QSortFilterProxyModel;
|
||||||
class QTreeWidgetItem;
|
class QTreeWidgetItem;
|
||||||
class RSTreeWidgetItemCompareRole;
|
class RSTreeWidgetItemCompareRole;
|
||||||
class RsGxsForumMsg;
|
class RsGxsForumMsg;
|
||||||
class GxsForumsFillThread;
|
class GxsForumsFillThread;
|
||||||
|
class QItemSelection;
|
||||||
class RsGxsForumGroup;
|
class RsGxsForumGroup;
|
||||||
|
class RsGxsForumModel;
|
||||||
|
class RsGxsForumMsg;
|
||||||
|
class ForumModelPostEntry;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class GxsForumThreadWidget;
|
class GxsForumThreadWidget;
|
||||||
@ -41,6 +46,8 @@ class GxsForumThreadWidget : public GxsMessageFrameWidget
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
typedef void (GxsForumThreadWidget::*MsgMethod)(const RsGxsForumMsg&) ;
|
||||||
|
|
||||||
Q_PROPERTY(QColor textColorRead READ textColorRead WRITE setTextColorRead)
|
Q_PROPERTY(QColor textColorRead READ textColorRead WRITE setTextColorRead)
|
||||||
Q_PROPERTY(QColor textColorUnread READ textColorUnread WRITE setTextColorUnread)
|
Q_PROPERTY(QColor textColorUnread READ textColorUnread WRITE setTextColorUnread)
|
||||||
Q_PROPERTY(QColor textColorUnreadChildren READ textColorUnreadChildren WRITE setTextColorUnreadChildren)
|
Q_PROPERTY(QColor textColorUnreadChildren READ textColorUnreadChildren WRITE setTextColorUnreadChildren)
|
||||||
@ -57,32 +64,28 @@ public:
|
|||||||
QColor textColorNotSubscribed() const { return mTextColorNotSubscribed; }
|
QColor textColorNotSubscribed() const { return mTextColorNotSubscribed; }
|
||||||
QColor textColorMissing() const { return mTextColorMissing; }
|
QColor textColorMissing() const { return mTextColorMissing; }
|
||||||
|
|
||||||
void setTextColorRead(QColor color) { mTextColorRead = color; }
|
void setTextColorRead (QColor color) ;
|
||||||
void setTextColorUnread(QColor color) { mTextColorUnread = color; }
|
void setTextColorUnread (QColor color) ;
|
||||||
void setTextColorUnreadChildren(QColor color) { mTextColorUnreadChildren = color; }
|
void setTextColorUnreadChildren(QColor color) ;
|
||||||
void setTextColorNotSubscribed(QColor color) { mTextColorNotSubscribed = color; }
|
void setTextColorNotSubscribed (QColor color) ;
|
||||||
void setTextColorMissing(QColor color) { mTextColorMissing = color; }
|
void setTextColorMissing (QColor color) ;
|
||||||
|
|
||||||
/* GxsMessageFrameWidget */
|
/* GxsMessageFrameWidget */
|
||||||
virtual void groupIdChanged();
|
virtual void groupIdChanged();
|
||||||
virtual QString groupName(bool withUnreadCount);
|
virtual QString groupName(bool withUnreadCount);
|
||||||
virtual QIcon groupIcon();
|
virtual QIcon groupIcon();
|
||||||
virtual bool navigate(const RsGxsMessageId& msgId);
|
virtual bool navigate(const RsGxsMessageId& msgId);
|
||||||
virtual bool isLoading();
|
|
||||||
|
|
||||||
unsigned int newCount() { return mNewCount; }
|
unsigned int newCount() { return mNewCount; }
|
||||||
unsigned int unreadCount() { return mUnreadCount; }
|
unsigned int unreadCount() { return mUnreadCount; }
|
||||||
|
|
||||||
QTreeWidgetItem *convertMsgToThreadWidget(const RsGxsForumMsg &msg, bool useChildTS, uint32_t filterColumn, QTreeWidgetItem *parent);
|
|
||||||
QTreeWidgetItem *generateMissingItem(const RsGxsMessageId &msgId);
|
QTreeWidgetItem *generateMissingItem(const RsGxsMessageId &msgId);
|
||||||
|
|
||||||
// Callback for all Loads.
|
|
||||||
virtual void loadRequest(const TokenQueue *queue, const TokenRequest &req);
|
|
||||||
virtual void blank();
|
virtual void blank();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool eventFilter(QObject *obj, QEvent *ev);
|
//bool eventFilter(QObject *obj, QEvent *ev);
|
||||||
void changeEvent(QEvent *e);
|
//void changeEvent(QEvent *e);
|
||||||
|
|
||||||
/* RsGxsUpdateBroadcastWidget */
|
/* RsGxsUpdateBroadcastWidget */
|
||||||
virtual void updateDisplay(bool complete);
|
virtual void updateDisplay(bool complete);
|
||||||
@ -95,9 +98,11 @@ private slots:
|
|||||||
void threadListCustomPopupMenu(QPoint point);
|
void threadListCustomPopupMenu(QPoint point);
|
||||||
void contextMenuTextBrowser(QPoint point);
|
void contextMenuTextBrowser(QPoint point);
|
||||||
|
|
||||||
void changedThread();
|
void changedSelection(const QModelIndex &, const QModelIndex &);
|
||||||
|
void changedThread(QModelIndex index);
|
||||||
void changedVersion();
|
void changedVersion();
|
||||||
void clickedThread (QTreeWidgetItem *item, int column);
|
void clickedThread (QModelIndex index);
|
||||||
|
void postForumLoading();
|
||||||
|
|
||||||
void reply_with_private_message();
|
void reply_with_private_message();
|
||||||
void replytoforummessage();
|
void replytoforummessage();
|
||||||
@ -108,13 +113,11 @@ private slots:
|
|||||||
void replyForumMessageData(const RsGxsForumMsg &msg);
|
void replyForumMessageData(const RsGxsForumMsg &msg);
|
||||||
void showAuthorInPeople(const RsGxsForumMsg& msg);
|
void showAuthorInPeople(const RsGxsForumMsg& msg);
|
||||||
|
|
||||||
|
// This method is used to perform an asynchroneous action on the message data. Any of the methods above can be used as parameter.
|
||||||
|
void async_msg_action(const MsgMethod& method);
|
||||||
|
|
||||||
void saveImage();
|
void saveImage();
|
||||||
|
|
||||||
|
|
||||||
//void print();
|
|
||||||
//void printpreview();
|
|
||||||
|
|
||||||
//void removemessage();
|
|
||||||
void markMsgAsRead();
|
void markMsgAsRead();
|
||||||
void markMsgAsReadChildren();
|
void markMsgAsReadChildren();
|
||||||
void markMsgAsUnread();
|
void markMsgAsUnread();
|
||||||
@ -141,59 +144,41 @@ private slots:
|
|||||||
|
|
||||||
void filterColumnChanged(int column);
|
void filterColumnChanged(int column);
|
||||||
void filterItems(const QString &text);
|
void filterItems(const QString &text);
|
||||||
|
|
||||||
void fillThreadFinished();
|
|
||||||
void fillThreadProgress(int current, int count);
|
|
||||||
void fillThreadStatus(QString text);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void insertMessageData(const RsGxsForumMsg &msg);
|
void insertMessageData(const RsGxsForumMsg &msg);
|
||||||
|
bool getCurrentPost(ForumModelPostEntry& fmpe) const ;
|
||||||
|
QModelIndex getCurrentIndex() const;
|
||||||
|
|
||||||
void insertThreads();
|
|
||||||
void insertMessage();
|
void insertMessage();
|
||||||
|
void insertGroupData();
|
||||||
|
|
||||||
void fillThreads(QList<QTreeWidgetItem *> &threadList, bool expandNewMessages, QList<QTreeWidgetItem*> &itemToExpand);
|
void recursRestoreExpandedItems(const QModelIndex& index, const QList<RsGxsMessageId>& expanded_items);
|
||||||
void fillChildren(QTreeWidgetItem *parentItem, QTreeWidgetItem *newParentItem, bool expandNewMessages, QList<QTreeWidgetItem*> &itemToExpand);
|
void recursSaveExpandedItems(const QModelIndex& index, QList<RsGxsMessageId>& expanded_items) const;
|
||||||
|
void saveExpandedItems(QList<RsGxsMessageId>& expanded_items) const;
|
||||||
|
|
||||||
int getSelectedMsgCount(QList<QTreeWidgetItem*> *pRows, QList<QTreeWidgetItem*> *pRowsRead, QList<QTreeWidgetItem*> *pRowsUnread);
|
int getSelectedMsgCount(QList<QTreeWidgetItem*> *pRows, QList<QTreeWidgetItem*> *pRowsRead, QList<QTreeWidgetItem*> *pRowsUnread);
|
||||||
void setMsgReadStatus(QList<QTreeWidgetItem*> &rows, bool read);
|
void setMsgReadStatus(QList<QTreeWidgetItem*> &rows, bool read);
|
||||||
void markMsgAsReadUnread(bool read, bool children, bool forum);
|
void markMsgAsReadUnread(bool read, bool children, bool forum);
|
||||||
void calculateIconsAndFonts(QTreeWidgetItem *item = NULL);
|
|
||||||
void calculateIconsAndFonts(QTreeWidgetItem *item, bool &hasReadChilddren, bool &hasUnreadChilddren);
|
|
||||||
void calculateUnreadCount();
|
void calculateUnreadCount();
|
||||||
|
|
||||||
void togglethreadview_internal();
|
void togglethreadview_internal();
|
||||||
|
|
||||||
bool filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn);
|
//bool filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn);
|
||||||
|
|
||||||
void processSettings(bool bLoad);
|
void processSettings(bool bLoad);
|
||||||
|
|
||||||
void requestGroupData();
|
void updateGroupData();
|
||||||
void loadGroupData(const uint32_t &token);
|
|
||||||
void insertGroupData();
|
|
||||||
static void loadAuthorIdCallback(GxsIdDetailsType type, const RsIdentityDetails &details, QObject *object, const QVariant &/*data*/);
|
static void loadAuthorIdCallback(GxsIdDetailsType type, const RsIdentityDetails &details, QObject *object, const QVariant &/*data*/);
|
||||||
|
|
||||||
void requestMessageData(const RsGxsGrpMsgIdPair &msgId);
|
void updateMessageData(const RsGxsMessageId& msgId);
|
||||||
void requestMsgData_ReplyWithPrivateMessage(const RsGxsGrpMsgIdPair &msgId);
|
void updateForumDescription();
|
||||||
void requestMsgData_ShowAuthorInPeople(const RsGxsGrpMsgIdPair &msgId);
|
|
||||||
void requestMsgData_ReplyForumMessage(const RsGxsGrpMsgIdPair &msgId);
|
|
||||||
void requestMsgData_EditForumMessage(const RsGxsGrpMsgIdPair &msgId);
|
|
||||||
|
|
||||||
void loadMessageData(const uint32_t &token);
|
|
||||||
void loadMsgData_ReplyMessage(const uint32_t &token);
|
|
||||||
void loadMsgData_ReplyForumMessage(const uint32_t &token);
|
|
||||||
void loadMsgData_EditForumMessage(const uint32_t &token);
|
|
||||||
void loadMsgData_ShowAuthorInPeople(const uint32_t &token);
|
|
||||||
void loadMsgData_SetAuthorOpinion(const uint32_t &token, RsReputations::Opinion opinion);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RsGxsGroupId mLastForumID;
|
RsGxsGroupId mLastForumID;
|
||||||
RsGxsMessageId mThreadId;
|
RsGxsMessageId mThreadId;
|
||||||
RsGxsMessageId mOrigThreadId;
|
RsGxsMessageId mOrigThreadId;
|
||||||
RsGxsForumGroup mForumGroup;
|
RsGxsForumGroup mForumGroup;
|
||||||
QString mForumDescription;
|
//bool mUpdating;
|
||||||
int mSubscribeFlags;
|
|
||||||
int mSignFlags;
|
|
||||||
bool mInProcessSettings;
|
bool mInProcessSettings;
|
||||||
bool mInMsgAsReadUnread;
|
bool mInMsgAsReadUnread;
|
||||||
int mLastViewType;
|
int mLastViewType;
|
||||||
@ -202,17 +187,6 @@ private:
|
|||||||
unsigned int mUnreadCount;
|
unsigned int mUnreadCount;
|
||||||
unsigned int mNewCount;
|
unsigned int mNewCount;
|
||||||
|
|
||||||
uint32_t mTokenTypeGroupData;
|
|
||||||
uint32_t mTokenTypeInsertThreads;
|
|
||||||
uint32_t mTokenTypeMessageData;
|
|
||||||
uint32_t mTokenTypeReplyMessage;
|
|
||||||
uint32_t mTokenTypeReplyForumMessage;
|
|
||||||
uint32_t mTokenTypeEditForumMessage;
|
|
||||||
uint32_t mTokenTypeShowAuthorInPeople;
|
|
||||||
uint32_t mTokenTypeNegativeAuthor;
|
|
||||||
uint32_t mTokenTypePositiveAuthor;
|
|
||||||
uint32_t mTokenTypeNeutralAuthor;
|
|
||||||
|
|
||||||
/* Color definitions (for standard see qss.default) */
|
/* Color definitions (for standard see qss.default) */
|
||||||
QColor mTextColorRead;
|
QColor mTextColorRead;
|
||||||
QColor mTextColorUnread;
|
QColor mTextColorUnread;
|
||||||
@ -223,7 +197,9 @@ private:
|
|||||||
RsGxsMessageId mNavigatePendingMsgId;
|
RsGxsMessageId mNavigatePendingMsgId;
|
||||||
QList<RsGxsMessageId> mIgnoredMsgId;
|
QList<RsGxsMessageId> mIgnoredMsgId;
|
||||||
|
|
||||||
QMap<RsGxsMessageId,QVector<QPair<time_t,RsGxsMessageId> > > mPostVersions ; // holds older versions of posts
|
RsGxsForumModel *mThreadModel;
|
||||||
|
QSortFilterProxyModel *mThreadProxyModel;
|
||||||
|
QList<RsGxsMessageId> mSavedExpandedMessages;
|
||||||
|
|
||||||
Ui::GxsForumThreadWidget *ui;
|
Ui::GxsForumThreadWidget *ui;
|
||||||
};
|
};
|
||||||
|
@ -215,7 +215,7 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="RSTreeWidget" name="threadTreeWidget">
|
<widget class="QTreeView" name="threadTreeWidget">
|
||||||
<property name="contextMenuPolicy">
|
<property name="contextMenuPolicy">
|
||||||
<enum>Qt::CustomContextMenu</enum>
|
<enum>Qt::CustomContextMenu</enum>
|
||||||
</property>
|
</property>
|
||||||
@ -225,42 +225,9 @@
|
|||||||
<property name="allColumnsShowFocus">
|
<property name="allColumnsShowFocus">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<column>
|
<attribute name="headerCascadingSectionResizes">
|
||||||
<property name="text">
|
<bool>true</bool>
|
||||||
<string>Title</string>
|
</attribute>
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
<column>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="../images.qrc">
|
|
||||||
<normaloff>:/images/message-state-header.png</normaloff>:/images/message-state-header.png</iconset>
|
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
<column>
|
|
||||||
<property name="text">
|
|
||||||
<string>Date</string>
|
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
<column>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Distribution</string>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="../icons.qrc">
|
|
||||||
<normaloff>:/icons/flag-green.png</normaloff>:/icons/flag-green.png</iconset>
|
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
<column>
|
|
||||||
<property name="text">
|
|
||||||
<string>Author</string>
|
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -272,7 +239,7 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QGridLayout" name="postLayout">
|
<layout class="QGridLayout" name="postLayout">
|
||||||
<item row="0" column="5">
|
<item row="0" column="6">
|
||||||
<widget class="QToolButton" name="downloadButton">
|
<widget class="QToolButton" name="downloadButton">
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
<size>
|
<size>
|
||||||
@ -286,28 +253,18 @@
|
|||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Download all files</string>
|
<string>Download all files</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="layoutDirection">
|
||||||
|
<enum>Qt::LeftToRight</enum>
|
||||||
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../images.qrc">
|
<iconset resource="../icons.qrc">
|
||||||
<normaloff>:/images/down.png</normaloff>:/images/down.png</iconset>
|
<normaloff>:/icons/global_switch_on_128.png</normaloff>:/icons/global_switch_on_128.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="autoRaise">
|
<property name="autoRaise">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="13">
|
|
||||||
<widget class="QPushButton" name="nextUnreadButton">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Next unread</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QToolButton" name="newmessageButton">
|
<widget class="QToolButton" name="newmessageButton">
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
@ -323,21 +280,21 @@
|
|||||||
<string>Reply Message</string>
|
<string>Reply Message</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Reply</string>
|
<string notr="true"/>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../images.qrc">
|
<iconset resource="../images.qrc">
|
||||||
<normaloff>:/images/mail_reply.png</normaloff>:/images/mail_reply.png</iconset>
|
<normaloff>:/images/replymailall24-hover.png</normaloff>:/images/replymailall24-hover.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolButtonStyle">
|
<property name="toolButtonStyle">
|
||||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
<enum>Qt::ToolButtonIconOnly</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="autoRaise">
|
<property name="autoRaise">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="15">
|
<item row="0" column="16">
|
||||||
<widget class="QPushButton" name="expandButton">
|
<widget class="QPushButton" name="expandButton">
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
<size>
|
<size>
|
||||||
@ -363,21 +320,14 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="6">
|
<item row="0" column="10">
|
||||||
<widget class="Line" name="lineLeft">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="9">
|
|
||||||
<widget class="Line" name="lineRight">
|
<widget class="Line" name="lineRight">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="12">
|
<item row="0" column="13">
|
||||||
<spacer name="postHSpacer">
|
<spacer name="postHSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
@ -469,28 +419,55 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="11">
|
<item row="0" column="12">
|
||||||
<widget class="GxsIdLabel" name="by_label">
|
<widget class="GxsIdLabel" name="by_label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true"/>
|
<string notr="true"/>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="10">
|
<item row="0" column="7">
|
||||||
|
<widget class="Line" name="lineLeft">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="9">
|
||||||
|
<widget class="QComboBox" name="versions_CB"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="8">
|
||||||
|
<widget class="QLabel" name="time_label">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="11">
|
||||||
<widget class="QLabel" name="by_text_label">
|
<widget class="QLabel" name="by_text_label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>By </string>
|
<string>By </string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="8">
|
<item row="0" column="5">
|
||||||
<widget class="QComboBox" name="versions_CB"/>
|
<widget class="QToolButton" name="nextUnreadButton">
|
||||||
</item>
|
<property name="sizePolicy">
|
||||||
<item row="0" column="7">
|
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||||
<widget class="QLabel" name="time_label">
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Next unread message</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true"/>
|
<string notr="true"/>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../images.qrc">
|
||||||
|
<normaloff>:/images/start.png</normaloff>:/images/start.png</iconset>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@ -558,11 +535,6 @@
|
|||||||
<extends>QTextBrowser</extends>
|
<extends>QTextBrowser</extends>
|
||||||
<header>gui/common/RSTextBrowser.h</header>
|
<header>gui/common/RSTextBrowser.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
<customwidget>
|
|
||||||
<class>RSTreeWidget</class>
|
|
||||||
<extends>QTreeWidget</extends>
|
|
||||||
<header>gui/common/RSTreeWidget.h</header>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>ElidedLabel</class>
|
<class>ElidedLabel</class>
|
||||||
<extends>QLabel</extends>
|
<extends>QLabel</extends>
|
||||||
|
@ -1,556 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.cpp *
|
|
||||||
* *
|
|
||||||
* Copyright 2012 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 <QApplication>
|
|
||||||
#include <QTreeWidgetItem>
|
|
||||||
|
|
||||||
#include "GxsForumsFillThread.h"
|
|
||||||
#include "GxsForumThreadWidget.h"
|
|
||||||
|
|
||||||
#include "retroshare/rsgxsflags.h"
|
|
||||||
#include <retroshare/rsgxsforums.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
//#define DEBUG_FORUMS
|
|
||||||
|
|
||||||
#define PROGRESSBAR_MAX 100
|
|
||||||
|
|
||||||
GxsForumsFillThread::GxsForumsFillThread(GxsForumThreadWidget *parent)
|
|
||||||
: QThread(parent), mParent(parent)
|
|
||||||
{
|
|
||||||
mStopped = false;
|
|
||||||
mCompareRole = NULL;
|
|
||||||
|
|
||||||
mExpandNewMessages = true;
|
|
||||||
mFillComplete = false;
|
|
||||||
|
|
||||||
mFilterColumn = 0;
|
|
||||||
|
|
||||||
mViewType = 0;
|
|
||||||
mFlatView = false;
|
|
||||||
mUseChildTS = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GxsForumsFillThread::~GxsForumsFillThread()
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << "GxsForumsFillThread::~GxsForumsFillThread" << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// remove all items (when items are available, the thread was terminated)
|
|
||||||
QList<QTreeWidgetItem *>::iterator item;
|
|
||||||
for (item = mItems.begin (); item != mItems.end (); ++item) {
|
|
||||||
if (*item) {
|
|
||||||
delete (*item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mItems.clear();
|
|
||||||
|
|
||||||
mItemToExpand.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GxsForumsFillThread::stop()
|
|
||||||
{
|
|
||||||
disconnect();
|
|
||||||
mStopped = true;
|
|
||||||
QApplication::processEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GxsForumsFillThread::calculateExpand(const RsGxsForumMsg &msg, QTreeWidgetItem *item)
|
|
||||||
{
|
|
||||||
if (mFillComplete && mExpandNewMessages && IS_MSG_UNREAD(msg.mMeta.mMsgStatus)) {
|
|
||||||
QTreeWidgetItem *parentItem = item;
|
|
||||||
while ((parentItem = parentItem->parent()) != NULL) {
|
|
||||||
if (std::find(mItemToExpand.begin(), mItemToExpand.end(), parentItem) == mItemToExpand.end()) {
|
|
||||||
mItemToExpand.push_back(parentItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool decreasing_time_comp(const QPair<time_t,RsGxsMessageId>& e1,const QPair<time_t,RsGxsMessageId>& e2) { return e2.first < e1.first ; }
|
|
||||||
|
|
||||||
void GxsForumsFillThread::run()
|
|
||||||
{
|
|
||||||
RsTokenService *service = rsGxsForums->getTokenService();
|
|
||||||
uint32_t msg_token;
|
|
||||||
uint32_t grp_token;
|
|
||||||
|
|
||||||
emit status(tr("Waiting"));
|
|
||||||
|
|
||||||
{
|
|
||||||
/* get all messages of the forum */
|
|
||||||
RsTokReqOptions opts;
|
|
||||||
opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA;
|
|
||||||
|
|
||||||
std::list<RsGxsGroupId> grpIds;
|
|
||||||
grpIds.push_back(mForumId);
|
|
||||||
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << "GxsForumsFillThread::run() forum id " << mForumId << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
service->requestMsgInfo(msg_token, RS_TOKREQ_ANSTYPE_DATA, opts, grpIds);
|
|
||||||
|
|
||||||
/* wait for the answer */
|
|
||||||
uint32_t requestStatus = RsTokenService::PENDING;
|
|
||||||
while (!wasStopped()) {
|
|
||||||
requestStatus = service->requestStatus(msg_token);
|
|
||||||
if (requestStatus == RsTokenService::FAILED ||
|
|
||||||
requestStatus == RsTokenService::COMPLETE) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
msleep(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requestStatus == RsTokenService::FAILED)
|
|
||||||
{
|
|
||||||
deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// also get the forum meta data.
|
|
||||||
{
|
|
||||||
RsTokReqOptions opts;
|
|
||||||
opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA;
|
|
||||||
|
|
||||||
std::list<RsGxsGroupId> grpIds;
|
|
||||||
grpIds.push_back(mForumId);
|
|
||||||
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << "GxsForumsFillThread::run() forum id " << mForumId << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
service->requestGroupInfo(grp_token, RS_TOKREQ_ANSTYPE_DATA, opts, grpIds);
|
|
||||||
|
|
||||||
/* wait for the answer */
|
|
||||||
uint32_t requestStatus = RsTokenService::PENDING;
|
|
||||||
while (!wasStopped()) {
|
|
||||||
requestStatus = service->requestStatus(grp_token);
|
|
||||||
if (requestStatus == RsTokenService::FAILED ||
|
|
||||||
requestStatus == RsTokenService::COMPLETE) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
msleep(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requestStatus == RsTokenService::FAILED)
|
|
||||||
{
|
|
||||||
deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wasStopped())
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << "GxsForumsFillThread::run() thread stopped, cancel request" << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* cancel request */
|
|
||||||
service->cancelRequest(msg_token);
|
|
||||||
service->cancelRequest(grp_token);
|
|
||||||
deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit status(tr("Retrieving"));
|
|
||||||
|
|
||||||
std::vector<RsGxsForumGroup> forum_groups;
|
|
||||||
|
|
||||||
if (!rsGxsForums->getGroupData(grp_token, forum_groups) || forum_groups.size() != 1)
|
|
||||||
{
|
|
||||||
deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RsGxsForumGroup forum_group = *forum_groups.begin();
|
|
||||||
|
|
||||||
//#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << "Retrieved group data: " << std::endl;
|
|
||||||
std::cerr << " Group ID: " << forum_group.mMeta.mGroupId << std::endl;
|
|
||||||
std::cerr << " Admin lst: " << forum_group.mAdminList.ids.size() << " elements." << std::endl;
|
|
||||||
for(auto it(forum_group.mAdminList.ids.begin());it!=forum_group.mAdminList.ids.end();++it)
|
|
||||||
std::cerr << " " << *it << std::endl;
|
|
||||||
std::cerr << " Pinned Post: " << forum_group.mPinnedPosts.ids.size() << " messages." << std::endl;
|
|
||||||
for(auto it(forum_group.mPinnedPosts.ids.begin());it!=forum_group.mPinnedPosts.ids.end();++it)
|
|
||||||
std::cerr << " " << *it << std::endl;
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
/* get messages */
|
|
||||||
std::map<RsGxsMessageId,RsGxsForumMsg> msgs;
|
|
||||||
|
|
||||||
{ // This forces to delete msgs_array after the conversion to std::map.
|
|
||||||
|
|
||||||
std::vector<RsGxsForumMsg> msgs_array;
|
|
||||||
|
|
||||||
if (!rsGxsForums->getMsgData(msg_token, msgs_array))
|
|
||||||
{
|
|
||||||
deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// now put everything into a map in order to make search log(n)
|
|
||||||
|
|
||||||
for(uint32_t i=0;i<msgs_array.size();++i)
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << "Adding message " << msgs_array[i].mMeta.mMsgId << " with parent " << msgs_array[i].mMeta.mParentId << " to message map" << std::endl;
|
|
||||||
#endif
|
|
||||||
msgs[msgs_array[i].mMeta.mMsgId] = msgs_array[i] ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
emit status(tr("Loading"));
|
|
||||||
|
|
||||||
int count = msgs.size();
|
|
||||||
int pos = 0;
|
|
||||||
int steps = count / PROGRESSBAR_MAX;
|
|
||||||
int step = 0;
|
|
||||||
|
|
||||||
// ThreadList contains the list of parent threads. The algorithm below iterates through all messages
|
|
||||||
// and tries to establish parenthood relationships between them, given that we only know the
|
|
||||||
// immediate parent of a message and now its children. Some messages have a missing parent and for them
|
|
||||||
// a fake top level parent is generated.
|
|
||||||
|
|
||||||
// In order to be efficient, we first create a structure that lists the children of every mesage ID in the list.
|
|
||||||
// Then the hierarchy of message is build by attaching the kids to every message until all of them have been processed.
|
|
||||||
// The messages with missing parents will be the last ones remaining in the list.
|
|
||||||
|
|
||||||
std::list<std::pair< RsGxsMessageId, QTreeWidgetItem* > > threadStack;
|
|
||||||
std::map<RsGxsMessageId,std::list<RsGxsMessageId> > kids_array ;
|
|
||||||
std::set<RsGxsMessageId> missing_parents;
|
|
||||||
|
|
||||||
// First of all, remove all older versions of posts. This is done by first adding all posts into a hierarchy structure
|
|
||||||
// and then removing all posts which have a new versions available. The older versions are kept appart.
|
|
||||||
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << "GxsForumsFillThread::run() Collecting post versions" << std::endl;
|
|
||||||
#endif
|
|
||||||
mPostVersions.clear();
|
|
||||||
std::list<RsGxsMessageId> msg_stack ;
|
|
||||||
|
|
||||||
for ( std::map<RsGxsMessageId,RsGxsForumMsg>::iterator msgIt = msgs.begin(); msgIt != msgs.end();++msgIt)
|
|
||||||
{
|
|
||||||
if(wasStopped())
|
|
||||||
{
|
|
||||||
deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(!msgIt->second.mMeta.mOrigMsgId.isNull() && msgIt->second.mMeta.mOrigMsgId != msgIt->second.mMeta.mMsgId)
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << " Post " << msgIt->second.mMeta.mMsgId << " is a new version of " << msgIt->second.mMeta.mOrigMsgId << std::endl;
|
|
||||||
#endif
|
|
||||||
std::map<RsGxsMessageId,RsGxsForumMsg>::iterator msgIt2 = msgs.find(msgIt->second.mMeta.mOrigMsgId);
|
|
||||||
|
|
||||||
// Ensuring that the post exists allows to only collect the existing data.
|
|
||||||
|
|
||||||
if(msgIt2 == msgs.end())
|
|
||||||
continue ;
|
|
||||||
|
|
||||||
// Make sure that the author is the same than the original message, or is a moderator. This should always happen when messages are constructed using
|
|
||||||
// the UI but nothing can prevent a nasty user to craft a new version of a message with his own signature.
|
|
||||||
|
|
||||||
if(msgIt2->second.mMeta.mAuthorId != msgIt->second.mMeta.mAuthorId)
|
|
||||||
{
|
|
||||||
if( !IS_FORUM_MSG_MODERATION(msgIt->second.mMeta.mMsgFlags) ) // if authors are different the moderation flag needs to be set on the editing msg
|
|
||||||
continue ;
|
|
||||||
|
|
||||||
if( forum_group.mAdminList.ids.find(msgIt->second.mMeta.mAuthorId)==forum_group.mAdminList.ids.end()) // if author is not a moderator, continue
|
|
||||||
continue ;
|
|
||||||
}
|
|
||||||
|
|
||||||
// always add the post a self version
|
|
||||||
|
|
||||||
if(mPostVersions[msgIt->second.mMeta.mOrigMsgId].empty())
|
|
||||||
mPostVersions[msgIt->second.mMeta.mOrigMsgId].push_back(QPair<time_t,RsGxsMessageId>(msgIt2->second.mMeta.mPublishTs,msgIt2->second.mMeta.mMsgId)) ;
|
|
||||||
|
|
||||||
mPostVersions[msgIt->second.mMeta.mOrigMsgId].push_back(QPair<time_t,RsGxsMessageId>(msgIt->second.mMeta.mPublishTs,msgIt->second.mMeta.mMsgId)) ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The following code assembles all new versions of a given post into the same array, indexed by the oldest version of the post.
|
|
||||||
|
|
||||||
for(QMap<RsGxsMessageId,QVector<QPair<time_t,RsGxsMessageId> > >::iterator it(mPostVersions.begin());it!=mPostVersions.end();++it)
|
|
||||||
{
|
|
||||||
if(wasStopped())
|
|
||||||
{
|
|
||||||
deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QVector<QPair<time_t,RsGxsMessageId> >& v(*it) ;
|
|
||||||
|
|
||||||
for(int32_t i=0;i<v.size();++i)
|
|
||||||
{
|
|
||||||
if(wasStopped())
|
|
||||||
{
|
|
||||||
deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(v[i].second != it.key())
|
|
||||||
{
|
|
||||||
RsGxsMessageId sub_msg_id = v[i].second ;
|
|
||||||
|
|
||||||
QMap<RsGxsMessageId,QVector<QPair<time_t,RsGxsMessageId> > >::iterator it2 = mPostVersions.find(sub_msg_id);
|
|
||||||
|
|
||||||
if(it2 != mPostVersions.end())
|
|
||||||
{
|
|
||||||
for(int32_t j=0;j<(*it2).size();++j)
|
|
||||||
if((*it2)[j].second != sub_msg_id) // dont copy it, since it is already present at slot i
|
|
||||||
v.append((*it2)[j]) ;
|
|
||||||
|
|
||||||
mPostVersions.erase(it2) ; // it2 is never equal to it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Now remove from msg ids, all posts except the most recent one. And make the mPostVersion be indexed by the most recent version of the post,
|
|
||||||
// which corresponds to the item in the tree widget.
|
|
||||||
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << "Final post versions: " << std::endl;
|
|
||||||
#endif
|
|
||||||
QMap<RsGxsMessageId,QVector<QPair<time_t,RsGxsMessageId> > > mTmp;
|
|
||||||
std::map<RsGxsMessageId,RsGxsMessageId> most_recent_versions ;
|
|
||||||
|
|
||||||
for(QMap<RsGxsMessageId,QVector<QPair<time_t,RsGxsMessageId> > >::iterator it(mPostVersions.begin());it!=mPostVersions.end();++it)
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << "Original post: " << it.key() << std::endl;
|
|
||||||
#endif
|
|
||||||
if(wasStopped())
|
|
||||||
{
|
|
||||||
deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Finally, sort the posts from newer to older
|
|
||||||
|
|
||||||
qSort((*it).begin(),(*it).end(),decreasing_time_comp) ;
|
|
||||||
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << " most recent version " << (*it)[0].first << " " << (*it)[0].second << std::endl;
|
|
||||||
#endif
|
|
||||||
for(int32_t i=1;i<(*it).size();++i)
|
|
||||||
{
|
|
||||||
if(wasStopped())
|
|
||||||
{
|
|
||||||
deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
msgs.erase((*it)[i].second) ;
|
|
||||||
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << " older version " << (*it)[i].first << " " << (*it)[i].second << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
mTmp[(*it)[0].second] = *it ; // index the versions map by the ID of the most recent post.
|
|
||||||
|
|
||||||
// Now make sure that message parents are consistent. Indeed, an old post may have the old version of a post as parent. So we need to change that parent
|
|
||||||
// to the newest version. So we create a map of which is the most recent version of each message, so that parent messages can be searched in it.
|
|
||||||
|
|
||||||
for(int i=1;i<(*it).size();++i)
|
|
||||||
{
|
|
||||||
if(wasStopped())
|
|
||||||
{
|
|
||||||
deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
most_recent_versions[(*it)[i].second] = (*it)[0].second ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mPostVersions = mTmp ;
|
|
||||||
|
|
||||||
// The next step is to find the top level thread messages. These are defined as the messages without
|
|
||||||
// any parent message ID.
|
|
||||||
|
|
||||||
// this trick is needed because while we remove messages, the parents a given msg may already have been removed
|
|
||||||
// and wrongly understand as a missing parent.
|
|
||||||
|
|
||||||
std::map<RsGxsMessageId,RsGxsForumMsg> kept_msgs;
|
|
||||||
|
|
||||||
for ( std::map<RsGxsMessageId,RsGxsForumMsg>::iterator msgIt = msgs.begin(); msgIt != msgs.end();++msgIt)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (wasStopped())
|
|
||||||
{
|
|
||||||
deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(mFlatView || msgIt->second.mMeta.mParentId.isNull())
|
|
||||||
{
|
|
||||||
|
|
||||||
/* add all threads */
|
|
||||||
if (wasStopped())
|
|
||||||
{
|
|
||||||
deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const RsGxsForumMsg& msg = msgIt->second;
|
|
||||||
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << "GxsForumsFillThread::run() Adding TopLevel Thread: mId: " << msg.mMeta.mMsgId << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QTreeWidgetItem *item = mParent->convertMsgToThreadWidget(msg, mUseChildTS, mFilterColumn,NULL);
|
|
||||||
|
|
||||||
if (!mFlatView)
|
|
||||||
threadStack.push_back(std::make_pair(msg.mMeta.mMsgId,item)) ;
|
|
||||||
|
|
||||||
calculateExpand(msg, item);
|
|
||||||
|
|
||||||
mItems.append(item);
|
|
||||||
|
|
||||||
if (++step >= steps) {
|
|
||||||
step = 0;
|
|
||||||
emit progress(++pos, PROGRESSBAR_MAX);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << "GxsForumsFillThread::run() Storing kid " << msgIt->first << " of message " << msgIt->second.mMeta.mParentId << std::endl;
|
|
||||||
#endif
|
|
||||||
// The same missing parent may appear multiple times, so we first store them into a unique container.
|
|
||||||
|
|
||||||
RsGxsMessageId parent_msg = msgIt->second.mMeta.mParentId;
|
|
||||||
|
|
||||||
if(msgs.find(parent_msg) == msgs.end())
|
|
||||||
{
|
|
||||||
// also check that the message is not versionned
|
|
||||||
|
|
||||||
std::map<RsGxsMessageId,RsGxsMessageId>::const_iterator mrit = most_recent_versions.find(parent_msg) ;
|
|
||||||
|
|
||||||
if(mrit != most_recent_versions.end())
|
|
||||||
parent_msg = mrit->second ;
|
|
||||||
else
|
|
||||||
missing_parents.insert(parent_msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
kids_array[parent_msg].push_back(msgIt->first) ;
|
|
||||||
kept_msgs.insert(*msgIt) ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
msgs = kept_msgs;
|
|
||||||
|
|
||||||
// Also create a list of posts by time, when they are new versions of existing posts. Only the last one will have an item created.
|
|
||||||
|
|
||||||
// Add a fake toplevel item for the parent IDs that we dont actually have.
|
|
||||||
|
|
||||||
for(std::set<RsGxsMessageId>::const_iterator it(missing_parents.begin());it!=missing_parents.end();++it)
|
|
||||||
{
|
|
||||||
// add dummy parent item
|
|
||||||
QTreeWidgetItem *parent = mParent->generateMissingItem(*it);
|
|
||||||
mItems.append( parent );
|
|
||||||
|
|
||||||
threadStack.push_back(std::make_pair(*it,parent)) ;
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << "GxsForumsFillThread::run() Processing stack:" << std::endl;
|
|
||||||
#endif
|
|
||||||
// Now use a stack to go down the hierarchy
|
|
||||||
|
|
||||||
while (!threadStack.empty())
|
|
||||||
{
|
|
||||||
if (wasStopped())
|
|
||||||
{
|
|
||||||
deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<RsGxsMessageId, QTreeWidgetItem*> threadPair = threadStack.front();
|
|
||||||
threadStack.pop_front();
|
|
||||||
|
|
||||||
std::map<RsGxsMessageId, std::list<RsGxsMessageId> >::iterator it = kids_array.find(threadPair.first) ;
|
|
||||||
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << "GxsForumsFillThread::run() Node: " << threadPair.first << std::endl;
|
|
||||||
#endif
|
|
||||||
if(it == kids_array.end())
|
|
||||||
continue ;
|
|
||||||
|
|
||||||
|
|
||||||
for(std::list<RsGxsMessageId>::const_iterator it2(it->second.begin());it2!=it->second.end();++it2)
|
|
||||||
{
|
|
||||||
if(wasStopped())
|
|
||||||
{
|
|
||||||
deleteLater();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// We iterate through the top level thread items, and look for which message has the current item as parent.
|
|
||||||
// When found, the item is put in the thread list itself, as a potential new parent.
|
|
||||||
|
|
||||||
std::map<RsGxsMessageId,RsGxsForumMsg>::iterator mit = msgs.find(*it2) ;
|
|
||||||
|
|
||||||
if(mit == msgs.end())
|
|
||||||
{
|
|
||||||
std::cerr << "GxsForumsFillThread::run() Cannot find submessage " << *it2 << " !!!" << std::endl;
|
|
||||||
continue ;
|
|
||||||
}
|
|
||||||
|
|
||||||
const RsGxsForumMsg& msg(mit->second) ;
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << "GxsForumsFillThread::run() adding sub_item " << msg.mMeta.mMsgId << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QTreeWidgetItem *item = mParent->convertMsgToThreadWidget(msg, mUseChildTS, mFilterColumn, threadPair.second);
|
|
||||||
calculateExpand(msg, item);
|
|
||||||
|
|
||||||
/* add item to process list */
|
|
||||||
threadStack.push_back(std::make_pair(msg.mMeta.mMsgId, item));
|
|
||||||
|
|
||||||
if (++step >= steps) {
|
|
||||||
step = 0;
|
|
||||||
emit progress(++pos, PROGRESSBAR_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
msgs.erase(mit);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << "GxsForumsFillThread::run() Erasing entry " << it->first << " from kids tab." << std::endl;
|
|
||||||
#endif
|
|
||||||
kids_array.erase(it) ; // This is not strictly needed, but it improves performance by reducing the search space.
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_FORUMS
|
|
||||||
std::cerr << "Kids array now has " << kids_array.size() << " elements" << std::endl;
|
|
||||||
for(std::map<RsGxsMessageId,std::list<RsGxsMessageId> >::const_iterator it(kids_array.begin());it!=kids_array.end();++it)
|
|
||||||
{
|
|
||||||
std::cerr << "Node " << it->first << std::endl;
|
|
||||||
for(std::list<RsGxsMessageId>::const_iterator it2(it->second.begin());it2!=it->second.end();++it2)
|
|
||||||
std::cerr << " " << *it2 << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << "GxsForumsFillThread::run() stopped: " << (wasStopped() ? "yes" : "no") << std::endl;
|
|
||||||
#endif
|
|
||||||
if(wasStopped())
|
|
||||||
deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* retroshare-gui/src/gui/gxsforums/GxsForumsFillThread.h *
|
|
||||||
* *
|
|
||||||
* Copyright 2012 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/>. *
|
|
||||||
* *
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#ifndef GXSFORUMSFILLTHREAD_H
|
|
||||||
#define GXSFORUMSFILLTHREAD_H
|
|
||||||
|
|
||||||
#include <QThread>
|
|
||||||
#include <QMap>
|
|
||||||
#include <QPair>
|
|
||||||
#include "retroshare/rsgxsifacetypes.h"
|
|
||||||
|
|
||||||
class GxsForumThreadWidget;
|
|
||||||
class RsGxsForumMsg;
|
|
||||||
class RSTreeWidgetItemCompareRole;
|
|
||||||
class QTreeWidgetItem;
|
|
||||||
|
|
||||||
class GxsForumsFillThread : public QThread
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
GxsForumsFillThread(GxsForumThreadWidget *parent);
|
|
||||||
~GxsForumsFillThread();
|
|
||||||
|
|
||||||
void run();
|
|
||||||
void stop();
|
|
||||||
bool wasStopped() { return mStopped; }
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void progress(int current, int count);
|
|
||||||
void status(QString text);
|
|
||||||
|
|
||||||
public:
|
|
||||||
RsGxsGroupId mForumId;
|
|
||||||
int mFilterColumn;
|
|
||||||
bool mFillComplete;
|
|
||||||
int mViewType;
|
|
||||||
bool mFlatView;
|
|
||||||
bool mUseChildTS;
|
|
||||||
bool mExpandNewMessages;
|
|
||||||
std::string mFocusMsgId;
|
|
||||||
RSTreeWidgetItemCompareRole *mCompareRole;
|
|
||||||
|
|
||||||
QList<QTreeWidgetItem*> mItems;
|
|
||||||
QList<QTreeWidgetItem*> mItemToExpand;
|
|
||||||
|
|
||||||
QMap<RsGxsMessageId,QVector<QPair<time_t,RsGxsMessageId> > > mPostVersions ;
|
|
||||||
private:
|
|
||||||
void calculateExpand(const RsGxsForumMsg &msg, QTreeWidgetItem *item);
|
|
||||||
|
|
||||||
GxsForumThreadWidget *mParent;
|
|
||||||
volatile bool mStopped;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // GXSFORUMSFILLTHREAD_H
|
|
@ -1230,7 +1230,7 @@ gxsforums {
|
|||||||
gui/gxsforums/GxsForumGroupDialog.h \
|
gui/gxsforums/GxsForumGroupDialog.h \
|
||||||
gui/gxsforums/CreateGxsForumMsg.h \
|
gui/gxsforums/CreateGxsForumMsg.h \
|
||||||
gui/gxsforums/GxsForumThreadWidget.h \
|
gui/gxsforums/GxsForumThreadWidget.h \
|
||||||
gui/gxsforums/GxsForumsFillThread.h \
|
gui/gxsforums/GxsForumModel.h \
|
||||||
gui/gxsforums/GxsForumUserNotify.h \
|
gui/gxsforums/GxsForumUserNotify.h \
|
||||||
gui/feeds/GxsForumGroupItem.h \
|
gui/feeds/GxsForumGroupItem.h \
|
||||||
gui/feeds/GxsForumMsgItem.h
|
gui/feeds/GxsForumMsgItem.h
|
||||||
@ -1244,7 +1244,7 @@ gxsforums {
|
|||||||
gui/gxsforums/GxsForumGroupDialog.cpp \
|
gui/gxsforums/GxsForumGroupDialog.cpp \
|
||||||
gui/gxsforums/CreateGxsForumMsg.cpp \
|
gui/gxsforums/CreateGxsForumMsg.cpp \
|
||||||
gui/gxsforums/GxsForumThreadWidget.cpp \
|
gui/gxsforums/GxsForumThreadWidget.cpp \
|
||||||
gui/gxsforums/GxsForumsFillThread.cpp \
|
gui/gxsforums/GxsForumModel.cpp \
|
||||||
gui/gxsforums/GxsForumUserNotify.cpp \
|
gui/gxsforums/GxsForumUserNotify.cpp \
|
||||||
gui/feeds/GxsForumGroupItem.cpp \
|
gui/feeds/GxsForumGroupItem.cpp \
|
||||||
gui/feeds/GxsForumMsgItem.cpp
|
gui/feeds/GxsForumMsgItem.cpp
|
||||||
|
Loading…
Reference in New Issue
Block a user