merged upstream/master

This commit is contained in:
csoler 2020-09-11 21:36:45 +02:00
commit 2e6a87a2ea
84 changed files with 2515 additions and 968 deletions

File diff suppressed because it is too large Load Diff

View 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

View File

@ -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

View File

@ -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,

View File

@ -196,7 +196,6 @@ bool RsGxsGrpMetaData::deserialise(void *data, uint32_t &pktsize)
return ok;
}
int RsGxsMsgMetaData::refcount = 0;
RsGxsMsgMetaData::RsGxsMsgMetaData(){
clear();

View File

@ -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;

View File

@ -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 ;

View File

@ -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);

View File

@ -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;

View File

@ -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(

View File

@ -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 **/

View File

@ -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}

View File

@ -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;

View File

@ -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
*/

View File

@ -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;

View File

@ -19,9 +19,10 @@
*******************************************************************************/
#pragma once
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "ui_ChatLobbyWidget.h"
#include "RsAutoUpdatePage.h"
#include "chat/ChatLobbyUserNotify.h"
#include "gui/gxs/GxsIdChooser.h"

View File

@ -20,7 +20,7 @@
#pragma once
#include "RsAutoUpdatePage.h"
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "ui_BannedFilesDialog.h"
class BannedFilesDialog: public QDialog

View File

@ -24,7 +24,8 @@
#include <QWidget>
#include <QPainter>
#include <QBitmap>
#include "RsAutoUpdatePage.h"
#include <retroshare-gui/RsAutoUpdatePage.h>
#include <retroshare/rstypes.h>
struct FileChunksInfo ;

View File

@ -23,7 +23,7 @@
#include <retroshare/rstypes.h>
#include "ui_SearchDialog.h"
#include "mainpage.h"
#include <retroshare-gui/mainpage.h>
class AdvancedSearchDialog;
class RSTreeWidgetItemCompareRole;

View File

@ -23,7 +23,7 @@
#include "ui_SharedFilesDialog.h"
#include "RsAutoUpdatePage.h"
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "gui/RetroShareLink.h"
#include "util/RsProtectedTimer.h"

View File

@ -25,7 +25,7 @@
#include <retroshare/rstypes.h>
#include <retroshare/rsevents.h>
#include "RsAutoUpdatePage.h"
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "ui_TransfersDialog.h"

View File

@ -21,9 +21,9 @@
#ifndef _GETTING_STARTED_DIALOG_H
#define _GETTING_STARTED_DIALOG_H
//#include <retroshare/rstypes.h>
#include <retroshare-gui/mainpage.h>
#include "ui_GetStartedDialog.h"
#include "mainpage.h"
#include <QTimer>

View File

@ -21,8 +21,10 @@
#ifndef _CONNECTIONSDIALOG_H
#define _CONNECTIONSDIALOG_H
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "ui_NetworkDialog.h"
#include "RsAutoUpdatePage.h"
#include "gui/NetworkDialog/pgpid_item_model.h"
#include "gui/NetworkDialog/pgpid_item_proxy.h"

View File

@ -25,7 +25,7 @@
#include <retroshare/rstypes.h>
#include "RsAutoUpdatePage.h"
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "ui_NetworkView.h"

View File

@ -21,7 +21,7 @@
#ifndef _NEWS_FEED_DIALOG_H
#define _NEWS_FEED_DIALOG_H
#include "mainpage.h"
#include <retroshare-gui/mainpage.h>
#include "gui/feeds/FeedHolder.h"
#include "util/TokenQueue.h"

View File

@ -21,7 +21,7 @@
#ifndef _PLUGINS_PAGE_H_
#define _PLUGINS_PAGE_H_
#include "mainpage.h"
#include <retroshare-gui/mainpage.h>
#include <QGroupBox>
#include <QString>

View File

@ -20,7 +20,8 @@
#include "RemoteDirModel.h"
#include "RsAutoUpdatePage.h"
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "gui/common/FilesDefs.h"
#include "gui/common/GroupDefs.h"
#include "gui/common/RsCollection.h"
@ -1103,15 +1104,9 @@ Qt::ItemFlags RetroshareDirModel::flags( const QModelIndex & index ) const
/* Callback from Core*/
void RetroshareDirModel::preMods()
{
emit layoutAboutToBeChanged();
mUpdating = true ;
#if QT_VERSION < 0x050000
reset();
#else
beginResetModel();
endResetModel();
#endif
beginResetModel();
#ifdef RDM_DEBUG
std::cerr << "RetroshareDirModel::preMods()" << std::endl;
#endif
@ -1120,20 +1115,14 @@ void RetroshareDirModel::preMods()
/* Callback from Core*/
void RetroshareDirModel::postMods()
{
// emit layoutAboutToBeChanged();
mUpdating = false ;
#if QT_VERSION >= 0x040600
beginResetModel();
#endif
#ifdef RDM_DEBUG
std::cerr << "RetroshareDirModel::postMods()" << std::endl;
#endif
#if QT_VERSION >= 0x040600
endResetModel();
#endif
emit layoutChanged();
emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(rowCount()-1,COLUMN_COUNT-1,(void*)NULL));
}
void FlatStyle_RDM::postMods()

View File

@ -19,7 +19,8 @@
*******************************************************************************/
#include <QTimer>
#include "RsAutoUpdatePage.h"
#include <retroshare-gui/RsAutoUpdatePage.h>
bool RsAutoUpdatePage::_locked = false ;

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -31,7 +31,8 @@
#include <retroshare/rspeers.h>
#include <retroshare/rsidentity.h>
#include "RsAutoUpdatePage.h"
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "PopupDistantChatDialog.h"
#define IMAGE_RED_LED ":/icons/bullet_red_128.png"

View File

@ -152,15 +152,13 @@ void RsFriendListModel::setDisplayGroups(bool b)
}
void RsFriendListModel::preMods()
{
emit layoutAboutToBeChanged();
beginResetModel();
}
void RsFriendListModel::postMods()
{
endResetModel();
emit layoutChanged();
emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mTopLevel.size()-1,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL));
emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(rowCount()-1,columnCount()-1,(void*)NULL));
}
int RsFriendListModel::rowCount(const QModelIndex& parent) const
@ -1060,14 +1058,16 @@ void RsFriendListModel::updateInternalData()
preMods();
beginRemoveRows(QModelIndex(),0,mTopLevel.size()-1);
endRemoveRows();
mGroups.clear();
mProfiles.clear();
mLocations.clear();
mTopLevel.clear();
endRemoveRows();
auto TL = mTopLevel ; // This allows to fill TL without touching mTopLevel outside of [begin/end]InsertRows().
// create a map of profiles and groups
std::map<RsPgpId,uint32_t> pgp_indices;
@ -1155,7 +1155,6 @@ void RsFriendListModel::updateInternalData()
RsDbg() << "Creating top level list" << std::endl;
#endif
mTopLevel.clear();
std::set<RsPgpId> already_in_a_group;
if(mDisplayGroups) // in this case, we list all groups at the top level followed by the profiles without parent group
@ -1170,7 +1169,7 @@ void RsFriendListModel::updateInternalData()
e.type = ENTRY_TYPE_GROUP;
e.group_index = i;
mTopLevel.push_back(e);
TL.push_back(e);
for(uint32_t j=0;j<mGroups[i].child_profile_indices.size();++j)
already_in_a_group.insert(mProfiles[mGroups[i].child_profile_indices[j]].profile_info.gpg_id);
@ -1189,12 +1188,15 @@ void RsFriendListModel::updateInternalData()
e.profile_index = i;
e.group_index = UNDEFINED_GROUP_INDEX_VALUE;
mTopLevel.push_back(e);
TL.push_back(e);
}
// finally, tell the model client that layout has changed.
beginInsertRows(QModelIndex(),0,mTopLevel.size()-1);
beginInsertRows(QModelIndex(),0,TL.size()-1);
mTopLevel = TL;
endInsertRows();
postMods();
@ -1234,7 +1236,7 @@ void RsFriendListModel::collapseItem(const QModelIndex& index)
mExpandedProfiles.erase(s);
// apparently we cannot be subtle here.
emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mTopLevel.size()-1,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL));
emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mTopLevel.size()-1,columnCount()-1,(void*)NULL));
}
void RsFriendListModel::expandItem(const QModelIndex& index)
@ -1256,10 +1258,10 @@ void RsFriendListModel::expandItem(const QModelIndex& index)
if(hp) s += hp->profile_info.gpg_id.toStdString();
if(!s.empty())
mExpandedProfiles.insert(s);
mExpandedProfiles.insert(s);
// apparently we cannot be subtle here.
emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mTopLevel.size()-1,COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL));
emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mTopLevel.size()-1,columnCount()-1,(void*)NULL));
}
bool RsFriendListModel::isProfileExpanded(const EntryIndex& e) const

View File

@ -454,6 +454,7 @@ void NewFriendList::processSettings(bool load)
if (load) // load settings
{
std::cerr <<"Re-loading settings..." << std::endl;
// states
setShowUnconnected(!Settings->value("hideUnconnected", !mProxyModel->showOfflineNodes()).toBool());
setShowState(Settings->value("showState", mModel->getDisplayStatusString()).toBool());
@ -1088,16 +1089,46 @@ void NewFriendList::removeGroup()
checkInternalData(true);
}
void NewFriendList::checkInternalData(bool force)
void NewFriendList::applyWhileKeepingTree(std::function<void()> predicate)
{
std::set<QString> expanded_indexes;
std::set<QString> selected_indexes;
std::set<QString> selected_indexes;
saveExpandedPathsAndSelection(expanded_indexes, selected_indexes);
saveExpandedPathsAndSelection(expanded_indexes, selected_indexes);
mModel->checkInternalData(force);
// This is a hack to avoid crashes on windows while calling endInsertRows(). I'm not sure wether these crashes are
// due to a Qt bug, or a misuse of the proxy model on my side. Anyway, this solves them for good.
// As a side effect we need to save/restore hidden columns because setSourceModel() resets this setting.
restoreExpandedPathsAndSelection(expanded_indexes, selected_indexes);
// save hidden columns and sizes
std::vector<bool> col_visible(RsFriendListModel::COLUMN_THREAD_NB_COLUMNS);
std::vector<int> col_sizes(RsFriendListModel::COLUMN_THREAD_NB_COLUMNS);
for(int i=0;i<RsFriendListModel::COLUMN_THREAD_NB_COLUMNS;++i)
{
col_visible[i] = !ui->peerTreeWidget->isColumnHidden(i);
col_sizes[i] = ui->peerTreeWidget->columnWidth(i);
}
mProxyModel->setSourceModel(nullptr);
predicate();
mProxyModel->setSourceModel(mModel);
restoreExpandedPathsAndSelection(expanded_indexes, selected_indexes);
// restore hidden columns
for(uint32_t i=0;i<RsFriendListModel::COLUMN_THREAD_NB_COLUMNS;++i)
{
ui->peerTreeWidget->setColumnHidden(i,!col_visible[i]);
ui->peerTreeWidget->setColumnWidth(i,col_sizes[i]);
}
}
void NewFriendList::checkInternalData(bool force)
{
applyWhileKeepingTree([force,this]() { mModel->checkInternalData(force) ; });
}
void NewFriendList::exportFriendlistClicked()
@ -1485,6 +1516,7 @@ bool NewFriendList::isColumnVisible(int col) const
}
void NewFriendList::setColumnVisible(int col,bool visible)
{
std::cerr << "Setting column " << col << " to be visible: " << visible << std::endl;
ui->peerTreeWidget->setColumnHidden(col, !visible);
}
void NewFriendList::toggleColumnVisible()
@ -1502,12 +1534,12 @@ void NewFriendList::toggleColumnVisible()
void NewFriendList::setShowState(bool show)
{
mModel->setDisplayStatusString(show);
applyWhileKeepingTree([show,this]() { mModel->setDisplayStatusString(show) ; });
}
void NewFriendList::setShowGroups(bool show)
{
mModel->setDisplayGroups(show);
applyWhileKeepingTree([show,this]() { mModel->setDisplayGroups(show) ; });
}
/**

View File

@ -25,8 +25,9 @@
#include <QWidget>
#include <QTreeView>
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "FriendListModel.h"
#include "RsAutoUpdatePage.h"
#include "retroshare/rsstatus.h"
namespace Ui {
@ -102,7 +103,9 @@ private:
RsFriendListModel *mModel;
QAction *mActionSortByState;
void expandGroup(const RsNodeGroupId& gid);
void applyWhileKeepingTree(std::function<void()> predicate);
void expandGroup(const RsNodeGroupId& gid);
void recursRestoreExpandedItems(const QModelIndex& index, const QString& parent_path, const std::set<QString>& exp, const std::set<QString> &sel);
void recursSaveExpandedItems(const QModelIndex& index,const QString& parent_path,std::set<QString>& exp, std::set<QString>& sel);
void saveExpandedPathsAndSelection(std::set<QString>& expanded_indexes, std::set<QString>& selected_indexes);

View File

@ -32,6 +32,8 @@
#include <retroshare/rsdisc.h>
#include <retroshare/rsmsgs.h>
#include <retroshare-gui/mainpage.h>
#include "gui/help/browser/helpbrowser.h"
#include "gui/common/PeerDefs.h"
#include "gui/common/StatusDefs.h"
@ -40,7 +42,6 @@
#include "gui/common/AvatarDefs.h"
#include "gui/common/FilesDefs.h"
#include "gui/MainWindow.h"
#include "mainpage.h"
#include "util/DateTime.h"
#include "util/misc.h"

View File

@ -33,6 +33,8 @@
#include <retroshare/rsdisc.h>
#include <retroshare/rsmsgs.h>
#include <retroshare-gui/mainpage.h>
#include "gui/help/browser/helpbrowser.h"
#include "gui/common/PeerDefs.h"
#include "gui/common/StatusDefs.h"
@ -40,7 +42,6 @@
#include "gui/notifyqt.h"
#include "gui/common/AvatarDefs.h"
#include "gui/MainWindow.h"
#include "mainpage.h"
#include "util/DateTime.h"
#include "util/misc.h"

View File

@ -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()";

View File

@ -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();

View File

@ -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)
{

View File

@ -80,6 +80,9 @@ public slots:
void markSpammer();
void banUser();
signals:
void commentsLoaded(int);
protected:
void vote(const RsGxsGroupId &groupId, const RsGxsMessageId &threadId,

View File

@ -112,6 +112,12 @@ p, li { white-space: pre-wrap; }
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="2" column="0">

View File

@ -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)

View File

@ -21,8 +21,9 @@
#ifndef _GXSGROUPFRAMEDIALOG_H
#define _GXSGROUPFRAMEDIALOG_H
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "gui/gxs/RsGxsUpdateBroadcastPage.h"
#include "RsAutoUpdatePage.h"
#include "gui/RetroShareLink.h"
#include "gui/settings/rsharesettings.h"
#include "util/RsUserdata.h"

View File

@ -20,7 +20,7 @@
#pragma once
#include "mainpage.h"
#include <retroshare-gui/mainpage.h>
#include <retroshare/rsgxsifacetypes.h>
// This class implement a basic RS functionality which is that widgets displaying info

View File

@ -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);
}

View File

@ -64,6 +64,7 @@ private slots:
void sendMsg();
void pasteLink() ;
void contextMenu(QPoint) ;
void changeAspectRatio(int s);
void addThumbnail();
void allowAutoMediaThumbNail(bool);

View File

@ -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>

View File

@ -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);

View File

@ -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;

View 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));
}

View File

@ -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;
};

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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))

View File

@ -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);

View File

@ -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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;justify&quot;&gt;The number of posts at friends is progressively updated.&lt;/p&gt;&lt;p align=&quot;justify&quot;&gt;The new numbers will show next time you load this channel.&lt;/p&gt;&lt;p align=&quot;justify&quot;&gt;The two numbers differ depending on your friends synchronization&lt;/p&gt;&lt;p&gt;time limits as well as yours.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>

View File

@ -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>

View 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

View 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

View 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

View 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

View 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

View 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

View File

@ -23,7 +23,8 @@
#include <QSortFilterProxyModel>
#include "mainpage.h"
#include <retroshare-gui/mainpage.h>
#include "ui_MessagesDialog.h"
#define IMAGE_MESSAGES ":/icons/png/message.png"

View File

@ -33,7 +33,7 @@
#include <retroshare/rsidentity.h>
#include <util/rsdir.h>
#include "RsAutoUpdatePage.h"
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "MainWindow.h"
#include "toaster/OnlineToaster.h"

View File

@ -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;
}

View File

@ -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"));

View File

@ -43,9 +43,6 @@ public:
private slots:
void updateEmotes();
protected slots:
void updateLoadThread() ;
private:
Ui::ChannelPage ui;
};

View File

@ -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">

View File

@ -24,8 +24,9 @@
#include "gui/common/FilesDefs.h"
#include <QDialog>
#include <retroshare-gui/configpage.h>
#include <retroshare-gui/mainpage.h>
#include "ui_settingsw.h"
#include "mainpage.h"
class FloatingHelpBrowser;

View File

@ -24,7 +24,7 @@
#include <QAbstractItemDelegate>
#include "RsAutoUpdatePage.h"
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "gui/common/RSGraphWidget.h"
#include "ui_BwCtrlWindow.h"

View File

@ -21,7 +21,8 @@
#ifndef RSDHT_WINDOW_H
#define RSDHT_WINDOW_H
#include "RsAutoUpdatePage.h"
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "ui_DhtWindow.h"
class DhtWindow : public RsAutoUpdatePage/*, public Ui::DhtWindow*/ {

View File

@ -24,7 +24,8 @@
#include <retroshare/rsgrouter.h>
#include <retroshare/rstypes.h>
#include "RsAutoUpdatePage.h"
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "ui_GlobalRouterStatistics.h"
class GlobalRouterStatisticsWidget ;

View File

@ -24,7 +24,8 @@
#include <retroshare/rsidentity.h>
#include <retroshare/rstypes.h>
#include "RsAutoUpdatePage.h"
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "Histogram.h"
#include "ui_GxsIdStatistics.h"

View File

@ -27,7 +27,8 @@
#include <retroshare/rstypes.h>
#include <retroshare/rsgxstrans.h>
#include "RsAutoUpdatePage.h"
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "ui_GxsTransportStatistics.h"
#include "gui/gxs/RsGxsUpdateBroadcastPage.h"
#include "util/rstime.h"

View File

@ -22,8 +22,9 @@
#include <QPoint>
#include <retroshare/rsrtt.h>
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "ui_RttStatistics.h"
#include "RsAutoUpdatePage.h"
#include <gui/common/RSGraphWidget.h>
class RttStatisticsWidget ;

View File

@ -22,9 +22,11 @@
#include <retroshare/rsturtle.h>
#include <retroshare/rstypes.h>
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "ui_TurtleRouterDialog.h"
#include "ui_TurtleRouterStatistics.h"
#include "RsAutoUpdatePage.h"
class TurtleRouterDialog: public RsAutoUpdatePage, public Ui::TurtleRouterDialogForm

View File

@ -23,8 +23,10 @@
#include <QPoint>
#include <retroshare/rsturtle.h>
#include <retroshare/rstypes.h>
#include <retroshare-gui/RsAutoUpdatePage.h>
#include "ui_TurtleRouterStatistics.h"
#include "RsAutoUpdatePage.h"
class TurtleRouterStatisticsWidget ;

View File

@ -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;
}

View File

@ -1295,7 +1295,9 @@ PostedCardView > QFrame#mainFrame[new=true] {
background-color: #005000;
}
WireGroupItem QFrame#frame{
WireGroupItem QFrame#wire_frame
{
border: 1px solid #38444d;
background: transparent;
}
@ -1307,5 +1309,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;
}

View File

@ -25,8 +25,8 @@ CONFIG += console
TARGET = retroshare
DEFINES += TARGET=\\\"$${TARGET}\\\"
DEPENDPATH *= $${PWD} $${RS_INCLUDE_DIR} retroshare-gui
INCLUDEPATH *= $${PWD} retroshare-gui
DEPENDPATH *= $${PWD} $${RS_INCLUDE_DIR}
INCLUDEPATH *= $${PWD}
!include("../../libretroshare/src/use_libretroshare.pri"):error("Including")
@ -1382,7 +1382,8 @@ gxschannels {
gui/gxschannels/GxsChannelPostsModel.cpp \
gui/gxschannels/GxsChannelPostFilesModel.cpp \
gui/gxschannels/GxsChannelFilesWidget.cpp \
gui/gxschannels/GxsChannelFilesStatusWidget.cpp \
gui/gxschannels/GxsChannelPostThumbnail.cpp \
gui/gxschannels/GxsChannelFilesStatusWidget.cpp \
gui/gxschannels/GxsChannelGroupDialog.cpp \
gui/gxschannels/CreateGxsChannelMsg.cpp \
gui/feeds/GxsChannelGroupItem.cpp \

View File

@ -308,8 +308,10 @@ 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 FilesDefs::getPixmapFromQtResourcePath(fileName).scaledToHeight(height, Qt::SmoothTransformation).copy( 0, 0, width, height);
//return FilesDefs::getPixmapFromQtResourcePath(fileName).scaledToHeight(width, height, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
if(width > 0 && height > 0)
return FilesDefs::getPixmapFromQtResourcePath(fileName).scaledToHeight(height, Qt::SmoothTransformation).copy( 0, 0, width, height);
else
return FilesDefs::getPixmapFromQtResourcePath(fileName);
}
bool misc::getOpenFileName(QWidget *parent, RshareSettings::enumLastDir type

View File

@ -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) ;