mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-12-24 23:19:29 -05:00
merged upstream
This commit is contained in:
commit
5915c27b9f
File diff suppressed because it is too large
Load Diff
55
libbitdht/src/bitdht/bdboot_generate.sh
Executable file
55
libbitdht/src/bitdht/bdboot_generate.sh
Executable file
@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
|
||||
<<LICENSE
|
||||
|
||||
Copyright (C) 2020 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
LICENSE
|
||||
|
||||
<<README
|
||||
Generate a clean DHT bootstrap node list.
|
||||
Feeds on previously known nodes from standard input and a few well known
|
||||
mainline DHT bootstrap nodes. Prints only nodes that appears to be active to a
|
||||
quick nmap check. Make sure your internet connection is working well before
|
||||
using this.
|
||||
|
||||
Example usage:
|
||||
--------------------------------
|
||||
cat bdboot.txt | bdboot_generate.sh | tee /tmp/bdboot_generated.txt
|
||||
cat /tmp/bdboot_generated.txt | sort -u > bdboot.txt
|
||||
--------------------------------
|
||||
README
|
||||
|
||||
function check_dht_host()
|
||||
{
|
||||
mHost="$1"
|
||||
mPort="$2"
|
||||
|
||||
sudo nmap -oG - -sU -p $mPort $mHost | grep open | \
|
||||
awk '{print $2" "$5}' | awk -F/ '{print $1}'
|
||||
}
|
||||
|
||||
cat | while read line; do
|
||||
hostIP="$(echo $line | awk '{print $1}')"
|
||||
hostPort="$(echo $line | awk '{print $2}')"
|
||||
check_dht_host $hostIP $hostPort
|
||||
done
|
||||
|
||||
check_dht_host router.utorrent.com 6881
|
||||
check_dht_host router.bittorrent.com 6881
|
||||
check_dht_host dht.libtorrent.org 25401
|
||||
check_dht_host dht.transmissionbt.com 6881
|
||||
|
@ -388,7 +388,12 @@ void p3discovery2::recvOwnContactInfo(const RsPeerId &fromId, const RsDiscContac
|
||||
|
||||
setPeerVersion(fromId, item->version);
|
||||
|
||||
updatePeerAddresses(item);
|
||||
// Hidden nodes do not need IP information. So that information is dropped.
|
||||
// However, that doesn't mean hidden nodes do not know that information. Normally
|
||||
// normal nodes should not send it, but old nodes still do.
|
||||
|
||||
if(!mPeerMgr->isHiddenNode(rsPeers->getOwnId()))
|
||||
updatePeerAddresses(item);
|
||||
|
||||
// if the peer is not validated, we stop the exchange here
|
||||
|
||||
|
@ -61,7 +61,7 @@ static const uint32_t INDEX_AUTHEN_ADMIN = 0x00000040; // admin key
|
||||
|
||||
#define GXS_MASK "GXS_MASK_HACK"
|
||||
|
||||
//#define GEN_EXCH_DEBUG 1
|
||||
#define GEN_EXCH_DEBUG 1
|
||||
|
||||
static const uint32_t MSG_CLEANUP_PERIOD = 60*59; // 59 minutes
|
||||
static const uint32_t INTEGRITY_CHECK_PERIOD = 60*31; // 31 minutes
|
||||
@ -282,7 +282,7 @@ bool RsGenExchange::messagePublicationTest(const RsGxsMsgMetaData& meta)
|
||||
|
||||
rstime_t storageTimeLimit = meta.mPublishTs + st;
|
||||
|
||||
return meta.mMsgStatus & GXS_SERV::GXS_MSG_STATUS_KEEP || st == 0 || storageTimeLimit >= time(NULL);
|
||||
return meta.mMsgStatus & GXS_SERV::GXS_MSG_STATUS_KEEP_FOREVER || st == 0 || storageTimeLimit >= time(NULL);
|
||||
}
|
||||
|
||||
bool RsGenExchange::acknowledgeTokenMsg(const uint32_t& token,
|
||||
|
@ -196,7 +196,6 @@ bool RsGxsGrpMetaData::deserialise(void *data, uint32_t &pktsize)
|
||||
|
||||
return ok;
|
||||
}
|
||||
int RsGxsMsgMetaData::refcount = 0;
|
||||
|
||||
RsGxsMsgMetaData::RsGxsMsgMetaData(){
|
||||
clear();
|
||||
|
@ -99,8 +99,6 @@ public:
|
||||
void clear();
|
||||
void operator =(const RsMsgMetaData& rMeta);
|
||||
|
||||
static int refcount;
|
||||
|
||||
//Sort data in same order than serialiser and deserializer
|
||||
RsGxsGroupId mGroupId;
|
||||
RsGxsMessageId mMsgId;
|
||||
|
@ -167,7 +167,12 @@ public:
|
||||
class RsGxsNetTunnelTurtleSearchGroupDataItem: public RsGxsNetTunnelItem
|
||||
{
|
||||
public:
|
||||
explicit RsGxsNetTunnelTurtleSearchGroupDataItem(): RsGxsNetTunnelItem(RS_PKT_SUBTYPE_GXS_NET_TUNNEL_TURTLE_SEARCH_GROUP_DATA) {}
|
||||
explicit RsGxsNetTunnelTurtleSearchGroupDataItem()
|
||||
: RsGxsNetTunnelItem(RS_PKT_SUBTYPE_GXS_NET_TUNNEL_TURTLE_SEARCH_GROUP_DATA),
|
||||
encrypted_group_data(NULL),
|
||||
encrypted_group_data_len(0)
|
||||
{}
|
||||
|
||||
virtual ~RsGxsNetTunnelTurtleSearchGroupDataItem() {}
|
||||
|
||||
uint16_t service ;
|
||||
|
@ -107,7 +107,7 @@ bool RsGxsMessageCleanUp::clean()
|
||||
bool remove = store_period > 0 && ((meta->mPublishTs + store_period) < now) && !have_kids;
|
||||
|
||||
// check client does not want the message kept regardless of age
|
||||
remove &= !(meta->mMsgStatus & GXS_SERV::GXS_MSG_STATUS_KEEP);
|
||||
remove &= !(meta->mMsgStatus & GXS_SERV::GXS_MSG_STATUS_KEEP_FOREVER);
|
||||
|
||||
// if not subscribed remove messages (can optimise this really)
|
||||
remove = remove || (grpMeta->mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_NOT_SUBSCRIBED);
|
||||
|
@ -111,27 +111,6 @@ typedef t_RsGxsGenericDataTemporaryMapVector<RsNxsMsg> RsNxsMsgDa
|
||||
typedef t_RsGxsGenericDataTemporaryList<RsNxsGrp> RsNxsGrpDataTemporaryList ;
|
||||
typedef t_RsGxsGenericDataTemporaryList<RsNxsMsg> RsNxsMsgDataTemporaryList ;
|
||||
|
||||
#ifdef UNUSED
|
||||
template<class T>
|
||||
class RsGxsMetaDataTemporaryMapVector: public std::vector<T*>
|
||||
{
|
||||
public:
|
||||
virtual ~RsGxsMetaDataTemporaryMapVector()
|
||||
{
|
||||
clear() ;
|
||||
}
|
||||
|
||||
virtual void clear()
|
||||
{
|
||||
for(typename RsGxsMetaDataTemporaryMapVector<T>::iterator it = this->begin();it!=this->end();++it)
|
||||
if(it->second != NULL)
|
||||
delete it->second ;
|
||||
std::vector<T*>::clear() ;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
inline RsGxsGrpMsgIdPair getMsgIdPair(RsNxsMsg& msg)
|
||||
{
|
||||
return RsGxsGrpMsgIdPair(std::make_pair(msg.grpId, msg.msgId));
|
||||
@ -146,7 +125,7 @@ inline RsGxsGrpMsgIdPair getMsgIdPair(RsGxsMsgItem& msg)
|
||||
* Does message clean up based on individual group expirations first
|
||||
* if avialable. If not then deletion s
|
||||
*/
|
||||
class RsGxsMessageCleanUp //: public RsThread
|
||||
class RsGxsMessageCleanUp
|
||||
{
|
||||
public:
|
||||
|
||||
@ -166,11 +145,6 @@ public:
|
||||
*/
|
||||
bool clean();
|
||||
|
||||
/*!
|
||||
* TODO: Rather than manual progressions consider running through a thread
|
||||
*/
|
||||
//virtual void data_tick(){}
|
||||
|
||||
private:
|
||||
|
||||
RsGeneralDataService* const mDs;
|
||||
|
@ -195,8 +195,6 @@ public:
|
||||
/**
|
||||
* @brief Post event to the event queue.
|
||||
* @param[in] event
|
||||
* @param[out] errorMessage Optional storage for error messsage, meaningful
|
||||
* only on failure.
|
||||
* @return Success or error details.
|
||||
*/
|
||||
virtual std::error_condition postEvent(
|
||||
@ -206,8 +204,6 @@ public:
|
||||
* @brief Send event directly to handlers. Blocking API
|
||||
* The handlers get exectuded on the caller thread.
|
||||
* @param[in] event
|
||||
* @param[out] errorMessage Optional storage for error messsage, meaningful
|
||||
* only on failure.
|
||||
* @return Success or error details.
|
||||
*/
|
||||
virtual std::error_condition sendEvent(
|
||||
|
@ -107,7 +107,8 @@ namespace GXS_SERV {
|
||||
static const uint32_t GXS_MSG_STATUS_UNPROCESSED = 0x00000001; // Flags to store the read/process status of group messages.
|
||||
static const uint32_t GXS_MSG_STATUS_GUI_UNREAD = 0x00000002; // The actual meaning may depend on the type of service.
|
||||
static const uint32_t GXS_MSG_STATUS_GUI_NEW = 0x00000004; //
|
||||
static const uint32_t GXS_MSG_STATUS_KEEP = 0x00000008; //
|
||||
/** Do not delete message even if older then group maximum storage time */
|
||||
static const uint32_t GXS_MSG_STATUS_KEEP_FOREVER = 0x00000008;
|
||||
static const uint32_t GXS_MSG_STATUS_DELETE = 0x00000020; //
|
||||
|
||||
/** END GXS Msg status flags **/
|
||||
|
@ -363,12 +363,25 @@ public:
|
||||
* @param[in] parentId id of the post of which child posts (aka replies)
|
||||
* are requested.
|
||||
* @param[out] childPosts storage for the child posts
|
||||
* @return false if something failed, true otherwhise
|
||||
* @return Success or error details
|
||||
*/
|
||||
virtual std::error_condition getChildPosts(
|
||||
const RsGxsGroupId& forumId, const RsGxsMessageId& parentId,
|
||||
std::vector<RsGxsForumMsg>& childPosts ) = 0;
|
||||
|
||||
/**
|
||||
* @brief Set keep forever flag on a post so it is not deleted even if older
|
||||
* then group maximum storage time
|
||||
* @jsonapi{development}
|
||||
* @param[in] forumId id of the forum of which the post pertain
|
||||
* @param[in] postId id of the post on which to set the flag
|
||||
* @param[in] keepForever true to set the flag, false to unset it
|
||||
* @return Success or error details
|
||||
*/
|
||||
virtual std::error_condition setPostKeepForever(
|
||||
const RsGxsGroupId& forumId, const RsGxsMessageId& postId,
|
||||
bool keepForever ) = 0;
|
||||
|
||||
/**
|
||||
* @brief Create forum. Blocking API.
|
||||
* @jsonapi{development}
|
||||
|
@ -237,11 +237,10 @@ RsGenExchange::ServiceCreate_Return p3GxsChannels::service_CreateGroup(RsGxsGrpI
|
||||
|
||||
void p3GxsChannels::notifyChanges(std::vector<RsGxsNotify *> &changes)
|
||||
{
|
||||
#ifdef GXSCHANNELS_DEBUG
|
||||
std::cerr << "p3GxsChannels::notifyChanges() : " << changes.size() << "changes to notify" << std::endl;
|
||||
#ifdef GXSCHANNEL_DEBUG
|
||||
RsDbg() << " Processing " << changes.size() << " channel changes..." << std::endl;
|
||||
#endif
|
||||
|
||||
/* iterate through and grab any new messages */
|
||||
/* iterate through and grab any new messages */
|
||||
std::set<RsGxsGroupId> unprocessedGroups;
|
||||
|
||||
std::vector<RsGxsNotify *>::iterator it;
|
||||
@ -295,6 +294,10 @@ void p3GxsChannels::notifyChanges(std::vector<RsGxsNotify *> &changes)
|
||||
|
||||
if (grpChange && rsEvents)
|
||||
{
|
||||
#ifdef GXSCHANNEL_DEBUG
|
||||
RsDbg() << " Grp Change Event or type " << grpChange->getType() << ":" << std::endl;
|
||||
#endif
|
||||
|
||||
switch (grpChange->getType())
|
||||
{
|
||||
case RsGxsNotify::TYPE_PROCESSED: // happens when the group is subscribed
|
||||
@ -322,18 +325,27 @@ void p3GxsChannels::notifyChanges(std::vector<RsGxsNotify *> &changes)
|
||||
|
||||
RS_STACK_MUTEX(mKnownChannelsMutex);
|
||||
|
||||
if(mKnownChannels.find(grpChange->mGroupId) == mKnownChannels.end())
|
||||
#ifdef GXSCHANNEL_DEBUG
|
||||
RsDbg() << " Type = Published/New " << std::endl;
|
||||
#endif
|
||||
if(mKnownChannels.find(grpChange->mGroupId) == mKnownChannels.end())
|
||||
{
|
||||
mKnownChannels.insert(std::make_pair(grpChange->mGroupId,time(NULL))) ;
|
||||
#ifdef GXSCHANNEL_DEBUG
|
||||
RsDbg() << " Status: unknown. Sending notification event." << std::endl;
|
||||
#endif
|
||||
|
||||
mKnownChannels.insert(std::make_pair(grpChange->mGroupId,time(NULL))) ;
|
||||
IndicateConfigChanged();
|
||||
|
||||
auto ev = std::make_shared<RsGxsChannelEvent>();
|
||||
ev->mChannelGroupId = grpChange->mGroupId;
|
||||
ev->mChannelEventCode = RsChannelEventCode::NEW_CHANNEL;
|
||||
rsEvents->postEvent(ev);
|
||||
}
|
||||
}
|
||||
#ifdef GXSCHANNEL_DEBUG
|
||||
else
|
||||
std::cerr << "(II) Not notifying already known channel " << grpChange->mGroupId << std::endl;
|
||||
RsDbg() << " Not notifying already known channel " << grpChange->mGroupId << std::endl;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -919,6 +919,9 @@ void p3GxsForums::setMessageReadStatus(uint32_t& token, const RsGxsGrpMsgIdPair&
|
||||
|
||||
setMsgStatusFlags(token, msgId, status, mask);
|
||||
|
||||
/* WARNING: The event may be received before the operation is completed!
|
||||
* TODO: move notification to blocking method markRead(...) which wait the
|
||||
* operation to complete */
|
||||
if (rsEvents)
|
||||
{
|
||||
auto ev = std::make_shared<RsGxsForumEvent>();
|
||||
@ -933,6 +936,37 @@ void p3GxsForums::setMessageReadStatus(uint32_t& token, const RsGxsGrpMsgIdPair&
|
||||
/********************************************************************************************/
|
||||
/********************************************************************************************/
|
||||
|
||||
std::error_condition p3GxsForums::setPostKeepForever(
|
||||
const RsGxsGroupId& forumId, const RsGxsMessageId& postId,
|
||||
bool keepForever )
|
||||
{
|
||||
if(forumId.isNull() || postId.isNull()) return std::errc::invalid_argument;
|
||||
|
||||
uint32_t mask = GXS_SERV::GXS_MSG_STATUS_KEEP_FOREVER;
|
||||
uint32_t status = keepForever ? GXS_SERV::GXS_MSG_STATUS_KEEP_FOREVER : 0;
|
||||
|
||||
uint32_t token;
|
||||
setMsgStatusFlags(token, RsGxsGrpMsgIdPair(forumId, postId), status, mask);
|
||||
|
||||
switch(waitToken(token))
|
||||
{
|
||||
case RsTokenService::PENDING: // [[fallthrough]];
|
||||
case RsTokenService::PARTIAL: return std::errc::timed_out;
|
||||
case RsTokenService::COMPLETE: // [[fallthrough]];
|
||||
case RsTokenService::DONE:
|
||||
{
|
||||
auto ev = std::make_shared<RsGxsForumEvent>();
|
||||
ev->mForumGroupId = forumId;
|
||||
ev->mForumMsgId = postId;
|
||||
ev->mForumEventCode = RsForumEventCode::UPDATED_MESSAGE;
|
||||
rsEvents->postEvent(ev);
|
||||
return std::error_condition();
|
||||
}
|
||||
case RsTokenService::CANCELLED: return std::errc::operation_canceled;
|
||||
default: return std::errc::bad_message;
|
||||
}
|
||||
}
|
||||
|
||||
/* so we need the same tick idea as wiki for generating dummy forums
|
||||
*/
|
||||
|
||||
|
@ -137,6 +137,11 @@ public:
|
||||
const RsGxsGroupId& forumId, const RsGxsMessageId& parentId,
|
||||
std::vector<RsGxsForumMsg>& childPosts ) override;
|
||||
|
||||
/// @see RsGxsForums
|
||||
std::error_condition setPostKeepForever(
|
||||
const RsGxsGroupId& forumId, const RsGxsMessageId& postId,
|
||||
bool keepForever );
|
||||
|
||||
/// implementation of rsGxsGorums
|
||||
///
|
||||
bool getGroupData(const uint32_t &token, std::vector<RsGxsForumGroup> &groups) override;
|
||||
|
@ -40,10 +40,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QFrame#frame{border: 2px solid #CCCCCC;
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
|
||||
stop: 0 #EEEEEE, stop: 1 #CCCCCC);
|
||||
border-radius: 10px}</string>
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
|
@ -40,10 +40,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QFrame#frame{border: 2px solid #CCCCCC;
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
|
||||
stop: 0 #EEEEEE, stop: 1 #CCCCCC);
|
||||
border-radius: 10px}</string>
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
|
@ -40,10 +40,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QFrame#frame{border: 2px solid #CCCCCC;
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
|
||||
stop: 0 #EEEEEE, stop: 1 #CCCCCC);
|
||||
border-radius: 10px}</string>
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
|
@ -527,6 +527,8 @@ void GroupTreeWidget::fillGroupItems(QTreeWidgetItem *categoryItem, const QList<
|
||||
|
||||
tooltip += "\n" + tr("Description") + ": " + itemInfo.description;
|
||||
|
||||
tooltip += "\n" + tr("Id") + ": " + itemInfo.id;
|
||||
|
||||
item->setToolTip(COLUMN_NAME, tooltip);
|
||||
item->setToolTip(COLUMN_UNREAD, tooltip);
|
||||
item->setToolTip(COLUMN_POPULARITY, tooltip);
|
||||
|
@ -52,6 +52,7 @@ void GxsCommentDialog::init()
|
||||
connect(ui->refreshButton, SIGNAL(clicked()), this, SLOT(refresh()));
|
||||
connect(ui->idChooser, SIGNAL(currentIndexChanged( int )), this, SLOT(voterSelectionChanged( int )));
|
||||
connect(ui->idChooser, SIGNAL(idsLoaded()), this, SLOT(idChooserReady()));
|
||||
connect(ui->treeWidget,SIGNAL(commentsLoaded(int)),this,SLOT(notifyCommentsLoaded(int)));
|
||||
|
||||
connect(ui->commentButton, SIGNAL(clicked()), ui->treeWidget, SLOT(makeComment()));
|
||||
connect(ui->sortBox, SIGNAL(currentIndexChanged(int)), this, SLOT(sortComments(int)));
|
||||
@ -95,6 +96,11 @@ void GxsCommentDialog::commentLoad(const RsGxsGroupId &grpId, const std::set<RsG
|
||||
ui->treeWidget->requestComments(mGrpId,msg_versions,most_recent_msgId);
|
||||
}
|
||||
|
||||
void GxsCommentDialog::notifyCommentsLoaded(int n)
|
||||
{
|
||||
emit commentsLoaded(n);
|
||||
}
|
||||
|
||||
void GxsCommentDialog::refresh()
|
||||
{
|
||||
std::cerr << "GxsCommentDialog::refresh()";
|
||||
|
@ -48,6 +48,10 @@ private slots:
|
||||
void idChooserReady();
|
||||
void voterSelectionChanged( int index );
|
||||
void sortComments(int);
|
||||
void notifyCommentsLoaded(int n);
|
||||
|
||||
signals:
|
||||
void commentsLoaded(int);
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
@ -228,8 +228,10 @@ void GxsCommentTreeWidget::customPopUpMenu(const QPoint& /*point*/)
|
||||
|
||||
void GxsCommentTreeWidget::voteUp()
|
||||
{
|
||||
std::cerr << "GxsCommentTreeWidget::voteUp()";
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::voteUp()";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
vote(mGroupId, mLatestMsgId, mCurrentCommentMsgId, mVoterId, true);
|
||||
}
|
||||
@ -237,8 +239,10 @@ void GxsCommentTreeWidget::voteUp()
|
||||
|
||||
void GxsCommentTreeWidget::voteDown()
|
||||
{
|
||||
std::cerr << "GxsCommentTreeWidget::voteDown()";
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::voteDown()";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
vote(mGroupId, mLatestMsgId, mCurrentCommentMsgId, mVoterId, false);
|
||||
}
|
||||
@ -246,8 +250,10 @@ void GxsCommentTreeWidget::voteDown()
|
||||
void GxsCommentTreeWidget::setVoteId(const RsGxsId &voterId)
|
||||
{
|
||||
mVoterId = voterId;
|
||||
std::cerr << "GxsCommentTreeWidget::setVoterId(" << mVoterId << ")";
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::setVoterId(" << mVoterId << ")";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -270,6 +276,7 @@ void GxsCommentTreeWidget::vote(const RsGxsGroupId &groupId, const RsGxsMessageI
|
||||
vote.mVoteType = GXS_VOTE_DOWN;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::vote()";
|
||||
std::cerr << std::endl;
|
||||
|
||||
@ -277,6 +284,7 @@ void GxsCommentTreeWidget::vote(const RsGxsGroupId &groupId, const RsGxsMessageI
|
||||
std::cerr << "ThreadId : " << vote.mMeta.mThreadId << std::endl;
|
||||
std::cerr << "ParentId : " << vote.mMeta.mParentId << std::endl;
|
||||
std::cerr << "AuthorId : " << vote.mMeta.mAuthorId << std::endl;
|
||||
#endif
|
||||
|
||||
uint32_t token;
|
||||
mCommentService->createNewVote(token, vote);
|
||||
@ -361,13 +369,17 @@ void GxsCommentTreeWidget::requestComments(const RsGxsGroupId& group, const std:
|
||||
void GxsCommentTreeWidget::service_requestComments(const RsGxsGroupId& group_id,const std::set<RsGxsMessageId> & msgIds)
|
||||
{
|
||||
/* request comments */
|
||||
std::cerr << "GxsCommentTreeWidget::service_requestComments for group " << group_id << std::endl;
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::service_requestComments for group " << group_id << std::endl;
|
||||
#endif
|
||||
|
||||
std::vector<RsGxsGrpMsgIdPair> ids_to_ask;
|
||||
|
||||
for(std::set<RsGxsMessageId>::const_iterator it(msgIds.begin());it!=msgIds.end();++it)
|
||||
{
|
||||
std::cerr << " asking for msg " << *it << std::endl;
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << " asking for msg " << *it << std::endl;
|
||||
#endif
|
||||
|
||||
ids_to_ask.push_back(std::make_pair(group_id,*it));
|
||||
}
|
||||
@ -399,14 +411,18 @@ void GxsCommentTreeWidget::completeItems()
|
||||
std::map<RsGxsMessageId, QTreeWidgetItem *>::iterator lit;
|
||||
std::multimap<RsGxsMessageId, QTreeWidgetItem *>::iterator pit;
|
||||
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() " << mPendingInsertMap.size();
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() " << mPendingInsertMap.size();
|
||||
std::cerr << " PendingItems";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
for(pit = mPendingInsertMap.begin(); pit != mPendingInsertMap.end(); ++pit)
|
||||
{
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() item->parent: " << pit->first;
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() item->parent: " << pit->first;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
if (pit->first != parentId)
|
||||
{
|
||||
@ -425,15 +441,19 @@ void GxsCommentTreeWidget::completeItems()
|
||||
|
||||
if (parent)
|
||||
{
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() Added to Parent";
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() Added to Parent";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
parent->addChild(pit->second);
|
||||
}
|
||||
else if (mMsgVersions.find(parentId) != mMsgVersions.end())
|
||||
{
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() Added to topLevelItems";
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() Added to topLevelItems";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
topLevelItems.append(pit->second);
|
||||
}
|
||||
@ -443,8 +463,10 @@ void GxsCommentTreeWidget::completeItems()
|
||||
/* missing parent -> insert At Top Level */
|
||||
QTreeWidgetItem *missingItem = service_createMissingItem(pit->first);
|
||||
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() Added MissingItem";
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() Added MissingItem";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
parent = missingItem;
|
||||
parent->addChild(pit->second);
|
||||
@ -464,9 +486,11 @@ void GxsCommentTreeWidget::completeItems()
|
||||
|
||||
void GxsCommentTreeWidget::addItem(RsGxsMessageId itemId, RsGxsMessageId parentId, QTreeWidgetItem *item)
|
||||
{
|
||||
std::cerr << "GxsCommentTreeWidget::addItem() Id: " << itemId;
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::addItem() Id: " << itemId;
|
||||
std::cerr << " ParentId: " << parentId;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
/* store in map -> for children */
|
||||
mLoadingMap[itemId] = item;
|
||||
@ -475,20 +499,48 @@ void GxsCommentTreeWidget::addItem(RsGxsMessageId itemId, RsGxsMessageId parentI
|
||||
it = mLoadingMap.find(parentId);
|
||||
if (it != mLoadingMap.end())
|
||||
{
|
||||
std::cerr << "GxsCommentTreeWidget::addItem() Added to Parent";
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::addItem() Added to Parent";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
it->second->addChild(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "GxsCommentTreeWidget::addItem() Added to Pending List";
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::addItem() Added to Pending List";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
mPendingInsertMap.insert(std::make_pair(parentId, item));
|
||||
}
|
||||
}
|
||||
|
||||
int treeCount(QTreeWidget *tree, QTreeWidgetItem *parent = 0)
|
||||
{
|
||||
int count = 0;
|
||||
if (parent == 0) {
|
||||
int topCount = tree->topLevelItemCount();
|
||||
for (int i = 0; i < topCount; i++) {
|
||||
QTreeWidgetItem *item = tree->topLevelItem(i);
|
||||
if (item->isExpanded()) {
|
||||
count += treeCount(tree, item);
|
||||
}
|
||||
}
|
||||
count += topCount;
|
||||
} else {
|
||||
int childCount = parent->childCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
QTreeWidgetItem *item = parent->child(i);
|
||||
if (item->isExpanded()) {
|
||||
count += treeCount(tree, item);
|
||||
}
|
||||
}
|
||||
count += childCount;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
void GxsCommentTreeWidget::loadThread(const uint32_t &token)
|
||||
{
|
||||
clearItems();
|
||||
@ -496,6 +548,8 @@ void GxsCommentTreeWidget::loadThread(const uint32_t &token)
|
||||
service_loadThread(token);
|
||||
|
||||
completeItems();
|
||||
|
||||
emit commentsLoaded(treeCount(this));
|
||||
}
|
||||
|
||||
void GxsCommentTreeWidget::acknowledgeComment(const uint32_t &token)
|
||||
@ -615,8 +669,10 @@ QTreeWidgetItem *GxsCommentTreeWidget::service_createMissingItem(const RsGxsMess
|
||||
|
||||
void GxsCommentTreeWidget::loadRequest(const TokenQueue *queue, const TokenRequest &req)
|
||||
{
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::loadRequest() UserType: " << req.mUserType;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
if (queue != mTokenQueue)
|
||||
{
|
||||
|
@ -80,6 +80,9 @@ public slots:
|
||||
void markSpammer();
|
||||
void banUser();
|
||||
|
||||
signals:
|
||||
void commentsLoaded(int);
|
||||
|
||||
protected:
|
||||
|
||||
void vote(const RsGxsGroupId &groupId, const RsGxsMessageId &threadId,
|
||||
|
@ -312,6 +312,12 @@ void GxsGroupFrameDialog::updateSearchResults(const TurtleRequestId& sid)
|
||||
|
||||
auto it2 = mSearchGroupsItems.find(sid);
|
||||
|
||||
if(it2 == mSearchGroupsItems.end())
|
||||
{
|
||||
std::cerr << "(EE) received a channel group turtle search result with ID " << sid << " but no item is known for this search" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
QList<GroupItemInfo> group_items ;
|
||||
|
||||
for(auto it3(group_infos.begin());it3!=group_infos.end();++it3)
|
||||
|
@ -78,10 +78,19 @@ CreateGxsChannelMsg::CreateGxsChannelMsg(const RsGxsGroupId &cId, RsGxsMessageId
|
||||
connect(thumbNailCb, SIGNAL(toggled(bool)), this, SLOT(allowAutoMediaThumbNail(bool)));
|
||||
connect(stackedWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenu(QPoint)));
|
||||
connect(generateCheckBox, SIGNAL(toggled(bool)), generateSpinBox, SLOT(setEnabled(bool)));
|
||||
connect(aspectRatio_CB,SIGNAL(currentIndexChanged(int)),this,SLOT(changeAspectRatio(int)));
|
||||
|
||||
aspectRatio_CB->setItemIcon(0,FilesDefs::getIconFromQtResourcePath(":/icons/svg/ratio-auto.svg"));
|
||||
aspectRatio_CB->setItemIcon(1,FilesDefs::getIconFromQtResourcePath(":/icons/svg/ratio-1-1.svg"));
|
||||
aspectRatio_CB->setItemIcon(2,FilesDefs::getIconFromQtResourcePath(":/icons/svg/ratio-3-4.svg"));
|
||||
aspectRatio_CB->setItemIcon(3,FilesDefs::getIconFromQtResourcePath(":/icons/svg/ratio-16-9.svg"));
|
||||
|
||||
generateSpinBox->setEnabled(false);
|
||||
|
||||
thumbNailCb->setVisible(false);
|
||||
preview_W->setPixmap(FilesDefs::getPixmapFromQtResourcePath(ChannelPostThumbnailView::CHAN_DEFAULT_IMAGE),true);
|
||||
preview_W->setText("[Text preview]");
|
||||
|
||||
thumbNailCb->setVisible(false);
|
||||
thumbNailCb->setEnabled(false);
|
||||
#ifdef CHANNELS_FRAME_CATCHER
|
||||
fCatcher = new framecatcher();
|
||||
@ -107,6 +116,19 @@ CreateGxsChannelMsg::~CreateGxsChannelMsg()
|
||||
#endif
|
||||
}
|
||||
|
||||
void CreateGxsChannelMsg::changeAspectRatio(int s)
|
||||
{
|
||||
switch(s)
|
||||
{
|
||||
case 0: break;
|
||||
case 1: preview_W->setAspectRatio(ChannelPostThumbnailView::ASPECT_RATIO_1_1);
|
||||
break;
|
||||
case 2: preview_W->setAspectRatio(ChannelPostThumbnailView::ASPECT_RATIO_2_3);
|
||||
break;
|
||||
case 3: preview_W->setAspectRatio(ChannelPostThumbnailView::ASPECT_RATIO_16_9);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void CreateGxsChannelMsg::contextMenu(QPoint /*point*/)
|
||||
{
|
||||
QList<RetroShareLink> links ;
|
||||
@ -688,7 +710,7 @@ void CreateGxsChannelMsg::sendMessage(const std::string &subject, const std::str
|
||||
// send chan image
|
||||
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
picture.save(&buffer, "PNG"); // writes image into ba in PNG format
|
||||
preview_W->getCroppedScaledPicture().save(&buffer, "PNG"); // writes image into ba in PNG format
|
||||
post.mThumbnail.copy((uint8_t *) ba.data(), ba.size());
|
||||
}
|
||||
|
||||
@ -723,7 +745,7 @@ void CreateGxsChannelMsg::sendMessage(const std::string &subject, const std::str
|
||||
|
||||
void CreateGxsChannelMsg::addThumbnail()
|
||||
{
|
||||
QPixmap img = misc::getOpenThumbnailedPicture(this, tr("Load thumbnail picture"), 107,156); // these absolute sizes are terrible
|
||||
QPixmap img = misc::getOpenThumbnailedPicture(this, tr("Load thumbnail picture"), 0,0); // 0,0 means: no scale.
|
||||
|
||||
if (img.isNull())
|
||||
return;
|
||||
@ -731,7 +753,8 @@ void CreateGxsChannelMsg::addThumbnail()
|
||||
picture = img;
|
||||
|
||||
// to show the selected
|
||||
preview_W->setPixmap(picture);
|
||||
preview_W->setPixmap(picture, aspectRatio_CB->currentIndex()==0);
|
||||
|
||||
}
|
||||
|
||||
void CreateGxsChannelMsg::loadOriginalChannelPostInfo()
|
||||
@ -775,7 +798,7 @@ void CreateGxsChannelMsg::loadOriginalChannelPostInfo()
|
||||
if(post.mThumbnail.mData != NULL)
|
||||
{
|
||||
GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData,post.mThumbnail.mSize,picture,GxsIdDetails::ORIGINAL);
|
||||
preview_W->setPixmap(picture);
|
||||
preview_W->setPixmap(picture,true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -64,6 +64,7 @@ private slots:
|
||||
void sendMsg();
|
||||
void pasteLink() ;
|
||||
void contextMenu(QPoint) ;
|
||||
void changeAspectRatio(int s);
|
||||
|
||||
void addThumbnail();
|
||||
void allowAutoMediaThumbNail(bool);
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>736</width>
|
||||
<height>271</height>
|
||||
<width>881</width>
|
||||
<height>383</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="acceptDrops">
|
||||
@ -79,32 +79,35 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="stackedWidgetPage1">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetFixedSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="ChannelPostThumbnailView" name="preview_W" native="true"/>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="ChannelPostThumbnailView" name="preview_W" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
@ -168,7 +171,7 @@ p, li { white-space: pre-wrap; }
|
||||
<string>Add Channel Thumbnail</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../icons.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/icons/png/add-image.png</normaloff>:/icons/png/add-image.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -179,13 +182,43 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="aspectRatio_CB">
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1:1</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>3:4</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>16:9</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addfilepushButton">
|
||||
<property name="text">
|
||||
<string>Add File to Attach</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../icons.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/icons/png/add-file.png</normaloff>:/icons/png/add-file.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -285,7 +318,7 @@ p, li { white-space: pre-wrap; }
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../icons.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/icons/png/add-file.png</normaloff>:/icons/png/add-file.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -309,7 +342,7 @@ p, li { white-space: pre-wrap; }
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>81</width>
|
||||
<width>84</width>
|
||||
<height>24</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -389,7 +422,7 @@ p, li { white-space: pre-wrap; }
|
||||
<string>Channel Post</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../icons.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/icons/png/comment.png</normaloff>:/icons/png/comment.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -419,7 +452,7 @@ p, li { white-space: pre-wrap; }
|
||||
<string>Attachments</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../icons.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/icons/png/attachements.png</normaloff>:/icons/png/attachements.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -491,7 +524,6 @@ p, li { white-space: pre-wrap; }
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../images.qrc"/>
|
||||
<include location="../icons.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
@ -35,9 +35,9 @@ public:
|
||||
/** Default Destructor */
|
||||
~GxsChannelDialog();
|
||||
|
||||
virtual QIcon iconPixmap() const { return QIcon(IMAGE_GXSCHANNELS) ; } //MainPage
|
||||
virtual QString pageName() const { return tr("Channels") ; } //MainPage
|
||||
virtual QString helpText() const { return ""; } //MainPage
|
||||
virtual QIcon iconPixmap() const override { return QIcon(IMAGE_GXSCHANNELS) ; } //MainPage
|
||||
virtual QString pageName() const override { return tr("Channels") ; } //MainPage
|
||||
virtual QString helpText() const override { return ""; } //MainPage
|
||||
|
||||
void shareOnChannel(const RsGxsGroupId& channel_id, const QList<RetroShareLink>& file_link) ;
|
||||
|
||||
@ -69,17 +69,17 @@ private slots:
|
||||
|
||||
private:
|
||||
/* GxsGroupFrameDialog */
|
||||
virtual QString text(TextType type);
|
||||
virtual QString icon(IconType type);
|
||||
virtual QString settingsGroupName() { return "ChannelDialog"; }
|
||||
virtual GxsGroupDialog *createNewGroupDialog();
|
||||
virtual GxsGroupDialog *createGroupDialog(GxsGroupDialog::Mode mode, RsGxsGroupId groupId);
|
||||
virtual int shareKeyType();
|
||||
virtual GxsMessageFrameWidget *createMessageFrameWidget(const RsGxsGroupId &groupId);
|
||||
virtual void groupTreeCustomActions(RsGxsGroupId grpId, int subscribeFlags, QList<QAction*> &actions);
|
||||
virtual RsGxsCommentService *getCommentService();
|
||||
virtual QWidget *createCommentHeaderWidget(const RsGxsGroupId &grpId, const RsGxsMessageId &msgId);
|
||||
virtual uint32_t requestGroupSummaryType() { return GXS_REQUEST_TYPE_GROUP_DATA; } // request complete group data
|
||||
virtual QString text(TextType type) override;
|
||||
virtual QString icon(IconType type) override;
|
||||
virtual QString settingsGroupName() override { return "ChannelDialog"; }
|
||||
virtual GxsGroupDialog *createNewGroupDialog() override;
|
||||
virtual GxsGroupDialog *createGroupDialog(GxsGroupDialog::Mode mode, RsGxsGroupId groupId) override;
|
||||
virtual int shareKeyType() override;
|
||||
virtual GxsMessageFrameWidget *createMessageFrameWidget(const RsGxsGroupId &groupId) override;
|
||||
virtual void groupTreeCustomActions(RsGxsGroupId grpId, int subscribeFlags, QList<QAction*> &actions) override;
|
||||
virtual RsGxsCommentService *getCommentService() override;
|
||||
virtual QWidget *createCommentHeaderWidget(const RsGxsGroupId &grpId, const RsGxsMessageId &msgId) override;
|
||||
virtual uint32_t requestGroupSummaryType() override { return GXS_REQUEST_TYPE_GROUP_DATA; } // request complete group data
|
||||
|
||||
void handleEvent_main_thread(std::shared_ptr<const RsEvent> event);
|
||||
|
||||
|
@ -306,7 +306,7 @@ void RsGxsChannelPostFilesModel::setFilter(const QStringList& strings, uint32_t&
|
||||
if(strings.empty())
|
||||
{
|
||||
mFilteredFiles.clear();
|
||||
for(int i=0;i<mFiles.size();++i)
|
||||
for(uint32_t i=0;i<mFiles.size();++i)
|
||||
mFilteredFiles.push_back(i);
|
||||
}
|
||||
else
|
||||
@ -314,7 +314,7 @@ void RsGxsChannelPostFilesModel::setFilter(const QStringList& strings, uint32_t&
|
||||
mFilteredFiles.clear();
|
||||
//mFilteredPosts.push_back(0);
|
||||
|
||||
for(int i=0;i<mFiles.size();++i)
|
||||
for(uint32_t i=0;i<mFiles.size();++i)
|
||||
{
|
||||
bool passes_strings = true;
|
||||
|
||||
|
324
retroshare-gui/src/gui/gxschannels/GxsChannelPostThumbnail.cpp
Normal file
324
retroshare-gui/src/gui/gxschannels/GxsChannelPostThumbnail.cpp
Normal file
@ -0,0 +1,324 @@
|
||||
/*******************************************************************************
|
||||
* retroshare-gui/src/gui/gxschannels/GxsChannelPostThumbnail.cpp *
|
||||
* *
|
||||
* Copyright 2020 by Retroshare Team <retroshare.project@gmail.com> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#include <QWheelEvent>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "gui/common/FilesDefs.h"
|
||||
#include "gui/gxschannels/GxsChannelPostThumbnail.h"
|
||||
|
||||
const float ChannelPostThumbnailView::DEFAULT_SIZE_IN_FONT_HEIGHT = 5.0;
|
||||
const float ChannelPostThumbnailView::FONT_SCALE_FACTOR = 1.5;
|
||||
|
||||
ChannelPostThumbnailView::ChannelPostThumbnailView(const RsGxsChannelPost& post,uint32_t flags,QWidget *parent)
|
||||
: QWidget(parent),mPostTitle(nullptr),mFlags(flags), mAspectRatio(ASPECT_RATIO_2_3)
|
||||
{
|
||||
// now fill the data
|
||||
|
||||
init(post);
|
||||
}
|
||||
|
||||
ChannelPostThumbnailView::ChannelPostThumbnailView(QWidget *parent,uint32_t flags)
|
||||
: QWidget(parent),mFlags(flags), mAspectRatio(ASPECT_RATIO_2_3)
|
||||
{
|
||||
init(RsGxsChannelPost());
|
||||
}
|
||||
|
||||
ChannelPostThumbnailView::~ChannelPostThumbnailView()
|
||||
{
|
||||
delete mPostImage;
|
||||
}
|
||||
|
||||
void ChannelPostThumbnailView::setText(const QString& s)
|
||||
{
|
||||
if(mPostTitle == NULL)
|
||||
{
|
||||
std::cerr << "(EE) calling setText on a ChannelPostThumbnailView without SHOW_TEXT flag!"<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
QString ss;
|
||||
if(s.length() > 30)
|
||||
ss = s.left(30)+"...";
|
||||
else
|
||||
ss =s;
|
||||
|
||||
mPostTitle->setText(ss);
|
||||
}
|
||||
|
||||
void ChannelPostThumbnailView::setPixmap(const QPixmap& p, bool guess_aspect_ratio)
|
||||
{
|
||||
mPostImage->setPicture(p);
|
||||
|
||||
if(guess_aspect_ratio)// aspect ratio is automatically guessed.
|
||||
{
|
||||
// compute closest aspect ratio
|
||||
float r = p.width()/(float)p.height();
|
||||
|
||||
if(r < 0.8)
|
||||
setAspectRatio(ChannelPostThumbnailView::ASPECT_RATIO_2_3);
|
||||
else if(r < 1.15)
|
||||
setAspectRatio(ChannelPostThumbnailView::ASPECT_RATIO_1_1);
|
||||
else
|
||||
setAspectRatio(ChannelPostThumbnailView::ASPECT_RATIO_16_9);
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelPostThumbnailView::setAspectRatio(AspectRatio r)
|
||||
{
|
||||
mAspectRatio = r;
|
||||
|
||||
QFontMetricsF fm(font());
|
||||
int W = THUMBNAIL_OVERSAMPLE_FACTOR * thumbnail_w() * fm.height() ;
|
||||
int H = THUMBNAIL_OVERSAMPLE_FACTOR * thumbnail_h() * fm.height() ;
|
||||
|
||||
mPostImage->setFixedSize(W,H);
|
||||
mPostImage->reset();
|
||||
mPostImage->updateView();
|
||||
}
|
||||
|
||||
void ChannelPostThumbnailView::init(const RsGxsChannelPost& post)
|
||||
{
|
||||
QString msg = QString::fromUtf8(post.mMeta.mMsgName.c_str());
|
||||
bool is_msg_new = IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus);
|
||||
|
||||
QPixmap thumbnail;
|
||||
|
||||
if(post.mThumbnail.mSize > 0)
|
||||
GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL);
|
||||
else if(post.mMeta.mPublishTs > 0) // this is for testing that the post is not an empty post (happens at the end of the last row)
|
||||
thumbnail = FilesDefs::getPixmapFromQtResourcePath(CHAN_DEFAULT_IMAGE);
|
||||
|
||||
mPostImage = new ZoomableLabel(this);
|
||||
mPostImage->setEnableZoom(mFlags & FLAG_ALLOW_PAN);
|
||||
mPostImage->setScaledContents(true);
|
||||
mPostImage->setPicture(thumbnail);
|
||||
|
||||
if(mFlags & FLAG_ALLOW_PAN)
|
||||
mPostImage->setToolTip(tr("Use mouse to center and zoom into the image"));
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
|
||||
layout->addWidget(mPostImage);
|
||||
|
||||
QFontMetricsF fm(font());
|
||||
int W = THUMBNAIL_OVERSAMPLE_FACTOR * thumbnail_w() * fm.height() ;
|
||||
int H = THUMBNAIL_OVERSAMPLE_FACTOR * thumbnail_h() * fm.height() ;
|
||||
|
||||
mPostImage->setFixedSize(W,H);
|
||||
|
||||
if(mFlags & FLAG_SHOW_TEXT)
|
||||
{
|
||||
mPostTitle = new QLabel(this);
|
||||
layout->addWidget(mPostTitle);
|
||||
|
||||
QString ss = (msg.length() > 30)? (msg.left(30)+"..."):msg;
|
||||
|
||||
mPostTitle->setText(ss);
|
||||
|
||||
QFont font = mPostTitle->font();
|
||||
|
||||
if(mFlags & ChannelPostThumbnailView::FLAG_SCALE_FONT)
|
||||
font.setPointSizeF(FONT_SCALE_FACTOR * DEFAULT_SIZE_IN_FONT_HEIGHT / 5.0 * font.pointSizeF());
|
||||
else
|
||||
font.setPointSizeF(DEFAULT_SIZE_IN_FONT_HEIGHT / 5.0 * font.pointSizeF());
|
||||
|
||||
if(is_msg_new)
|
||||
font.setBold(true);
|
||||
|
||||
mPostTitle->setFont(font);
|
||||
mPostTitle->setMaximumWidth(W);
|
||||
mPostTitle->setWordWrap(true);
|
||||
}
|
||||
setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding);
|
||||
|
||||
layout->addStretch();
|
||||
|
||||
setLayout(layout);
|
||||
adjustSize();
|
||||
update();
|
||||
}
|
||||
|
||||
ChannelPostThumbnailView::AspectRatio ChannelPostThumbnailView::bestAspectRatio()
|
||||
{
|
||||
if(mPostImage->originalImage().isNull())
|
||||
return ASPECT_RATIO_1_1;
|
||||
|
||||
float as = mPostImage->originalImage().height() / (float)mPostImage->originalImage().width() ;
|
||||
|
||||
if(as <= 0.8)
|
||||
return ASPECT_RATIO_16_9;
|
||||
else if(as < 1.15)
|
||||
return ASPECT_RATIO_1_1;
|
||||
else
|
||||
return ASPECT_RATIO_2_3;
|
||||
}
|
||||
QSize ChannelPostThumbnailView::actualSize() const
|
||||
{
|
||||
QFontMetricsF fm(font());
|
||||
|
||||
if(mPostTitle != nullptr)
|
||||
{
|
||||
QMargins cm = layout()->contentsMargins();
|
||||
|
||||
return QSize(width(),
|
||||
mPostTitle->height() + mPostImage->height() + 0.5*fm.height()
|
||||
+ cm.top() + cm.bottom() + layout()->spacing());
|
||||
}
|
||||
else
|
||||
return size();
|
||||
}
|
||||
|
||||
float ChannelPostThumbnailView::thumbnail_w() const
|
||||
{
|
||||
switch(mAspectRatio)
|
||||
{
|
||||
default:
|
||||
case ASPECT_RATIO_1_1:
|
||||
case ASPECT_RATIO_UNKNOWN: return DEFAULT_SIZE_IN_FONT_HEIGHT;
|
||||
|
||||
case ASPECT_RATIO_2_3: return DEFAULT_SIZE_IN_FONT_HEIGHT;
|
||||
case ASPECT_RATIO_16_9: return DEFAULT_SIZE_IN_FONT_HEIGHT;
|
||||
}
|
||||
}
|
||||
float ChannelPostThumbnailView::thumbnail_h() const
|
||||
{
|
||||
switch(mAspectRatio)
|
||||
{
|
||||
default:
|
||||
case ASPECT_RATIO_1_1:
|
||||
case ASPECT_RATIO_UNKNOWN: return DEFAULT_SIZE_IN_FONT_HEIGHT;
|
||||
|
||||
case ASPECT_RATIO_2_3: return DEFAULT_SIZE_IN_FONT_HEIGHT * 3.0/2.0;
|
||||
case ASPECT_RATIO_16_9: return DEFAULT_SIZE_IN_FONT_HEIGHT * 9.0/16.0;
|
||||
}
|
||||
}
|
||||
|
||||
void ZoomableLabel::reset()
|
||||
{
|
||||
mCenterX = mFullImage.width()/2.0;
|
||||
mCenterY = mFullImage.height()/2.0;
|
||||
mZoomFactor = 1.0/std::max(width() / (float)mFullImage.width(), height()/(float)mFullImage.height());
|
||||
|
||||
updateView();
|
||||
}
|
||||
void ZoomableLabel::mouseMoveEvent(QMouseEvent *me)
|
||||
{
|
||||
if(!mZoomEnabled)
|
||||
return;
|
||||
|
||||
float new_center_x = mCenterX - (me->x() - mLastX);
|
||||
float new_center_y = mCenterY - (me->y() - mLastY);
|
||||
|
||||
mLastX = me->x();
|
||||
mLastY = me->y();
|
||||
|
||||
if(new_center_x - 0.5 * width()*mZoomFactor < 0) return;
|
||||
if(new_center_y - 0.5 *height()*mZoomFactor < 0) return;
|
||||
|
||||
if(new_center_x + 0.5 * width()*mZoomFactor >= mFullImage.width()) return;
|
||||
if(new_center_y + 0.5 *height()*mZoomFactor >=mFullImage.height()) return;
|
||||
|
||||
mCenterX = new_center_x;
|
||||
mCenterY = new_center_y;
|
||||
|
||||
updateView();
|
||||
}
|
||||
void ZoomableLabel::mousePressEvent(QMouseEvent *me)
|
||||
{
|
||||
mMoving = true;
|
||||
mLastX = me->x();
|
||||
mLastY = me->y();
|
||||
}
|
||||
void ZoomableLabel::mouseReleaseEvent(QMouseEvent *)
|
||||
{
|
||||
mMoving = false;
|
||||
}
|
||||
void ZoomableLabel::wheelEvent(QWheelEvent *me)
|
||||
{
|
||||
if(!mZoomEnabled)
|
||||
return;
|
||||
|
||||
float new_zoom_factor = (me->delta() > 0)?(mZoomFactor*1.05):(mZoomFactor/1.05);
|
||||
float new_center_x = mCenterX;
|
||||
float new_center_y = mCenterY;
|
||||
|
||||
// Try to find centerX and centerY so that the crop does not overlap the original image
|
||||
|
||||
float min_x = 0.5 * width()*new_zoom_factor;
|
||||
float max_x = mFullImage.width() - 0.5 * width()*new_zoom_factor;
|
||||
float min_y = 0.5 * height()*new_zoom_factor;
|
||||
float max_y = mFullImage.height() - 0.5 * height()*new_zoom_factor;
|
||||
|
||||
if(min_x >= max_x) return;
|
||||
if(min_y >= max_y) return;
|
||||
|
||||
if(new_center_x < min_x) new_center_x = min_x;
|
||||
if(new_center_y < min_y) new_center_y = min_y;
|
||||
if(new_center_x > max_x) new_center_x = max_x;
|
||||
if(new_center_y > max_y) new_center_y = max_y;
|
||||
|
||||
mZoomFactor = new_zoom_factor;
|
||||
mCenterX = new_center_x;
|
||||
mCenterY = new_center_y;
|
||||
|
||||
updateView();
|
||||
}
|
||||
|
||||
QPixmap ZoomableLabel::extractCroppedScaledPicture() const
|
||||
{
|
||||
QRect rect(mCenterX - 0.5 * width()*mZoomFactor, mCenterY - 0.5 * height()*mZoomFactor, width()*mZoomFactor, height()*mZoomFactor);
|
||||
QPixmap pix = mFullImage.copy(rect).scaledToHeight(height(),Qt::SmoothTransformation);
|
||||
|
||||
return pix;
|
||||
}
|
||||
|
||||
void ZoomableLabel::setPicture(const QPixmap& pix)
|
||||
{
|
||||
mFullImage = pix;
|
||||
|
||||
reset();
|
||||
updateView();
|
||||
}
|
||||
void ZoomableLabel::resizeEvent(QResizeEvent *e)
|
||||
{
|
||||
QLabel::resizeEvent(e);
|
||||
|
||||
updateView();
|
||||
}
|
||||
|
||||
void ZoomableLabel::updateView()
|
||||
{
|
||||
// The new image will be cropped from the original image, using the following rules:
|
||||
// - first the cropped image size is computed
|
||||
// - then center is calculated so that
|
||||
// - the original center is preferred
|
||||
// - if the crop overlaps the image border, the center is moved.
|
||||
|
||||
QRect rect(mCenterX - 0.5 * width()*mZoomFactor, mCenterY - 0.5 * height()*mZoomFactor, width()*mZoomFactor, height()*mZoomFactor);
|
||||
QLabel::setPixmap(mFullImage.copy(rect));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -32,6 +32,39 @@
|
||||
#include "gui/gxs/GxsIdDetails.h"
|
||||
#include "gui/common/FilesDefs.h"
|
||||
|
||||
// Class to provide a label in which the image can be zoomed/moved. The widget size is fixed by the GUI and the user can move/zoom the image
|
||||
// inside the window formed by the widget. When happy, the view-able part of the image can be extracted.
|
||||
|
||||
class ZoomableLabel: public QLabel
|
||||
{
|
||||
public:
|
||||
ZoomableLabel(QWidget *parent): QLabel(parent),mZoomFactor(1.0),mCenterX(0.0),mCenterY(0.0),mZoomEnabled(true) {}
|
||||
|
||||
void setPicture(const QPixmap& pix);
|
||||
void setEnableZoom(bool b) { mZoomEnabled = b; }
|
||||
void reset();
|
||||
QPixmap extractCroppedScaledPicture() const;
|
||||
void updateView();
|
||||
|
||||
const QPixmap& originalImage() const { return mFullImage ; }
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *ev) override;
|
||||
void mouseReleaseEvent(QMouseEvent *ev) override;
|
||||
void mouseMoveEvent(QMouseEvent *ev) override;
|
||||
void resizeEvent(QResizeEvent *ev) override;
|
||||
void wheelEvent(QWheelEvent *me) override;
|
||||
|
||||
QPixmap mFullImage;
|
||||
|
||||
float mCenterX;
|
||||
float mCenterY;
|
||||
float mZoomFactor;
|
||||
int mLastX,mLastY;
|
||||
bool mMoving;
|
||||
bool mZoomEnabled;
|
||||
};
|
||||
|
||||
// Class to paint the thumbnails with title
|
||||
|
||||
class ChannelPostThumbnailView: public QWidget
|
||||
@ -39,8 +72,20 @@ class ChannelPostThumbnailView: public QWidget
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
typedef enum {
|
||||
ASPECT_RATIO_UNKNOWN = 0x00,
|
||||
ASPECT_RATIO_2_3 = 0x01,
|
||||
ASPECT_RATIO_1_1 = 0x02,
|
||||
ASPECT_RATIO_16_9 = 0x03,
|
||||
} AspectRatio;
|
||||
|
||||
// This variable determines the zoom factor on the text below thumbnails. 2.0 is mostly correct for all screen.
|
||||
static constexpr float THUMBNAIL_OVERSAMPLE_FACTOR = 2.0;
|
||||
static constexpr float THUMBNAIL_OVERSAMPLE_FACTOR = 2.0;
|
||||
|
||||
static constexpr uint32_t FLAG_NONE = 0x00;
|
||||
static constexpr uint32_t FLAG_SHOW_TEXT = 0x01;
|
||||
static constexpr uint32_t FLAG_ALLOW_PAN = 0x02;
|
||||
static constexpr uint32_t FLAG_SCALE_FONT= 0x04;
|
||||
|
||||
// Size of thumbnails as a function of the height of the font. An aspect ratio of 3/4 is good.
|
||||
|
||||
@ -49,77 +94,40 @@ public:
|
||||
|
||||
static constexpr char *CHAN_DEFAULT_IMAGE = ":images/thumb-default-video.png";
|
||||
|
||||
virtual ~ChannelPostThumbnailView()
|
||||
{
|
||||
delete lb;
|
||||
delete lt;
|
||||
}
|
||||
virtual ~ChannelPostThumbnailView();
|
||||
ChannelPostThumbnailView(QWidget *parent=NULL,uint32_t flags=FLAG_ALLOW_PAN | FLAG_SHOW_TEXT | FLAG_SCALE_FONT);
|
||||
ChannelPostThumbnailView(const RsGxsChannelPost& post,uint32_t flags,QWidget *parent=NULL);
|
||||
|
||||
ChannelPostThumbnailView(QWidget *parent=NULL): QWidget(parent)
|
||||
{
|
||||
init(FilesDefs::getPixmapFromQtResourcePath(CHAN_DEFAULT_IMAGE), QString("New post"),false);
|
||||
}
|
||||
void init(const RsGxsChannelPost& post);
|
||||
|
||||
ChannelPostThumbnailView(const RsGxsChannelPost& post,QWidget *parent=NULL)
|
||||
: QWidget(parent)
|
||||
{
|
||||
// now fill the data
|
||||
void setAspectRatio(AspectRatio r);
|
||||
void setPixmap(const QPixmap& p,bool guess_aspect_ratio) ;
|
||||
QPixmap getCroppedScaledPicture() const { return mPostImage->extractCroppedScaledPicture() ; }
|
||||
|
||||
QPixmap thumbnail;
|
||||
void setText(const QString& s);
|
||||
|
||||
if(post.mThumbnail.mSize > 0)
|
||||
GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL);
|
||||
else if(post.mMeta.mPublishTs > 0) // this is for testing that the post is not an empty post (happens at the end of the last row)
|
||||
thumbnail = FilesDefs::getPixmapFromQtResourcePath(CHAN_DEFAULT_IMAGE);
|
||||
// This is used to allow to render the widget into a pixmap without the white space that Qt adds vertically. There is *no way* apparently
|
||||
// to get rid of that bloody space. It depends on the aspect ratio of the image and it only shows up when the text label is shown.
|
||||
// The label however has a correct size. It seems that Qt doesn't like widgets with horizontal aspect ratio and forces the size accordingly.
|
||||
|
||||
init(thumbnail, QString::fromUtf8(post.mMeta.mMsgName.c_str()), IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus) );
|
||||
|
||||
}
|
||||
|
||||
void init(const QPixmap& thumbnail,const QString& msg,bool is_msg_new)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
|
||||
lb = new QLabel(this);
|
||||
lb->setScaledContents(true);
|
||||
layout->addWidget(lb);
|
||||
|
||||
lt = new QLabel(this);
|
||||
layout->addWidget(lt);
|
||||
|
||||
setLayout(layout);
|
||||
|
||||
setSizePolicy(QSizePolicy::Maximum,QSizePolicy::Maximum);
|
||||
|
||||
QFontMetricsF fm(font());
|
||||
int W = THUMBNAIL_OVERSAMPLE_FACTOR * THUMBNAIL_W * fm.height() ;
|
||||
int H = THUMBNAIL_OVERSAMPLE_FACTOR * THUMBNAIL_H * fm.height() ;
|
||||
|
||||
lb->setFixedSize(W,H);
|
||||
lb->setPixmap(thumbnail);
|
||||
|
||||
lt->setText(msg);
|
||||
|
||||
QFont font = lt->font();
|
||||
|
||||
if(is_msg_new)
|
||||
{
|
||||
font.setBold(true);
|
||||
lt->setFont(font);
|
||||
}
|
||||
|
||||
lt->setMaximumWidth(W);
|
||||
lt->setWordWrap(true);
|
||||
|
||||
adjustSize();
|
||||
update();
|
||||
}
|
||||
|
||||
void setPixmap(const QPixmap& p) { lb->setPixmap(p); }
|
||||
void setText(const QString& s) { lt->setText(s); }
|
||||
QSize actualSize() const ;
|
||||
|
||||
/*!
|
||||
* \brief bestAspectRatio
|
||||
* Computes the preferred aspect ratio for the image in the post. The default is 1:1.
|
||||
* \return the prefered aspect ratio
|
||||
*/
|
||||
AspectRatio bestAspectRatio() ;
|
||||
private:
|
||||
QLabel *lb;
|
||||
QLabel *lt;
|
||||
static const float DEFAULT_SIZE_IN_FONT_HEIGHT ;
|
||||
static const float FONT_SCALE_FACTOR ;
|
||||
|
||||
float thumbnail_w() const;
|
||||
float thumbnail_h() const;
|
||||
|
||||
ZoomableLabel *mPostImage;
|
||||
QLabel *mPostTitle;
|
||||
uint32_t mFlags;
|
||||
AspectRatio mAspectRatio;
|
||||
};
|
||||
|
||||
|
@ -44,7 +44,7 @@ Q_DECLARE_METATYPE(RsGxsChannelPost)
|
||||
std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsewhere
|
||||
|
||||
RsGxsChannelPostsModel::RsGxsChannelPostsModel(QObject *parent)
|
||||
: QAbstractItemModel(parent), mTreeMode(TREE_MODE_PLAIN), mColumns(6)
|
||||
: QAbstractItemModel(parent), mTreeMode(RsGxsChannelPostsModel::TREE_MODE_GRID), mColumns(6)
|
||||
{
|
||||
initEmptyHierarchy();
|
||||
|
||||
@ -62,6 +62,16 @@ RsGxsChannelPostsModel::~RsGxsChannelPostsModel()
|
||||
rsEvents->unregisterEventsHandler(mEventHandlerId);
|
||||
}
|
||||
|
||||
void RsGxsChannelPostsModel::setMode(TreeMode mode)
|
||||
{
|
||||
mTreeMode = mode;
|
||||
|
||||
if(mode == TREE_MODE_LIST)
|
||||
setNumColumns(2);
|
||||
|
||||
triggerViewUpdate();
|
||||
}
|
||||
|
||||
void RsGxsChannelPostsModel::handleEvent_main_thread(std::shared_ptr<const RsEvent> event)
|
||||
{
|
||||
const RsGxsChannelEvent *e = dynamic_cast<const RsGxsChannelEvent*>(event.get());
|
||||
@ -106,7 +116,7 @@ void RsGxsChannelPostsModel::handleEvent_main_thread(std::shared_ptr<const RsEve
|
||||
{
|
||||
mPosts[j] = posts[i];
|
||||
|
||||
emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mFilteredPosts.size(),mColumns-1,(void*)NULL));
|
||||
triggerViewUpdate();
|
||||
}
|
||||
}
|
||||
},this);
|
||||
@ -124,25 +134,23 @@ void RsGxsChannelPostsModel::initEmptyHierarchy()
|
||||
|
||||
mPosts.clear();
|
||||
mFilteredPosts.clear();
|
||||
// mPosts.resize(1); // adds a sentinel item
|
||||
// mPosts[0].mMeta.mMsgName = "Root sentinel post" ;
|
||||
// mFilteredPosts.resize(1);
|
||||
// mFilteredPosts[0] = 1;
|
||||
|
||||
postMods();
|
||||
}
|
||||
|
||||
void RsGxsChannelPostsModel::preMods()
|
||||
{
|
||||
//emit layoutAboutToBeChanged(); //Generate SIGSEGV when click on button move next/prev.
|
||||
|
||||
beginResetModel();
|
||||
}
|
||||
void RsGxsChannelPostsModel::postMods()
|
||||
{
|
||||
endResetModel();
|
||||
|
||||
emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mFilteredPosts.size(),mColumns-1,(void*)NULL));
|
||||
triggerViewUpdate();
|
||||
}
|
||||
void RsGxsChannelPostsModel::triggerViewUpdate()
|
||||
{
|
||||
emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(rowCount()-1,mColumns-1,(void*)NULL));
|
||||
}
|
||||
|
||||
void RsGxsChannelPostsModel::getFilesList(std::list<ChannelPostFileInfo>& files)
|
||||
@ -161,35 +169,30 @@ void RsGxsChannelPostsModel::getFilesList(std::list<ChannelPostFileInfo>& files)
|
||||
files.push_back(it.second);
|
||||
}
|
||||
|
||||
void RsGxsChannelPostsModel::setFilter(const QStringList& strings, uint32_t& count)
|
||||
void RsGxsChannelPostsModel::setFilter(const QStringList& strings,bool only_unread, uint32_t& count)
|
||||
{
|
||||
preMods();
|
||||
|
||||
beginRemoveRows(QModelIndex(),0,rowCount()-1);
|
||||
endRemoveRows();
|
||||
|
||||
if(strings.empty())
|
||||
mFilteredPosts.clear();
|
||||
//mFilteredPosts.push_back(0);
|
||||
|
||||
for(size_t i=0;i<mPosts.size();++i)
|
||||
{
|
||||
mFilteredPosts.clear();
|
||||
for(size_t i=0;i<mPosts.size();++i)
|
||||
bool passes_strings = true;
|
||||
|
||||
for(auto& s:strings)
|
||||
passes_strings = passes_strings && QString::fromStdString(mPosts[i].mMeta.mMsgName).contains(s,Qt::CaseInsensitive);
|
||||
|
||||
if(strings.empty())
|
||||
passes_strings = true;
|
||||
|
||||
if(passes_strings && (!only_unread || (IS_MSG_UNREAD(mPosts[i].mMeta.mMsgStatus) || IS_MSG_NEW(mPosts[i].mMeta.mMsgStatus))))
|
||||
mFilteredPosts.push_back(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
mFilteredPosts.clear();
|
||||
//mFilteredPosts.push_back(0);
|
||||
|
||||
for(size_t i=0;i<mPosts.size();++i)
|
||||
{
|
||||
bool passes_strings = true;
|
||||
|
||||
for(auto& s:strings)
|
||||
passes_strings = passes_strings && QString::fromStdString(mPosts[i].mMeta.mMsgName).contains(s,Qt::CaseInsensitive);
|
||||
|
||||
if(passes_strings)
|
||||
mFilteredPosts.push_back(i);
|
||||
}
|
||||
}
|
||||
count = mFilteredPosts.size();
|
||||
|
||||
std::cerr << "After filtering: " << count << " posts remain." << std::endl;
|
||||
@ -209,7 +212,12 @@ int RsGxsChannelPostsModel::rowCount(const QModelIndex& parent) const
|
||||
return 0;
|
||||
|
||||
if(!parent.isValid())
|
||||
return (mFilteredPosts.size() + mColumns-1)/mColumns; // mFilteredPosts always has an item at 0, so size()>=1, and mColumn>=1
|
||||
{
|
||||
if(mTreeMode == TREE_MODE_GRID)
|
||||
return (mFilteredPosts.size() + mColumns-1)/mColumns; // mFilteredPosts always has an item at 0, so size()>=1, and mColumn>=1
|
||||
else
|
||||
return mFilteredPosts.size();
|
||||
}
|
||||
|
||||
RsErr() << __PRETTY_FUNCTION__ << " rowCount cannot figure out the porper number of rows." << std::endl;
|
||||
return 0;
|
||||
@ -217,7 +225,10 @@ int RsGxsChannelPostsModel::rowCount(const QModelIndex& parent) const
|
||||
|
||||
int RsGxsChannelPostsModel::columnCount(const QModelIndex &/*parent*/) const
|
||||
{
|
||||
return std::min((int)mFilteredPosts.size(),(int)mColumns) ;
|
||||
if(mTreeMode == TREE_MODE_GRID)
|
||||
return std::min((int)mFilteredPosts.size(),(int)mColumns) ;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool RsGxsChannelPostsModel::getPostData(const QModelIndex& i,RsGxsChannelPost& fmpe) const
|
||||
@ -284,7 +295,7 @@ QModelIndex RsGxsChannelPostsModel::index(int row, int column, const QModelIndex
|
||||
if(row < 0 || column < 0 || column >= (int)mColumns)
|
||||
return QModelIndex();
|
||||
|
||||
quintptr ref = getChildRef(parent.internalId(),column + row*mColumns);
|
||||
quintptr ref = getChildRef(parent.internalId(),(mTreeMode == TREE_MODE_GRID)?(column + row*mColumns):row);
|
||||
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << "index-3(" << row << "," << column << " parent=" << parent << ") : " << createIndex(row,column,ref) << std::endl;
|
||||
@ -363,8 +374,6 @@ quintptr RsGxsChannelPostsModel::getParentRow(quintptr ref,int& row) const
|
||||
|
||||
int RsGxsChannelPostsModel::getChildrenCount(quintptr ref) const
|
||||
{
|
||||
uint32_t entry = 0 ;
|
||||
|
||||
if(ref == quintptr(0))
|
||||
return rowCount()-1;
|
||||
|
||||
@ -421,7 +430,7 @@ QVariant RsGxsChannelPostsModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
}
|
||||
|
||||
QVariant RsGxsChannelPostsModel::sizeHintRole(int col) const
|
||||
QVariant RsGxsChannelPostsModel::sizeHintRole(int /* col */) const
|
||||
{
|
||||
float factor = QFontMetricsF(QApplication::font()).height()/14.0f ;
|
||||
|
||||
@ -493,7 +502,7 @@ void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vecto
|
||||
std::sort(mPosts.begin(),mPosts.end());
|
||||
|
||||
mFilteredPosts.clear();
|
||||
for(int i=0;i<mPosts.size();++i)
|
||||
for(uint32_t i=0;i<mPosts.size();++i)
|
||||
mFilteredPosts.push_back(i);
|
||||
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
@ -564,8 +573,6 @@ void RsGxsChannelPostsModel::update_posts(const RsGxsGroupId& group_id)
|
||||
});
|
||||
}
|
||||
|
||||
static bool decreasing_time_comp(const std::pair<time_t,RsGxsMessageId>& e1,const std::pair<time_t,RsGxsMessageId>& e2) { return e2.first < e1.first ; }
|
||||
|
||||
void RsGxsChannelPostsModel::createPostsArray(std::vector<RsGxsChannelPost>& posts)
|
||||
{
|
||||
// collect new versions of posts if any
|
||||
@ -689,10 +696,25 @@ void RsGxsChannelPostsModel::setAllMsgReadStatus(bool read_status)
|
||||
// No need to call preMods()/postMods() here because we're not changing the model
|
||||
// All operations below are done async
|
||||
|
||||
RsThread::async([this, read_status]()
|
||||
// 1 - copy all msg/grp id groups, so that changing the mPosts list while calling the async method will not break the work
|
||||
|
||||
std::vector<RsGxsGrpMsgIdPair> pairs;
|
||||
|
||||
for(uint32_t i=0;i<mPosts.size();++i)
|
||||
{
|
||||
for(uint32_t i=0;i<mPosts.size();++i)
|
||||
rsGxsChannels->markRead(RsGxsGrpMsgIdPair(mPosts[i].mMeta.mGroupId,mPosts[i].mMeta.mMsgId),read_status);
|
||||
bool post_status = !((IS_MSG_UNREAD(mPosts[i].mMeta.mMsgStatus) || IS_MSG_NEW(mPosts[i].mMeta.mMsgStatus)));
|
||||
|
||||
if(post_status != read_status)
|
||||
pairs.push_back(RsGxsGrpMsgIdPair(mPosts[i].mMeta.mGroupId,mPosts[i].mMeta.mMsgId));
|
||||
}
|
||||
|
||||
// 2 - then call the async methods
|
||||
|
||||
RsThread::async([pairs, read_status]()
|
||||
{
|
||||
for(uint32_t i=0;i<pairs.size();++i)
|
||||
if(!rsGxsChannels->markRead(pairs[i],read_status))
|
||||
RsErr() << "setAllMsgReadStatus: failed to change status of msg " << pairs[i].first << " in group " << pairs[i].second << " to status " << read_status << std::endl;
|
||||
});
|
||||
}
|
||||
|
||||
@ -720,15 +742,18 @@ QModelIndex RsGxsChannelPostsModel::getIndexOfMessage(const RsGxsMessageId& mid)
|
||||
|
||||
for(uint32_t i=0;i<mFilteredPosts.size();++i)
|
||||
{
|
||||
// First look into msg versions, in case the msg is a version of an existing message
|
||||
// First look into msg versions, in case the msg is a version of an existing message
|
||||
|
||||
for(auto& msg_id:mPosts[mFilteredPosts[i]].mOlderVersions)
|
||||
if(msg_id == postId)
|
||||
{
|
||||
quintptr ref ;
|
||||
convertTabEntryToRefPointer(i,ref); // we dont use i+1 here because i is not a row, but an index in the mPosts tab
|
||||
quintptr ref ;
|
||||
convertTabEntryToRefPointer(i,ref); // we dont use i+1 here because i is not a row, but an index in the mPosts tab
|
||||
|
||||
return createIndex(i/mColumns,i%mColumns, ref);
|
||||
if(mTreeMode == TREE_MODE_GRID)
|
||||
return createIndex(i/mColumns,i%mColumns, ref);
|
||||
else
|
||||
return createIndex(i,0, ref);
|
||||
}
|
||||
|
||||
if(mPosts[mFilteredPosts[i]].mMeta.mMsgId == postId)
|
||||
@ -736,7 +761,10 @@ QModelIndex RsGxsChannelPostsModel::getIndexOfMessage(const RsGxsMessageId& mid)
|
||||
quintptr ref ;
|
||||
convertTabEntryToRefPointer(i,ref); // we dont use i+1 here because i is not a row, but an index in the mPosts tab
|
||||
|
||||
return createIndex(i/mColumns,i%mColumns, ref);
|
||||
if(mTreeMode == TREE_MODE_GRID)
|
||||
return createIndex(i/mColumns,i%mColumns, ref);
|
||||
else
|
||||
return createIndex(i,0, ref);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,8 +92,8 @@ public:
|
||||
#endif
|
||||
|
||||
enum TreeMode{ TREE_MODE_UNKWN = 0x00,
|
||||
TREE_MODE_PLAIN = 0x01,
|
||||
TREE_MODE_FILES = 0x02,
|
||||
TREE_MODE_GRID = 0x01,
|
||||
TREE_MODE_LIST = 0x02,
|
||||
};
|
||||
|
||||
#ifdef TODO
|
||||
@ -107,11 +107,18 @@ public:
|
||||
|
||||
std::vector<std::pair<time_t,RsGxsMessageId> > getPostVersions(const RsGxsMessageId& mid) const;
|
||||
|
||||
uint32_t getNumberOfPosts() { return mPosts.size() ; }
|
||||
const RsGxsChannelPost& post(uint32_t i) const { return mPosts[i]; }
|
||||
|
||||
// This method will asynchroneously update the data
|
||||
void updateChannel(const RsGxsGroupId& channel_group_id);
|
||||
const RsGxsGroupId& currentGroupId() const;
|
||||
|
||||
void triggerViewUpdate();
|
||||
|
||||
void setNumColumns(int n);
|
||||
void setMode(TreeMode mode);
|
||||
TreeMode getMode() const { return mTreeMode; }
|
||||
|
||||
// Retrieve the full list of files for all posts.
|
||||
|
||||
@ -130,7 +137,7 @@ public:
|
||||
void setMsgReadStatus(const QModelIndex &i, bool read_status);
|
||||
void setAllMsgReadStatus(bool read_status);
|
||||
|
||||
void setFilter(const QStringList &strings, uint32_t &count) ;
|
||||
void setFilter(const QStringList &strings, bool only_unread,uint32_t &count) ;
|
||||
|
||||
#ifdef TODO
|
||||
void setAuthorOpinion(const QModelIndex& indx,RsOpinion op);
|
||||
@ -228,8 +235,6 @@ private:
|
||||
std::vector<int> mFilteredPosts; // stores the list of displayes indices due to filtering.
|
||||
std::vector<RsGxsChannelPost> mPosts ; // store the list of posts updated from rsForums.
|
||||
|
||||
//std::map<RsGxsMessageId,std::vector<std::pair<time_t,RsGxsMessageId> > > mPostVersions; // stores versions of posts
|
||||
|
||||
QColor mTextColorRead ;
|
||||
QColor mTextColorUnread ;
|
||||
QColor mTextColorUnreadChildren;
|
||||
|
@ -61,6 +61,8 @@ static const int CHANNEL_TABS_DETAILS= 0;
|
||||
static const int CHANNEL_TABS_POSTS = 1;
|
||||
static const int CHANNEL_TABS_FILES = 2;
|
||||
|
||||
QColor SelectedColor = QRgb(0xff308dc7);
|
||||
|
||||
/* View mode */
|
||||
#define VIEW_MODE_FEEDS 1
|
||||
#define VIEW_MODE_FILES 2
|
||||
@ -74,14 +76,23 @@ static const int CHANNEL_TABS_FILES = 2;
|
||||
|
||||
#define STAR_OVERLAY_IMAGE ":icons/star_overlay_128.png"
|
||||
#define IMAGE_COPYLINK ":/images/copyrslink.png"
|
||||
#define IMAGE_GRID_VIEW ":icons/png/menu.png"
|
||||
#define IMAGE_DOWNLOAD ":icons/png/download.png"
|
||||
|
||||
Q_DECLARE_METATYPE(ChannelPostFileInfo)
|
||||
|
||||
// Delegate used to paint into the table of thumbnails
|
||||
|
||||
int ChannelPostDelegate::cellSize(const QFont& font) const
|
||||
//===============================================================================================================================================//
|
||||
//=== ChannelPostDelegate ===//
|
||||
//===============================================================================================================================================//
|
||||
|
||||
int ChannelPostDelegate::cellSize(int col,const QFont& font,uint32_t parent_width) const
|
||||
{
|
||||
return mZoom*COLUMN_SIZE_FONT_FACTOR_W*QFontMetricsF(font).height();
|
||||
if(mUseGrid || col==0)
|
||||
return mZoom*COLUMN_SIZE_FONT_FACTOR_W*QFontMetricsF(font).height();
|
||||
else
|
||||
return 0.8*parent_width - mZoom*COLUMN_SIZE_FONT_FACTOR_W*QFontMetricsF(font).height();
|
||||
}
|
||||
|
||||
void ChannelPostDelegate::zoom(bool zoom_or_unzoom)
|
||||
@ -91,53 +102,106 @@ void ChannelPostDelegate::zoom(bool zoom_or_unzoom)
|
||||
else
|
||||
mZoom /= 1.02;
|
||||
|
||||
std::cerr << "zoom factor: " << mZoom << std::endl;
|
||||
if(mZoom < 0.5)
|
||||
mZoom = 0.5;
|
||||
if(mZoom > 2.0)
|
||||
mZoom = 2.0;
|
||||
}
|
||||
|
||||
void ChannelPostDelegate::setAspectRatio(ChannelPostThumbnailView::AspectRatio r)
|
||||
{
|
||||
mAspectRatio = r;
|
||||
}
|
||||
void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
|
||||
{
|
||||
// prepare
|
||||
painter->save();
|
||||
painter->setClipRect(option.rect);
|
||||
// prepare
|
||||
painter->save();
|
||||
painter->setClipRect(option.rect);
|
||||
|
||||
RsGxsChannelPost post = index.data(Qt::UserRole).value<RsGxsChannelPost>() ;
|
||||
RsGxsChannelPost post = index.data(Qt::UserRole).value<RsGxsChannelPost>() ;
|
||||
|
||||
painter->fillRect( option.rect, option.backgroundBrush);
|
||||
painter->restore();
|
||||
|
||||
ChannelPostThumbnailView w(post);
|
||||
if(mUseGrid || index.column()==0)
|
||||
{
|
||||
// Draw a thumbnail
|
||||
|
||||
QPixmap pixmap(w.size());
|
||||
uint32_t flags = (mUseGrid)?(ChannelPostThumbnailView::FLAG_SHOW_TEXT | ChannelPostThumbnailView::FLAG_SCALE_FONT):0;
|
||||
ChannelPostThumbnailView w(post,flags);
|
||||
w.setAspectRatio(mAspectRatio);
|
||||
w.updateGeometry();
|
||||
w.adjustSize();
|
||||
|
||||
if((option.state & QStyle::State_Selected) && post.mMeta.mPublishTs > 0) // check if post is selected and is not empty (end of last row)
|
||||
pixmap.fill(QRgb(0xff308dc7)); // I dont know how to grab the backgroud color for selected objects automatically.
|
||||
else
|
||||
pixmap.fill(QRgb(0x00ffffff)); // choose a fully transparent background
|
||||
QPixmap pixmap(w.size());
|
||||
|
||||
w.render(&pixmap,QPoint(),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background
|
||||
if((option.state & QStyle::State_Selected) && post.mMeta.mPublishTs > 0) // check if post is selected and is not empty (end of last row)
|
||||
pixmap.fill(SelectedColor); // I dont know how to grab the backgroud color for selected objects automatically.
|
||||
else
|
||||
pixmap.fill(QRgb(0x00ffffff)); // choose a fully transparent background
|
||||
|
||||
if(mZoom != 1.0)
|
||||
pixmap = pixmap.scaled(mZoom*pixmap.size(),Qt::KeepAspectRatio,Qt::SmoothTransformation);
|
||||
w.render(&pixmap,QPoint(),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background
|
||||
|
||||
if(IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus))
|
||||
{
|
||||
QPainter p(&pixmap);
|
||||
QFontMetricsF fm(option.font);
|
||||
p.drawPixmap(mZoom*QPoint(6.2*fm.height(),6.9*fm.height()),FilesDefs::getPixmapFromQtResourcePath(STAR_OVERLAY_IMAGE).scaled(mZoom*7*fm.height(),mZoom*7*fm.height(),Qt::KeepAspectRatio,Qt::SmoothTransformation));
|
||||
}
|
||||
// We extract from the pixmap the part of the widget that we want. Saddly enough, Qt adds some white space
|
||||
// below the widget and there is no way to control that.
|
||||
|
||||
// debug
|
||||
// if(index.row()==0 && index.column()==0)
|
||||
// {
|
||||
// QFile file("yourFile.png");
|
||||
// file.open(QIODevice::WriteOnly);
|
||||
// pixmap.save(&file, "PNG");
|
||||
// std::cerr << "Saved pxmap to png" << std::endl;
|
||||
// }
|
||||
//std::cerr << "option.rect = " << option.rect.width() << "x" << option.rect.height() << ". fm.height()=" << QFontMetricsF(option.font).height() << std::endl;
|
||||
pixmap = pixmap.copy(QRect(0,0,w.actualSize().width(),w.actualSize().height()));
|
||||
|
||||
painter->drawPixmap(option.rect.topLeft(),
|
||||
pixmap.scaled(option.rect.width(),option.rect.width()*w.height()/(float)w.width(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation));
|
||||
// if(index.row()==0 && index.column()==0)
|
||||
// {
|
||||
// QFile file("yourFile.png");
|
||||
// file.open(QIODevice::WriteOnly);
|
||||
// pixmap.save(&file, "PNG");
|
||||
// file.close();
|
||||
// }
|
||||
|
||||
if(mUseGrid || index.column()==0)
|
||||
{
|
||||
if(mZoom != 1.0)
|
||||
pixmap = pixmap.scaled(mZoom*pixmap.size(),Qt::KeepAspectRatio,Qt::SmoothTransformation);
|
||||
|
||||
if(IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus))
|
||||
{
|
||||
QPainter p(&pixmap);
|
||||
QFontMetricsF fm(option.font);
|
||||
|
||||
p.drawPixmap(mZoom*QPoint(0.1*fm.height(),-3.6*fm.height()),FilesDefs::getPixmapFromQtResourcePath(STAR_OVERLAY_IMAGE).scaled(mZoom*7*fm.height(),mZoom*7*fm.height(),Qt::KeepAspectRatio,Qt::SmoothTransformation));
|
||||
}
|
||||
}
|
||||
|
||||
painter->drawPixmap(option.rect.topLeft(),
|
||||
pixmap.scaled(option.rect.width(),option.rect.width()*pixmap.height()/(float)pixmap.width(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation));
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're drawing the text on the second column
|
||||
|
||||
uint32_t font_height = QFontMetricsF(option.font).height();
|
||||
QPoint p = option.rect.topLeft();
|
||||
float y = p.y() + font_height;
|
||||
|
||||
painter->save();
|
||||
|
||||
if((option.state & QStyle::State_Selected) && post.mMeta.mPublishTs > 0) // check if post is selected and is not empty (end of last row)
|
||||
painter->setPen(SelectedColor);
|
||||
|
||||
if(IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus))
|
||||
{
|
||||
QFont font(option.font);
|
||||
font.setBold(true);
|
||||
painter->setFont(font);
|
||||
}
|
||||
painter->drawText(QPoint(p.x()+0.5*font_height,y),QString::fromUtf8(post.mMeta.mMsgName.c_str()));
|
||||
y += font_height;
|
||||
|
||||
painter->drawText(QPoint(p.x()+0.5*font_height,y),QDateTime::fromSecsSinceEpoch(post.mMeta.mPublishTs).toString(Qt::DefaultLocaleShortDate));
|
||||
y += font_height;
|
||||
|
||||
painter->drawText(QPoint(p.x()+0.5*font_height,y),QString::number(post.mCount)+ " " +((post.mCount>1)?tr("files"):tr("file")) + " (" + QString::number(post.mSize) + " " + tr("bytes") + ")" );
|
||||
y += font_height;
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
}
|
||||
|
||||
QSize ChannelPostDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
@ -146,9 +210,36 @@ QSize ChannelPostDelegate::sizeHint(const QStyleOptionViewItem& option, const QM
|
||||
|
||||
QFontMetricsF fm(option.font);
|
||||
|
||||
return QSize(mZoom*COLUMN_SIZE_FONT_FACTOR_W*fm.height(),mZoom*COLUMN_SIZE_FONT_FACTOR_H*fm.height());
|
||||
RsGxsChannelPost post = index.data(Qt::UserRole).value<RsGxsChannelPost>() ;
|
||||
uint32_t flags = (mUseGrid)?(ChannelPostThumbnailView::FLAG_SHOW_TEXT | ChannelPostThumbnailView::FLAG_SCALE_FONT):0;
|
||||
|
||||
ChannelPostThumbnailView w(post,flags);
|
||||
w.setAspectRatio(mAspectRatio);
|
||||
w.updateGeometry();
|
||||
w.adjustSize();
|
||||
|
||||
//std::cerr << "w.size(): " << w.width() << " x " << w.height() << ". Actual size: " << w.actualSize().width() << " x " << w.actualSize().height() << std::endl;
|
||||
|
||||
float aspect_ratio = w.actualSize().height()/(float)w.actualSize().width();
|
||||
|
||||
float cell_width = mZoom*COLUMN_SIZE_FONT_FACTOR_W*fm.height();
|
||||
float cell_height = mZoom*COLUMN_SIZE_FONT_FACTOR_W*fm.height()*aspect_ratio;
|
||||
|
||||
if(mUseGrid || index.column()==0)
|
||||
return QSize(cell_width,cell_height);
|
||||
else
|
||||
return QSize(option.rect.width()-cell_width,cell_height);
|
||||
}
|
||||
|
||||
void ChannelPostDelegate::setWidgetGrid(bool use_grid)
|
||||
{
|
||||
mUseGrid = use_grid;
|
||||
}
|
||||
|
||||
//===============================================================================================================================================//
|
||||
//=== ChannelPostFilesDelegate ===//
|
||||
//===============================================================================================================================================//
|
||||
|
||||
QWidget *ChannelPostFilesDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex& index) const
|
||||
{
|
||||
ChannelPostFileInfo file = index.data(Qt::UserRole).value<ChannelPostFileInfo>() ;
|
||||
@ -222,6 +313,10 @@ QSize ChannelPostFilesDelegate::sizeHint(const QStyleOptionViewItem& option, con
|
||||
}
|
||||
}
|
||||
|
||||
//===============================================================================================================================================//
|
||||
//=== GxsChannelPostWidgetWithModel ===//
|
||||
//===============================================================================================================================================//
|
||||
|
||||
/** Constructor */
|
||||
GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupId &channelId, QWidget *parent) :
|
||||
GxsMessageFrameWidget(rsGxsChannels, parent),
|
||||
@ -230,13 +325,25 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI
|
||||
/* Invoke the Qt Designer generated object setup routine */
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->postsTree->setModel(mChannelPostsModel = new RsGxsChannelPostsModel());
|
||||
ui->viewType_TB->setIcon(FilesDefs::getIconFromQtResourcePath(":icons/svg/gridlayout.svg"));
|
||||
ui->viewType_TB->setToolTip(tr("Click to switch to list view"));
|
||||
connect(ui->viewType_TB,SIGNAL(clicked()),this,SLOT(switchView()));
|
||||
|
||||
ui->showUnread_TB->setIcon(FilesDefs::getIconFromQtResourcePath(":/images/message-state-unread.png"));
|
||||
ui->showUnread_TB->setChecked(false);
|
||||
ui->showUnread_TB->setToolTip(tr("Show unread posts only"));
|
||||
connect(ui->showUnread_TB,SIGNAL(toggled(bool)),this,SLOT(switchOnlyUnread(bool)));
|
||||
|
||||
ui->postsTree->setModel(mChannelPostsModel = new RsGxsChannelPostsModel());
|
||||
ui->postsTree->setItemDelegate(mChannelPostsDelegate = new ChannelPostDelegate());
|
||||
ui->postsTree->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // prevents bug on w10, since row size depends on widget width
|
||||
ui->postsTree->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);// more beautiful if we scroll at pixel level
|
||||
ui->postsTree->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
|
||||
mChannelPostsDelegate->setAspectRatio(ChannelPostThumbnailView::ASPECT_RATIO_16_9);
|
||||
|
||||
connect(ui->postsTree,SIGNAL(zoomRequested(bool)),this,SLOT(updateZoomFactor(bool)));
|
||||
connect(ui->commentsDialog,SIGNAL(commentsLoaded(int)),this,SLOT(updateCommentsCount(int)));
|
||||
|
||||
ui->channelPostFiles_TV->setModel(mChannelPostFilesModel = new RsGxsChannelPostFilesModel(this));
|
||||
ui->channelPostFiles_TV->setItemDelegate(new ChannelPostFilesDelegate());
|
||||
@ -262,7 +369,7 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI
|
||||
ui->postTime_LB->hide();
|
||||
ui->postLogo_LB->hide();
|
||||
|
||||
ui->postDetails_TE->setPlaceholderText(tr("No post selected"));
|
||||
ui->postDetails_TE->setPlaceholderText(tr("No text to display"));
|
||||
|
||||
// Set initial size of the splitter
|
||||
ui->splitter->setStretchFactor(0, 1);
|
||||
@ -270,8 +377,9 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI
|
||||
|
||||
QFontMetricsF fm(font());
|
||||
|
||||
for(int i=0;i<mChannelPostsModel->columnCount();++i)
|
||||
ui->postsTree->setColumnWidth(i,mChannelPostsDelegate->cellSize(font()));
|
||||
if(mChannelPostsModel->getMode() == RsGxsChannelPostsModel::TREE_MODE_GRID)
|
||||
for(int i=0;i<mChannelPostsModel->columnCount();++i)
|
||||
ui->postsTree->setColumnWidth(i,mChannelPostsDelegate->cellSize(i,font(),ui->postsTree->width()));
|
||||
|
||||
/* Setup UI helper */
|
||||
|
||||
@ -339,12 +447,11 @@ void GxsChannelPostsWidgetWithModel::updateZoomFactor(bool zoom_or_unzoom)
|
||||
mChannelPostsDelegate->zoom(zoom_or_unzoom);
|
||||
|
||||
for(int i=0;i<mChannelPostsModel->columnCount();++i)
|
||||
ui->postsTree->setColumnWidth(i,mChannelPostsDelegate->cellSize(font()));
|
||||
ui->postsTree->setColumnWidth(i,mChannelPostsDelegate->cellSize(i,font(),ui->postsTree->width()));
|
||||
|
||||
QSize s = ui->postsTree->size();
|
||||
|
||||
int n_columns = std::max(1,(int)floor(s.width() / (mChannelPostsDelegate->cellSize(font()))));
|
||||
std::cerr << "nb columns: " << n_columns << std::endl;
|
||||
int n_columns = std::max(1,(int)floor(s.width() / (mChannelPostsDelegate->cellSize(0,font(),s.width()))));
|
||||
|
||||
mChannelPostsModel->setNumColumns(n_columns); // forces the update
|
||||
|
||||
@ -366,7 +473,28 @@ void GxsChannelPostsWidgetWithModel::postContextMenu(const QPoint&)
|
||||
{
|
||||
QMenu menu(this);
|
||||
|
||||
menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyMessageLink()));
|
||||
#ifdef TO_REMOVE
|
||||
if(mChannelPostsModel->getMode() == RsGxsChannelPostsModel::TREE_MODE_GRID)
|
||||
menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_GRID_VIEW), tr("Switch to list view"), this, SLOT(switchView()));
|
||||
else
|
||||
menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_GRID_VIEW), tr("Switch to grid view"), this, SLOT(switchView()));
|
||||
|
||||
menu.addSeparator();
|
||||
#endif
|
||||
|
||||
QModelIndex index = ui->postsTree->selectionModel()->currentIndex();
|
||||
|
||||
if(index.isValid())
|
||||
{
|
||||
RsGxsChannelPost post = index.data(Qt::UserRole).value<RsGxsChannelPost>() ;
|
||||
|
||||
if(!post.mFiles.empty())
|
||||
menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_DOWNLOAD), tr("Download files"), this, SLOT(download()));
|
||||
|
||||
if(!IS_MSG_UNREAD(post.mMeta.mMsgStatus) && !IS_MSG_NEW(post.mMeta.mMsgStatus))
|
||||
menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_COPYLINK), tr("Mark as unread"), this, SLOT(markMessageUnread()));
|
||||
}
|
||||
menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyMessageLink()));
|
||||
|
||||
if(IS_GROUP_PUBLISHER(mGroup.mMeta.mSubscribeFlags))
|
||||
menu.addAction(FilesDefs::getIconFromQtResourcePath(":/images/edit_16.png"), tr("Edit"), this, SLOT(editPost()));
|
||||
@ -374,6 +502,70 @@ void GxsChannelPostsWidgetWithModel::postContextMenu(const QPoint&)
|
||||
menu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::markMessageUnread()
|
||||
{
|
||||
QModelIndex index = ui->postsTree->selectionModel()->currentIndex();
|
||||
|
||||
mChannelPostsModel->setMsgReadStatus(index,false);
|
||||
}
|
||||
|
||||
RsGxsMessageId GxsChannelPostsWidgetWithModel::getCurrentItemId() const
|
||||
{
|
||||
RsGxsMessageId selected_msg_id ;
|
||||
QModelIndex index = ui->postsTree->selectionModel()->currentIndex();
|
||||
|
||||
if(index.isValid())
|
||||
selected_msg_id = index.data(Qt::UserRole).value<RsGxsChannelPost>().mMeta.mMsgId ;
|
||||
|
||||
return selected_msg_id;
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::selectItem(const RsGxsMessageId& msg_id)
|
||||
{
|
||||
auto index = mChannelPostsModel->getIndexOfMessage(msg_id);
|
||||
|
||||
ui->postsTree->selectionModel()->setCurrentIndex(index,QItemSelectionModel::ClearAndSelect);
|
||||
ui->postsTree->scrollTo(index);//May change if model reloaded
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::switchView()
|
||||
{
|
||||
auto msg_id = getCurrentItemId();
|
||||
|
||||
if(mChannelPostsModel->getMode() == RsGxsChannelPostsModel::TREE_MODE_GRID)
|
||||
{
|
||||
ui->viewType_TB->setIcon(FilesDefs::getIconFromQtResourcePath(":icons/svg/listlayout.svg"));
|
||||
ui->viewType_TB->setToolTip(tr("Click to switch to grid view"));
|
||||
|
||||
ui->postsTree->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
|
||||
mChannelPostsDelegate->setWidgetGrid(false);
|
||||
mChannelPostsModel->setMode(RsGxsChannelPostsModel::TREE_MODE_LIST);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->viewType_TB->setIcon(FilesDefs::getIconFromQtResourcePath(":icons/svg/gridlayout.svg"));
|
||||
ui->viewType_TB->setToolTip(tr("Click to switch to list view"));
|
||||
|
||||
ui->postsTree->setSelectionBehavior(QAbstractItemView::SelectItems);
|
||||
|
||||
mChannelPostsDelegate->setWidgetGrid(true);
|
||||
mChannelPostsModel->setMode(RsGxsChannelPostsModel::TREE_MODE_GRID);
|
||||
|
||||
handlePostsTreeSizeChange(ui->postsTree->size(),true);
|
||||
}
|
||||
|
||||
for(int i=0;i<mChannelPostsModel->columnCount();++i)
|
||||
ui->postsTree->setColumnWidth(i,mChannelPostsDelegate->cellSize(i,font(),ui->postsTree->width()));
|
||||
|
||||
selectItem(msg_id);
|
||||
ui->postsTree->setFocus();
|
||||
|
||||
mChannelPostsModel->triggerViewUpdate(); // This is already called by setMode(), but the model cannot know how many
|
||||
// columns is actually has until we call handlePostsTreeSizeChange(), so
|
||||
// we have to call it again here.
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::copyMessageLink()
|
||||
{
|
||||
try
|
||||
@ -405,6 +597,30 @@ void GxsChannelPostsWidgetWithModel::copyMessageLink()
|
||||
QMessageBox::critical(NULL,tr("Link creation error"),tr("Link could not be created: ")+e.what());
|
||||
}
|
||||
}
|
||||
void GxsChannelPostsWidgetWithModel::download()
|
||||
{
|
||||
QModelIndex index = ui->postsTree->selectionModel()->currentIndex();
|
||||
RsGxsChannelPost post = index.data(Qt::UserRole).value<RsGxsChannelPost>() ;
|
||||
|
||||
std::string destination;
|
||||
rsGxsChannels->getChannelDownloadDirectory(mGroup.mMeta.mGroupId,destination);
|
||||
|
||||
for(auto file:post.mFiles)
|
||||
{
|
||||
std::list<RsPeerId> sources;
|
||||
std::string destination;
|
||||
|
||||
// Add possible direct sources.
|
||||
FileInfo fileInfo;
|
||||
rsFiles->FileDetails(file.mHash, RS_FILE_HINTS_REMOTE, fileInfo);
|
||||
|
||||
for(std::vector<TransferInfo>::const_iterator it = fileInfo.peers.begin(); it != fileInfo.peers.end(); ++it) {
|
||||
sources.push_back((*it).peerId);
|
||||
}
|
||||
|
||||
rsFiles->FileRequest(file.mName, file.mHash, file.mSize, destination, RS_FILE_REQ_ANONYMOUS_ROUTING, sources);
|
||||
}
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::editPost()
|
||||
{
|
||||
@ -415,12 +631,15 @@ void GxsChannelPostsWidgetWithModel::editPost()
|
||||
msgDialog->show();
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::handlePostsTreeSizeChange(QSize s)
|
||||
void GxsChannelPostsWidgetWithModel::handlePostsTreeSizeChange(QSize s,bool force)
|
||||
{
|
||||
int n_columns = std::max(1,(int)floor(s.width() / (mChannelPostsDelegate->cellSize(font()))));
|
||||
std::cerr << "nb columns: " << n_columns << std::endl;
|
||||
if(mChannelPostsModel->getMode() != RsGxsChannelPostsModel::TREE_MODE_GRID)
|
||||
return;
|
||||
|
||||
if(n_columns != mChannelPostsModel->columnCount())
|
||||
int n_columns = std::max(1,(int)floor(s.width() / (mChannelPostsDelegate->cellSize(0,font(),ui->postsTree->width()))));
|
||||
std::cerr << "nb columns: " << n_columns << " current count=" << mChannelPostsModel->columnCount() << std::endl;
|
||||
|
||||
if(force || (n_columns != mChannelPostsModel->columnCount()))
|
||||
mChannelPostsModel->setNumColumns(n_columns);
|
||||
}
|
||||
|
||||
@ -461,10 +680,12 @@ void GxsChannelPostsWidgetWithModel::showPostDetails()
|
||||
ui->postLogo_LB->hide();
|
||||
ui->postName_LB->hide();
|
||||
ui->postTime_LB->hide();
|
||||
mChannelPostFilesModel->clear();
|
||||
mChannelPostFilesModel->clear();
|
||||
ui->details_TW->setEnabled(false);
|
||||
|
||||
return;
|
||||
}
|
||||
ui->details_TW->setEnabled(true);
|
||||
|
||||
ui->postLogo_LB->show();
|
||||
ui->postName_LB->show();
|
||||
@ -506,7 +727,7 @@ void GxsChannelPostsWidgetWithModel::showPostDetails()
|
||||
ui->postLogo_LB->setFixedSize(W,postImage.height()/(float)postImage.width()*W);
|
||||
|
||||
ui->postName_LB->setText(QString::fromUtf8(post.mMeta.mMsgName.c_str()));
|
||||
ui->postName_LB->setFixedWidth(W);
|
||||
|
||||
ui->postTime_LB->setText(QDateTime::fromMSecsSinceEpoch(post.mMeta.mPublishTs*1000).toString("MM/dd/yyyy, hh:mm"));
|
||||
ui->postTime_LB->setFixedWidth(W);
|
||||
|
||||
@ -526,6 +747,13 @@ void GxsChannelPostsWidgetWithModel::showPostDetails()
|
||||
}
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::updateCommentsCount(int n)
|
||||
{
|
||||
if(n > 0)
|
||||
ui->details_TW->setTabText(2,tr("Comments (%1)").arg(n));
|
||||
else
|
||||
ui->details_TW->setTabText(2,tr("Comments"));
|
||||
}
|
||||
void GxsChannelPostsWidgetWithModel::updateGroupData()
|
||||
{
|
||||
if(groupId().isNull())
|
||||
@ -553,6 +781,8 @@ void GxsChannelPostsWidgetWithModel::updateGroupData()
|
||||
{
|
||||
mGroup = group;
|
||||
mChannelPostsModel->updateChannel(groupId());
|
||||
whileBlocking(ui->filterLineEdit)->clear();
|
||||
whileBlocking(ui->showUnread_TB)->setChecked(false);
|
||||
|
||||
insertChannelDetails(mGroup);
|
||||
|
||||
@ -585,10 +815,30 @@ void GxsChannelPostsWidgetWithModel::postChannelPostLoad()
|
||||
mChannelPostsModel->getFilesList(files);
|
||||
mChannelFilesModel->setFiles(files);
|
||||
|
||||
//ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE);
|
||||
//ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE);
|
||||
ui->channelFiles_TV->setAutoSelect(true);
|
||||
ui->channelFiles_TV->sortByColumn(0, Qt::AscendingOrder);
|
||||
|
||||
ui->infoPosts->setText(QString::number(mChannelPostsModel->getNumberOfPosts()) + " / " + QString::number(mGroup.mMeta.mVisibleMsgCount));
|
||||
|
||||
// now compute aspect ratio for posts. We do that by looking at the 5 latest posts and compute the best aspect ratio for them.
|
||||
|
||||
std::vector<uint32_t> ar_votes(4,0);
|
||||
|
||||
for(uint32_t i=0;i<std::min(mChannelPostsModel->getNumberOfPosts(),5u);++i)
|
||||
{
|
||||
const RsGxsChannelPost& post = mChannelPostsModel->post(i);
|
||||
ChannelPostThumbnailView v(post,ChannelPostThumbnailView::FLAG_SHOW_TEXT | ChannelPostThumbnailView::FLAG_SCALE_FONT);
|
||||
|
||||
++ar_votes[ static_cast<uint32_t>( v.bestAspectRatio() )];
|
||||
}
|
||||
int best=0;
|
||||
for(uint32_t i=0;i<4;++i)
|
||||
if(ar_votes[i] > ar_votes[best])
|
||||
best = i;
|
||||
|
||||
mChannelPostsDelegate->setAspectRatio(static_cast<ChannelPostThumbnailView::AspectRatio>(best));
|
||||
mChannelPostsModel->triggerViewUpdate();
|
||||
handlePostsTreeSizeChange(ui->postsTree->size(),true); // force the update
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::updateDisplay(bool complete)
|
||||
@ -769,8 +1019,6 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou
|
||||
rsGxsChannels->getChannelAutoDownload(group.mMeta.mGroupId,autoDownload);
|
||||
setAutoDownload(autoDownload);
|
||||
|
||||
RetroShareLink link;
|
||||
|
||||
if (IS_GROUP_SUBSCRIBED(group.mMeta.mSubscribeFlags))
|
||||
{
|
||||
ui->subscribeToolButton->setText(tr("Subscribed") + " " + QString::number(group.mMeta.mPop) );
|
||||
@ -789,6 +1037,7 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou
|
||||
|
||||
|
||||
ui->infoPosts->setText(QString::number(group.mMeta.mVisibleMsgCount));
|
||||
|
||||
if(group.mMeta.mLastPost==0)
|
||||
ui->infoLastPost->setText(tr("Never"));
|
||||
else
|
||||
@ -808,8 +1057,11 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou
|
||||
|
||||
ui->infoAdministrator->setId(group.mMeta.mAuthorId) ;
|
||||
|
||||
link = RetroShareLink::createMessage(group.mMeta.mAuthorId, "");
|
||||
ui->infoAdministrator->setText(link.toHtml());
|
||||
if(!group.mMeta.mAuthorId.isNull())
|
||||
{
|
||||
RetroShareLink link = RetroShareLink::createMessage(group.mMeta.mAuthorId, "");
|
||||
ui->infoAdministrator->setText(link.toHtml());
|
||||
}
|
||||
|
||||
ui->infoCreated->setText(DateTime::formatLongDateTime(group.mMeta.mPublishTs));
|
||||
|
||||
@ -850,6 +1102,7 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou
|
||||
#endif
|
||||
ui->subscribeToolButton->setText(tr("Subscribe ") + " " + QString::number(group.mMeta.mPop) );
|
||||
|
||||
showPostDetails();
|
||||
}
|
||||
|
||||
#ifdef TODO
|
||||
@ -893,15 +1146,17 @@ void GxsChannelPostsWidgetWithModel::setViewMode(int viewMode)
|
||||
#endif
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::switchOnlyUnread(bool)
|
||||
{
|
||||
filterChanged(ui->filterLineEdit->text());
|
||||
std::cerr << "Switched to unread/read"<< std::endl;
|
||||
}
|
||||
void GxsChannelPostsWidgetWithModel::filterChanged(QString s)
|
||||
{
|
||||
QStringList ql = s.split(' ',QString::SkipEmptyParts);
|
||||
uint32_t count;
|
||||
mChannelPostsModel->setFilter(ql,count);
|
||||
mChannelPostsModel->setFilter(ql,ui->showUnread_TB->isChecked(),count);
|
||||
mChannelFilesModel->setFilter(ql,count);
|
||||
|
||||
//mChannelPostFilesProxyModel->setFilterKeyColumn(RsGxsChannelPostFilesModel::COLUMN_FILES_NAME);
|
||||
//mChannelPostFilesProxyModel->setFilterRegExp(s) ;// triggers a re-display. s is actually not used.
|
||||
}
|
||||
|
||||
#ifdef TODO
|
||||
@ -1148,25 +1403,6 @@ public:
|
||||
uint32_t mLastToken;
|
||||
};
|
||||
|
||||
#ifdef TO_REMOVE
|
||||
static void setAllMessagesReadCallback(FeedItem *feedItem, void *data)
|
||||
{
|
||||
GxsChannelPostItem *channelPostItem = dynamic_cast<GxsChannelPostItem*>(feedItem);
|
||||
if (!channelPostItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
GxsChannelPostsReadData *readData = (GxsChannelPostsReadData*) data;
|
||||
bool isRead = !channelPostItem->isUnread() ;
|
||||
|
||||
if(channelPostItem->isLoaded() && (isRead == readData->mRead))
|
||||
return ;
|
||||
|
||||
RsGxsGrpMsgIdPair msgPair = std::make_pair(channelPostItem->groupId(), channelPostItem->messageId());
|
||||
rsGxsChannels->setMessageReadStatus(readData->mLastToken, msgPair, readData->mRead);
|
||||
}
|
||||
#endif
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::setAllMessagesReadDo(bool read, uint32_t& /*token*/)
|
||||
{
|
||||
if (groupId().isNull() || !IS_GROUP_SUBSCRIBED(mGroup.mMeta.mSubscribeFlags))
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include "gui/gxs/GxsMessageFramePostWidget.h"
|
||||
#include "gui/feeds/FeedHolder.h"
|
||||
|
||||
#include "GxsChannelPostThumbnail.h"
|
||||
|
||||
namespace Ui {
|
||||
class GxsChannelPostsWidgetWithModel;
|
||||
}
|
||||
@ -60,21 +62,26 @@ class ChannelPostDelegate: public QAbstractItemDelegate
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ChannelPostDelegate(QObject *parent=0) : QAbstractItemDelegate(parent), mZoom(1.0){}
|
||||
ChannelPostDelegate(QObject *parent=0) : QAbstractItemDelegate(parent), mZoom(1.0), mUseGrid(true){}
|
||||
virtual ~ChannelPostDelegate(){}
|
||||
|
||||
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
|
||||
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
|
||||
int cellSize(const QFont& font) const;
|
||||
int cellSize(int col, const QFont& font, uint32_t parent_width) const;
|
||||
void zoom(bool zoom_or_unzoom) ;
|
||||
private:
|
||||
void setWidgetGrid(bool use_grid) ;
|
||||
void setAspectRatio(ChannelPostThumbnailView::AspectRatio r) ;
|
||||
|
||||
private:
|
||||
static constexpr float IMAGE_MARGIN_FACTOR = 1.0;
|
||||
static constexpr float IMAGE_SIZE_FACTOR_W = 4.0 ;
|
||||
static constexpr float IMAGE_SIZE_FACTOR_H = 6.0 ;
|
||||
static constexpr float IMAGE_ZOOM_FACTOR = 1.0;
|
||||
|
||||
float mZoom; // zoom factor for the whole thumbnail
|
||||
bool mUseGrid; // wether we use the grid widget or the list widget
|
||||
ChannelPostThumbnailView::AspectRatio mAspectRatio;
|
||||
};
|
||||
|
||||
class GxsChannelPostsWidgetWithModel: public GxsMessageFrameWidget
|
||||
@ -135,25 +142,32 @@ protected:
|
||||
private slots:
|
||||
void showPostDetails();
|
||||
void updateGroupData();
|
||||
void createMsg();
|
||||
void download();
|
||||
void createMsg();
|
||||
void toggleAutoDownload();
|
||||
void subscribeGroup(bool subscribe);
|
||||
void filterChanged(QString);
|
||||
void setViewMode(int viewMode);
|
||||
void settingsChanged();
|
||||
void handlePostsTreeSizeChange(QSize s);
|
||||
void handlePostsTreeSizeChange(QSize s, bool force=false);
|
||||
void postChannelPostLoad();
|
||||
void editPost();
|
||||
void postContextMenu(const QPoint&);
|
||||
void copyMessageLink();
|
||||
void updateZoomFactor(bool zoom_or_unzoom);
|
||||
void switchView();
|
||||
void switchOnlyUnread(bool b);
|
||||
void markMessageUnread();
|
||||
|
||||
public slots:
|
||||
void sortColumnFiles(int col,Qt::SortOrder so);
|
||||
void sortColumnPostFiles(int col,Qt::SortOrder so);
|
||||
void updateCommentsCount(int n);
|
||||
|
||||
private:
|
||||
void processSettings(bool load);
|
||||
RsGxsMessageId getCurrentItemId() const;
|
||||
void selectItem(const RsGxsMessageId& msg_id);
|
||||
|
||||
void setAutoDownload(bool autoDl);
|
||||
static bool filterItem(FeedItem *feedItem, const QString &text, int filter);
|
||||
|
@ -120,6 +120,26 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="showUnread_TB">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="viewType_TB">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="viewModeLayout">
|
||||
<property name="spacing">
|
||||
@ -161,7 +181,7 @@
|
||||
<item>
|
||||
<widget class="QTabWidget" name="channel_TW">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_3">
|
||||
<attribute name="title">
|
||||
@ -199,26 +219,6 @@
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="infoLastPost">
|
||||
<property name="text">
|
||||
<string notr="true">unknown</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Created:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="GxsIdLabel" name="infoAdministrator">
|
||||
<property name="text">
|
||||
@ -229,26 +229,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Distribution:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="infoPosts">
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QLabel" name="infoLastPostLabel">
|
||||
<property name="sizePolicy">
|
||||
@ -268,8 +248,8 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="infoDistribution">
|
||||
<item row="4" column="3">
|
||||
<widget class="QLabel" name="infoCreated">
|
||||
<property name="text">
|
||||
<string>unknown</string>
|
||||
</property>
|
||||
@ -288,8 +268,48 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QLabel" name="infoCreated">
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="infoLastPost">
|
||||
<property name="text">
|
||||
<string notr="true">unknown</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Distribution:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Created:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="infoPosts">
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="infoDistribution">
|
||||
<property name="text">
|
||||
<string>unknown</string>
|
||||
</property>
|
||||
@ -309,8 +329,11 @@
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p align="justify">The number of posts at friends is progressively updated.</p><p align="justify">The new numbers will show next time you load this channel.</p><p align="justify">The two numbers differ depending on your friends synchronization</p><p>time limits as well as yours.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Posts:</string>
|
||||
<string>Posts (locally / at friends):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -412,9 +435,6 @@ p, li { white-space: pre-wrap; }
|
||||
<string>Details</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="bottomMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
@ -433,16 +453,6 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="postName_LB">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="postTime_LB">
|
||||
<property name="text">
|
||||
@ -466,11 +476,22 @@ p, li { white-space: pre-wrap; }
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="postDetails_TE">
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="postName_LB">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="postDetails_TE">
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@ -526,7 +547,7 @@ p, li { white-space: pre-wrap; }
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_5">
|
||||
<attribute name="title">
|
||||
<string>Files</string>
|
||||
<string>All files</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
|
@ -445,10 +445,13 @@ QVariant RsGxsForumModel::textColorRole(const ForumModelPostEntry& fmpe,int /*co
|
||||
if( (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING))
|
||||
return QVariant(mTextColorMissing);
|
||||
|
||||
if(IS_MSG_UNREAD(fmpe.mMsgStatus) || (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED))
|
||||
if(IS_MSG_UNREAD(fmpe.mMsgStatus))
|
||||
return QVariant(mTextColorUnread);
|
||||
else
|
||||
return QVariant(mTextColorRead);
|
||||
if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED)
|
||||
return QVariant(mTextColorPinned);
|
||||
else
|
||||
return QVariant(mTextColorRead);
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
@ -593,10 +596,10 @@ QVariant RsGxsForumModel::pinnedRole(const ForumModelPostEntry& fmpe,int /*colum
|
||||
QVariant RsGxsForumModel::backgroundRole(const ForumModelPostEntry& fmpe,int /*column*/) const
|
||||
{
|
||||
if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED)
|
||||
return QVariant(QBrush(QColor(255,200,180)));
|
||||
return QVariant(QBrush(mBackgroundColorPinned));
|
||||
|
||||
if(mFilteringEnabled && (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_PASSES_FILTER))
|
||||
return QVariant(QBrush(QColor(255,240,210)));
|
||||
return QVariant(QBrush(mBackgroundColorFiltered));
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
@ -116,6 +116,10 @@ public:
|
||||
void setTextColorUnreadChildren(QColor color) { mTextColorUnreadChildren = color;}
|
||||
void setTextColorNotSubscribed (QColor color) { mTextColorNotSubscribed = color;}
|
||||
void setTextColorMissing (QColor color) { mTextColorMissing = color;}
|
||||
void setTextColorPinned (QColor color) { mTextColorPinned = color;}
|
||||
|
||||
void setBackgroundColorPinned (QColor color) { mBackgroundColorPinned = color;}
|
||||
void setBackgroundColorFiltered (QColor color) { mBackgroundColorFiltered = color;}
|
||||
|
||||
void setMsgReadStatus(const QModelIndex &i, bool read_status, bool with_children);
|
||||
void setFilter(int column, const QStringList &strings, uint32_t &count) ;
|
||||
@ -202,6 +206,10 @@ private:
|
||||
QColor mTextColorUnreadChildren;
|
||||
QColor mTextColorNotSubscribed ;
|
||||
QColor mTextColorMissing ;
|
||||
QColor mTextColorPinned ;
|
||||
|
||||
QColor mBackgroundColorPinned;
|
||||
QColor mBackgroundColorFiltered;
|
||||
|
||||
friend class const_iterator;
|
||||
};
|
||||
|
@ -230,6 +230,11 @@ void GxsForumThreadWidget::setTextColorUnread (QColor color) { mTextColor
|
||||
void GxsForumThreadWidget::setTextColorUnreadChildren(QColor color) { mTextColorUnreadChildren = color; mThreadModel->setTextColorUnreadChildren(color);}
|
||||
void GxsForumThreadWidget::setTextColorNotSubscribed (QColor color) { mTextColorNotSubscribed = color; mThreadModel->setTextColorNotSubscribed (color);}
|
||||
void GxsForumThreadWidget::setTextColorMissing (QColor color) { mTextColorMissing = color; mThreadModel->setTextColorMissing (color);}
|
||||
// Suppose to be different from unread one
|
||||
void GxsForumThreadWidget::setTextColorPinned (QColor color) { mTextColorPinned = color; mThreadModel->setTextColorPinned (color);}
|
||||
|
||||
void GxsForumThreadWidget::setBackgroundColorPinned (QColor color) { mBackgroundColorPinned = color; mThreadModel->setBackgroundColorPinned (color);}
|
||||
void GxsForumThreadWidget::setBackgroundColorFiltered(QColor color) { mBackgroundColorFiltered = color; mThreadModel->setBackgroundColorFiltered (color);}
|
||||
|
||||
GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget *parent) :
|
||||
GxsMessageFrameWidget(rsGxsForums, parent),
|
||||
@ -331,6 +336,9 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget
|
||||
ttheader->hideSection (RsGxsForumModel::COLUMN_THREAD_MSGID);
|
||||
ttheader->hideSection (RsGxsForumModel::COLUMN_THREAD_DATA);
|
||||
|
||||
ttheader->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(ttheader, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(headerContextMenuRequested(QPoint)));
|
||||
|
||||
ui->progressBar->hide();
|
||||
ui->progressText->hide();
|
||||
|
||||
@ -343,6 +351,8 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget
|
||||
// load settings
|
||||
processSettings(true);
|
||||
|
||||
mDisplayBannedText = false;
|
||||
|
||||
blankPost();
|
||||
|
||||
ui->subscribeToolButton->setToolTip(tr( "<p>Subscribing to the forum will gather \
|
||||
@ -611,6 +621,11 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/)
|
||||
QAction* expandAll = new QAction(tr("Expand all"), &contextMnu);
|
||||
connect(expandAll, SIGNAL(triggered()), ui->threadTreeWidget, SLOT(expandAll()));
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
|
||||
QAction* expandSubtree = new QAction(tr("Expand subtree"), &contextMnu);
|
||||
connect(expandSubtree, SIGNAL(triggered()), this, SLOT(expandSubtree()));
|
||||
#endif
|
||||
|
||||
QAction* collapseAll = new QAction(tr( "Collapse all"), &contextMnu);
|
||||
connect(collapseAll, SIGNAL(triggered()), ui->threadTreeWidget, SLOT(collapseAll()));
|
||||
|
||||
@ -629,11 +644,19 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/)
|
||||
QAction *showinpeopleAct = new QAction(FilesDefs::getIconFromQtResourcePath(":/images/info16.png"), tr("Show author in people tab"), &contextMnu);
|
||||
connect(showinpeopleAct, SIGNAL(triggered()), this, SLOT(showInPeopleTab()));
|
||||
|
||||
bool has_children = false;
|
||||
if (has_current_post) {
|
||||
has_children = !current_post.mChildren.empty();
|
||||
}
|
||||
|
||||
if (IS_GROUP_SUBSCRIBED(mForumGroup.mMeta.mSubscribeFlags))
|
||||
{
|
||||
markMsgAsReadChildren->setEnabled(current_post.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN);
|
||||
markMsgAsUnreadChildren->setEnabled(current_post.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_READ_CHILDREN);
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
|
||||
expandSubtree->setEnabled(has_children);
|
||||
#endif
|
||||
replyAct->setEnabled (true);
|
||||
replyauthorAct->setEnabled (true);
|
||||
}
|
||||
@ -645,6 +668,22 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/)
|
||||
markMsgAsUnreadChildren->setDisabled(true);
|
||||
replyAct->setDisabled (true);
|
||||
replyauthorAct->setDisabled (true);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
|
||||
expandSubtree->setDisabled(true);
|
||||
expandSubtree->setVisible(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
// disable visibility for childless
|
||||
if (has_current_post) {
|
||||
// still no setEnabled
|
||||
markMsgAsRead->setVisible(IS_MSG_UNREAD(current_post.mMsgStatus));
|
||||
markMsgAsUnread->setVisible(!IS_MSG_UNREAD(current_post.mMsgStatus));
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
|
||||
expandSubtree->setVisible(has_children);
|
||||
#endif
|
||||
markMsgAsReadChildren->setVisible(has_children);
|
||||
markMsgAsUnreadChildren->setVisible(has_children);
|
||||
}
|
||||
|
||||
if(has_current_post)
|
||||
@ -678,7 +717,7 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/)
|
||||
}
|
||||
|
||||
contextMnu.addAction(replyAct);
|
||||
contextMnu.addAction(newthreadAct);
|
||||
contextMnu.addAction(newthreadAct);
|
||||
QAction* action = contextMnu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyMessageLink()));
|
||||
action->setEnabled(!groupId().isNull() && !mThreadId.isNull());
|
||||
contextMnu.addSeparator();
|
||||
@ -688,6 +727,9 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/)
|
||||
contextMnu.addAction(markMsgAsUnreadChildren);
|
||||
contextMnu.addSeparator();
|
||||
contextMnu.addAction(expandAll);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
|
||||
contextMnu.addAction(expandSubtree);
|
||||
#endif
|
||||
contextMnu.addAction(collapseAll);
|
||||
|
||||
if(has_current_post)
|
||||
@ -739,6 +781,64 @@ void GxsForumThreadWidget::contextMenuTextBrowser(QPoint point)
|
||||
delete(contextMnu);
|
||||
}
|
||||
|
||||
void GxsForumThreadWidget::headerContextMenuRequested(const QPoint &pos)
|
||||
{
|
||||
QMenu* header_context_menu = new QMenu(tr("Show column"), this);
|
||||
|
||||
QAction* title = header_context_menu->addAction(QIcon(), tr("Title"));
|
||||
title->setCheckable(true);
|
||||
title->setChecked(!ui->threadTreeWidget->isColumnHidden(RsGxsForumModel::COLUMN_THREAD_TITLE));
|
||||
title->setData(RsGxsForumModel::COLUMN_THREAD_TITLE);
|
||||
connect(title, SIGNAL(toggled(bool)), this, SLOT(changeHeaderColumnVisibility(bool)));
|
||||
|
||||
QAction* read = header_context_menu->addAction(QIcon(), tr("Read"));
|
||||
read->setCheckable(true);
|
||||
read->setChecked(!ui->threadTreeWidget->isColumnHidden(RsGxsForumModel::COLUMN_THREAD_READ));
|
||||
read->setData(RsGxsForumModel::COLUMN_THREAD_READ);
|
||||
connect(read, SIGNAL(toggled(bool)), this, SLOT(changeHeaderColumnVisibility(bool)));
|
||||
|
||||
QAction* date = header_context_menu->addAction(QIcon(), tr("Date"));
|
||||
date->setCheckable(true);
|
||||
date->setChecked(!ui->threadTreeWidget->isColumnHidden(RsGxsForumModel::COLUMN_THREAD_DATE));
|
||||
date->setData(RsGxsForumModel::COLUMN_THREAD_DATE);
|
||||
connect(date, SIGNAL(toggled(bool)), this, SLOT(changeHeaderColumnVisibility(bool)));
|
||||
|
||||
QAction* distribution = header_context_menu->addAction(QIcon(), tr("Distribution"));
|
||||
distribution->setCheckable(true);
|
||||
distribution->setChecked(!ui->threadTreeWidget->isColumnHidden(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION));
|
||||
distribution->setData(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION);
|
||||
connect(distribution, SIGNAL(toggled(bool)), this, SLOT(changeHeaderColumnVisibility(bool)));
|
||||
|
||||
// QAction* author = header_context_menu->addAction(QIcon(), tr("Author"));
|
||||
// author->setCheckable(true);
|
||||
// author->setChecked(!ui->threadTreeWidget->isColumnHidden(RsGxsForumModel::COLUMN_THREAD_AUTHOR));
|
||||
// author->setData(RsGxsForumModel::COLUMN_THREAD_AUTHOR);
|
||||
// connect(author, SIGNAL(toggled(bool)), this, SLOT(changeHeaderColumnVisibility(bool)));
|
||||
|
||||
QAction* show_text_from_banned = header_context_menu->addAction(QIcon(), tr("Show text from banned persons"));
|
||||
show_text_from_banned->setCheckable(true);
|
||||
show_text_from_banned->setChecked(mDisplayBannedText);
|
||||
connect(show_text_from_banned, SIGNAL(toggled(bool)), this, SLOT(showBannedText(bool)));
|
||||
|
||||
header_context_menu->exec(mapToGlobal(pos));
|
||||
delete(header_context_menu);
|
||||
}
|
||||
|
||||
void GxsForumThreadWidget::changeHeaderColumnVisibility(bool visibility) {
|
||||
QAction* the_action = qobject_cast<QAction*>(sender());
|
||||
if ( !the_action ) {
|
||||
return;
|
||||
}
|
||||
ui->threadTreeWidget->setColumnHidden(the_action->data().toInt(), !visibility);
|
||||
}
|
||||
|
||||
void GxsForumThreadWidget::showBannedText(bool display) {
|
||||
mDisplayBannedText = display;
|
||||
if (!mThreadId.isNull()) {
|
||||
updateMessageData(mThreadId);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TODO
|
||||
bool GxsForumThreadWidget::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
@ -916,6 +1016,9 @@ void GxsForumThreadWidget::updateForumDescription(bool success)
|
||||
if (!mThreadId.isNull())
|
||||
return;
|
||||
|
||||
// still call it to not left leftovers from previous post if any
|
||||
blankPost();
|
||||
|
||||
RsIdentityDetails details;
|
||||
|
||||
rsIdentity->getIdDetails(mForumGroup.mMeta.mAuthorId,details);
|
||||
@ -1042,6 +1145,7 @@ void GxsForumThreadWidget::insertMessage()
|
||||
|
||||
/* blank text, incase we get nothing */
|
||||
blankPost();
|
||||
ui->nextUnreadButton->setEnabled(true);
|
||||
|
||||
// We use this instead of getCurrentIndex() because right here the currentIndex() is not set yet.
|
||||
|
||||
@ -1157,7 +1261,8 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg)
|
||||
rsReputations->overallReputationLevel(msg.mMeta.mAuthorId);
|
||||
bool redacted =
|
||||
(overall_reputation == RsReputationLevel::LOCALLY_NEGATIVE);
|
||||
|
||||
|
||||
// TODO enabled even when there are no new message
|
||||
ui->nextUnreadButton->setEnabled(true);
|
||||
ui->lineLeft->show();
|
||||
ui->time_label->setText(DateTime::formatLongDateTime(msg.mMeta.mPublishTs));
|
||||
@ -1167,32 +1272,46 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg)
|
||||
ui->by_label->show();
|
||||
ui->threadTreeWidget->setFocus();
|
||||
|
||||
QString banned_text_info = "";
|
||||
if(redacted) {
|
||||
QString extraTxt = tr( "<p><font color=\"#ff0000\"><b>The author of this message (with ID %1) is banned.</b>").arg(QString::fromStdString(msg.mMeta.mAuthorId.toStdString())) ;
|
||||
extraTxt += tr( "<UL><li><b><font color=\"#ff0000\">Messages from this author are not forwarded. </font></b></li>") ;
|
||||
extraTxt += tr( "<li><b><font color=\"#ff0000\">Messages from this author are replaced by this text. </font></b></li></ul>") ;
|
||||
extraTxt += tr( "<p><b><font color=\"#ff0000\">You can force the visibility and forwarding of messages by setting a different opinion for that Id in People's tab.</font></b></p>") ;
|
||||
ui->downloadButton->setDisabled(true);
|
||||
if (!mDisplayBannedText) {
|
||||
QString extraTxt = tr( "<p><font color=\"#ff0000\"><b>The author of this message (with ID %1) is banned.</b>").arg(QString::fromStdString(msg.mMeta.mAuthorId.toStdString())) ;
|
||||
extraTxt += tr( "<UL><li><b><font color=\"#ff0000\">Messages from this author are not forwarded. </font></b></li>") ;
|
||||
extraTxt += tr( "<li><b><font color=\"#ff0000\">Messages from this author are replaced by this text. </font></b></li></ul>") ;
|
||||
extraTxt += tr( "<p><b><font color=\"#ff0000\">You can force the visibility and forwarding of messages by setting a different opinion for that Id in People's tab.</font></b></p>") ;
|
||||
|
||||
ui->postText->setHtml(extraTxt) ;
|
||||
} else {
|
||||
uint32_t flags = RSHTML_FORMATTEXT_EMBED_LINKS;
|
||||
if(Settings->getForumLoadEmoticons())
|
||||
flags |= RSHTML_FORMATTEXT_EMBED_SMILEYS ;
|
||||
flags |= RSHTML_OPTIMIZEHTML_MASK;
|
||||
ui->postText->setHtml(extraTxt) ;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
RsIdentityDetails details;
|
||||
rsIdentity->getIdDetails(msg.mMeta.mAuthorId, details);
|
||||
QString name = GxsIdDetails::getName(details);
|
||||
|
||||
QColor backgroundColor = ui->postText->palette().base().color();
|
||||
qreal desiredContrast = Settings->valueFromGroup("Forum",
|
||||
"MinimumContrast", 4.5).toDouble();
|
||||
int desiredMinimumFontSize = Settings->valueFromGroup("Forum",
|
||||
"MinimumFontSize", 10).toInt();
|
||||
|
||||
QString extraTxt = RsHtml().formatText(ui->postText->document(),
|
||||
QString::fromUtf8(msg.mMsg.c_str()), flags
|
||||
, backgroundColor, desiredContrast, desiredMinimumFontSize
|
||||
);
|
||||
ui->postText->setHtml(extraTxt);
|
||||
banned_text_info += "<p><font color=\"#e00000\"><b>" + tr( "The author of this message (with ID %1) is banned. And named by name ( %2 )").arg(QString::fromStdString(msg.mMeta.mAuthorId.toStdString()), name) + "</b>";
|
||||
banned_text_info += "<ul><li><b><font color=\"#e00000\">" + tr( "Messages from this author are not forwarded.") + "</font></b></li></ul>";
|
||||
banned_text_info += "<p><b><font color=\"#e00000\">" + tr( "You can force the visibility and forwarding of messages by setting a different opinion for that Id in People's tab.") + "</font></b></p><hr>";
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t flags = RSHTML_FORMATTEXT_EMBED_LINKS;
|
||||
if(Settings->getForumLoadEmoticons())
|
||||
flags |= RSHTML_FORMATTEXT_EMBED_SMILEYS ;
|
||||
flags |= RSHTML_OPTIMIZEHTML_MASK;
|
||||
|
||||
QColor backgroundColor = ui->postText->palette().base().color();
|
||||
qreal desiredContrast = Settings->valueFromGroup("Forum",
|
||||
"MinimumContrast", 4.5).toDouble();
|
||||
int desiredMinimumFontSize = Settings->valueFromGroup("Forum",
|
||||
"MinimumFontSize", 10).toInt();
|
||||
|
||||
QString extraTxt = banned_text_info + RsHtml().formatText(ui->postText->document(),
|
||||
QString::fromUtf8(msg.mMsg.c_str()), flags
|
||||
, backgroundColor, desiredContrast, desiredMinimumFontSize
|
||||
);
|
||||
ui->postText->setHtml(extraTxt);
|
||||
|
||||
QStringList urls;
|
||||
RsHtml::findAnchors(ui->postText->toHtml(), urls);
|
||||
ui->downloadButton->setEnabled(urls.count() > 0);
|
||||
@ -1340,6 +1459,20 @@ void GxsForumThreadWidget::setAllMessagesReadDo(bool read, uint32_t &/*token*/)
|
||||
markMsgAsReadUnread(read, true, true);
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
|
||||
void GxsForumThreadWidget::expandSubtree() {
|
||||
QAction* the_action = qobject_cast<QAction*>(sender());
|
||||
if (!the_action) {
|
||||
return;
|
||||
}
|
||||
const QModelIndex current_index = ui->threadTreeWidget->currentIndex();
|
||||
if (!current_index.isValid()) {
|
||||
return;
|
||||
}
|
||||
ui->threadTreeWidget->expandRecursively(current_index);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GxsForumThreadWidget::navigate(const RsGxsMessageId &msgId)
|
||||
{
|
||||
QModelIndex source_index = mThreadModel->getIndexOfMessage(msgId);
|
||||
@ -1683,10 +1816,26 @@ void GxsForumThreadWidget::filterItems(const QString& text)
|
||||
// We do this in order to trigger a new filtering action in the proxy model.
|
||||
mThreadProxyModel->setFilterRegExp(QRegExp(QString(RsGxsForumModel::FilterString))) ;
|
||||
|
||||
if(!lst.empty())
|
||||
if(!lst.empty())
|
||||
ui->threadTreeWidget->expandAll();
|
||||
else
|
||||
else {
|
||||
// currentIndex() not on the clicked message, so not this way
|
||||
// if (!mThreadId.isNull()) {
|
||||
// an_index = mThreadProxyModel->mapToSource(ui->threadTreeWidget->currentIndex());
|
||||
// }
|
||||
ui->threadTreeWidget->collapseAll();
|
||||
if (!mThreadId.isNull()) {
|
||||
// ...but this one
|
||||
QModelIndex an_index = mThreadModel->getIndexOfMessage(mThreadId);
|
||||
if (an_index.isValid()) {
|
||||
QModelIndex the_index = mThreadProxyModel->mapFromSource(an_index);
|
||||
ui->threadTreeWidget->setCurrentIndex(the_index);
|
||||
ui->threadTreeWidget->scrollTo(the_index);
|
||||
// don't change focus
|
||||
// ui->threadTreeWidget->setFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(count > 0)
|
||||
ui->filterLineEdit->setToolTip(tr("No result.")) ;
|
||||
|
@ -52,6 +52,10 @@ class GxsForumThreadWidget : public GxsMessageFrameWidget
|
||||
Q_PROPERTY(QColor textColorUnreadChildren READ textColorUnreadChildren WRITE setTextColorUnreadChildren)
|
||||
Q_PROPERTY(QColor textColorNotSubscribed READ textColorNotSubscribed WRITE setTextColorNotSubscribed)
|
||||
Q_PROPERTY(QColor textColorMissing READ textColorMissing WRITE setTextColorMissing)
|
||||
Q_PROPERTY(QColor textColorPinned READ textColorPinned WRITE setTextColorPinned)
|
||||
|
||||
Q_PROPERTY(QColor backgroundColorPinned READ backgroundColorPinned WRITE setBackgroundColorPinned)
|
||||
Q_PROPERTY(QColor backgroundColorFiltered READ backgroundColorFiltered WRITE setBackgroundColorFiltered)
|
||||
|
||||
public:
|
||||
explicit GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget *parent = NULL);
|
||||
@ -62,12 +66,20 @@ public:
|
||||
QColor textColorUnreadChildren() const { return mTextColorUnreadChildren; }
|
||||
QColor textColorNotSubscribed() const { return mTextColorNotSubscribed; }
|
||||
QColor textColorMissing() const { return mTextColorMissing; }
|
||||
QColor textColorPinned() const { return mTextColorPinned; }
|
||||
|
||||
QColor backgroundColorPinned() const { return mBackgroundColorPinned; }
|
||||
QColor backgroundColorFiltered() const { return mBackgroundColorFiltered; }
|
||||
|
||||
void setTextColorRead (QColor color) ;
|
||||
void setTextColorUnread (QColor color) ;
|
||||
void setTextColorUnreadChildren(QColor color) ;
|
||||
void setTextColorNotSubscribed (QColor color) ;
|
||||
void setTextColorMissing (QColor color) ;
|
||||
void setTextColorPinned (QColor color) ;
|
||||
|
||||
void setBackgroundColorPinned (QColor color);
|
||||
void setBackgroundColorFiltered (QColor color);
|
||||
|
||||
/* GxsMessageFrameWidget */
|
||||
virtual void groupIdChanged();
|
||||
@ -97,6 +109,7 @@ private slots:
|
||||
/** Create the context popup menu and it's submenus */
|
||||
void threadListCustomPopupMenu(QPoint point);
|
||||
void contextMenuTextBrowser(QPoint point);
|
||||
void headerContextMenuRequested(const QPoint& pos);
|
||||
|
||||
void changedSelection(const QModelIndex &, const QModelIndex &);
|
||||
void changedThread(QModelIndex index);
|
||||
@ -144,6 +157,12 @@ private slots:
|
||||
|
||||
void filterColumnChanged(int column);
|
||||
void filterItems(const QString &text);
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
|
||||
void expandSubtree();
|
||||
#endif
|
||||
void changeHeaderColumnVisibility(bool visibility);
|
||||
void showBannedText(bool display);
|
||||
private:
|
||||
void insertMessageData(const RsGxsForumMsg &msg);
|
||||
bool getCurrentPost(ForumModelPostEntry& fmpe) const ;
|
||||
@ -192,6 +211,7 @@ private:
|
||||
GxsForumsFillThread *mFillThread;
|
||||
unsigned int mUnreadCount;
|
||||
unsigned int mNewCount;
|
||||
bool mDisplayBannedText;
|
||||
|
||||
/* Color definitions (for standard see qss.default) */
|
||||
QColor mTextColorRead;
|
||||
@ -199,6 +219,10 @@ private:
|
||||
QColor mTextColorUnreadChildren;
|
||||
QColor mTextColorNotSubscribed;
|
||||
QColor mTextColorMissing;
|
||||
QColor mTextColorPinned;
|
||||
|
||||
QColor mBackgroundColorPinned;
|
||||
QColor mBackgroundColorFiltered;
|
||||
|
||||
RsGxsMessageId mNavigatePendingMsgId;
|
||||
QList<RsGxsMessageId> mIgnoredMsgId;
|
||||
|
@ -2,8 +2,14 @@
|
||||
<qresource prefix="/">
|
||||
<file>icons/onion.png</file>
|
||||
<file>icons/svg/hidden.svg</file>
|
||||
<file>icons/svg/ratio-auto.svg</file>
|
||||
<file>icons/svg/ratio-1-1.svg</file>
|
||||
<file>icons/svg/ratio-3-4.svg</file>
|
||||
<file>icons/svg/ratio-16-9.svg</file>
|
||||
<file>icons/svg/randomness.svg</file>
|
||||
<file>icons/svg/password.svg</file>
|
||||
<file>icons/svg/listlayout.svg</file>
|
||||
<file>icons/svg/gridlayout.svg</file>
|
||||
<file>icons/stars/star0.png</file>
|
||||
<file>icons/stars/star1.png</file>
|
||||
<file>icons/stars/star2.png</file>
|
||||
|
11
retroshare-gui/src/gui/icons/svg/gridlayout.svg
Normal file
11
retroshare-gui/src/gui/icons/svg/gridlayout.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 35 35" style="enable-background:new 0 0 35 35;" xml:space="preserve" class=""><g transform="matrix(0.922745 0 0 0.922745 1.35197 1.35197)"><g>
|
||||
<g>
|
||||
<rect width="9.182" height="15.5" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/>
|
||||
<rect y="19.5" width="9.182" height="15.5" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/>
|
||||
<rect x="12.9" y="19.5" width="9.202" height="15.5" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/>
|
||||
<rect x="12.9" width="9.202" height="15.5" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/>
|
||||
<rect x="25.82" width="9.18" height="15.5" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/>
|
||||
<rect x="25.82" y="19.5" width="9.18" height="15.5" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/>
|
||||
</g>
|
||||
</g></g> </svg>
|
After Width: | Height: | Size: 1.1 KiB |
2
retroshare-gui/src/gui/icons/svg/listlayout.svg
Normal file
2
retroshare-gui/src/gui/icons/svg/listlayout.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" enable-background="new 0 0 512 512" height="512px" viewBox="0 0 512 512" width="512px" class=""><g transform="matrix(0.94148 0 0 0.94148 14.9811 14.9811)"><path d="m464.883 64.267h-417.766c-25.98 0-47.117 21.136-47.117 47.149 0 25.98 21.137 47.117 47.117 47.117h417.766c25.98 0 47.117-21.137 47.117-47.117 0-26.013-21.137-47.149-47.117-47.149z" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/><path d="m464.883 208.867h-417.766c-25.98 0-47.117 21.136-47.117 47.149 0 25.98 21.137 47.117 47.117 47.117h417.766c25.98 0 47.117-21.137 47.117-47.117 0-26.013-21.137-47.149-47.117-47.149z" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/><path d="m464.883 353.467h-417.766c-25.98 0-47.117 21.137-47.117 47.149 0 25.98 21.137 47.117 47.117 47.117h417.766c25.98 0 47.117-21.137 47.117-47.117 0-26.012-21.137-47.149-47.117-47.149z" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/></g> </svg>
|
After Width: | Height: | Size: 1.0 KiB |
97
retroshare-gui/src/gui/icons/svg/ratio-1-1.svg
Normal file
97
retroshare-gui/src/gui/icons/svg/ratio-1-1.svg
Normal file
@ -0,0 +1,97 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
height="512"
|
||||
viewBox="0 -64 512 512"
|
||||
width="512"
|
||||
version="1.1"
|
||||
id="svg18"
|
||||
sodipodi:docname="ratio-1-1.svg"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
|
||||
<metadata
|
||||
id="metadata24">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs22" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="705"
|
||||
id="namedview20"
|
||||
showgrid="true"
|
||||
inkscape:zoom="0.65186406"
|
||||
inkscape:cx="256"
|
||||
inkscape:cy="342.77966"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g16">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid834" />
|
||||
</sodipodi:namedview>
|
||||
<g
|
||||
transform="matrix(0.922745 0 0 0.922745 19.7773 14.833)"
|
||||
id="g16">
|
||||
<path
|
||||
d="m 366.53972,252.68845 c -8.53125,0 -17.0664,-6.39844 -17.0664,-17.06641 v -93.86719 c 0,-8.53125 6.40234,-17.0664 17.0664,-17.0664 10.66797,0 14.9336,6.39843 14.9336,17.0664 v 96 c 0,8.53516 -6.39844,14.9336 -14.9336,14.9336 z m 0,0"
|
||||
data-original="#000000"
|
||||
class="active-path"
|
||||
data-old_color="#000000"
|
||||
style="fill:#039bd5"
|
||||
id="path4"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m277.332031 149.332031c0 11.785157-9.550781 21.335938-21.332031 21.335938s-21.332031-9.550781-21.332031-21.335938c0-11.78125 9.550781-21.332031 21.332031-21.332031s21.332031 9.550781 21.332031 21.332031zm0 0"
|
||||
data-original="#000000"
|
||||
class="active-path"
|
||||
data-old_color="#000000"
|
||||
style="fill:#039BD5"
|
||||
id="path10" />
|
||||
<path
|
||||
d="m277.332031 234.667969c0 11.78125-9.550781 21.332031-21.332031 21.332031s-21.332031-9.550781-21.332031-21.332031c0-11.785157 9.550781-21.335938 21.332031-21.335938s21.332031 9.550781 21.332031 21.335938zm0 0"
|
||||
data-original="#000000"
|
||||
class="active-path"
|
||||
data-old_color="#000000"
|
||||
style="fill:#039BD5"
|
||||
id="path12" />
|
||||
<path
|
||||
d="m454.398438 384h-394.664063c-34.132813 0-59.734375-25.601562-59.734375-57.601562v-266.664063c0-34.132813 25.601562-59.734375 59.734375-59.734375h394.664063c32 0 57.601562 25.601562 57.601562 59.734375v266.664063c0 32-25.601562 57.601562-57.601562 57.601562zm-394.664063-352c-14.933594 0-27.734375 12.800781-27.734375 27.734375v266.664063c0 14.933593 12.800781 27.734374 27.734375 27.734374h394.664063c14.933593 0 27.734374-12.800781 27.734374-27.734374v-266.664063c0-14.933594-12.800781-27.734375-27.734374-27.734375zm0 0"
|
||||
data-original="#000000"
|
||||
class="active-path"
|
||||
data-old_color="#000000"
|
||||
style="fill:#039BD5"
|
||||
id="path14" />
|
||||
<path
|
||||
d="m 156.29747,252.68845 c -8.53125,0 -17.0664,-6.39844 -17.0664,-17.0664 v -93.8672 c 0,-8.53125 6.40234,-17.0664 17.0664,-17.0664 10.66797,0 14.9336,6.39843 14.9336,17.0664 v 96.00001 c 0,8.53515 -6.39844,14.93359 -14.9336,14.93359 z"
|
||||
data-original="#000000"
|
||||
class="active-path"
|
||||
data-old_color="#000000"
|
||||
style="fill:#039bd5;stroke-width:1"
|
||||
id="path4-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="sssssss" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.9 KiB |
2
retroshare-gui/src/gui/icons/svg/ratio-16-9.svg
Normal file
2
retroshare-gui/src/gui/icons/svg/ratio-16-9.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="512" viewBox="0 -64 512 512" width="512" class=""><g transform="matrix(0.932065 0 0 0.932065 17.3913 13.0434)"><path d="m454.398438 384h-394.664063c-34.132813 0-59.734375-25.601562-59.734375-57.601562v-266.664063c0-34.132813 25.601562-59.734375 59.734375-59.734375h394.664063c32 0 57.601562 25.601562 57.601562 59.734375v266.664063c0 32-25.601562 57.601562-57.601562 57.601562zm-394.664063-352c-14.933594 0-27.734375 12.800781-27.734375 27.734375v266.664063c0 14.933593 12.800781 27.734374 27.734375 27.734374h394.664063c14.933593 0 27.734374-12.800781 27.734374-27.734374v-266.664063c0-14.933594-12.800781-27.734375-27.734374-27.734375zm0 0" data-original="#000000" class="active-path" style="fill:#039BD5" data-old_color="#000000"/><path d="m177.066406 256h-10.667968c-21.332032 0-38.398438-17.066406-38.398438-38.398438v-53.335937c0-19.199219 17.066406-36.265625 38.398438-36.265625h32c8.535156 0 14.933593 6.398438 14.933593 17.066406 0 10.667969-6.398437 17.066406-17.066406 17.066406h-29.867187c-2.132813 0-6.398438 2.132813-6.398438 6.402344v10.664063h17.066406c21.332032 0 38.398438 17.066406 38.398438 38.402343v6.398438c-2.132813 14.933594-19.199219 32-38.398438 32zm-17.066406-46.933594v10.667969c0 2.132813 2.132812 6.398437 6.398438 6.398437h10.667968c2.132813 0 6.398438-2.132812 6.398438-6.398437v-6.402344c0-2.132812-2.132813-6.398437-6.398438-6.398437h-17.066406zm0 0" data-original="#000000" class="active-path" style="fill:#039BD5" data-old_color="#000000"/><path d="m390.398438 256h-32c-8.53125 0-17.066407-6.398438-17.066407-17.066406 0-10.667969 6.402344-17.066406 17.066407-17.066406h32c2.136718 0 6.402343-2.132813 6.402343-6.402344v-10.664063h-17.066406c-21.335937 0-38.402344-17.066406-38.402344-38.402343v-6.398438c0-21.332031 17.066407-38.398438 38.402344-38.398438h10.664063c21.335937 0 38.402343 17.066407 38.402343 38.398438v53.332031c-2.132812 25.601563-19.199219 42.667969-38.402343 42.667969zm-10.664063-96c-2.132813 0-6.402344 2.132812-6.402344 6.398438v4.269531c0 2.132812 2.132813 6.398437 6.402344 6.398437h17.066406v-10.667968c0-2.132813-2.132812-6.398438-6.402343-6.398438zm0 0" data-original="#000000" class="active-path" style="fill:#039BD5" data-old_color="#000000"/><path d="m91.734375 256c-8.535156 0-17.066406-6.398438-17.066406-17.066406v-93.867188c0-10.667968 6.398437-17.066406 17.066406-17.066406 10.664063 0 14.933594 6.398438 14.933594 17.066406v96c0 8.535156-6.402344 14.933594-14.933594 14.933594zm0 0" data-original="#000000" class="active-path" style="fill:#039BD5" data-old_color="#000000"/><path d="m298.667969 149.332031c0 11.785157-9.550781 21.335938-21.335938 21.335938-11.78125 0-21.332031-9.550781-21.332031-21.335938 0-11.78125 9.550781-21.332031 21.332031-21.332031 11.785157 0 21.335938 9.550781 21.335938 21.332031zm0 0" data-original="#000000" class="active-path" style="fill:#039BD5" data-old_color="#000000"/><path d="m298.667969 234.667969c0 11.78125-9.550781 21.332031-21.335938 21.332031-11.78125 0-21.332031-9.550781-21.332031-21.332031 0-11.785157 9.550781-21.335938 21.332031-21.335938 11.785157 0 21.335938 9.550781 21.335938 21.335938zm0 0" data-original="#000000" class="active-path" style="fill:#039BD5" data-old_color="#000000"/></g> </svg>
|
After Width: | Height: | Size: 3.2 KiB |
2
retroshare-gui/src/gui/icons/svg/ratio-3-4.svg
Normal file
2
retroshare-gui/src/gui/icons/svg/ratio-3-4.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="512" viewBox="0 -64 512 512" width="512"><g transform="matrix(0.922745 0 0 0.922745 19.7773 14.833)"><path d="m390.398438 209.066406h-32c-21.332032 0-38.398438-17.066406-38.398438-38.398437v-25.601563c0-10.667968 6.398438-17.066406 17.066406-17.066406 10.667969 0 17.066406 6.398438 17.066406 17.066406v25.601563c0 2.132812 2.132813 6.398437 6.402344 6.398437h32c8.53125 0 17.066406 6.398438 17.066406 17.066406 0 10.667969-10.667968 14.933594-19.203124 14.933594zm0 0" data-original="#000000" class="active-path" data-old_color="#000000" style="fill:#039BD5"/><path d="m390.398438 256c-8.53125 0-17.066407-6.398438-17.066407-17.066406v-93.867188c0-8.53125 6.402344-17.066406 17.066407-17.066406 10.667968 0 14.933593 6.398438 14.933593 17.066406v96c0 8.535156-6.398437 14.933594-14.933593 14.933594zm0 0" data-original="#000000" class="active-path" data-old_color="#000000" style="fill:#039BD5"/><path d="m177.066406 209.066406h-53.332031c-10.667969 0-17.066406-8.53125-17.066406-17.066406s6.398437-17.066406 17.066406-17.066406h53.332031c8.535156 2.132812 14.933594 8.53125 14.933594 17.066406s-6.398438 17.066406-14.933594 17.066406zm0 0" data-original="#000000" class="active-path" data-old_color="#000000" style="fill:#039BD5"/><path d="m155.734375 256h-32c-10.667969 0-17.066406-6.398438-17.066406-14.933594 0-8.53125 6.398437-17.066406 17.066406-17.066406h32c2.132813 0 6.398437-2.132812 6.398437-6.398438v-53.335937c0-2.132813-2.132812-6.398437-6.398437-6.398437h-32c-10.667969 2.132812-17.066406-4.265626-17.066406-12.800782 0-8.53125 6.398437-17.066406 17.066406-17.066406h32c19.199219 0 36.265625 17.066406 36.265625 38.398438v53.335937c0 19.199219-17.066406 36.265625-36.265625 36.265625zm0 0" data-original="#000000" class="active-path" data-old_color="#000000" style="fill:#039BD5"/><path d="m277.332031 149.332031c0 11.785157-9.550781 21.335938-21.332031 21.335938s-21.332031-9.550781-21.332031-21.335938c0-11.78125 9.550781-21.332031 21.332031-21.332031s21.332031 9.550781 21.332031 21.332031zm0 0" data-original="#000000" class="active-path" data-old_color="#000000" style="fill:#039BD5"/><path d="m277.332031 234.667969c0 11.78125-9.550781 21.332031-21.332031 21.332031s-21.332031-9.550781-21.332031-21.332031c0-11.785157 9.550781-21.335938 21.332031-21.335938s21.332031 9.550781 21.332031 21.335938zm0 0" data-original="#000000" class="active-path" data-old_color="#000000" style="fill:#039BD5"/><path d="m454.398438 384h-394.664063c-34.132813 0-59.734375-25.601562-59.734375-57.601562v-266.664063c0-34.132813 25.601562-59.734375 59.734375-59.734375h394.664063c32 0 57.601562 25.601562 57.601562 59.734375v266.664063c0 32-25.601562 57.601562-57.601562 57.601562zm-394.664063-352c-14.933594 0-27.734375 12.800781-27.734375 27.734375v266.664063c0 14.933593 12.800781 27.734374 27.734375 27.734374h394.664063c14.933593 0 27.734374-12.800781 27.734374-27.734374v-266.664063c0-14.933594-12.800781-27.734375-27.734374-27.734375zm0 0" data-original="#000000" class="active-path" data-old_color="#000000" style="fill:#039BD5"/></g> </svg>
|
After Width: | Height: | Size: 3.0 KiB |
14
retroshare-gui/src/gui/icons/svg/ratio-auto.svg
Normal file
14
retroshare-gui/src/gui/icons/svg/ratio-auto.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve" width="512" height="512" class="hovered-paths"><g transform="matrix(0.922745 0 0 0.922745 19.7773 19.7773)"><g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M0,64v384h512V64H0z M480,416H32V96h448V416z" data-original="#000000" class="hovered-path active-path" style="fill:#039BD5" data-old_color="#000000"/>
|
||||
<polygon points="96,160 160,160 160,128 64,128 64,224 96,224 " data-original="#000000" class="hovered-path active-path" style="fill:#039BD5" data-old_color="#000000"/>
|
||||
<polygon points="448,288 416,288 416,352 352,352 352,384 448,384 " data-original="#000000" class="hovered-path active-path" style="fill:#039BD5" data-old_color="#000000"/>
|
||||
<rect x="192" y="128" width="32" height="32" data-original="#000000" class="hovered-path active-path" style="fill:#039BD5" data-old_color="#000000"/>
|
||||
<rect x="64" y="256" width="32" height="32" data-original="#000000" class="hovered-path active-path" style="fill:#039BD5" data-old_color="#000000"/>
|
||||
<rect x="416" y="224" width="32" height="32" data-original="#000000" class="hovered-path active-path" style="fill:#039BD5" data-old_color="#000000"/>
|
||||
<rect x="288" y="352" width="32" height="32" data-original="#000000" class="hovered-path active-path" style="fill:#039BD5" data-old_color="#000000"/>
|
||||
</g>
|
||||
</g>
|
||||
</g></g> </svg>
|
After Width: | Height: | Size: 1.5 KiB |
@ -928,3 +928,9 @@ MessagesDialog QWidget#messageTreeWidget::item:hover {
|
||||
GxsForumThreadWidget QWidget#threadTreeWidget::item {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
PulseTopLevel QFrame#frame, PulseViewGroup QFrame#frame, PulseReply QFrame#frame {
|
||||
border: 2px solid #7ecbfb;
|
||||
border-radius: 6px;
|
||||
background: white;
|
||||
}
|
||||
|
@ -138,6 +138,10 @@ ForumsDialog, GxsForumThreadWidget
|
||||
qproperty-textColorUnreadChildren: darkgray;
|
||||
qproperty-textColorNotSubscribed: black;
|
||||
qproperty-textColorMissing: darkRed;
|
||||
qproperty-textColorPinned: darkOrange;
|
||||
|
||||
qproperty-backgroundColorPinned: rgb(255, 200, 180);
|
||||
qproperty-backgroundColorFiltered: rgb(255, 240, 210);
|
||||
}
|
||||
|
||||
GroupTreeWidget
|
||||
|
@ -33,17 +33,10 @@ ChannelPage::ChannelPage(QWidget * parent, Qt::WindowFlags flags)
|
||||
ui.groupFrameSettingsWidget->setOpenAllInNewTabText(tr("Open each channel in a new tab"));
|
||||
ui.groupFrameSettingsWidget->setType(GroupFrameSettings::Channel) ;
|
||||
|
||||
connect(ui.loadThreadCheckBox,SIGNAL(toggled(bool)),this,SLOT(updateLoadThread())) ;
|
||||
connect(ui.emoteicon_checkBox,SIGNAL(toggled(bool)),this,SLOT(updateEmotes())) ;
|
||||
|
||||
}
|
||||
|
||||
void ChannelPage::updateLoadThread()
|
||||
{
|
||||
Settings->setChannelLoadThread(ui.loadThreadCheckBox->isChecked());
|
||||
NotifyQt::getInstance()->notifySettingsChanged();
|
||||
}
|
||||
|
||||
ChannelPage::~ChannelPage()
|
||||
{
|
||||
}
|
||||
@ -51,7 +44,6 @@ ChannelPage::~ChannelPage()
|
||||
/** Loads the settings for this page */
|
||||
void ChannelPage::load()
|
||||
{
|
||||
whileBlocking(ui.loadThreadCheckBox)->setChecked(Settings->getChannelLoadThread());
|
||||
ui.groupFrameSettingsWidget->loadSettings(GroupFrameSettings::Channel);
|
||||
|
||||
Settings->beginGroup(QString("ChannelPostsWidget"));
|
||||
|
@ -42,9 +42,6 @@ public:
|
||||
private slots:
|
||||
void updateEmotes();
|
||||
|
||||
protected slots:
|
||||
void updateLoadThread() ;
|
||||
|
||||
private:
|
||||
Ui::ChannelPage ui;
|
||||
};
|
||||
|
@ -29,13 +29,6 @@
|
||||
<string>General</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="loadThreadCheckBox">
|
||||
<property name="text">
|
||||
<string>Load posts in background (Thread)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="emoteicon_checkBox">
|
||||
<property name="text">
|
||||
|
@ -35,6 +35,8 @@
|
||||
#include <retroshare/rsstatus.h>
|
||||
#include <retroshare/rspeers.h>
|
||||
#include <retroshare/rsservicecontrol.h>
|
||||
#include "rsitems/rsserviceids.h"
|
||||
#include <QTextDocument>
|
||||
|
||||
#define NOT_IMPLEMENTED std::cerr << __PRETTY_FUNCTION__ << ": not yet implemented." << std::endl;
|
||||
|
||||
@ -531,6 +533,45 @@ void RSPermissionMatrixWidget::paintEvent(QPaintEvent *)
|
||||
_max_height = S*fMATRIX_START_Y + (peer_ids.size()+3) * S*fROW_SIZE ;
|
||||
_max_width = matrix_start_x + (service_ids.size()+3) * S*fCOL_SIZE ;
|
||||
|
||||
if(n_row_selected == -1)
|
||||
{
|
||||
for(uint32_t i=0;i<service_ids.size();++i)
|
||||
{
|
||||
if(_current_service_id == service_ids[i])
|
||||
{
|
||||
//uint16_t serviceOrig = (uint16_t)((service_ids[i] - (((uint32_t)RS_PKT_VERSION_SERVICE) << 24) ) >> 8);
|
||||
uint16_t serviceOrig=(service_ids[i]>>8) & 0xffff;
|
||||
QTextDocument td;
|
||||
td.setHtml(ServiceDescription(serviceOrig));
|
||||
QString service_name = "Service: 0x"+ QString::number(serviceOrig,16) + " " + QString::fromStdString(rsServiceControl->getServiceName(service_ids[i]));
|
||||
QBrush brush ;
|
||||
brush.setColor(QColor::fromHsvF(0.0f,0.0f,1.0f,0.8f));
|
||||
brush.setStyle(Qt::SolidPattern) ;
|
||||
QPen pen ;
|
||||
pen.setWidth(1) ;
|
||||
pen.setBrush(FOREGROUND_COLOR) ;
|
||||
_painter->setPen(pen) ;
|
||||
QRect position = computeNodePosition(0,i,false) ;
|
||||
int popup_x = position.x() + (50 * S / 14.0);
|
||||
int popup_y = position.y() - (10 * S / 14.0) + line_height;
|
||||
int popup_width = std::max((int)td.size().width(), fm.width(service_name)) + S;
|
||||
int popup_height = td.size().height() + line_height*2;
|
||||
while (popup_x + popup_width > _max_width)
|
||||
popup_x -= S;
|
||||
if (popup_y + popup_height > _max_height)
|
||||
popup_y -= popup_height;
|
||||
QRect info_pos(popup_x, popup_y, popup_width, popup_height) ;
|
||||
_painter->fillRect(info_pos,brush) ;
|
||||
_painter->drawRect(info_pos) ;
|
||||
float x = info_pos.x() + 5*S/14.0 ;
|
||||
float y = info_pos.y() + line_height + 1*S/14.0 ;
|
||||
_painter->drawText(QPointF(x,y), service_name) ; y += line_height ;
|
||||
_painter->translate(QPointF(popup_x, popup_y+2*line_height));
|
||||
td.drawContents(_painter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Stop the painter */
|
||||
_painter->end();
|
||||
}
|
||||
@ -611,4 +652,33 @@ void RSPermissionMatrixWidget::userPermissionSwitched(uint32_t /* ServiceId */,c
|
||||
NOT_IMPLEMENTED ;
|
||||
}
|
||||
|
||||
|
||||
QString RSPermissionMatrixWidget::ServiceDescription(uint16_t serviceid)
|
||||
{
|
||||
switch(serviceid)
|
||||
{
|
||||
case RS_SERVICE_TYPE_DISC: return tr("Location info exchange between friends. Helps to find actual address in case of dynamic IPs<br>Without it you will have to rely on DHT only for getting fresh addresses");
|
||||
case RS_SERVICE_TYPE_CHAT: return tr("Used by direct F2F chat, distant chat and chat lobbies");
|
||||
case RS_SERVICE_TYPE_MSG: return tr("Mailing service. Also required for direct f2f chat");
|
||||
case RS_SERVICE_TYPE_TURTLE: return tr("Anonymous routing. Used by file transfers and file search,<br> distant chat, distant mail and distant channels/etc sync");
|
||||
case RS_SERVICE_TYPE_HEARTBEAT: return tr("Checks if peers alive");
|
||||
case RS_SERVICE_TYPE_FILE_TRANSFER: return tr("File transfer. If you kill it - you won't be able to dl files from friend shares. Anonymous access unnaffected");
|
||||
case RS_SERVICE_TYPE_GROUTER: return tr("Used by distant mail for immediate delivery using anonymous tunnels (turtle router)");
|
||||
case RS_SERVICE_TYPE_FILE_DATABASE: return tr("Exchange shared directories info, aka browsable(visible) files");
|
||||
case RS_SERVICE_TYPE_SERVICEINFO: return tr("Allows your node to tell to your friends which service are ON on your side, and vice-versa");
|
||||
case RS_SERVICE_TYPE_BWCTRL: return tr("Speed management");
|
||||
case RS_SERVICE_TYPE_GXS_TUNNEL: return tr("Used by distant chat, distant mail, and distant channels sync for transfer data using anonymous tunnels");
|
||||
case RS_SERVICE_TYPE_BANLIST: return tr("IP filter lists exchange");
|
||||
case RS_SERVICE_TYPE_STATUS: return tr("Share user status like online, away, busy with friends");
|
||||
case RS_SERVICE_GXS_TYPE_GXSID: return tr("Identity data exchange. Required by all identities-related functions like chats, forums, mail, etc");
|
||||
case RS_SERVICE_GXS_TYPE_PHOTO: return tr("RS_SERVICE_GXS_TYPE_PHOTO");
|
||||
case RS_SERVICE_GXS_TYPE_WIKI: return tr("RS_SERVICE_GXS_TYPE_WIKI");
|
||||
case RS_SERVICE_GXS_TYPE_FORUMS: return tr("Transfer Forums");
|
||||
case RS_SERVICE_GXS_TYPE_POSTED: return tr("Transfer Posted");
|
||||
case RS_SERVICE_GXS_TYPE_CHANNELS: return tr("Transfer Channels");
|
||||
case RS_SERVICE_GXS_TYPE_GXSCIRCLE: return tr("Transfer Circles");
|
||||
case RS_SERVICE_GXS_TYPE_REPUTATION:return tr("Votes exchange - bans/upvotes for Identities");
|
||||
case RS_SERVICE_TYPE_GXS_TRANS: return tr("Used by distant mail for deferred delivery - stored at friends when target offline");
|
||||
case RS_SERVICE_TYPE_RTT: return tr("Measures the Round Trip Time between you and your friends");
|
||||
default: return tr("unknown");
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ class RSPermissionMatrixWidget: public QFrame
|
||||
public:
|
||||
RSPermissionMatrixWidget(QWidget *parent=NULL);
|
||||
virtual ~RSPermissionMatrixWidget() ;
|
||||
QString ServiceDescription(uint16_t serviceid);
|
||||
|
||||
public slots:
|
||||
void setHideOffline(bool hide);
|
||||
|
@ -2143,8 +2143,8 @@ PostedCardView > QFrame#mainFrame[new=true] {
|
||||
background-color: #005000;
|
||||
}
|
||||
|
||||
WireGroupItem QFrame#frame{
|
||||
background: transparent;
|
||||
WireGroupItem QFrame#wire_frame{
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
GxsChannelDialog GroupTreeWidget QTreeWidget#treeWidget::item{
|
||||
@ -2157,3 +2157,8 @@ RSTextBrowser, MimeTextEdit
|
||||
/*qproperty-textColorQuote: rgb(125, 125, 255);*/
|
||||
qproperty-textColorQuotes: ColorList(#789922 #039bd5 #800000 #800080 #008080 #b10dc9 #85144b #3d9970);
|
||||
}
|
||||
|
||||
PulseTopLevel QFrame#frame, PulseViewGroup QFrame#frame, PulseReply QFrame#frame {
|
||||
border: 2px solid #38444d;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
@ -93,6 +93,10 @@ ForumsDialog, GxsForumThreadWidget
|
||||
qproperty-textColorUnreadChildren: red;
|
||||
qproperty-textColorNotSubscribed: white;
|
||||
qproperty-textColorMissing: darkred;
|
||||
qproperty-textColorPinned: #D07000;
|
||||
|
||||
qproperty-backgroundColorPinned: #202020;
|
||||
qproperty-backgroundColorFiltered: darkGreen;
|
||||
}
|
||||
|
||||
QMenuBar
|
||||
@ -1295,7 +1299,9 @@ PostedCardView > QFrame#mainFrame[new=true] {
|
||||
background-color: #005000;
|
||||
}
|
||||
|
||||
WireGroupItem QFrame#frame{
|
||||
WireGroupItem QFrame#wire_frame
|
||||
{
|
||||
border: 1px solid #38444d;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
@ -1307,5 +1313,10 @@ RSTextBrowser, MimeTextEdit
|
||||
|
||||
ChatWidget QFrame#pluginTitleFrame
|
||||
{
|
||||
background: transparent;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
PulseTopLevel QFrame#frame, PulseViewGroup QFrame#frame, PulseReply QFrame#frame {
|
||||
border: 2px solid #38444d;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
@ -1377,6 +1377,8 @@ gxschannels {
|
||||
gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp \
|
||||
gui/gxschannels/GxsChannelPostFilesModel.cpp \
|
||||
gui/gxschannels/GxsChannelFilesStatusWidget.cpp \
|
||||
gui/gxschannels/GxsChannelFilesWidget.cpp \
|
||||
gui/gxschannels/GxsChannelPostThumbnail.cpp \
|
||||
gui/gxschannels/GxsChannelGroupDialog.cpp \
|
||||
gui/gxschannels/CreateGxsChannelMsg.cpp \
|
||||
gui/feeds/GxsChannelGroupItem.cpp \
|
||||
|
@ -307,7 +307,11 @@ QPixmap misc::getOpenThumbnailedPicture(QWidget *parent, const QString &caption,
|
||||
if (!getOpenFileName(parent, RshareSettings::LASTDIR_IMAGES, caption, tr("Pictures (*.png *.jpeg *.xpm *.jpg *.tiff *.gif)"), fileName))
|
||||
return QPixmap();
|
||||
|
||||
return QPixmap(fileName).scaledToHeight(height, Qt::SmoothTransformation).copy( 0, 0, width, height);
|
||||
if(width > 0 && height > 0)
|
||||
return QPixmap(fileName).scaledToHeight(height, Qt::SmoothTransformation).copy( 0, 0, width, height);
|
||||
else
|
||||
return QPixmap(fileName);
|
||||
|
||||
//return QPixmap(fileName).scaledToHeight(width, height, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,6 @@ void init_item(RsGxsMsgMetaData* metaMsg)
|
||||
|
||||
init_random(metaMsg->mGroupId) ;
|
||||
init_random(metaMsg->mMsgId) ;
|
||||
metaMsg->refcount = 1;
|
||||
init_random(metaMsg->mThreadId) ;
|
||||
init_random(metaMsg->mParentId) ;
|
||||
init_random(metaMsg->mOrigMsgId) ;
|
||||
|
Loading…
Reference in New Issue
Block a user