merged with upstreamm/master

This commit is contained in:
csoler 2020-05-09 22:33:27 +02:00
commit 6f6e0de5f1
No known key found for this signature in database
GPG key ID: 7BCA522266C0804C
59 changed files with 1438 additions and 1164 deletions

View file

@ -8,7 +8,15 @@ Requirements: about 12 GB of free space
The resulting binary is a 32-bit build of Retroshare which will also work The resulting binary is a 32-bit build of Retroshare which will also work
fine on a 64-bit system. fine on a 64-bit system.
### MSYS2 INSTALLATION **If you want to make complet solution without debugging it, prefer to use \build_scripts\Windows-msys2\build.bat**
This batch will install and build all for you.
You only have to clone this repository (with [git for windows](https://gitforwindows.org/)) to a local folder, then start it in a terminal.
At the end, you'll get at ..\\*-msys2\deploy\ the Portable 7zip file.
### MSYS2 INSTALLATION (for editing or debugging)
Download MSYS2 from [MSYS2](http://www.msys2.org/). Get the i686 version Download MSYS2 from [MSYS2](http://www.msys2.org/). Get the i686 version
if you run a 32-bit Windows or the x86_64 if you run a 64-bit Windows. if you run a 32-bit Windows or the x86_64 if you run a 64-bit Windows.
@ -49,6 +57,12 @@ Install all needed dependencies:
pacman -S mingw32/mingw-w64-i686-cmake pacman -S mingw32/mingw-w64-i686-cmake
pacman -S mingw-w64-i686-rapidjson pacman -S mingw-w64-i686-rapidjson
If you want to use QtCreator as IDE, prefer using this one publish by MSYS2 as all build Kit are already setted.
pacman -S mingw-w64-i686-qt-creator
*You can start it from MSYS2 terminal.*
We're done installing MSYS2, close the shell terminal. We're done installing MSYS2, close the shell terminal.
### BUILDING RETROSHARE ### BUILDING RETROSHARE

View file

@ -289,7 +289,7 @@ bool GxsSecurity::generateKeyPair(RsTlvPublicRSAKey& public_key,RsTlvPrivateRSAK
if(!(private_key.checkKey() && public_key.checkKey())) if(!(private_key.checkKey() && public_key.checkKey()))
{ {
std::cerr << "(EE) ERROR while generating keys. Something inconsistent in flags. This is probably a bad sign!" << std::endl; std::cerr << "(EE) ERROR while generating keys. Something inconsistent in flags. This is probably a bad sign!" << std::endl;
return false ; return false ;
} }
return true ; return true ;
@ -418,11 +418,11 @@ bool GxsSecurity::validateNxsMsg(const RsNxsMsg& msg, const RsTlvKeySignature& s
/* check signature timeperiod */ /* check signature timeperiod */
if ((msgMeta.mPublishTs < key.startTS) || (key.endTS != 0 && msgMeta.mPublishTs > key.endTS)) if ((msgMeta.mPublishTs < key.startTS) || (key.endTS != 0 && msgMeta.mPublishTs > key.endTS))
{ {
RsWarn() << __PRETTY_FUNCTION__ << " GxsSecurity::validateNxsMsg() TS out of range for key " << msgMeta.mAuthorId RsWarn() << __PRETTY_FUNCTION__ << " GxsSecurity::validateNxsMsg() TS out of range for key " << msgMeta.mAuthorId
<< " usage is limited to TS=[" << key.startTS << "," << key.endTS << "] and msg publish time is " << msgMeta.mPublishTs << std::endl; << " usage is limited to TS=[" << key.startTS << "," << key.endTS << "] and msg publish time is " << msgMeta.mPublishTs << std::endl;
return false; return false;
} }
/* decode key */ /* decode key */
const unsigned char *keyptr = (const unsigned char *) key.keyData.bin_data; const unsigned char *keyptr = (const unsigned char *) key.keyData.bin_data;

View file

@ -274,12 +274,12 @@
NXS_NET_DEBUG_8 gxs distant sync NXS_NET_DEBUG_8 gxs distant sync
***/ ***/
#define NXS_NET_DEBUG_0 1 //#define NXS_NET_DEBUG_0 1
#define NXS_NET_DEBUG_1 1 //#define NXS_NET_DEBUG_1 1
//#define NXS_NET_DEBUG_2 1 //#define NXS_NET_DEBUG_2 1
//#define NXS_NET_DEBUG_3 1 //#define NXS_NET_DEBUG_3 1
#define NXS_NET_DEBUG_4 1 //#define NXS_NET_DEBUG_4 1
#define NXS_NET_DEBUG_5 1 //#define NXS_NET_DEBUG_5 1
//#define NXS_NET_DEBUG_6 1 //#define NXS_NET_DEBUG_6 1
//#define NXS_NET_DEBUG_7 1 //#define NXS_NET_DEBUG_7 1
//#define NXS_NET_DEBUG_8 1 //#define NXS_NET_DEBUG_8 1
@ -321,7 +321,7 @@ static const uint32_t RS_NXS_ITEM_ENCRYPTION_STATUS_GXS_KEY_MISSING = 0x05 ;
|| defined(NXS_NET_DEBUG_8) || defined(NXS_NET_DEBUG_8)
static const RsPeerId peer_to_print = RsPeerId();//std::string("a97fef0e2dc82ddb19200fb30f9ac575")) ; static const RsPeerId peer_to_print = RsPeerId();//std::string("a97fef0e2dc82ddb19200fb30f9ac575")) ;
static const RsGxsGroupId group_id_to_print = RsGxsGroupId(std::string("66052380f5d1d0c5992e2b55dc402ce6")) ; // use this to allow to this group id only, or "" for all IDs static const RsGxsGroupId group_id_to_print = RsGxsGroupId() ; // use this to allow to this group id only, or "" for all IDs
static const uint32_t service_to_print = RS_SERVICE_GXS_TYPE_GXSCIRCLE; // use this to allow to this service id only, or 0 for all services static const uint32_t service_to_print = RS_SERVICE_GXS_TYPE_GXSCIRCLE; // use this to allow to this service id only, or 0 for all services
// warning. Numbers should be SERVICE IDS (see serialiser/rsserviceids.h. E.g. 0x0215 for forums) // warning. Numbers should be SERVICE IDS (see serialiser/rsserviceids.h. E.g. 0x0215 for forums)

View file

@ -806,22 +806,22 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
X509_NAME_free(issuer_name); X509_NAME_free(issuer_name);
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
// (does not leak the key creation date to the outside anymore. for more privacy) // (does not leak the key creation date to the outside anymore. for more privacy)
ASN1_TIME_set(X509_get_notBefore(x509), 0); ASN1_TIME_set(X509_get_notBefore(x509), 0);
ASN1_TIME_set(X509_get_notAfter(x509), 0); ASN1_TIME_set(X509_get_notAfter(x509), 0);
#else #else
// NEW code, set validity time between 2010 and 2110 (remember to change it when, if OpenSSL check it by default. ;) ) // NEW code, set validity time between 2010 and 2110 (remember to change it when, if OpenSSL check it by default. ;) )
// (does not leak the key creation date to the outside anymore. for more privacy) // (does not leak the key creation date to the outside anymore. for more privacy)
if (!ASN1_TIME_set_string(X509_getm_notBefore(x509), "20100101000000Z")) if (!ASN1_TIME_set_string(X509_getm_notBefore(x509), "20100101000000Z"))
{ {
RsErr() << __PRETTY_FUNCTION__ << " Set notBefore FAIL" << std::endl; RsErr() << __PRETTY_FUNCTION__ << " Set notBefore FAIL" << std::endl;
return NULL; return NULL;
} }
if (!ASN1_TIME_set_string(X509_getm_notAfter(x509), "21100101000000Z")) if (!ASN1_TIME_set_string(X509_getm_notAfter(x509), "21100101000000Z"))
{ {
RsErr() << __PRETTY_FUNCTION__ << " Set notAfter FAIL" << std::endl; RsErr() << __PRETTY_FUNCTION__ << " Set notAfter FAIL" << std::endl;
return NULL; return NULL;
} }
#endif #endif
if (!X509_set_subject_name(x509, X509_REQ_get_subject_name(req))) if (!X509_set_subject_name(x509, X509_REQ_get_subject_name(req)))

View file

@ -56,6 +56,69 @@ const int PQISSL_UDP_FLAG = 0x02;
/* TCP buffer size for Windows systems */ /* TCP buffer size for Windows systems */
const int WINDOWS_TCP_BUFFER_SIZE = 512 * 1024; // 512 KB const int WINDOWS_TCP_BUFFER_SIZE = 512 * 1024; // 512 KB
// This is a (very) simple overview of the different state machnines. The tree includes high level funtions only.
//
// connect_parameter() is used to pass down settings, like address or timeout values
//
// tick() or connect()
// |
// +----- ConnectAttempt()
// |
// +--WAITING_NOT or WAITING_DELAY
// | |
// | +----- Delay_Connection()
// | |
// | +--WAITING_NOT
// | | - set 'waiting' to WAITING_DELAY and set delay for next connection attempt
// | |
// | +--WAITING_DELAY
// | |
// | +----- Initiate_Connection()
// | |
// | +----- setup socket
// | +----- connect
// | - on success: set "waiting" to WAITING_SOCK_CONNECT and "sockfd" to newly created socket
// | - on failure: set "waiting" to WAITING_FAIL_INTERFACE
// |
// +--WAITING_SOCK_CONNECT
// | |
// | +----- Initiate_SSL_Connection()
// | |
// | +----- Basic_Connection_Complete()
// | | |
// | | +----- CheckConnectionTimeout()
// | | |
// | | +----- ready up socket.
// | | - SOCKS, udp tou, i2p BOB intercept here
// | | - on failure: set "waiting" to WAITING_FAIL_INTERFACE and "sockfd" to -1
// | |
// | +----- create SSL context and attach file descriptors
// | - on success:_set "waiting" to WAITING_SSL_CONNECTION
// |
// +--WAITING_SSL_CONNECTION or WAITING_SSL_AUTHORISE
// | |
// | +----- Authorise_SSL_Connection()
// | |
// | +----- SSL_Connection_Complete()
// | | |
// | | +----- performes TSL handshake
// | | - on success: set "waiting" to WAITING_SSL_AUTHORISE
// | | - on failure: set "waiting" to WAITING_FAIL_INTERFACE
// | |
// | +----- set "waiting" to WAITING_NOT
// | |
// | +----- accept_locked()
// | - add peer to the rest of RS and start pqi thread
// |
// |
// +--WAITING_FAIL_INTERFACE
// |
// +----- Failed_Connection()
// - set "waiting" to WAITING_NOT
//
/***************************** pqi Net SSL Interface ********************************* /***************************** pqi Net SSL Interface *********************************
* This provides the base SSL interface class, * This provides the base SSL interface class,
* and handles most of the required functionality. * and handles most of the required functionality.
@ -203,9 +266,9 @@ bool CheckConnectionTimeout();
uint32_t mConnectTimeout; uint32_t mConnectTimeout;
rstime_t mTimeoutTS; rstime_t mTimeoutTS;
RS_SET_CONTEXT_DEBUG_LEVEL(1)
private: private:
// ssl only fns. // ssl only fns.
int connectInterface(const struct sockaddr_storage &addr); int connectInterface(const struct sockaddr_storage &addr);
RS_SET_CONTEXT_DEBUG_LEVEL(1)
}; };

View file

@ -34,6 +34,73 @@
#define RS_PQISSL_AUTH_DOUBLE_CHECK 1 #define RS_PQISSL_AUTH_DOUBLE_CHECK 1
// This is a simple overview of how the listener is setup, ticked (calling accept) and peers added to it.
// On the highest level (RsServer) the listener lives inside the pqisslpersongrp class (variable: "pqih").
// Inside pqisslpersongrp the listener is stored in "pqil".
//
// The listener has an internal list with incoming connections that are handled in a similar fashion to pqissl.
// (Mainly setting up the socket (non-blocking) and establisching the ssl handshake.)
// When everything went fine the connection is passed to pqissl in finaliseConnection()
//
// This is how the listener is initialized during start up:
//
// RsServer::StartupRetroShare()
// |
// +----- pqih = new pqisslpersongrp(serviceCtrl, flags, mPeerMgr);
// +----- pqih->init_listener();
// |
// +----- pqil = locked_createListener(laddr);
// |
// +----- return new pqissllistener(laddr, mPeerMgr);
//
//
// This is how the listener is ticked to call accept:
//
// RsServer::StartupRetroShare()
// |
// +----- pqih->tick();
// |
// +----- pqil->tick();
// |
// +----- acceptconnection();
// | |
// | +----- accecpt()
// |
// +----- continueaccepts();
// +----- finaliseAccepts();
// |
// +----- finaliseConnection()
// |
// +----- pqis->accept()
//
//
// This is how peers (their id) are registered to the listener:
// (This is only used to tell if a connection peer is known or a new one (which is then added))
//
// pqipersongrp::addPeer()
// |
// +----- pqiperson *pqip = locked_createPerson(id, pqil);
// | |
// | +----- pqiperson *pqip = new pqiperson(id, this);
// | +----- pqissl *pqis = new pqissl((pqissllistener *) listener, pqip, mLinkMgr);
// | +----- pqiconnect *pqisc = new pqiconnect(pqip, rss, pqis);
// | +----- pqip->addChildInterface(PQI_CONNECT_TCP, pqisc);
// | |
// | +-- sets kids[type] = pqisc;
// |
// +----- pqip->reset();
// +----- pqip->listen();
// |
// +-- for all kids[]
// |
// +----- listen() ( of class pqiconnect )
// |
// +----- listen() ( of class pqissl )
// |
// +----- pqil->addlistenaddr(PeerId(), this);
/***************************** pqi Net SSL Interface ********************************* /***************************** pqi Net SSL Interface *********************************
*/ */

View file

@ -333,6 +333,19 @@ public:
std::vector<RsGxsChannelPost>& posts, std::vector<RsGxsChannelPost>& posts,
std::vector<RsGxsComment>& comments ) = 0; std::vector<RsGxsComment>& comments ) = 0;
/**
* @brief Get channel comments corresponding to the given IDs.
* If the set is empty, nothing is returned.
* @jsonapi{development}
* @param[in] channelId id of the channel of which the content is requested
* @param[in] contentIds ids of requested contents
* @param[out] comments storage for the comments
* @return false if something failed, true otherwhise
*/
virtual bool getChannelComments(const RsGxsGroupId &channelId,
const std::set<RsGxsMessageId> &contentIds,
std::vector<RsGxsComment> &comments) = 0;
/** /**
* @brief Get channel content summaries * @brief Get channel content summaries
* @jsonapi{development} * @jsonapi{development}

View file

@ -41,11 +41,12 @@
#include "services/rseventsservice.h" #include "services/rseventsservice.h"
/**** /*******************
#define DEBUG_TICK 1 #define TICK_DEBUG 1
****/ *******************/
#define WARN_BIG_CYCLE_TIME (0.2) #define WARN_BIG_CYCLE_TIME (0.2)
#ifdef WINDOWS_SYS #ifdef WINDOWS_SYS
#include "util/rstime.h" #include "util/rstime.h"
#include <sys/timeb.h> #include <sys/timeb.h>
@ -73,14 +74,13 @@ static double getCurrentTS()
// In some cases (VOIP) it's likely that we will need to set them temporarily to a very low // In some cases (VOIP) it's likely that we will need to set them temporarily to a very low
// value, in order to favor a fast feedback // value, in order to favor a fast feedback
const double RsServer::minTimeDelta = 0.05; // 25; const double RsServer::minTickInterval = 0.05;
const double RsServer::maxTimeDelta = 0.2; const double RsServer::maxTickInterval = 0.2;
const double RsServer::kickLimit = 0.15;
RsServer::RsServer() : RsServer::RsServer() :
coreMutex("RsServer"), mShutdownCallback([](int){}), coreMutex("RsServer"), mShutdownCallback([](int){}),
coreReady(false) coreReady(false)
{ {
{ {
RsEventsService* tmpRsEvtPtr = new RsEventsService(); RsEventsService* tmpRsEvtPtr = new RsEventsService();
@ -108,21 +108,20 @@ RsServer::RsServer() :
msgSrv = NULL; msgSrv = NULL;
chatSrv = NULL; chatSrv = NULL;
mStatusSrv = NULL; mStatusSrv = NULL;
mGxsTunnels = NULL; mGxsTunnels = NULL;
mMin = 0; mLastts = getCurrentTS();
mLoop = 0; mTickInterval = maxTickInterval ;
mAvgRunDuration = 0;
mLastRunDuration = 0;
mCycle1 = 0;
mCycle2 = 0;
mCycle3 = 0;
mCycle4 = 0;
/* caches (that need ticking) */
mLastts = getCurrentTS(); /* config */
mLastSec = 0; /* for the slower ticked stuff */
mTimeDelta = 0.25 ;
mAvgTickRate = mTimeDelta;
/* caches (that need ticking) */
/* Config */
mConfigMgr = NULL; mConfigMgr = NULL;
mGeneralConfig = NULL; mGeneralConfig = NULL;
} }
@ -132,143 +131,132 @@ RsServer::~RsServer()
delete mGxsTrans; delete mGxsTrans;
} }
/* General Internal Helper Functions // General Internal Helper Functions ----> MUST BE LOCKED!
----> MUST BE LOCKED!
*/
/* Thread Fn: Run the Core */
void RsServer::threadTick() void RsServer::threadTick()
{ {
rstime::rs_usleep(mTimeDelta * 1000000); #ifdef TICK_DEBUG
RsDbg() << "TICK_DEBUG ticking interval "<< mTickInterval << std::endl;
double ts = getCurrentTS();
double delta = ts - mLastts;
/* for the fast ticked stuff */
if (delta > mTimeDelta)
{
#ifdef DEBUG_TICK
std::cerr << "Delta: " << delta << std::endl;
std::cerr << "Time Delta: " << mTimeDelta << std::endl;
std::cerr << "Avg Tick Rate: " << mAvgTickRate << std::endl;
#endif #endif
mLastts = ts; // we try to tick at a regular interval which depends on the load
// if there is time left, we sleep
double timeToSleep = mTickInterval - mAvgRunDuration;
/******************************** RUN SERVER *****************/ if (timeToSleep > 0)
lockRsCore(); {
#ifdef TICK_DEBUG
RsDbg() << "TICK_DEBUG will sleep " << timeToSleep << " ms" << std::endl;
#endif
rstime::rs_usleep(timeToSleep * 1000000);
}
int moreToTick = pqih->tick(); double ts = getCurrentTS();
mLastts = ts;
#ifdef DEBUG_TICK // stuff we do always
std::cerr << "RsServer::run() ftserver->tick(): moreToTick: " << moreToTick << std::endl; // tick the core
#ifdef TICK_DEBUG
RsDbg() << "TICK_DEBUG ticking server" << std::endl;
#endif
lockRsCore();
int moreToTick = pqih->tick();
unlockRsCore();
// tick the managers
#ifdef TICK_DEBUG
RsDbg() << "TICK_DEBUG ticking mPeerMgr" << std::endl;
#endif
mPeerMgr->tick();
#ifdef TICK_DEBUG
RsDbg() << "TICK_DEBUG ticking mLinkMgr" << std::endl;
#endif
mLinkMgr->tick();
#ifdef TICK_DEBUG
RsDbg() << "TICK_DEBUG ticking mNetMgr" << std::endl;
#endif
mNetMgr->tick();
// stuff we do every second
if (ts - mCycle1 > 1)
{
#ifdef TICK_DEBUG
RsDbg() << "TICK_DEBUG every second" << std::endl;
#endif
// slow services
if (rsPlugins)
rsPlugins->slowTickPlugins((rstime_t)ts);
// UDP keepalive
// tou_tick_stunkeepalive();
// other stuff to tick
// update();
mCycle1 = ts;
}
// stuff we do every five seconds
if (ts - mCycle2 > 5)
{
#ifdef TICK_DEBUG
RsDbg() << "TICK_DEBUG every 5 seconds" << std::endl;
#endif
// save stuff
mConfigMgr->tick();
mCycle2 = ts;
}
// stuff we do every minute
if (ts - mCycle3 > 60)
{
#ifdef TICK_DEBUG
RsDbg() << "TICK_DEBUG every 60 seconds" << std::endl;
#endif
// force saving FileTransferStatus TODO
// ftserver->saveFileTransferStatus();
// see if we need to resave certs
// AuthSSL::getAuthSSL()->CheckSaveCertificates();
mCycle3 = ts;
}
// stuff we do every hour
if (ts - mCycle4 > 3600)
{
#ifdef TICK_DEBUG
RsDbg() << "TICK_DEBUG every hour" << std::endl;
#endif
mCycle4 = ts;
}
// ticking is done, now compute new values of mLastRunDuration, mAvgRunDuration and mTickInterval
ts = getCurrentTS();
mLastRunDuration = ts - mLastts;
mAvgRunDuration = 0.1 * mLastRunDuration + 0.9 * mAvgRunDuration;
#ifdef TICK_DEBUG
RsDbg() << "TICK_DEBUG new mLastRunDuration " << mLastRunDuration << " mAvgRunDuration " << mAvgRunDuration << std::endl;
if (mLastRunDuration > WARN_BIG_CYCLE_TIME)
RsDbg() << "TICK_DEBUG excessively long lycle time " << mLastRunDuration << std::endl;
#endif #endif
unlockRsCore(); // if the core has returned that there is more to tick we decrease the ticking interval, else we increse it
// this should be studied closer as I dont think that the core ever returns 1
/* tick the Managers */ #ifdef TICK_DEBUG
mPeerMgr->tick(); RsDbg() << "TICK_DEBUG moreToTick " << moreToTick << std::endl;
mLinkMgr->tick(); #endif
mNetMgr->tick(); if (moreToTick == 1)
/******************************** RUN SERVER *****************/ mTickInterval = 0.9 * mTickInterval;
else
/* adjust tick rate depending on whether there is more. mTickInterval = 1.1 * mTickInterval;
*/ #ifdef TICK_DEBUG
RsDbg() << "TICK_DEBUG new tick interval " << mTickInterval << std::endl;
mAvgTickRate = 0.2 * mTimeDelta + 0.8 * mAvgTickRate;
if (1 == moreToTick)
{
mTimeDelta = 0.9 * mAvgTickRate;
if (mTimeDelta > kickLimit)
{
/* force next tick in one sec
* if we are reading data.
*/
mTimeDelta = kickLimit;
mAvgTickRate = kickLimit;
}
}
else
{
mTimeDelta = 1.1 * mAvgTickRate;
}
/* limiter */
if (mTimeDelta < minTimeDelta)
{
mTimeDelta = minTimeDelta;
}
else if (mTimeDelta > maxTimeDelta)
{
mTimeDelta = maxTimeDelta;
}
/* Fast Updates */
/* now we have the slow ticking stuff */
/* stuff ticked once a second (but can be slowed down) */
if ((int) ts > mLastSec)
{
mLastSec = (int) ts;
// Every second! (UDP keepalive).
//tou_tick_stunkeepalive();
// every five loops (> 5 secs)
if (mLoop % 5 == 0)
{
// update_quick_stats();
// Update All Every 5 Seconds.
// These Update Functions do the locking themselves.
#ifdef DEBUG_TICK
std::cerr << "RsServer::run() Updates()" << std::endl;
#endif #endif
mConfigMgr->tick(); /* saves stuff */ // keep the tick interval within allowed limits
if (mTickInterval < minTickInterval)
} mTickInterval = minTickInterval;
else if (mTickInterval > maxTickInterval)
// every 60 loops (> 1 min) mTickInterval = maxTickInterval;
if (++mLoop >= 60) #ifdef TICK_DEBUG
{ RsDbg() << "TICK_DEBUG new tick interval after limiter " << mTickInterval << std::endl;
mLoop = 0;
/* force saving FileTransferStatus TODO */
//ftserver->saveFileTransferStatus();
/* see if we need to resave certs */
//AuthSSL::getAuthSSL()->CheckSaveCertificates();
/* hour loop */
if (++mMin >= 60)
{
mMin = 0;
}
}
/* Tick slow services */
if(rsPlugins)
rsPlugins->slowTickPlugins((rstime_t)ts);
// slow update tick as well.
// update();
} // end of slow tick.
} // end of only once a second.
#ifdef DEBUG_TICK
double endCycleTs = getCurrentTS();
double cycleTime = endCycleTs - ts;
if (cycleTime > WARN_BIG_CYCLE_TIME)
{
std::string out;
rs_sprintf(out, "RsServer::run() WARNING Excessively Long Cycle Time: %g secs => Please DEBUG", cycleTime);
std::cerr << out << std::endl;
}
#endif #endif
} }

View file

@ -172,8 +172,8 @@ public:
// p3Posted *mPosted; // p3Posted *mPosted;
// p3PhotoService *mPhoto; // p3PhotoService *mPhoto;
// p3GxsCircles *mGxsCircles; // p3GxsCircles *mGxsCircles;
// p3GxsNetService *mGxsNetService; // p3GxsNetService *mGxsNetService;
// p3IdService *mGxsIdService; // p3IdService *mGxsIdService;
// p3GxsForums *mGxsForums; // p3GxsForums *mGxsForums;
// p3GxsChannels *mGxsChannels; // p3GxsChannels *mGxsChannels;
// p3Wire *mWire; // p3Wire *mWire;
@ -188,16 +188,14 @@ public:
// Worker Data..... // Worker Data.....
int mMin ; double mLastts;
int mLoop ; double mTickInterval;
int mLastts ; double mLastRunDuration;
long mLastSec ; double mAvgRunDuration;
double mAvgTickRate ; double mCycle1, mCycle2, mCycle3, mCycle4;
double mTimeDelta ;
static const double minTimeDelta; // 25; static const double minTickInterval;
static const double maxTimeDelta; static const double maxTickInterval;
static const double kickLimit;
/// @see RsControl::setShutdownCallback /// @see RsControl::setShutdownCallback
std::function<void(int)> mShutdownCallback; std::function<void(int)> mShutdownCallback;

View file

@ -1193,7 +1193,7 @@ int RsServer::StartupRetroShare()
std::cerr << "(EE) Cannot create extensions directory " << extensions_dir std::cerr << "(EE) Cannot create extensions directory " << extensions_dir
<< ". This is not mandatory, but you probably have a permission problem." << std::endl; << ". This is not mandatory, but you probably have a permission problem." << std::endl;
#ifndef DEBUG_PLUGIN_SYSTEM #ifdef DEBUG_PLUGIN_SYSTEM
plugins_directories.push_back(".") ; // this list should be saved/set to some correct value. plugins_directories.push_back(".") ; // this list should be saved/set to some correct value.
// possible entries include: /usr/lib/retroshare, ~/.retroshare/extensions/, etc. // possible entries include: /usr/lib/retroshare, ~/.retroshare/extensions/, etc.
#endif #endif

View file

@ -542,22 +542,33 @@ void RsTypeSerializer::RawMemoryWrapper::serial_process(
ctx.mOffset += second; ctx.mOffset += second;
break; break;
case RsGenericSerializer::DESERIALIZE: case RsGenericSerializer::DESERIALIZE:
{ if(first || second)
uint32_t serialSize = 0; {
RS_SERIAL_PROCESS(serialSize); /* Items are created anew before deserialization so buffer pointer
* must be null and size 0 at this point */
RsWarn() << __PRETTY_FUNCTION__ << " DESERIALIZE got uninitialized "
<< " or pre-allocated buffer! Buffer pointer: " << first
<< " must be null and size: " << second << " must be 0 at "
<< "this point. Does your item costructor initialize them "
<< "properly?" << std::endl;
print_stacktrace();
}
RS_SERIAL_PROCESS(second);
if(!ctx.mOk) break; if(!ctx.mOk) break;
ctx.mOk = serialSize <= MAX_SERIALIZED_CHUNK_SIZE; ctx.mOk = (second <= MAX_SERIALIZED_CHUNK_SIZE);
if(!ctx.mOk) if(!ctx.mOk)
{ {
RsErr() << __PRETTY_FUNCTION__ RsErr() << __PRETTY_FUNCTION__
<< std::errc::message_size << " " << std::errc::message_size << " "
<< serialSize << " > " << MAX_SERIALIZED_CHUNK_SIZE << second << " > " << MAX_SERIALIZED_CHUNK_SIZE
<< std::endl; << std::endl;
clear(); clear();
break; break;
} }
if(!serialSize) if(!second)
{ {
Dbg3() << __PRETTY_FUNCTION__ << " Deserialized empty memory chunk" Dbg3() << __PRETTY_FUNCTION__ << " Deserialized empty memory chunk"
<< std::endl; << std::endl;
@ -565,7 +576,7 @@ void RsTypeSerializer::RawMemoryWrapper::serial_process(
break; break;
} }
ctx.mOk = ctx.mSize >= ctx.mOffset + serialSize; ctx.mOk = ctx.mSize >= ctx.mOffset + second;
if(!ctx.mOk) if(!ctx.mOk)
{ {
RsErr() << __PRETTY_FUNCTION__ << std::errc::no_buffer_space RsErr() << __PRETTY_FUNCTION__ << std::errc::no_buffer_space
@ -576,16 +587,10 @@ void RsTypeSerializer::RawMemoryWrapper::serial_process(
break; break;
} }
if(serialSize != second) first = reinterpret_cast<uint8_t*>(malloc(second));
{
first = reinterpret_cast<uint8_t*>(realloc(first, serialSize));
second = serialSize;
}
memcpy(first, ctx.mData + ctx.mOffset, second); memcpy(first, ctx.mData + ctx.mOffset, second);
ctx.mOffset += second; ctx.mOffset += second;
break; break;
}
case RsGenericSerializer::PRINT: break; case RsGenericSerializer::PRINT: break;
case RsGenericSerializer::TO_JSON: case RsGenericSerializer::TO_JSON:
{ {

View file

@ -1116,11 +1116,30 @@ bool p3GxsChannels::getChannelContent( const RsGxsGroupId& channelId,
msgIds[channelId] = contentIds; msgIds[channelId] = contentIds;
if( !requestMsgInfo(token, opts, msgIds) || waitToken(token) != RsTokenService::COMPLETE ) if( !requestMsgInfo(token, opts, msgIds) || waitToken(token) != RsTokenService::COMPLETE )
return false; return false;
return getPostData(token, posts, comments); return getPostData(token, posts, comments);
} }
bool p3GxsChannels::getChannelComments(const RsGxsGroupId &channelId,
const std::set<RsGxsMessageId> &contentIds,
std::vector<RsGxsComment> &comments)
{
std::vector<RsGxsGrpMsgIdPair> msgIds;
for (auto& msg:contentIds)
msgIds.push_back(RsGxsGrpMsgIdPair(channelId,msg));
RsTokReqOptions opts;
opts.mReqType = GXS_REQUEST_TYPE_MSG_RELATED_DATA;
opts.mOptions = RS_TOKREQOPT_MSG_THREAD | RS_TOKREQOPT_MSG_LATEST;
uint32_t token;
if( !requestMsgRelatedInfo(token, opts, msgIds) || waitToken(token) != RsTokenService::COMPLETE )
return false;
return getRelatedComments(token,comments);
}
bool p3GxsChannels::createChannelV2( bool p3GxsChannels::createChannelV2(
const std::string& name, const std::string& description, const std::string& name, const std::string& description,
const RsGxsImage& thumbnail, const RsGxsId& authorId, const RsGxsImage& thumbnail, const RsGxsId& authorId,

View file

@ -196,6 +196,11 @@ virtual bool ExtraFileRemove(const RsFileHash &hash);
std::vector<RsGxsChannelPost>& posts, std::vector<RsGxsChannelPost>& posts,
std::vector<RsGxsComment>& comments ) override; std::vector<RsGxsComment>& comments ) override;
/// Implementation of @see RsGxsChannels::getChannelComments
virtual bool getChannelComments(const RsGxsGroupId &channelId,
const std::set<RsGxsMessageId> &contentIds,
std::vector<RsGxsComment> &comments) override;
/// Implementation of @see RsGxsChannels::getContentSummaries /// Implementation of @see RsGxsChannels::getContentSummaries
bool getContentSummaries( bool getContentSummaries(
const RsGxsGroupId& channelId, const RsGxsGroupId& channelId,

View file

@ -40,7 +40,6 @@
/**** /****
* #define DEBUG_CIRCLES 1 * #define DEBUG_CIRCLES 1
****/ ****/
#define DEBUG_CIRCLES 1
/*extern*/ RsGxsCircles* rsGxsCircles = nullptr; /*extern*/ RsGxsCircles* rsGxsCircles = nullptr;

View file

@ -166,7 +166,13 @@ class RsTurtleRegExpSearchRequestItem: public RsTurtleFileSearchRequestItem
class RsTurtleGenericSearchRequestItem: public RsTurtleSearchRequestItem class RsTurtleGenericSearchRequestItem: public RsTurtleSearchRequestItem
{ {
public: public:
RsTurtleGenericSearchRequestItem() : RsTurtleSearchRequestItem(RS_TURTLE_SUBTYPE_GENERIC_SEARCH_REQUEST) {} RsTurtleGenericSearchRequestItem()
: RsTurtleSearchRequestItem(RS_TURTLE_SUBTYPE_GENERIC_SEARCH_REQUEST),
service_id(0),
search_data_len(0),
request_type(0),
search_data(nullptr)
{}
virtual ~RsTurtleGenericSearchRequestItem() { clear(); } virtual ~RsTurtleGenericSearchRequestItem() { clear(); }
uint16_t service_id ; // service to search uint16_t service_id ; // service to search
@ -221,7 +227,11 @@ class RsTurtleFTSearchResultItem: public RsTurtleSearchResultItem
class RsTurtleGenericSearchResultItem: public RsTurtleSearchResultItem class RsTurtleGenericSearchResultItem: public RsTurtleSearchResultItem
{ {
public: public:
RsTurtleGenericSearchResultItem() : RsTurtleSearchResultItem(RS_TURTLE_SUBTYPE_GENERIC_SEARCH_RESULT){} RsTurtleGenericSearchResultItem()
: RsTurtleSearchResultItem(RS_TURTLE_SUBTYPE_GENERIC_SEARCH_RESULT),
result_data(nullptr),
result_data_len(0)
{}
virtual ~RsTurtleGenericSearchResultItem() {} virtual ~RsTurtleGenericSearchResultItem() {}
uint32_t count() const { return result_data_len/50 ; } // This is a blind size estimate. We should probably use the actual size to limit search results. uint32_t count() const { return result_data_len/50 ; } // This is a blind size estimate. We should probably use the actual size to limit search results.

View file

@ -78,6 +78,11 @@ CreateCircleDialog::CreateCircleDialog()
headerText = headerItem->text(RSCIRCLEID_COL_KEYID); headerText = headerItem->text(RSCIRCLEID_COL_KEYID);
ui.IdFilter->addFilter(QIcon(), headerText, RSCIRCLEID_COL_KEYID, QString("%1 %2").arg(tr("Search"), headerText)); ui.IdFilter->addFilter(QIcon(), headerText, RSCIRCLEID_COL_KEYID, QString("%1 %2").arg(tr("Search"), headerText));
/* Set initial column width */
int fontWidth = QFontMetricsF(ui.treeWidget_IdList->font()).width("W");
ui.treeWidget_IdList->setColumnWidth(RSCIRCLEID_COL_NICKNAME, 17 * fontWidth);
ui.treeWidget_membership->setColumnWidth(RSCIRCLEID_COL_NICKNAME, 17 * fontWidth);
ui.removeButton->setEnabled(false); ui.removeButton->setEnabled(false);
ui.addButton->setEnabled(false); ui.addButton->setEnabled(false);
ui.radioButton_ListAll->setChecked(true); ui.radioButton_ListAll->setChecked(true);

View file

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1211</width> <width>721</width>
<height>647</height> <height>561</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -106,8 +106,8 @@
<string/> <string/>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../images.qrc"> <iconset resource="../icons.qrc">
<normaloff>:/images/back.png</normaloff>:/images/back.png</iconset> <normaloff>:/icons/png/arrow-left.png</normaloff>:/icons/png/arrow-left.png</iconset>
</property> </property>
</widget> </widget>
</item> </item>
@ -120,8 +120,8 @@
<string/> <string/>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../images.qrc"> <iconset resource="../icons.qrc">
<normaloff>:/images/forward.png</normaloff>:/images/forward.png</iconset> <normaloff>:/icons/png/arrow-right.png</normaloff>:/icons/png/arrow-right.png</iconset>
</property> </property>
</widget> </widget>
</item> </item>

View file

@ -34,6 +34,7 @@
#include "gui/RetroShareLink.h" #include "gui/RetroShareLink.h"
#include "gui/chat/ChatDialog.h" #include "gui/chat/ChatDialog.h"
#include "gui/Circles/CreateCircleDialog.h" #include "gui/Circles/CreateCircleDialog.h"
#include "gui/common/FilesDefs.h"
#include "gui/common/UIStateHelper.h" #include "gui/common/UIStateHelper.h"
#include "gui/common/UserNotify.h" #include "gui/common/UserNotify.h"
#include "gui/gxs/GxsIdDetails.h" #include "gui/gxs/GxsIdDetails.h"
@ -359,6 +360,9 @@ IdDialog::IdDialog(QWidget *parent) : MainPage(parent), ui(new Ui::IdDialog)
ui->idTreeWidget->setColumnWidth(RSID_COL_IDTYPE, 18 * fontWidth); ui->idTreeWidget->setColumnWidth(RSID_COL_IDTYPE, 18 * fontWidth);
ui->idTreeWidget->setColumnWidth(RSID_COL_VOTES, 2 * fontWidth); ui->idTreeWidget->setColumnWidth(RSID_COL_VOTES, 2 * fontWidth);
ui->idTreeWidget->setItemDelegateForColumn(
RSID_COL_NICKNAME,
new GxsIdTreeItemDelegate());
ui->idTreeWidget->setItemDelegateForColumn( ui->idTreeWidget->setItemDelegateForColumn(
RSID_COL_VOTES, RSID_COL_VOTES,
new ReputationItemDelegate(RsReputationLevel(0xff))); new ReputationItemDelegate(RsReputationLevel(0xff)));
@ -642,7 +646,6 @@ void IdDialog::loadCircles(const std::list<RsGroupMetaData>& groupInfo)
RsGxsCircleDetails details; RsGxsCircleDetails details;
rsGxsCircles->getCircleDetails(RsGxsCircleId(vit->mGroupId), details) ; rsGxsCircles->getCircleDetails(RsGxsCircleId(vit->mGroupId), details) ;
bool should_re_add = true ;
bool am_I_in_circle = details.mAmIAllowed ; bool am_I_in_circle = details.mAmIAllowed ;
bool am_I_admin (vit->mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN) ; bool am_I_admin (vit->mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN) ;
bool am_I_subscribed (vit->mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_SUBSCRIBED) ; bool am_I_subscribed (vit->mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_SUBSCRIBED) ;
@ -778,10 +781,13 @@ void IdDialog::loadCircles(const std::list<RsGroupMetaData>& groupInfo)
std::cerr << " no existing sub item. Creating new one." << std::endl; std::cerr << " no existing sub item. Creating new one." << std::endl;
#endif #endif
subitem = new RSTreeWidgetItem(NULL); subitem = new RSTreeWidgetItem(NULL);
subitem->setData(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,Qt::UserRole,QString::fromStdString(it->first.toStdString())); subitem->setData(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,Qt::UserRole,QString::fromStdString(it->first.toStdString()));
//Icon PlaceHolder
subitem->setIcon(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,FilesDefs::getIconFromQtResourcePath(":/icons/png/anonymous.png"));
RsIdentityDetails idd ; RsIdentityDetails idd ;
bool has_id = rsIdentity->getIdDetails(it->first,idd) ; //bool has_id =
rsIdentity->getIdDetails(it->first,idd) ;
// QPixmap pixmap ; // QPixmap pixmap ;
@ -846,31 +852,31 @@ void IdDialog::loadCircles(const std::list<RsGroupMetaData>& groupInfo)
} }
} }
// The bullet colors below are for the *Membership*. This is independent from admin rights, which cannot be shown as a color. // The bullet colors below are for the *Membership*. This is independent from admin rights, which cannot be shown as a color.
// Admin/non admin is shows using Bold font. // Admin/non admin is shows using Bold font.
if(am_I_in_circle) if(am_I_in_circle)
item->setIcon(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,QIcon(IMAGE_MEMBER)) ; item->setIcon(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,FilesDefs::getIconFromQtResourcePath(IMAGE_MEMBER)) ;
else if(am_I_invited || am_I_pending) else if(am_I_invited || am_I_pending)
item->setIcon(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,QIcon(IMAGE_INVITED)) ; item->setIcon(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,FilesDefs::getIconFromQtResourcePath(IMAGE_INVITED)) ;
else else
item->setIcon(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,QIcon(IMAGE_UNKNOWN)) ; item->setIcon(CIRCLEGROUP_CIRCLE_COL_GROUPNAME,FilesDefs::getIconFromQtResourcePath(IMAGE_UNKNOWN)) ;
} }
restoreExpandedCircleItems(expanded_top_level_items,expanded_circle_items); restoreExpandedCircleItems(expanded_top_level_items,expanded_circle_items);
} }
static void mark_matching_tree(QTreeWidget *w, const std::set<RsGxsId>& members, int col) //static void mark_matching_tree(QTreeWidget *w, const std::set<RsGxsId>& members, int col)
{ //{
w->selectionModel()->clearSelection() ; // w->selectionModel()->clearSelection() ;
//
for(std::set<RsGxsId>::const_iterator it(members.begin());it!=members.end();++it) // for(std::set<RsGxsId>::const_iterator it(members.begin());it!=members.end();++it)
{ // {
QList<QTreeWidgetItem*> clist = w->findItems( QString::fromStdString((*it).toStdString()), Qt::MatchExactly|Qt::MatchRecursive, col); // QList<QTreeWidgetItem*> clist = w->findItems( QString::fromStdString((*it).toStdString()), Qt::MatchExactly|Qt::MatchRecursive, col);
//
foreach(QTreeWidgetItem* item, clist) // foreach(QTreeWidgetItem* item, clist)
item->setSelected(true) ; // item->setSelected(true) ;
} // }
} //}
bool IdDialog::getItemCircleId(QTreeWidgetItem *item,RsGxsCircleId& id) bool IdDialog::getItemCircleId(QTreeWidgetItem *item,RsGxsCircleId& id)
{ {
@ -1257,7 +1263,7 @@ void IdDialog::updateIdList()
ui->removeIdentity->setEnabled(false); ui->removeIdentity->setEnabled(false);
ui->editIdentity->setEnabled(false); ui->editIdentity->setEnabled(false);
int accept = filter; //int accept = filter;
RsThread::async([this]() RsThread::async([this]()
{ {
@ -1364,8 +1370,9 @@ bool IdDialog::fillIdListItem(const RsGxsIdGroup& data, QTreeWidgetItem *&item,
} }
item->setText(RSID_COL_NICKNAME, QString::fromUtf8(data.mMeta.mGroupName.c_str()).left(RSID_MAXIMUM_NICKNAME_SIZE)); item->setText(RSID_COL_NICKNAME, QString::fromUtf8(data.mMeta.mGroupName.c_str()).left(RSID_MAXIMUM_NICKNAME_SIZE));
item->setText(RSID_COL_KEYID, QString::fromStdString(data.mMeta.mGroupId.toStdString())); item->setData(RSID_COL_NICKNAME, Qt::UserRole, QString::fromStdString(data.mMeta.mGroupId.toStdString()));
item->setText(RSID_COL_KEYID, QString::fromStdString(data.mMeta.mGroupId.toStdString()));
if(isBanned) if(isBanned)
{ {
@ -1416,14 +1423,16 @@ bool IdDialog::fillIdListItem(const RsGxsIdGroup& data, QTreeWidgetItem *&item,
item->setToolTip(RSID_COL_IDTYPE, tooltip) ; item->setToolTip(RSID_COL_IDTYPE, tooltip) ;
} }
QPixmap pixmap ; //QPixmap pixmap ;
//
//if(data.mImage.mSize == 0 || !GxsIdDetails::loadPixmapFromData(data.mImage.mData, data.mImage.mSize, pixmap,GxsIdDetails::SMALL))
// pixmap = GxsIdDetails::makeDefaultIcon(RsGxsId(data.mMeta.mGroupId),GxsIdDetails::SMALL) ;
//
//item->setIcon(RSID_COL_NICKNAME, QIcon(pixmap));
// Icon Place Holder
item->setIcon(RSID_COL_NICKNAME,FilesDefs::getIconFromQtResourcePath(":/icons/png/anonymous.png"));
if(data.mImage.mSize == 0 || !GxsIdDetails::loadPixmapFromData(data.mImage.mData, data.mImage.mSize, pixmap,GxsIdDetails::SMALL)) QString tooltip;
pixmap = GxsIdDetails::makeDefaultIcon(RsGxsId(data.mMeta.mGroupId),GxsIdDetails::SMALL) ;
item->setIcon(RSID_COL_NICKNAME, QIcon(pixmap));
QString tooltip;
if (data.mMeta.mGroupFlags & RSGXSID_GROUPFLAG_REALID_kept_for_compatibility) if (data.mMeta.mGroupFlags & RSGXSID_GROUPFLAG_REALID_kept_for_compatibility)
{ {
@ -1546,10 +1555,6 @@ void IdDialog::loadIdentities(const std::map<RsGxsGroupId,RsGxsIdGroup>& ids_set
else else
allItem->addChild(item); allItem->addChild(item);
GxsIdLabel *label = new GxsIdLabel();
label->setId(RsGxsId(data.mMeta.mGroupId)) ;
ui->treeWidget_membership->setItemWidget(item,0,label) ;
} }
} }

View file

@ -478,6 +478,9 @@ void MainWindow::initStackedPage()
} }
#endif #endif
addPage(newsFeed = new NewsFeed(ui->stackPages), grp, &notify);
//List All notify before Setting was created //List All notify before Setting was created
QList<QPair<MainPage*, QPair<QAction*, QListWidgetItem*> > >::iterator notifyIt; QList<QPair<MainPage*, QPair<QAction*, QListWidgetItem*> > >::iterator notifyIt;
for (notifyIt = notify.begin(); notifyIt != notify.end(); ++notifyIt) { for (notifyIt = notify.begin(); notifyIt != notify.end(); ++notifyIt) {
@ -489,7 +492,6 @@ void MainWindow::initStackedPage()
} }
} }
addPage(newsFeed = new NewsFeed(ui->stackPages), grp, &notify);
addPage(settingsDialog = new SettingsPage(ui->stackPages),grp,&notify); addPage(settingsDialog = new SettingsPage(ui->stackPages),grp,&notify);
/* Create the toolbar */ /* Create the toolbar */

View file

@ -573,7 +573,7 @@ void NewsFeed::addFeedItemIfUnique(FeedItem *item, bool replace)
} }
addFeedItem(item); addFeedItem(item);
sendNewsFeedChanged(); //sendNewsFeedChanged(); //Already done by addFeedItem()
} }
void NewsFeed::remUniqueFeedItem(FeedItem *item) void NewsFeed::remUniqueFeedItem(FeedItem *item)

View file

@ -94,6 +94,8 @@ private:
class PostedItem: public BasePostedItem class PostedItem: public BasePostedItem
{ {
Q_OBJECT
public: public:
PostedItem(FeedHolder *parent, uint32_t feedId, const RsGxsGroupId& groupId, const RsGxsMessageId& messageId, bool isHome, bool autoUpdate); PostedItem(FeedHolder *parent, uint32_t feedId, const RsGxsGroupId& groupId, const RsGxsMessageId& messageId, bool isHome, bool autoUpdate);
PostedItem(FeedHolder *parent, uint32_t feedId, const RsGroupMetaData& group_meta, const RsGxsMessageId& post_id, bool isHome, bool autoUpdate); PostedItem(FeedHolder *parent, uint32_t feedId, const RsGroupMetaData& group_meta, const RsGxsMessageId& post_id, bool isHome, bool autoUpdate);

View file

@ -27,7 +27,7 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="QFrame" name="frame"> <widget class="QFrame" name="wire_frame">
<property name="frameShape"> <property name="frameShape">
<enum>QFrame::StyledPanel</enum> <enum>QFrame::StyledPanel</enum>
</property> </property>

View file

@ -200,12 +200,14 @@ ChatWidget::ChatWidget(QWidget *parent)
#endif #endif
QMenu *menu = new QMenu(); QMenu *menu = new QMenu();
menu->addAction(ui->actionMessageHistory);
menu->addMenu(fontmenu);
menu->addSeparator();
menu->addAction(ui->actionSaveChatHistory);
menu->addAction(ui->actionClearChatHistory); menu->addAction(ui->actionClearChatHistory);
menu->addAction(ui->actionDeleteChatHistory); menu->addAction(ui->actionDeleteChatHistory);
menu->addAction(ui->actionSaveChatHistory);
menu->addAction(ui->actionMessageHistory);
ui->pushtoolsButton->setMenu(menu); ui->pushtoolsButton->setMenu(menu);
menu->addMenu(fontmenu);
ui->actionSendAsPlainText->setChecked(Settings->getChatSendAsPlainTextByDef()); ui->actionSendAsPlainText->setChecked(Settings->getChatSendAsPlainTextByDef());
ui->chatTextEdit->setOnlyPlainText(ui->actionSendAsPlainText->isChecked()); ui->chatTextEdit->setOnlyPlainText(ui->actionSendAsPlainText->isChecked());

View file

@ -241,6 +241,9 @@ border-image: url(:/images/closepressed.png)
</property> </property>
<item> <item>
<layout class="QHBoxLayout" name="typingHLayout"> <layout class="QHBoxLayout" name="typingHLayout">
<property name="leftMargin">
<number>2</number>
</property>
<item> <item>
<widget class="QLabel" name="typingPixmapLabel"> <widget class="QLabel" name="typingPixmapLabel">
<property name="minimumSize"> <property name="minimumSize">
@ -258,6 +261,9 @@ border-image: url(:/images/closepressed.png)
<property name="text"> <property name="text">
<string notr="true">T</string> <string notr="true">T</string>
</property> </property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignCenter</set> <set>Qt::AlignCenter</set>
</property> </property>
@ -448,133 +454,6 @@ border-image: url(:/images/closepressed.png)
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QToolButton" name="pushtoolsButton">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/options2.png</normaloff>:/icons/png/options2.png</iconset>
</property>
<property name="iconSize">
<size>
<width>28</width>
<height>28</height>
</size>
</property>
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="searchButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/search.png</normaloff>:/icons/png/search.png</iconset>
</property>
<property name="iconSize">
<size>
<width>28</width>
<height>28</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="LineEditClear" name="leSearch"/>
</item>
<item>
<widget class="QToolButton" name="markButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/highlight.png</normaloff>:/icons/png/highlight.png</iconset>
</property>
<property name="iconSize">
<size>
<width>28</width>
<height>28</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="searchBefore">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/arrow-left.png</normaloff>:/icons/png/arrow-left.png</iconset>
</property>
<property name="iconSize">
<size>
<width>28</width>
<height>28</height>
</size>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="searchAfter">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/arrow-right.png</normaloff>:/icons/png/arrow-right.png</iconset>
</property>
<property name="iconSize">
<size>
<width>28</width>
<height>28</height>
</size>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item> <item>
<widget class="QToolButton" name="notifyButton"> <widget class="QToolButton" name="notifyButton">
<property name="focusPolicy"> <property name="focusPolicy">
@ -786,6 +665,136 @@ border-image: url(:/images/closepressed.png)
</property> </property>
</spacer> </spacer>
</item> </item>
<item>
<widget class="QToolButton" name="searchButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/search.png</normaloff>:/icons/png/search.png</iconset>
</property>
<property name="iconSize">
<size>
<width>28</width>
<height>28</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="LineEditClear" name="leSearch"/>
</item>
<item>
<widget class="QToolButton" name="markButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/highlight.png</normaloff>:/icons/png/highlight.png</iconset>
</property>
<property name="iconSize">
<size>
<width>28</width>
<height>28</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="searchBefore">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/arrow-left.png</normaloff>:/icons/png/arrow-left.png</iconset>
</property>
<property name="iconSize">
<size>
<width>28</width>
<height>28</height>
</size>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="searchAfter">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/arrow-right.png</normaloff>:/icons/png/arrow-right.png</iconset>
</property>
<property name="iconSize">
<size>
<width>28</width>
<height>28</height>
</size>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="pushtoolsButton">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Chat menu&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/menu.png</normaloff>:/icons/png/menu.png</iconset>
</property>
<property name="iconSize">
<size>
<width>28</width>
<height>28</height>
</size>
</property>
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item> <item>
<widget class="QFrame" name="pluginTitleFrame"> <widget class="QFrame" name="pluginTitleFrame">
<property name="frameShape"> <property name="frameShape">

View file

@ -85,25 +85,32 @@ void ElidedLabel::paintEvent(QPaintEvent *event)
td.setHtml(mContent); td.setHtml(mContent);
plainText = td.toPlainText(); plainText = td.toPlainText();
} }
QRect cr(contentsRect()); QRect cr(contentsRect());
cr.adjust(margin(), margin(), -margin(), -margin()); cr.adjust(margin(), margin(), -margin(), -margin());
bool didElide = paintElidedLine(painter,plainText,cr,alignment(),wordWrap(),true,mRectElision); bool didElide = paintElidedLine(&painter,plainText,cr,font(),alignment(),wordWrap(),true,&mRectElision);
//Send signal if changed //Send signal if changed
if (didElide != mElided) if (didElide != mElided)
{ {
mElided = didElide; mElided = didElide;
emit elisionChanged(didElide); emit elisionChanged(didElide);
} }
} }
bool ElidedLabel::paintElidedLine(QPainter& painter,QString plainText,const QRect& cr,Qt::Alignment alignment,bool wordWrap,bool drawRoundRect,QRect& rectElision) bool ElidedLabel::paintElidedLine( QPainter* painter, QString plainText
, const QRect& cr, QFont useFont
, Qt::Alignment alignment, bool wordWrap
, bool drawRoundedRect, QRect* rectElision/*=nullptr*/)
{ {
if (rectElision) *rectElision = QRect();
if (plainText.isEmpty())
return false;
QList<QPair<QTextLine,QPoint> > lLines; QList<QPair<QTextLine,QPoint> > lLines;
QString elidedLastLine = ""; QString elidedLastLine = "";
QFontMetrics fontMetrics = painter.fontMetrics(); QFontMetrics fontMetrics = QFontMetrics(useFont);
bool didElide = false; bool didElide = false;
QChar ellipsisChar(0x2026);//= "…" QChar ellipsisChar(0x2026);//= "…"
@ -113,12 +120,13 @@ bool ElidedLabel::paintElidedLine(QPainter& painter,QString plainText,const QRec
plainText = plainText.replace("\n",QChar(QChar::LineSeparator)); plainText = plainText.replace("\n",QChar(QChar::LineSeparator));
plainText = plainText.replace("\r",QChar(QChar::LineSeparator)); plainText = plainText.replace("\r",QChar(QChar::LineSeparator));
QTextLayout textLayout(plainText, painter.font()); QTextLayout textLayout(plainText, useFont);
QTextOption to = textLayout.textOption(); QTextOption to = textLayout.textOption();
to.setAlignment(alignment); to.setAlignment(alignment);
to.setWrapMode(wordWrap ? QTextOption::WrapAtWordBoundaryOrAnywhere : QTextOption::NoWrap); to.setWrapMode(wordWrap ? QTextOption::WrapAtWordBoundaryOrAnywhere : QTextOption::NoWrap);
textLayout.setTextOption(to); textLayout.setTextOption(to);
if (painter) painter->save();
textLayout.beginLayout(); textLayout.beginLayout();
forever { forever {
//Get new line for text. //Get new line for text.
@ -138,7 +146,13 @@ bool ElidedLabel::paintElidedLine(QPainter& painter,QString plainText,const QRec
//The next line can't be written. //The next line can't be written.
QString lastLine = plainText.mid(line.textStart()).split(QChar(QChar::LineSeparator)).at(0); QString lastLine = plainText.mid(line.textStart()).split(QChar(QChar::LineSeparator)).at(0);
QTextLine lineEnd = textLayout.createLine(); QTextLine lineEnd = textLayout.createLine();
if (!lineEnd.isValid() && (wordWrap || (fontMetrics.width(lastLine) < cr.width()))) { if (!lineEnd.isValid() && (wordWrap
#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
|| (fontMetrics.width(lastLine) < cr.width()) ))
#else
|| (fontMetrics.horizontalAdvance(lastLine) < cr.width()) ))
#endif
{
//No more text for next line so this one is OK //No more text for next line so this one is OK
lLines.append(QPair<QTextLine, QPoint>(line, QPoint(0, y))); lLines.append(QPair<QTextLine, QPoint>(line, QPoint(0, y)));
elidedLastLine=""; elidedLastLine="";
@ -176,13 +190,17 @@ bool ElidedLabel::paintElidedLine(QPainter& painter,QString plainText,const QRec
//Now we know how many lines to redraw at good position //Now we know how many lines to redraw at good position
foreach (pair, lLines){ foreach (pair, lLines){
lastPos = pair.second + QPoint(0+ cr.left(), iTransY + cr.top()); lastPos = pair.second + QPoint(0+ cr.left(), iTransY + cr.top());
pair.first.draw(&painter, lastPos); if (painter) pair.first.draw(painter, lastPos);
} }
//Print last elided line //Print last elided line
if (didElide) if (didElide)
{ {
#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
int width = fontMetrics.width(elidedLastLine); int width = fontMetrics.width(elidedLastLine);
#else
int width = fontMetrics.horizontalAdvance(elidedLastLine);
#endif
if (lastPos.y() == -1){ if (lastPos.y() == -1){
y = iTransY;// Only one line y = iTransY;// Only one line
} else { } else {
@ -200,26 +218,32 @@ bool ElidedLabel::paintElidedLine(QPainter& painter,QString plainText,const QRec
iTransX = 0; iTransX = 0;
} }
if(width+iTransX+cr.left() <= cr.right()) if(width+iTransX+cr.left() <= cr.right())
painter.drawText(QPoint(iTransX + cr.left(), y + fontMetrics.ascent() + cr.top()), elidedLastLine); if (painter)
{
painter->setFont(useFont);
painter->drawText(QPoint(iTransX + cr.left(), y + fontMetrics.ascent() + cr.top()), elidedLastLine);
}
//Draw button to get ToolTip //Draw button to get ToolTip
#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
int fontWidth = fontMetrics.width(ellipsisChar);
#else
int fontWidth = fontMetrics.horizontalAdvance(ellipsisChar);
#endif
QRect mRectElision = QRect( iTransX + width - fontWidth + cr.left()
, y + cr.top()
, fontWidth
, fontMetrics.height() - 1);
if (rectElision)
*rectElision = mRectElision;
if(drawRoundRect) if(drawRoundedRect)
{ if (painter) painter->drawRoundedRect(mRectElision, 2 , 2);
rectElision = QRect(iTransX + width - fontMetrics.width(ellipsisChar) + cr.left()
, y + cr.top()
, fontMetrics.width(ellipsisChar)
, fontMetrics.height() - 1);
painter.drawRoundRect(rectElision);
}
else
rectElision = QRect();
} }
else
rectElision = QRect();
return didElide;
if (painter) painter->restore();
return didElide;
} }
void ElidedLabel::mousePressEvent(QMouseEvent *ev) void ElidedLabel::mousePressEvent(QMouseEvent *ev)

View file

@ -48,7 +48,23 @@ public:
QColor textColor() const { return mTextColor; } QColor textColor() const { return mTextColor; }
void setTextColor(const QColor &color); void setTextColor(const QColor &color);
static bool paintElidedLine(QPainter& painter, QString plainText, const QRect &cr, Qt::Alignment alignment, bool wordWrap, bool drawRoundRect, QRect &rectElision); /**
* @brief paintElidedLine: Draw elided() line to a painter.
* @param painter: wher to paint line. If null, only calculate rectElision.
* painter pen have to be setted before. This doesn't paint background.
* @param plainText: Plain text to paint.
* @param cr: Area where to paint. If too close, text is elided.
* @param font: Font to use to pain text.
* @param alignment: Which alignement to use for text.
* @param wordWrap: If it elide by char or by word.
* @param drawRoundRect: If rounded rect around is need. To notice user he can click on it.
* @param rectElision: Where elision occurs. To manage click. Can be omitted.
* @return If text need to be elided.
*/
static bool paintElidedLine( QPainter* painter, QString plainText
, const QRect& cr, QFont font
, Qt::Alignment alignment,bool wordWrap
, bool drawRoundedRect,QRect* rectElision = nullptr);
public slots: public slots:
void setText(const QString &text); void setText(const QString &text);

View file

@ -145,6 +145,48 @@ QIcon FilesDefs::getIconFromQtResourcePath(const QString& resource_path)
return icon; return icon;
} }
QIcon FilesDefs::getIconFromGxsIdCache(const RsGxsId& id,const QIcon& setIcon, bool& exist)
{
static std::map<RsGxsId,QIcon> mIconCache;
exist = false;
QIcon icon;
#ifdef DEBUG_FILESDEFS
std::cerr << "Creating Icon from id " << id.toStdString() ;
#endif
if (setIcon.isNull())
{
if (id.isNull())
return getIconFromQtResourcePath(":/icons/notification.png");
auto item = mIconCache.find(id);
if (item == mIconCache.end())
{
#ifdef DEBUG_FILESDEFS
std::cerr << " Not in cache. And not setted." << std::endl;
#endif
icon = getIconFromQtResourcePath(":/icons/png/anonymous.png");
}
else
{
#ifdef DEBUG_FILESDEFS
std::cerr << " In cache. " << std::endl;
#endif
icon = item->second;
exist = true;
}
}
else
{
#ifdef DEBUG_FILESDEFS
std::cerr << " Have to set it." << std::endl;
#endif
icon = setIcon;
mIconCache[id] = icon;
}
return icon;
}
QIcon FilesDefs::getIconFromFileType(const QString& filename) QIcon FilesDefs::getIconFromFileType(const QString& filename)
{ {
return getIconFromQtResourcePath(getInfoFromFilename(filename,true,true)); return getIconFromQtResourcePath(getInfoFromFilename(filename,true,true));

View file

@ -24,6 +24,8 @@
#include <QString> #include <QString>
#include <QIcon> #include <QIcon>
#include "retroshare/rsids.h"
class FilesDefs class FilesDefs
{ {
public: public:
@ -35,6 +37,7 @@ public:
static QIcon getIconFromQtResourcePath(const QString& resource_path); static QIcon getIconFromQtResourcePath(const QString& resource_path);
static QPixmap getPixmapFromQtResourcePath(const QString& resource_path); static QPixmap getPixmapFromQtResourcePath(const QString& resource_path);
static QIcon getIconFromGxsIdCache(const RsGxsId& id, const QIcon& setIcon, bool& exist);
// This method returns a QIcon that is suitable to represent a file of a particular type (image, movie, etc.) // This method returns a QIcon that is suitable to represent a file of a particular type (image, movie, etc.)

View file

@ -212,7 +212,7 @@ NewFriendList::NewFriendList(QWidget *parent) : /* RsAutoUpdatePage(5000,parent)
// workaround for Qt bug, should be solved in next Qt release 4.7.0 // workaround for Qt bug, should be solved in next Qt release 4.7.0
// http://bugreports.qt.nokia.com/browse/QTBUG-8270 // http://bugreports.qt.nokia.com/browse/QTBUG-8270
QShortcut *Shortcut = new QShortcut(QKeySequence(Qt::Key_Delete), ui->peerTreeWidget, 0, 0, Qt::WidgetShortcut); QShortcut *Shortcut = new QShortcut(QKeySequence(Qt::Key_Delete), ui->peerTreeWidget, 0, 0, Qt::WidgetShortcut);
connect(Shortcut, SIGNAL(activated()), this, SLOT(removefriend()),Qt::QueuedConnection); connect(Shortcut, SIGNAL(activated()), this, SLOT(removeItem()),Qt::QueuedConnection);
QFontMetricsF fontMetrics(ui->peerTreeWidget->font()); QFontMetricsF fontMetrics(ui->peerTreeWidget->font());
@ -915,6 +915,25 @@ void FriendsDialog::viewprofile()
* *
* All of these rely on the finding of the current Id. * All of these rely on the finding of the current Id.
*/ */
void NewFriendList::removeItem()
{
QModelIndex index = getCurrentSourceIndex();
RsFriendListModel::EntryType type = mModel->getType(index);
if(index.isValid())
{
switch (type) {
case RsFriendListModel::ENTRY_TYPE_GROUP: removeGroup();
break;
case RsFriendListModel::ENTRY_TYPE_PROFILE: removeProfile();
break;
case RsFriendListModel::ENTRY_TYPE_NODE: removeNode();
break;
case RsFriendListModel::ENTRY_TYPE_UNKNOWN: RsErr()<<__PRETTY_FUNCTION__<<" Get Item of type unknow."<<std::endl;
}
}
}
void NewFriendList::removeNode() void NewFriendList::removeNode()
{ {
RsFriendListModel::RsNodeDetails det; RsFriendListModel::RsNodeDetails det;

View file

@ -144,6 +144,7 @@ private slots:
void msgGroup(); void msgGroup();
void msgProfile(); void msgProfile();
void recommendNode(); void recommendNode();
void removeItem();
void removeNode(); void removeNode();
void removeProfile(); void removeProfile();
void createNewGroup() ; void createNewGroup() ;

View file

@ -20,170 +20,229 @@
#include "RSElidedItemDelegate.h" #include "RSElidedItemDelegate.h"
#include "gui/common/StyledElidedLabel.h"
#include "util/rsdebug.h"
#include <QApplication>
#include <QPainter> #include <QPainter>
#include <QTextDocument> #include <QTextDocument>
#include <QTextLayout> #include <QTextLayout>
#include <QToolTip> #include <QToolTip>
RSElidedItemDelegate::RSElidedItemDelegate(QObject *parent) RSElidedItemDelegate::RSElidedItemDelegate(QObject *parent)
: RSItemDelegate(parent) : RSStyledItemDelegate(parent)
, mElided(false) , mOnlyPlainText(false), mPaintRoundedRect(true)
, mOnlyPlainText(false)
, mContent("")
{ {
mRectElision = QRect(); }
QSize RSElidedItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItem ownOption (option);
initStyleOption(&ownOption, index);
const QWidget* widget = option.widget;
QStyle* ownStyle = widget ? widget->style() : QApplication::style();
//Only need "…" for text
ownOption.text = "";
QRect checkRect = ownStyle->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &ownOption, widget);
QRect iconRect = ownStyle->subElementRect(QStyle::SE_ItemViewItemDecoration, &ownOption, widget);
QRect textRect = ownStyle->subElementRect(QStyle::SE_ItemViewItemText, &ownOption, widget);
QSize contSize = ownStyle->sizeFromContents( QStyle::CT_ItemViewItem,&ownOption
,QSize( checkRect.width()+iconRect.width()+textRect.width()
,qMax(checkRect.height(),qMax(iconRect.height(),textRect.height()))),widget);
return contSize;
} }
void RSElidedItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const void RSElidedItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{ {
RSItemDelegate::paint(painter, option, index); if(!index.isValid())
}
void RSElidedItemDelegate::drawDisplay(QPainter *painter, const QStyleOptionViewItem &option,
const QRect &rect, const QString &text) const
{
if (!text.isEmpty())
{ {
mContent = text; RsErr() << __PRETTY_FUNCTION__ << " attempt to draw an invalid index." << std::endl;
QList<QPair<QTextLine,QPoint> > lLines; return ;
QString elidedLastLine = "";
QFontMetrics fontMetrics = option.fontMetrics;
QRect cr = rect;
cr.adjust(spacing().width(), spacing().height(), -spacing().width(), -spacing().height());
bool didElide = false;
QChar ellipsisChar(0x2026);//= "…"
int lineSpacing = fontMetrics.lineSpacing();
int y = 0;
QString plainText = "";
if (mOnlyPlainText)
{
plainText = mContent;
} else {
QTextDocument td;
td.setHtml(mContent);
plainText = td.toPlainText();
}
plainText = plainText.replace("\n",QChar(QChar::LineSeparator));
plainText = plainText.replace("\r",QChar(QChar::LineSeparator));
if (painter) {
painter->setFont(option.font);
QPalette::ColorGroup cg = option.state & QStyle::State_Enabled
? QPalette::Normal : QPalette::Disabled;
if (cg == QPalette::Normal && !(option.state & QStyle::State_Active))
cg = QPalette::Inactive;
QColor textColor = option.palette.color(cg, QPalette::Text);
painter->setPen(textColor);
}
QTextLayout textLayout(plainText, option.font);
QTextOption to = textLayout.textOption();
to.setAlignment(option.displayAlignment);
#if QT_VERSION >= 0x050000
bool wordWrap = option.features.testFlag(QStyleOptionViewItem::WrapText);
#else
bool wordWrap = false;
#endif
to.setWrapMode(wordWrap ? QTextOption::WrapAtWordBoundaryOrAnywhere : QTextOption::NoWrap);
textLayout.setTextOption(to);
textLayout.beginLayout();
forever {
//Get new line for text.
QTextLine line = textLayout.createLine();
if (!line.isValid())
break;// No more line to write
line.setLineWidth(cr.width());
int nextLineY = y + lineSpacing;
if ((cr.height() >= nextLineY + lineSpacing) && wordWrap) {
//Line written normaly, next line will too
lLines.append(QPair<QTextLine, QPoint>(line, QPoint(0, y)));
y = nextLineY;
} else {
//The next line can't be written.
QString lastLine = plainText.mid(line.textStart()).split(QChar(QChar::LineSeparator)).at(0);
QTextLine lineEnd = textLayout.createLine();
if (!lineEnd.isValid() && (wordWrap
|| (fontMetrics.width(lastLine) < cr.width()))) {
//No more text for next line so this one is OK
lLines.append(QPair<QTextLine, QPoint>(line, QPoint(0, y)));
elidedLastLine="";
didElide = false;
} else {
//Text is left, so get elided text
if (lastLine == "") {
elidedLastLine = ellipsisChar;
} else {
elidedLastLine = fontMetrics.elidedText(lastLine, Qt::ElideRight, cr.width()-1);
if (elidedLastLine.right(1) != ellipsisChar)
elidedLastLine.append(ellipsisChar);//New line at end
}
didElide = true;
break;
}
}
}
textLayout.endLayout();
int iTransX, iTransY = iTransX = 0;
int iHeight = lLines.count() * lineSpacing;
if (didElide) iHeight += lineSpacing;
//Compute lines translation with alignment
if (option.displayAlignment & Qt::AlignTop)
iTransY = 0;
if (option.displayAlignment & Qt::AlignBottom)
iTransY = cr.height() - iHeight;
if (option.displayAlignment & Qt::AlignVCenter)
iTransY = (cr.height() - iHeight) / 2;
QPair<QTextLine,QPoint> pair;
QPoint lastPos(-1,-1);
//Now we know how many lines to redraw at good position
foreach (pair, lLines){
lastPos = pair.second + QPoint(0 + cr.left(), iTransY + cr.top());
if (painter) pair.first.draw(painter, lastPos);
}
//Print last elided line
if (didElide) {
int width = fontMetrics.width(elidedLastLine);
if (lastPos.y() == -1){
y = iTransY;// Only one line
} else {
y = lastPos.y() + lineSpacing;
}
if (width < cr.width()){
//Text don't taking all line (with line break), so align it
if (option.displayAlignment & Qt::AlignLeft)
iTransX = 0;
if (option.displayAlignment & Qt::AlignRight)
iTransX = cr.width() - width;
if (option.displayAlignment & Qt::AlignHCenter)
iTransX = (cr.width() - width) / 2;
if (option.displayAlignment & Qt::AlignJustify)
iTransX = 0;
}
if (painter) painter->drawText(QPoint(iTransX + cr.left(), y + fontMetrics.ascent() + cr.top()), elidedLastLine);
//Draw button to get ToolTip
mRectElision = QRect(iTransX + width - fontMetrics.width(ellipsisChar) + cr.left()
, y + cr.top()
, fontMetrics.width(ellipsisChar)
, fontMetrics.height() - 1);
if (painter) painter->drawRoundRect(mRectElision);
} else {
mRectElision = QRect();
}
mElided = didElide;
} }
painter->save();
// To draw with default for debug purpose
//QStyledItemDelegate::paint(painter, option, index);
QStyleOptionViewItem ownOption (option);
initStyleOption(&ownOption, index);
//Prefer use icon from option
if (!option.icon.isNull())
ownOption.icon = option.icon;
const QWidget* widget = option.widget;
QStyle* ownStyle = widget ? widget->style() : QApplication::style();
if (!mOnlyPlainText)
{
QTextDocument td;
td.setHtml(ownOption.text);
ownOption.text = td.toPlainText();
}
//Get Font as option.font is not accurate
if (index.data(Qt::FontRole).type() == QVariant::Font) {
QFont font = index.data(Qt::FontRole).value<QFont>();
ownOption.font = font;
ownOption.fontMetrics = QFontMetrics(font);
}
QColor textColor;
if (index.data(Qt::TextColorRole).canConvert(QMetaType::QColor)) {
textColor = QColor(index.data(Qt::TextColorRole).toString());//Needs to pass from string else loose RBG format.
}
if (index.data(Qt::BackgroundRole).canConvert(QMetaType::QBrush)) {
QBrush brush(index.data(Qt::BackgroundRole).convert(QMetaType::QBrush));
ownOption.backgroundBrush = brush;
}
//Code from: https://code.woboq.org/qt5/qtbase/src/widgets/styles/qcommonstyle.cpp.html#2271
QRect checkRect = ownStyle->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &ownOption, widget);
QRect iconRect = ownStyle->subElementRect(QStyle::SE_ItemViewItemDecoration, &ownOption, widget);
QRect textRect = ownStyle->subElementRect(QStyle::SE_ItemViewItemText, &ownOption, widget);
// draw the background
ownStyle->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, widget);
// draw the check mark
if (ownOption.features & QStyleOptionViewItem::HasCheckIndicator) {
QStyleOptionViewItem option(*&ownOption);
option.rect = checkRect;
option.state = option.state & ~QStyle::State_HasFocus;
switch (ownOption.checkState) {
case Qt::Unchecked:
option.state |= QStyle::State_Off;
break;
case Qt::PartiallyChecked:
option.state |= QStyle::State_NoChange;
break;
case Qt::Checked:
option.state |= QStyle::State_On;
break;
}
ownStyle->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &option, painter, widget);
}
// draw the icon
{
QIcon::Mode mode = QIcon::Normal;
if (!(ownOption.state & QStyle::State_Enabled))
mode = QIcon::Disabled;
else if (ownOption.state & QStyle::State_Selected)
mode = QIcon::Selected;
QIcon::State state = ownOption.state & QStyle::State_Open ? QIcon::On : QIcon::Off;
ownOption.icon.paint(painter, iconRect, ownOption.decorationAlignment, mode, state);
}
// draw the text
if (!ownOption.text.isEmpty()) {
QPalette::ColorGroup cg = ownOption.state & QStyle::State_Enabled
? QPalette::Normal : QPalette::Disabled;
if (cg == QPalette::Normal && !(ownOption.state & QStyle::State_Active))
cg = QPalette::Inactive;
if (ownOption.state & QStyle::State_Selected) {
painter->setPen(ownOption.palette.color(cg, QPalette::HighlightedText));
} else {
if (ownOption.state & QStyle::State_MouseOver) {
//TODO: Manage to get palette with HOVER css pseudoclass
// For now this is hidden by Qt: https://code.woboq.org/qt5/qtbase/src/widgets/styles/qstylesheetstyle.cpp.html#6103
// So we print default in image and get it's color...
QSize moSize=sizeHint(option,index);
QImage moImg(moSize,QImage::Format_ARGB32);
QPainter moPnt;
moPnt.begin(&moImg);
moPnt.setPen(Qt::black);//Fill Image with Black
moPnt.setBrush(Qt::black);
moPnt.drawRect(moImg.rect());
QStyleOptionViewItem moOption (option);
// Define option to get only what we want
{
moOption.rect = QRect(QPoint(0,0),moSize);
moOption.state = QStyle::State_MouseOver | QStyle::State_Enabled | QStyle::State_Sibling;
moOption.text = "████████████████";
// Remove unwanted info. Yes it can draw without that all public data ...
moOption.backgroundBrush = QBrush();
moOption.checkState = Qt::Unchecked;
moOption.decorationAlignment = Qt::AlignLeft;
moOption.decorationPosition = QStyleOptionViewItem::Left;
moOption.decorationSize = QSize();
moOption.displayAlignment = Qt::AlignLeft | Qt::AlignTop;
moOption.features=0;
moOption.font = QFont();
moOption.icon = QIcon();
moOption.index = QModelIndex();
moOption.locale = QLocale();
moOption.showDecorationSelected = false;
moOption.textElideMode = Qt::ElideNone;
moOption.viewItemPosition = QStyleOptionViewItem::Middle;
//moOption.widget = nullptr; //Needed.
moOption.direction = Qt::LayoutDirectionAuto;
moOption.fontMetrics = QFontMetrics(QFont());
moOption.palette = QPalette();
moOption.styleObject = nullptr;
}
QStyledItemDelegate::paint(&moPnt, moOption, QModelIndex());
//// But these lines doesn't works.
{
//QStyleOptionViewItem moOptionsState;
//moOptionsState.initFrom(moOption.widget);
//moOptionsState.rect = QRect(QPoint(0,0),moSize);
//moOptionsState.state = QStyle::State_MouseOver | QStyle::State_Enabled | QStyle::State_Sibling;
//moOptionsState.text = "████████";
//moOptionsState.widget = option.widget;
//QStyledItemDelegate::paint(&moPnt, moOptionsState, QModelIndex());
}
moPnt.end();
// To save what it paint
//moImg.save("image.bmp");
// Get Color in this black rect.
QColor moColor;
QColor moColorBorder;// To avoid Border pixel
int moWidth = moImg.size().width(), moHeight = moImg.size().height();
for (int x = 0; (x<moWidth) && (moColor.spec() == QColor::Invalid); x++)
for (int y = 0; (y<moHeight) && (moColor.spec() == QColor::Invalid); y++)
if (moImg.pixelColor(x,y) != Qt::black)
{
if (moImg.pixelColor(x,y) == moColorBorder)
moColor = QColor(moImg.pixelColor(x,y).name());
else
{
if (moColorBorder.spec() == QColor::Invalid)
{
// First pixel border move inside
x+=5;
y+=5;
}
moColorBorder = QColor(moImg.pixelColor(x,y).name());
}
}
// If not found color is black too.
if (moColor.spec() == QColor::Invalid)
moColor = Qt::black;
painter->setPen(moColor);
}
else
if (textColor.spec()==QColor::Invalid) {
painter->setPen(ownOption.palette.color(cg, QPalette::Text));
} else { //Only get color from index for unselected(as Qt does)
painter->setPen(textColor);
}
}
if (ownOption.state & QStyle::State_Editing) {
painter->setPen(ownOption.palette.color(cg, QPalette::Text));
painter->drawRect(textRect.adjusted(0, 0, -1, -1));
}
//d->viewItemDrawText(p, &ownOption, textRect);
QTextLayout textLayout(ownOption.text, painter->font());
QTextOption to = textLayout.textOption();
StyledElidedLabel::paintElidedLine(painter,ownOption.text,textRect,ownOption.font,ownOption.displayAlignment,to.wrapMode()&QTextOption::WordWrap,mPaintRoundedRect);
}
painter->restore();
} }
bool RSElidedItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) bool RSElidedItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
@ -192,38 +251,39 @@ bool RSElidedItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
QMouseEvent *ev = static_cast<QMouseEvent *>(event); QMouseEvent *ev = static_cast<QMouseEvent *>(event);
if (ev) { if (ev) {
if (ev->buttons()==Qt::LeftButton) { if (ev->buttons()==Qt::LeftButton) {
QVariant var = index.data();
if (index.data().type() == QVariant::String) { if (index.data().type() == QVariant::String) {
QString text = index.data().toString(); QString text = index.data().toString();
if (!text.isEmpty()) { if (!text.isEmpty()) {
QRect rect = option.rect;
//Get decoration Rect to get rect == to rect sent in drawDisplay QStyleOptionViewItem ownOption (option);
if (index.data(Qt::DecorationRole).type() == QVariant::Pixmap) { initStyleOption(&ownOption, index);
QPixmap pixmap = index.data(Qt::DecorationRole).value<QPixmap>();
if (!pixmap.isNull()) rect.adjust(pixmap.width() + 6,0,0,0);//Don't know where come from these 6 pixels... const QWidget* widget = option.widget;
} QStyle* ownStyle = widget ? widget->style() : QApplication::style();
if (index.data(Qt::DecorationRole).type() == QVariant::Image) {
QImage image = index.data(Qt::DecorationRole).value<QImage>(); if (!mOnlyPlainText)
if (!image.isNull()) rect.adjust(image.width() + 6,0,0,0);//Don't know where come from these 6 pixels... {
} QTextDocument td;
if (index.data(Qt::DecorationRole).type() == QVariant::Icon) { td.setHtml(ownOption.text);
QIcon icon = index.data(Qt::DecorationRole).value<QIcon>(); ownOption.text = td.toPlainText();
if (!icon.isNull()) {
QSize size = icon.actualSize(rect.size());
rect.adjust(size.width() + 6,0,0,0);//Don't know where come from these 6 pixels...
}
} }
//Get Font as option.font is not accurate //Get Font as option.font is not accurate
QStyleOptionViewItem newOption = option;
if (index.data(Qt::FontRole).type() == QVariant::Font) { if (index.data(Qt::FontRole).type() == QVariant::Font) {
QFont font = index.data(Qt::FontRole).value<QFont>(); QFont font = index.data(Qt::FontRole).value<QFont>();
newOption.font = font; ownOption.font = font;
newOption.fontMetrics = QFontMetrics(font); ownOption.fontMetrics = QFontMetrics(font);
} }
QRect textRect = ownStyle->subElementRect(QStyle::SE_ItemViewItemText, &ownOption, widget);
QTextLayout textLayout(text, ownOption.font);
QTextOption to = textLayout.textOption();
//Update RSElidedItemDelegate as only one delegate for all items //Update RSElidedItemDelegate as only one delegate for all items
drawDisplay(NULL, newOption, rect, text); QRect rectElision;
if (mElided && (mRectElision.contains(ev->pos()))){ bool elided = StyledElidedLabel::paintElidedLine(nullptr,text,textRect,ownOption.font,ownOption.displayAlignment,to.wrapMode()&QTextOption::WordWrap,true,&rectElision);
QToolTip::showText(ev->globalPos(),QString("<FONT>") + mContent + QString("</FONT>")); if (elided && (rectElision.contains(ev->pos()))){
QToolTip::showText(ev->globalPos(),QString("<FONT>") + text + QString("</FONT>"));
return true; // eat event return true; // eat event
} }
} }
@ -231,5 +291,5 @@ bool RSElidedItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
} }
} }
} }
return RSItemDelegate::editorEvent(event, model, option, index); return RSStyledItemDelegate::editorEvent(event, model, option, index);
} }

View file

@ -23,36 +23,32 @@
#include <gui/common/RSItemDelegate.h> #include <gui/common/RSItemDelegate.h>
class RSElidedItemDelegate : public RSItemDelegate class RSElidedItemDelegate : public RSStyledItemDelegate
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(bool isElided READ isElided)
Q_PROPERTY(bool isOnlyPlainText READ isOnlyPlainText WRITE setOnlyPlainText) Q_PROPERTY(bool isOnlyPlainText READ isOnlyPlainText WRITE setOnlyPlainText)
Q_PROPERTY(QRect rectElision READ rectElision) Q_PROPERTY(bool paintRoundedRect READ paintRoundedRect WRITE setPaintRoundedRect)
public: public:
RSElidedItemDelegate(QObject *parent = 0); RSElidedItemDelegate(QObject *parent = 0);
void paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
void paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
bool isElided() const { return mElided; }
bool isOnlyPlainText() const { return mOnlyPlainText; } bool isOnlyPlainText() const { return mOnlyPlainText; }
void setOnlyPlainText(const bool &value) { mOnlyPlainText = value; } void setOnlyPlainText(const bool &value) { mOnlyPlainText = value; }
QRect rectElision() { return mRectElision; } bool paintRoundedRect() const { return mPaintRoundedRect; }
void setPaintRoundedRect(const bool &value) { mPaintRoundedRect = value; }
protected: protected:
void drawDisplay(QPainter *painter, const QStyleOptionViewItem &option,
const QRect &rect, const QString &text) const;
bool editorEvent(QEvent *event, bool editorEvent(QEvent *event,
QAbstractItemModel *model, QAbstractItemModel *model,
const QStyleOptionViewItem &option, const QStyleOptionViewItem &option,
const QModelIndex &index); const QModelIndex &index) override;
private: private:
mutable bool mElided;
bool mOnlyPlainText; bool mOnlyPlainText;
mutable QString mContent; bool mPaintRoundedRect;
mutable QRect mRectElision;
}; };

View file

@ -19,6 +19,7 @@
*******************************************************************************/ *******************************************************************************/
#include "RSItemDelegate.h" #include "RSItemDelegate.h"
#include "util/rsdebug.h"
RSItemDelegate::RSItemDelegate(QObject *parent) : QItemDelegate(parent) RSItemDelegate::RSItemDelegate(QObject *parent) : QItemDelegate(parent)
{ {
@ -61,3 +62,48 @@ void RSItemDelegate::setSpacing(const QSize &spacing)
{ {
m_spacing = spacing; m_spacing = spacing;
} }
/** RSStyledItemDelegate **/
RSStyledItemDelegate::RSStyledItemDelegate(QObject *parent) : QStyledItemDelegate(parent)
{
}
void RSStyledItemDelegate::paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItem ownOption (option);
if (m_noFocusRect.indexOf(index.column()) >= 0) {
ownOption.state &= ~QStyle::State_HasFocus; // don't show text and focus rectangle
}
QStyledItemDelegate::paint (painter, ownOption, index);
}
QSize RSStyledItemDelegate::sizeHint (const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItem ownOption (option);
if (m_noFocusRect.indexOf(index.column()) >= 0) {
ownOption.state &= ~QStyle::State_HasFocus; // don't show text and focus rectangle
}
QSize size = QStyledItemDelegate::sizeHint(ownOption, index);
size += m_spacing;
return size;
}
void RSStyledItemDelegate::removeFocusRect(int column)
{
if (m_noFocusRect.indexOf(column) == -1) {
m_noFocusRect.push_back(column);
}
}
void RSStyledItemDelegate::setSpacing(const QSize &spacing)
{
m_spacing = spacing;
}

View file

@ -22,14 +22,32 @@
#define _RSITEMDELEGATE_H #define _RSITEMDELEGATE_H
#include <QItemDelegate> #include <QItemDelegate>
#include <QStyledItemDelegate>
class RSItemDelegate : public QItemDelegate class RSItemDelegate : public QItemDelegate
{ {
public: public:
RSItemDelegate(QObject *parent = 0); RSItemDelegate(QObject *parent = nullptr);
void paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
QSize sizeHint (const QStyleOptionViewItem &option, const QModelIndex &index) const; QSize sizeHint (const QStyleOptionViewItem &option, const QModelIndex &index) const override;
void removeFocusRect(int column);
void setSpacing(const QSize &spacing);
QSize spacing() const { return m_spacing; }
private:
QList<int> m_noFocusRect;
QSize m_spacing;
};
class RSStyledItemDelegate : public QStyledItemDelegate
{
public:
RSStyledItemDelegate(QObject *parent = nullptr);
void paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
QSize sizeHint (const QStyleOptionViewItem &option, const QModelIndex &index) const override;
void removeFocusRect(int column); void removeFocusRect(int column);
void setSpacing(const QSize &spacing); void setSpacing(const QSize &spacing);

View file

@ -62,9 +62,9 @@ GxsChannelPostItem::GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId,
v.push_back(messageId); v.push_back(messageId);
setMessageVersions(v) ; setMessageVersions(v) ;
setup(); setup();
// no call to loadGroup() here because we have it already. // no call to loadGroup() here because we have it already.
} }
GxsChannelPostItem::GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId& groupId, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate,const std::set<RsGxsMessageId>& older_versions) : GxsChannelPostItem::GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId& groupId, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate,const std::set<RsGxsMessageId>& older_versions) :
@ -82,9 +82,9 @@ GxsChannelPostItem::GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId,
v.push_back(messageId); v.push_back(messageId);
setMessageVersions(v) ; setMessageVersions(v) ;
setup(); setup();
loadGroup(); loadGroup();
} }
// GxsChannelPostItem::GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsChannelPost& post, bool isHome, bool autoUpdate,const std::set<RsGxsMessageId>& older_versions) : // GxsChannelPostItem::GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId, const RsGxsChannelPost& post, bool isHome, bool autoUpdate,const std::set<RsGxsMessageId>& older_versions) :
@ -162,7 +162,7 @@ void GxsChannelPostItem::setup()
ui->voteDownButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/images/vote_down.png")); ui->voteDownButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/images/vote_down.png"));
ui->downloadButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/download.png")); ui->downloadButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/download.png"));
ui->playButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/play.png")); ui->playButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/play.png"));
ui->commentButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/commnt.png")); ui->commentButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/comment.png"));
ui->editButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/pencil-edit-button.png")); ui->editButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/pencil-edit-button.png"));
ui->copyLinkButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/copy.png")); ui->copyLinkButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/copy.png"));
ui->expandButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/down-arrow.png")); ui->expandButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/down-arrow.png"));
@ -173,6 +173,7 @@ void GxsChannelPostItem::setup()
mInFill = false; mInFill = false;
mCloseOnRead = false; mCloseOnRead = false;
mLoaded = false;
/* clear ui */ /* clear ui */
ui->titleLabel->setText(tr("Loading...")); ui->titleLabel->setText(tr("Loading..."));
@ -385,13 +386,13 @@ void GxsChannelPostItem::loadComment()
std::vector<RsGxsChannelPost> posts; std::vector<RsGxsChannelPost> posts;
std::vector<RsGxsComment> comments; std::vector<RsGxsComment> comments;
if(! rsGxsChannels->getChannelContent( groupId(),msgIds,posts,comments)) if(! rsGxsChannels->getChannelComments( groupId(),msgIds,comments))
{ {
RsErr() << "GxsGxsChannelGroupItem::loadGroup() ERROR getting data" << std::endl; RsErr() << "GxsGxsChannelGroupItem::loadGroup() ERROR getting data" << std::endl;
return; return;
} }
int comNb = comments.size(); int comNb = comments.size();
RsQThreadUtils::postToObject( [comNb,this]() RsQThreadUtils::postToObject( [comNb,this]()
{ {

View file

@ -77,7 +77,7 @@
<item> <item>
<layout class="QHBoxLayout" name="tilteHLayout"> <layout class="QHBoxLayout" name="tilteHLayout">
<item> <item>
<widget class="StyledLabel" name="titleLabel"> <widget class="StyledElidedLabel" name="titleLabel">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -486,17 +486,17 @@
</layout> </layout>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget>
<class>StyledLabel</class>
<extends>QLabel</extends>
<header>gui/common/StyledLabel.h</header>
</customwidget>
<customwidget> <customwidget>
<class>ElidedLabel</class> <class>ElidedLabel</class>
<extends>QLabel</extends> <extends>QLabel</extends>
<header location="global">gui/common/ElidedLabel.h</header> <header location="global">gui/common/ElidedLabel.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>StyledElidedLabel</class>
<extends>QLabel</extends>
<header>gui/common/StyledElidedLabel.h</header>
</customwidget>
</customwidgets> </customwidgets>
<resources> <resources>
<include location="../icons.qrc"/> <include location="../icons.qrc"/>

View file

@ -162,7 +162,7 @@
<string>Reply Message</string> <string>Reply Message</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../images.qrc"> <iconset>
<normaloff>:/images/mail_reply.png</normaloff>:/images/mail_reply.png</iconset> <normaloff>:/images/mail_reply.png</normaloff>:/images/mail_reply.png</iconset>
</property> </property>
</widget> </widget>
@ -196,7 +196,7 @@
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../icons.qrc"> <iconset resource="../icons.qrc">
<normaloff>:/icons/png/cancel.png</normaloff>:/icons/png/cancel.png</iconset> <normaloff>:/icons/mail/delete.png</normaloff>:/icons/mail/delete.png</iconset>
</property> </property>
</widget> </widget>
</item> </item>

View file

@ -27,7 +27,7 @@
/** Constructor */ /** Constructor */
GxsIdRSTreeWidgetItem::GxsIdRSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, uint32_t icon_mask,bool auto_tooltip,QTreeWidget *parent) GxsIdRSTreeWidgetItem::GxsIdRSTreeWidgetItem(const RSTreeWidgetItemCompareRole *compareRole, uint32_t icon_mask,bool auto_tooltip,QTreeWidget *parent)
: QObject(NULL), RSTreeWidgetItem(compareRole, parent), mColumn(0), mIconTypeMask(icon_mask),mAutoTooltip(auto_tooltip) : QObject(NULL), RSTreeWidgetItem(compareRole, parent), mColumn(0), mAutoTooltip(auto_tooltip), mIconTypeMask(icon_mask)
{ {
init(); init();
} }
@ -35,8 +35,8 @@ GxsIdRSTreeWidgetItem::GxsIdRSTreeWidgetItem(const RSTreeWidgetItemCompareRole *
void GxsIdRSTreeWidgetItem::init() void GxsIdRSTreeWidgetItem::init()
{ {
mIdFound = false; mIdFound = false;
mBannedState = false ;
mRetryWhenFailed = false; mRetryWhenFailed = false;
mBannedState = false ;
} }
static void fillGxsIdRSTreeWidgetItemCallback(GxsIdDetailsType type, const RsIdentityDetails &details, QObject *object, const QVariant &/*data*/) static void fillGxsIdRSTreeWidgetItemCallback(GxsIdDetailsType type, const RsIdentityDetails &details, QObject *object, const QVariant &/*data*/)
@ -179,101 +179,41 @@ QVariant GxsIdRSTreeWidgetItem::data(int column, int role) const
return RSTreeWidgetItem::data(column, role); return RSTreeWidgetItem::data(column, role);
} }
QSize GxsIdTreeItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
RsGxsId id(index.data(Qt::UserRole).toString().toStdString());
if(id.isNull())
return QStyledItemDelegate::sizeHint(option,index);
QStyleOptionViewItemV4 opt = option;
initStyleOption(&opt, index);
// disable default icon
opt.icon = QIcon();
const QRect r = option.rect;
QString str;
QList<QIcon> icons;
QString comment;
QFontMetricsF fm(option.font);
float f = fm.height();
QIcon icon ;
if(!GxsIdDetails::MakeIdDesc(id, true, str, icons, comment,GxsIdDetails::ICON_TYPE_AVATAR))
{
icon = GxsIdDetails::getLoadingIcon(id);
launchAsyncLoading();
}
else
icon = *icons.begin();
QPixmap pix = icon.pixmap(r.size());
return QSize(1.2*(pix.width() + fm.width(str)),std::max(1.1*pix.height(),1.4*fm.height()));
}
void GxsIdTreeItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex& index) const void GxsIdTreeItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex& index) const
{ {
if(!index.isValid()) if(!index.isValid())
{ {
std::cerr << "(EE) attempt to draw an invalid index." << std::endl; RsErr() << __PRETTY_FUNCTION__ << " attempt to draw an invalid index." << std::endl;
return ; return ;
} }
QStyleOptionViewItem ownOption (option);
initStyleOption(&ownOption, index);
RsGxsId id(index.data(Qt::UserRole).toString().toStdString()); RsGxsId id(index.data(Qt::UserRole).toString().toStdString());
QString cmt;
if(id.isNull())
return QStyledItemDelegate::paint(painter,option,index);
QStyleOptionViewItemV4 opt = option;
initStyleOption(&opt, index);
// disable default icon
opt.icon = QIcon();
// draw default item
QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter, 0);
QRect r = option.rect;
QString str;
QString comment;
QFontMetricsF fm(painter->font());
float f = fm.height();
QIcon icon ;
if(id.isNull()) if(id.isNull())
{ {
str = tr("[Notification]"); if (ownOption.icon.isNull())
icon = QIcon(":/icons/notification.png"); ownOption.icon = FilesDefs::getIconFromQtResourcePath(":/icons/notification.png");
} }
else if(! computeNameIconAndComment(id,str,icon,comment)) else
if(mReloadPeriod > 3) {
if(! computeNameIconAndComment(id,ownOption.text,ownOption.icon,cmt))
{ {
str = tr("[Unknown]"); if(mReloadPeriod > 3)
icon = QIcon(":/icons/anonymous.png"); {
} ownOption.text = tr("[Unknown]");
else ownOption.icon = FilesDefs::getIconFromQtResourcePath(":/icons/png/anonymous.png");
{ }
icon = GxsIdDetails::getLoadingIcon(id); else
launchAsyncLoading(); {
ownOption.icon = GxsIdDetails::getLoadingIcon(id);
launchAsyncLoading();
}
} }
}
QRect pixmaprect(r); RSElidedItemDelegate::paint(painter,ownOption,index);
pixmaprect.adjust(r.height(),0,0,0);
QPixmap pix = icon.pixmap(pixmaprect.size());
const QPoint p = QPoint(r.height()/2.0, (r.height() - pix.height())/2);
// draw pixmap at center of item
painter->drawPixmap(r.topLeft() + p, pix);
QRect mRectElision;
r.adjust(pix.height()+f,(r.height()-f)/2.0,0,0);
bool didElide = ElidedLabel::paintElidedLine(*painter,str,r,Qt::AlignLeft,false,false,mRectElision);
} }

View file

@ -27,8 +27,10 @@
#include "retroshare/rsidentity.h" #include "retroshare/rsidentity.h"
#include "retroshare/rspeers.h" #include "retroshare/rspeers.h"
#include "gui/common/FilesDefs.h"
#include "gui/common/RSTreeWidgetItem.h" #include "gui/common/RSTreeWidgetItem.h"
#include "gui/common/ElidedLabel.h" #include "gui/common/RSElidedItemDelegate.h"
#include "gui/gxs/GxsIdDetails.h" #include "gui/gxs/GxsIdDetails.h"
/***** /*****
@ -70,7 +72,7 @@ private:
bool mIdFound; bool mIdFound;
bool mBannedState ; bool mBannedState ;
bool mRetryWhenFailed; bool mRetryWhenFailed;
bool mAutoTooltip; bool mAutoTooltip;
RsReputationLevel mReputationLevel; RsReputationLevel mReputationLevel;
uint32_t mIconTypeMask; uint32_t mIconTypeMask;
RsGxsImage mAvatar; RsGxsImage mAvatar;
@ -78,18 +80,17 @@ private:
// This class is responsible of rendering authors of type RsGxsId in tree views. Used in forums, messages, etc. // This class is responsible of rendering authors of type RsGxsId in tree views. Used in forums, messages, etc.
class GxsIdTreeItemDelegate: public QStyledItemDelegate class GxsIdTreeItemDelegate: public RSElidedItemDelegate
{ {
Q_OBJECT Q_OBJECT
public: public:
GxsIdTreeItemDelegate() GxsIdTreeItemDelegate(QObject *parent = nullptr)
{ :RSElidedItemDelegate(parent), mLoading(false), mReloadPeriod(0)
mLoading = false; {
mReloadPeriod = 0; //setPaintRoudedRect(false);
} }
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex& index) const override; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex& index) const override;
void launchAsyncLoading() const void launchAsyncLoading() const
@ -116,22 +117,27 @@ public:
return true; return true;
} }
static bool computeNameIconAndComment(const RsGxsId& id,QString& name,QIcon& icon,QString& comment) static bool computeNameIconAndComment(const RsGxsId& id,QString& name,QIcon& icon,QString& comment)
{ {
QList<QIcon> icons; QList<QIcon> icons;
bool exist = false;
if(rsPeers->isFriend(RsPeerId(id))) // horrible trick because some widgets still use locations as IDs (e.g. messages)
{ if(rsPeers->isFriend(RsPeerId(id))) // horrible trick because some widgets still use locations as IDs (e.g. messages)
{
name = QString::fromUtf8(rsPeers->getPeerName(RsPeerId(id)).c_str()) ; name = QString::fromUtf8(rsPeers->getPeerName(RsPeerId(id)).c_str()) ;
icon = QIcon(":/icons/avatar_128.png"); icon = FilesDefs::getIconFromQtResourcePath(":/icons/avatar_128.png");
} }
else if(!GxsIdDetails::MakeIdDesc(id, true, name, icons, comment,GxsIdDetails::ICON_TYPE_AVATAR))
return false;
else else
icon = *icons.begin(); if(!GxsIdDetails::MakeIdDesc(id, true, name, icons, comment,GxsIdDetails::ICON_TYPE_AVATAR))
return false;
else
icon = *icons.begin();
return true; FilesDefs::getIconFromGxsIdCache(id,icon,exist);
}
return true;
}
private slots: private slots:
void reload() { mLoading=false; emit commitData(NULL) ; } void reload() { mLoading=false; emit commitData(NULL) ; }

View file

@ -28,6 +28,7 @@
#include "util/HandleRichText.h" #include "util/HandleRichText.h"
#include "util/DateTime.h" #include "util/DateTime.h"
#include "gui/gxs/GxsIdDetails.h" #include "gui/gxs/GxsIdDetails.h"
#include "gui/gxs/GxsIdTreeWidgetItem.h"
#include "GxsForumModel.h" #include "GxsForumModel.h"
#include "retroshare/rsgxsflags.h" #include "retroshare/rsgxsflags.h"
#include "retroshare/rsgxsforums.h" #include "retroshare/rsgxsforums.h"
@ -42,13 +43,9 @@ std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsew
const QString RsGxsForumModel::FilterString("filtered"); const QString RsGxsForumModel::FilterString("filtered");
RsGxsForumModel::RsGxsForumModel(QObject *parent) RsGxsForumModel::RsGxsForumModel(QObject *parent)
: QAbstractItemModel(parent) : QAbstractItemModel(parent), mUseChildTS(false),mFilteringEnabled(false),mTreeMode(TREE_MODE_TREE)
{ {
initEmptyHierarchy(mPosts); initEmptyHierarchy(mPosts);
mUseChildTS=false;
mFilteringEnabled=false;
mTreeMode = TREE_MODE_TREE;
} }
void RsGxsForumModel::preMods() void RsGxsForumModel::preMods()
@ -673,7 +670,16 @@ QVariant RsGxsForumModel::displayRole(const ForumModelPostEntry& fmpe,int col) c
} }
case COLUMN_THREAD_DISTRIBUTION: case COLUMN_THREAD_DISTRIBUTION:
case COLUMN_THREAD_AUTHOR: return QVariant(); case COLUMN_THREAD_AUTHOR:{
QString name;
RsGxsId id = RsGxsId(fmpe.mAuthorId.toStdString());
if(id.isNull())
return QVariant(tr("[Notification]"));
if(GxsIdTreeItemDelegate::computeName(id,name))
return name;
return QVariant(tr("[Unknown]"));
}
case COLUMN_THREAD_MSGID: return QVariant(); case COLUMN_THREAD_MSGID: return QVariant();
#ifdef TODO #ifdef TODO
if (filterColumn == COLUMN_THREAD_CONTENT) { if (filterColumn == COLUMN_THREAD_CONTENT) {
@ -704,12 +710,17 @@ QVariant RsGxsForumModel::userRole(const ForumModelPostEntry& fmpe,int col) cons
QVariant RsGxsForumModel::decorationRole(const ForumModelPostEntry& fmpe,int col) const QVariant RsGxsForumModel::decorationRole(const ForumModelPostEntry& fmpe,int col) const
{ {
if(col == COLUMN_THREAD_DISTRIBUTION) bool exist=false;
return QVariant(fmpe.mReputationWarningLevel); switch(col)
else if(col == COLUMN_THREAD_READ) {
return QVariant(fmpe.mMsgStatus); case COLUMN_THREAD_DISTRIBUTION:
else return QVariant(fmpe.mReputationWarningLevel);
return QVariant(); case COLUMN_THREAD_READ:
return QVariant(fmpe.mMsgStatus);
case COLUMN_THREAD_AUTHOR://Return icon as place holder.
return FilesDefs::getIconFromGxsIdCache(RsGxsId(fmpe.mAuthorId.toStdString()),QIcon(), exist);
}
return QVariant();
} }
const RsGxsGroupId& RsGxsForumModel::currentGroupId() const const RsGxsGroupId& RsGxsForumModel::currentGroupId() const

View file

@ -292,9 +292,6 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget
mLastViewType = -1; mLastViewType = -1;
// load settings
processSettings(true);
float f = QFontMetricsF(font()).height()/14.0f ; float f = QFontMetricsF(font()).height()/14.0f ;
/* Set header resize modes and initial section sizes */ /* Set header resize modes and initial section sizes */
@ -328,15 +325,10 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget
//ui->threadTreeWidget->installEventFilter(this) ; //ui->threadTreeWidget->installEventFilter(this) ;
ui->postText->clear() ; // load settings
ui->by_label->setId(RsGxsId()) ; processSettings(true);
ui->time_label->clear();
ui->lineRight->hide(); blankPost();
ui->lineLeft->hide();
ui->by_text_label->hide();
ui->by_label->hide();
ui->postText->setImageBlockWidget(ui->imageBlockWidget) ;
ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages());
ui->subscribeToolButton->setToolTip(tr( "<p>Subscribing to the forum will gather \ ui->subscribeToolButton->setToolTip(tr( "<p>Subscribing to the forum will gather \
available posts from your subscribed friends, and make the \ available posts from your subscribed friends, and make the \
@ -376,29 +368,17 @@ void GxsForumThreadWidget::handleEvent_main_thread(std::shared_ptr<const RsEvent
void GxsForumThreadWidget::blank() void GxsForumThreadWidget::blank()
{ {
ui->progressBar->hide(); ui->subscribeToolButton->hide();
ui->progressText->hide(); ui->newthreadButton->hide();
ui->postText->clear() ;
ui->by_label->setId(RsGxsId()) ;
ui->time_label->clear();
ui->lineRight->hide();
ui->lineLeft->hide();
ui->by_text_label->hide();
ui->by_label->hide();
ui->postText->setImageBlockWidget(ui->imageBlockWidget) ;
ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages());
#ifdef SUSPENDED_CODE
ui->threadTreeWidget->clear();
#endif
ui->forumName->setText(""); ui->forumName->setText("");
ui->progressText->hide();
ui->progressBar->hide();
ui->viewBox->setEnabled(false);
ui->filterLineEdit->setEnabled(false);
//mThreadModel->clear(); mThreadModel->clear();
mStateHelper->setWidgetEnabled(ui->newthreadButton, false); blankPost();
mStateHelper->setWidgetEnabled(ui->previousButton, false);
mStateHelper->setWidgetEnabled(ui->nextButton, false);
ui->versions_CB->hide();
} }
GxsForumThreadWidget::~GxsForumThreadWidget() GxsForumThreadWidget::~GxsForumThreadWidget()
@ -883,16 +863,38 @@ void GxsForumThreadWidget::clearForumDescription()
ui->postText->clear(); ui->postText->clear();
} }
void GxsForumThreadWidget::blankPost()
{
ui->newmessageButton->setEnabled(false);
ui->previousButton->setEnabled(false);
ui->nextButton->setEnabled(false);
ui->nextUnreadButton->setEnabled(false);
ui->downloadButton->setEnabled(false);
ui->lineLeft->hide();
ui->time_label->clear();
ui->versions_CB->hide();
ui->lineRight->hide();
ui->by_text_label->hide();
ui->by_label->setId(RsGxsId()) ;
ui->by_label->hide();
ui->expandButton->hide();
ui->postText->clear() ;
ui->postText->setImageBlockWidget(ui->imageBlockWidget) ;
ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages());
}
void GxsForumThreadWidget::updateForumDescription(bool success) void GxsForumThreadWidget::updateForumDescription(bool success)
{ {
if(!success) if(!success)
{ {
blank();
QString forum_description = QString("<b>ERROR:</b> Forum could not be loaded. Database might be in heavy use. Please try later."); QString forum_description = QString("<b>ERROR:</b> Forum could not be loaded. Database might be in heavy use. Please try later.");
ui->postText->setText(forum_description); ui->postText->setText(forum_description);
mStateHelper->setWidgetEnabled(ui->newthreadButton, false); mStateHelper->setWidgetEnabled(ui->newthreadButton, false);
return;
return; }
}
std::cerr << "Updating forum description" << std::endl; std::cerr << "Updating forum description" << std::endl;
if (!mThreadId.isNull()) if (!mThreadId.isNull())
@ -906,7 +908,10 @@ void GxsForumThreadWidget::updateForumDescription(bool success)
const RsGxsForumGroup& group = mForumGroup; const RsGxsForumGroup& group = mForumGroup;
ui->forumName->setText(QString::fromUtf8(group.mMeta.mGroupName.c_str())); ui->newthreadButton->show();
ui->forumName->setText(QString::fromUtf8(group.mMeta.mGroupName.c_str()));
ui->viewBox->setEnabled(true);
ui->filterLineEdit->setEnabled(true);
QString anti_spam_features1 ; QString anti_spam_features1 ;
QString forum_description; QString forum_description;
@ -1019,6 +1024,9 @@ void GxsForumThreadWidget::insertMessage()
return; return;
} }
/* blank text, incase we get nothing */
blankPost();
// We use this instead of getCurrentIndex() because right here the currentIndex() is not set yet. // We use this instead of getCurrentIndex() because right here the currentIndex() is not set yet.
QModelIndex index = mThreadProxyModel->mapFromSource(mThreadModel->getIndexOfMessage(mOrigThreadId)); QModelIndex index = mThreadProxyModel->mapFromSource(mThreadModel->getIndexOfMessage(mOrigThreadId));
@ -1043,18 +1051,7 @@ void GxsForumThreadWidget::insertMessage()
return; return;
} }
mStateHelper->setWidgetEnabled(ui->newmessageButton, (IS_GROUP_SUBSCRIBED(mForumGroup.mMeta.mSubscribeFlags) && mThreadId.isNull() == false)); ui->newmessageButton->setEnabled(IS_GROUP_SUBSCRIBED(mForumGroup.mMeta.mSubscribeFlags) && mThreadId.isNull() == false);
/* blank text, incase we get nothing */
ui->postText->clear();
ui->by_label->setId(RsGxsId()) ;
ui->time_label->clear();
ui->lineRight->hide();
ui->lineLeft->hide();
ui->by_text_label->hide();
ui->by_label->hide();
ui->postText->setImageBlockWidget(ui->imageBlockWidget) ;
ui->postText->resetImagesStatus(Settings->getForumLoadEmbeddedImages());
// add/show combobox for versions, if applicable, and enable it. If no older versions of the post available, hide the combobox. // add/show combobox for versions, if applicable, and enable it. If no older versions of the post available, hide the combobox.
@ -1145,11 +1142,12 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg)
bool redacted = bool redacted =
(overall_reputation == RsReputationLevel::LOCALLY_NEGATIVE); (overall_reputation == RsReputationLevel::LOCALLY_NEGATIVE);
ui->time_label->setText(DateTime::formatLongDateTime(msg.mMeta.mPublishTs)); ui->nextUnreadButton->setEnabled(true);
ui->by_label->setId(msg.mMeta.mAuthorId);
ui->lineRight->show();
ui->lineLeft->show(); ui->lineLeft->show();
ui->time_label->setText(DateTime::formatLongDateTime(msg.mMeta.mPublishTs));
ui->lineRight->show();
ui->by_text_label->show(); ui->by_text_label->show();
ui->by_label->setId(msg.mMeta.mAuthorId);
ui->by_label->show(); ui->by_label->show();
ui->threadTreeWidget->setFocus(); ui->threadTreeWidget->setFocus();
@ -1171,6 +1169,10 @@ void GxsForumThreadWidget::insertMessageData(const RsGxsForumMsg &msg)
QString extraTxt = RsHtml().formatText(ui->postText->document(), QString::fromUtf8(msg.mMsg.c_str()),flags); QString extraTxt = RsHtml().formatText(ui->postText->document(), QString::fromUtf8(msg.mMsg.c_str()),flags);
ui->postText->setHtml(extraTxt); ui->postText->setHtml(extraTxt);
} }
QStringList urls;
RsHtml::findAnchors(ui->postText->toHtml(), urls);
ui->downloadButton->setEnabled(urls.count() > 0);
} }
void GxsForumThreadWidget::previousMessage() void GxsForumThreadWidget::previousMessage()
@ -1675,6 +1677,9 @@ void GxsForumThreadWidget::filterItems(const QString& text)
void GxsForumThreadWidget::postForumLoading() void GxsForumThreadWidget::postForumLoading()
{ {
if(groupId().isNull())
return;
#ifdef DEBUG_FORUMS #ifdef DEBUG_FORUMS
std::cerr << "Post forum loading..." << std::endl; std::cerr << "Post forum loading..." << std::endl;
#endif #endif
@ -1719,12 +1724,15 @@ void GxsForumThreadWidget::postForumLoading()
// we also need to restore expanded threads // we also need to restore expanded threads
} }
ui->newthreadButton->show();
ui->forumName->setText(QString::fromUtf8(mForumGroup.mMeta.mGroupName.c_str())); ui->forumName->setText(QString::fromUtf8(mForumGroup.mMeta.mGroupName.c_str()));
ui->threadTreeWidget->sortByColumn(RsGxsForumModel::COLUMN_THREAD_DATE, Qt::DescendingOrder); ui->threadTreeWidget->sortByColumn(RsGxsForumModel::COLUMN_THREAD_DATE, Qt::DescendingOrder);
ui->threadTreeWidget->update(); ui->threadTreeWidget->update();
ui->viewBox->setEnabled(true);
ui->filterLineEdit->setEnabled(true);
recursRestoreExpandedItems(mThreadProxyModel->mapFromSource(mThreadModel->root()),mSavedExpandedMessages); recursRestoreExpandedItems(mThreadProxyModel->mapFromSource(mThreadModel->root()),mSavedExpandedMessages);
//mUpdating = false; //mUpdating = false;
} }
void GxsForumThreadWidget::updateGroupData() void GxsForumThreadWidget::updateGroupData()

View file

@ -178,6 +178,7 @@ private:
private: private:
void setForumDescriptionLoading(); void setForumDescriptionLoading();
void clearForumDescription(); void clearForumDescription();
void blankPost();
RsGxsGroupId mLastForumID; RsGxsGroupId mLastForumID;
RsGxsMessageId mThreadId; RsGxsMessageId mThreadId;

View file

@ -245,32 +245,6 @@
</item> </item>
<item> <item>
<layout class="QGridLayout" name="postLayout"> <layout class="QGridLayout" name="postLayout">
<item row="0" column="6">
<widget class="QToolButton" name="downloadButton">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Download all files</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/download.png</normaloff>:/icons/png/download.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QToolButton" name="newmessageButton"> <widget class="QToolButton" name="newmessageButton">
<property name="maximumSize"> <property name="maximumSize">
@ -300,53 +274,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="16"> <item row="0" column="2">
<widget class="QPushButton" name="expandButton">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/edit_remove24.png</normaloff>:/images/edit_remove24.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="10">
<widget class="Line" name="lineRight">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="0" column="13">
<spacer name="postHSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="3">
<widget class="QToolButton" name="previousButton"> <widget class="QToolButton" name="previousButton">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed"> <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
@ -384,7 +312,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="4"> <item row="0" column="3">
<widget class="QToolButton" name="nextButton"> <widget class="QToolButton" name="nextButton">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
@ -425,38 +353,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="12"> <item row="0" column="4">
<widget class="GxsIdLabel" name="by_label">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="0" column="7">
<widget class="Line" name="lineLeft">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="0" column="9">
<widget class="QComboBox" name="versions_CB"/>
</item>
<item row="0" column="8">
<widget class="QLabel" name="time_label">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="0" column="11">
<widget class="QLabel" name="by_text_label">
<property name="text">
<string>By </string>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QToolButton" name="nextUnreadButton"> <widget class="QToolButton" name="nextUnreadButton">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
@ -479,6 +376,109 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="5">
<widget class="QToolButton" name="downloadButton">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Download all files</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/download.png</normaloff>:/icons/png/download.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="Line" name="lineLeft">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="0" column="7">
<widget class="QLabel" name="time_label">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="0" column="8">
<widget class="QComboBox" name="versions_CB"/>
</item>
<item row="0" column="9">
<widget class="Line" name="lineRight">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="0" column="10">
<widget class="QLabel" name="by_text_label">
<property name="text">
<string>By </string>
</property>
</widget>
</item>
<item row="0" column="11">
<widget class="GxsIdLabel" name="by_label">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="0" column="12">
<spacer name="postHSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="13">
<widget class="QPushButton" name="expandButton">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/edit_remove24.png</normaloff>:/images/edit_remove24.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>

View file

@ -91,6 +91,7 @@
<file>icons/png/leave2.png</file> <file>icons/png/leave2.png</file>
<file>icons/png/messages-notify.png</file> <file>icons/png/messages-notify.png</file>
<file>icons/png/messages.png</file> <file>icons/png/messages.png</file>
<file>icons/png/menu.png</file>
<file>icons/png/microphone_mute.png</file> <file>icons/png/microphone_mute.png</file>
<file>icons/png/microphone.png</file> <file>icons/png/microphone.png</file>
<file>icons/png/netgraph.png</file> <file>icons/png/netgraph.png</file>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -418,16 +418,23 @@ void ImHistoryBrowser::customContextMenuRequested(QPoint /*pos*/)
void ImHistoryBrowser::copyMessage() void ImHistoryBrowser::copyMessage()
{ {
QListWidgetItem *currentItem = ui.listWidget->currentItem(); QListWidgetItem *currentItem = ui.listWidget->currentItem();
if (currentItem) { if (currentItem) {
uint32_t msgId = currentItem->data(ROLE_MSGID).toString().toInt(); uint32_t msgId = currentItem->data(ROLE_MSGID).toString().toInt();
HistoryMsg msg; HistoryMsg msg;
if (rsHistory->getMessage(msgId, msg)) { if (rsHistory->getMessage(msgId, msg)) {
QTextDocument doc; RsIdentityDetails details;
doc.setHtml(QString::fromUtf8(msg.message.c_str())); QString name = (rsIdentity->getIdDetails(RsGxsId(msg.peerName), details))
QApplication::clipboard()->setText(doc.toPlainText()); ? QString::fromUtf8(details.mNickname.c_str())
} : QString::fromUtf8(msg.peerName.c_str());
} QDateTime date = msg.incoming
? QDateTime::fromTime_t(msg.sendTime)
: QDateTime::fromTime_t(msg.recvTime);
QTextDocument doc;
doc.setHtml(QString::fromUtf8(msg.message.c_str()));
QApplication::clipboard()->setText("> " + date.toString() + " " + name + ":" + doc.toPlainText());
}
}
} }
void ImHistoryBrowser::removeMessages() void ImHistoryBrowser::removeMessages()

View file

@ -487,7 +487,16 @@ QVariant RsMessageModel::displayRole(const Rs::Msgs::MsgInfoSummary& fmpe,int co
} }
return text; return text;
} }
case COLUMN_THREAD_AUTHOR: return QVariant(); case COLUMN_THREAD_AUTHOR:{
QString name;
RsGxsId id = RsGxsId(fmpe.srcId.toStdString());
if(id.isNull())
return QVariant(tr("[Notification]"));
if(GxsIdTreeItemDelegate::computeName(id,name))
return name;
return QVariant(tr("[Unknown]"));
}
default: default:
return QVariant("[ TODO ]"); return QVariant("[ TODO ]");
@ -510,42 +519,41 @@ QVariant RsMessageModel::userRole(const Rs::Msgs::MsgInfoSummary& fmpe,int col)
QVariant RsMessageModel::decorationRole(const Rs::Msgs::MsgInfoSummary& fmpe,int col) const QVariant RsMessageModel::decorationRole(const Rs::Msgs::MsgInfoSummary& fmpe,int col) const
{ {
if(col == COLUMN_THREAD_READ) bool exist=false;
if(fmpe.msgflags & (RS_MSG_NEW | RS_MSG_UNREAD_BY_USER)) switch(col)
return FilesDefs::getIconFromQtResourcePath(":/images/message-state-unread.png"); {
else case COLUMN_THREAD_READ:
return FilesDefs::getIconFromQtResourcePath(":/images/message-state-read.png"); return (fmpe.msgflags & (RS_MSG_NEW | RS_MSG_UNREAD_BY_USER))
? FilesDefs::getIconFromQtResourcePath(":/images/message-state-unread.png")
: FilesDefs::getIconFromQtResourcePath(":/images/message-state-read.png");
case COLUMN_THREAD_SUBJECT:
{
if(fmpe.msgflags & RS_MSG_NEW ) return FilesDefs::getIconFromQtResourcePath(":/images/message-state-new.png");
if(fmpe.msgflags & RS_MSG_USER_REQUEST) return FilesDefs::getIconFromQtResourcePath(":/images/user/user_request16.png");
if(fmpe.msgflags & RS_MSG_FRIEND_RECOMMENDATION) return FilesDefs::getIconFromQtResourcePath(":/images/user/friend_suggestion16.png");
if(fmpe.msgflags & RS_MSG_PUBLISH_KEY) return FilesDefs::getIconFromQtResourcePath(":/images/share-icon-16.png");
if(col == COLUMN_THREAD_SUBJECT) if(fmpe.msgflags & RS_MSG_UNREAD_BY_USER)
{ {
if(fmpe.msgflags & RS_MSG_NEW ) return FilesDefs::getIconFromQtResourcePath(":/images/message-state-new.png"); if((fmpe.msgflags & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == RS_MSG_REPLIED) return FilesDefs::getIconFromQtResourcePath(":/images/message-mail-replied.png");
if(fmpe.msgflags & RS_MSG_USER_REQUEST) return FilesDefs::getIconFromQtResourcePath(":/images/user/user_request16.png"); if((fmpe.msgflags & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == RS_MSG_FORWARDED) return FilesDefs::getIconFromQtResourcePath(":/images/message-mail-forwarded.png");
if(fmpe.msgflags & RS_MSG_FRIEND_RECOMMENDATION) return FilesDefs::getIconFromQtResourcePath(":/images/user/friend_suggestion16.png"); if((fmpe.msgflags & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == (RS_MSG_REPLIED | RS_MSG_FORWARDED)) return FilesDefs::getIconFromQtResourcePath(":/images/message-mail-replied-forw.png");
if(fmpe.msgflags & RS_MSG_PUBLISH_KEY) return FilesDefs::getIconFromQtResourcePath(":/images/share-icon-16.png");
if(fmpe.msgflags & RS_MSG_UNREAD_BY_USER) return FilesDefs::getIconFromQtResourcePath(":/images/message-mail.png");
{ }
if((fmpe.msgflags & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == RS_MSG_REPLIED) return FilesDefs::getIconFromQtResourcePath(":/images/message-mail-replied.png"); if((fmpe.msgflags & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == RS_MSG_REPLIED) return FilesDefs::getIconFromQtResourcePath(":/images/message-mail-replied-read.png");
if((fmpe.msgflags & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == RS_MSG_FORWARDED) return FilesDefs::getIconFromQtResourcePath(":/images/message-mail-forwarded.png"); if((fmpe.msgflags & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == RS_MSG_FORWARDED) return FilesDefs::getIconFromQtResourcePath(":/images/message-mail-forwarded-read.png");
if((fmpe.msgflags & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == (RS_MSG_REPLIED | RS_MSG_FORWARDED)) return FilesDefs::getIconFromQtResourcePath(":/images/message-mail-replied-forw.png"); if((fmpe.msgflags & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == (RS_MSG_REPLIED | RS_MSG_FORWARDED)) return FilesDefs::getIconFromQtResourcePath(":/images/message-mail-replied-forw-read.png");
return FilesDefs::getIconFromQtResourcePath(":/images/message-mail.png"); return FilesDefs::getIconFromQtResourcePath(":/images/message-mail-read.png");
} }
if((fmpe.msgflags & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == RS_MSG_REPLIED) return FilesDefs::getIconFromQtResourcePath(":/images/message-mail-replied-read.png");
if((fmpe.msgflags & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == RS_MSG_FORWARDED) return FilesDefs::getIconFromQtResourcePath(":/images/message-mail-forwarded-read.png");
if((fmpe.msgflags & (RS_MSG_REPLIED | RS_MSG_FORWARDED)) == (RS_MSG_REPLIED | RS_MSG_FORWARDED)) return FilesDefs::getIconFromQtResourcePath(":/images/message-mail-replied-forw-read.png");
return FilesDefs::getIconFromQtResourcePath(":/images/message-mail-read.png"); case COLUMN_THREAD_STAR:
} return FilesDefs::getIconFromQtResourcePath((fmpe.msgflags & RS_MSG_STAR) ? (IMAGE_STAR_ON ): (IMAGE_STAR_OFF));
if(col == COLUMN_THREAD_STAR)
return FilesDefs::getIconFromQtResourcePath((fmpe.msgflags & RS_MSG_STAR) ? (IMAGE_STAR_ON ): (IMAGE_STAR_OFF));
bool isNew = fmpe.msgflags & (RS_MSG_NEW | RS_MSG_UNREAD_BY_USER);
if(col == COLUMN_THREAD_READ)
return FilesDefs::getIconFromQtResourcePath(isNew ? ":/images/message-state-unread.png": ":/images/message-state-read.png");
case COLUMN_THREAD_AUTHOR://Return icon as place holder.
return FilesDefs::getIconFromGxsIdCache(RsGxsId(fmpe.srcId.toStdString()),QIcon(), exist);
}
return QVariant(); return QVariant();
} }

View file

@ -55,7 +55,7 @@ MessageWindow::MessageWindow(QWidget *parent, Qt::WindowFlags flags)
msgWidget = NULL; msgWidget = NULL;
// create tag menu // create tag menu
TagsMenu *menu = new TagsMenu (tr("Tags"), this); TagsMenu *menu = new TagsMenu (tr("Tags"), this);
connect(menu, SIGNAL(aboutToShow()), this, SLOT(tagAboutToShow())); connect(menu, SIGNAL(aboutToShow()), this, SLOT(tagAboutToShow()));
connect(menu, SIGNAL(tagSet(int, bool)), this, SLOT(tagSet(int, bool))); connect(menu, SIGNAL(tagSet(int, bool)), this, SLOT(tagSet(int, bool)));
@ -63,12 +63,6 @@ MessageWindow::MessageWindow(QWidget *parent, Qt::WindowFlags flags)
ui.tagButton->setMenu(menu); ui.tagButton->setMenu(menu);
// create print menu
QMenu *printmenu = new QMenu();
printmenu->addAction(ui.actionPrint);
printmenu->addAction(ui.actionPrint_Preview);
ui.printButton->setMenu(printmenu);
// create view menu // create view menu
QMenu *viewmenu = new QMenu(); QMenu *viewmenu = new QMenu();
viewmenu->addAction(ui.actionTextBesideIcon); viewmenu->addAction(ui.actionTextBesideIcon);
@ -92,7 +86,7 @@ void MessageWindow::processSettings(bool load)
// load settings // load settings
/* toolbar button style */ /* toolbar button style */
Qt::ToolButtonStyle style = (Qt::ToolButtonStyle) Settings->value("ToolButon_Stlye", Qt::ToolButtonIconOnly).toInt(); Qt::ToolButtonStyle style = (Qt::ToolButtonStyle) Settings->value("ToolButon_Stlye", Qt::ToolButtonTextBesideIcon).toInt();
setToolbarButtonStyle(style); setToolbarButtonStyle(style);
} else { } else {
// save settings // save settings
@ -115,11 +109,6 @@ void MessageWindow::addWidget(MessageWidget *widget)
ui.msgLayout->addWidget(msgWidget); ui.msgLayout->addWidget(msgWidget);
setWindowTitle(msgWidget->subject(true)); setWindowTitle(msgWidget->subject(true));
msgWidget->connectAction(MessageWidget::ACTION_REMOVE, ui.removemessageButton);
msgWidget->connectAction(MessageWidget::ACTION_REPLY, ui.replymessageButton);
msgWidget->connectAction(MessageWidget::ACTION_REPLY_ALL, ui.replyallmessageButton);
msgWidget->connectAction(MessageWidget::ACTION_FORWARD, ui.forwardmessageButton);
msgWidget->connectAction(MessageWidget::ACTION_PRINT, ui.printButton);
msgWidget->connectAction(MessageWidget::ACTION_PRINT, ui.actionPrint); msgWidget->connectAction(MessageWidget::ACTION_PRINT, ui.actionPrint);
msgWidget->connectAction(MessageWidget::ACTION_PRINT, actionPrint); msgWidget->connectAction(MessageWidget::ACTION_PRINT, actionPrint);
msgWidget->connectAction(MessageWidget::ACTION_PRINT_PREVIEW, ui.actionPrint_Preview); msgWidget->connectAction(MessageWidget::ACTION_PRINT_PREVIEW, ui.actionPrint_Preview);
@ -210,13 +199,7 @@ void MessageWindow::setupFileActions()
void MessageWindow::setToolbarButtonStyle(Qt::ToolButtonStyle style) void MessageWindow::setToolbarButtonStyle(Qt::ToolButtonStyle style)
{ {
ui.newmessageButton->setToolButtonStyle(style); ui.newmessageButton->setToolButtonStyle(style);
ui.removemessageButton->setToolButtonStyle(style);
ui.replymessageButton->setToolButtonStyle(style);
ui.replyallmessageButton->setToolButtonStyle(style);
ui.forwardmessageButton->setToolButtonStyle(style);
ui.tagButton->setToolButtonStyle(style); ui.tagButton->setToolButtonStyle(style);
ui.printButton->setToolButtonStyle(style);
ui.viewtoolButton->setToolButtonStyle(style);
} }
void MessageWindow::buttonStyle() void MessageWindow::buttonStyle()

View file

@ -81,8 +81,8 @@
<string>Compose</string> <string>Compose</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../images.qrc"> <iconset resource="../icons.qrc">
<normaloff>:/images/folder-draft24.png</normaloff>:/images/folder-draft24.png</iconset> <normaloff>:/icons/mail/compose.png</normaloff>:/icons/mail/compose.png</iconset>
</property> </property>
<property name="iconSize"> <property name="iconSize">
<size> <size>
@ -91,7 +91,7 @@
</size> </size>
</property> </property>
<property name="toolButtonStyle"> <property name="toolButtonStyle">
<enum>Qt::ToolButtonIconOnly</enum> <enum>Qt::ToolButtonTextBesideIcon</enum>
</property> </property>
<property name="autoRaise"> <property name="autoRaise">
<bool>true</bool> <bool>true</bool>
@ -105,174 +105,20 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="2"> <item row="0" column="4">
<widget class="QToolButton" name="replymessageButton"> <spacer name="toolBarFrameHSpacer">
<property name="focusPolicy"> <property name="orientation">
<enum>Qt::NoFocus</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="toolTip"> <property name="sizeHint" stdset="0">
<string>Reply to selected message</string>
</property>
<property name="text">
<string>Reply</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/replymail-pressed.png</normaloff>:/images/replymail-pressed.png</iconset>
</property>
<property name="iconSize">
<size> <size>
<width>24</width> <width>40</width>
<height>24</height> <height>20</height>
</size> </size>
</property> </property>
<property name="toolButtonStyle"> </spacer>
<enum>Qt::ToolButtonIconOnly</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item> </item>
<item row="0" column="3"> <item row="0" column="3">
<widget class="QToolButton" name="replyallmessageButton">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Reply all to selected message</string>
</property>
<property name="text">
<string>Reply all</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/replymailall24-hover.png</normaloff>:/images/replymailall24-hover.png</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonIconOnly</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QToolButton" name="forwardmessageButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777</width>
<height>16777</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Forward selected message</string>
</property>
<property name="text">
<string>Forward</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/mailforward24-hover.png</normaloff>:/images/mailforward24-hover.png</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonIconOnly</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="Line" name="toolBarFrameLineR">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="0" column="7">
<widget class="QToolButton" name="removemessageButton">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Remove selected message</string>
</property>
<property name="text">
<string>Delete</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/deletemail24.png</normaloff>:/images/deletemail24.png</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonIconOnly</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="8">
<widget class="QToolButton" name="printButton">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Print selected message</string>
</property>
<property name="text">
<string>Print</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/print24.png</normaloff>:/images/print24.png</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="popupMode">
<enum>QToolButton::MenuButtonPopup</enum>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonIconOnly</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="9">
<widget class="QToolButton" name="viewtoolButton"> <widget class="QToolButton" name="viewtoolButton">
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::NoFocus</enum> <enum>Qt::NoFocus</enum>
@ -291,27 +137,14 @@
</size> </size>
</property> </property>
<property name="popupMode"> <property name="popupMode">
<enum>QToolButton::MenuButtonPopup</enum> <enum>QToolButton::InstantPopup</enum>
</property> </property>
<property name="autoRaise"> <property name="autoRaise">
<bool>true</bool> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="10"> <item row="0" column="2">
<spacer name="toolBarFrameHSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="6">
<widget class="QToolButton" name="tagButton"> <widget class="QToolButton" name="tagButton">
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::NoFocus</enum> <enum>Qt::NoFocus</enum>
@ -323,8 +156,8 @@
<string>Tags</string> <string>Tags</string>
</property> </property>
<property name="icon"> <property name="icon">
<iconset resource="../images.qrc"> <iconset resource="../icons.qrc">
<normaloff>:/images/tag24.png</normaloff>:/images/tag24.png</iconset> <normaloff>:/icons/mail/tags.png</normaloff>:/icons/mail/tags.png</iconset>
</property> </property>
<property name="iconSize"> <property name="iconSize">
<size> <size>
@ -333,7 +166,10 @@
</size> </size>
</property> </property>
<property name="popupMode"> <property name="popupMode">
<enum>QToolButton::MenuButtonPopup</enum> <enum>QToolButton::InstantPopup</enum>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property> </property>
<property name="autoRaise"> <property name="autoRaise">
<bool>true</bool> <bool>true</bool>
@ -355,7 +191,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>698</width> <width>698</width>
<height>20</height> <height>21</height>
</rect> </rect>
</property> </property>
</widget> </widget>
@ -396,6 +232,7 @@
</widget> </widget>
<resources> <resources>
<include location="../images.qrc"/> <include location="../images.qrc"/>
<include location="../icons.qrc"/>
</resources> </resources>
<connections/> <connections/>
</ui> </ui>

View file

@ -147,11 +147,11 @@ MessagesDialog::MessagesDialog(QWidget *parent)
changeBox(0); // set to inbox changeBox(0); // set to inbox
ui.messageTreeWidget->setItemDelegateForColumn(RsMessageModel::COLUMN_THREAD_AUTHOR,new GxsIdTreeItemDelegate()) ;
RSElidedItemDelegate *itemDelegate = new RSElidedItemDelegate(this); RSElidedItemDelegate *itemDelegate = new RSElidedItemDelegate(this);
itemDelegate->setSpacing(QSize(0, 2)); itemDelegate->setSpacing(QSize(0, 2));
ui.messageTreeWidget->setItemDelegate(itemDelegate); ui.messageTreeWidget->setItemDelegateForColumn(RsMessageModel::COLUMN_THREAD_SUBJECT,itemDelegate);
ui.messageTreeWidget->setItemDelegateForColumn(RsMessageModel::COLUMN_THREAD_AUTHOR,new GxsIdTreeItemDelegate()) ;
// workaround for Qt bug, should be solved in next Qt release 4.7.0 // workaround for Qt bug, should be solved in next Qt release 4.7.0
// http://bugreports.qt.nokia.com/browse/QTBUG-8270 // http://bugreports.qt.nokia.com/browse/QTBUG-8270
@ -484,10 +484,9 @@ int MessagesDialog::getSelectedMsgCount (QList<QModelIndex> *items, QList<QModel
items->append(m); items->append(m);
if (m.data(RsMessageModel::UnreadRole).toBool()) if (m.data(RsMessageModel::UnreadRole).toBool())
if (itemsUnread) { if (itemsUnread) itemsUnread->append(m); }
itemsUnread->append(m); else
else if(itemsRead) { if (itemsRead) itemsRead->append(m); }
itemsRead->append(m);
if (itemsStar && m.data(RsMessageModel::MsgFlagsRole).toInt() & RS_MSG_STAR) if (itemsStar && m.data(RsMessageModel::MsgFlagsRole).toInt() & RS_MSG_STAR)
itemsStar->append(m); itemsStar->append(m);

View file

@ -571,54 +571,63 @@ IdEditDialog QLabel#info_label
background: #FFFFD7; background: #FFFFD7;
background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFFFD7, stop:1 #FFFFB2); background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFFFD7, stop:1 #FFFFB2);
} }
GenCertDialog QComboBox#genPGPuser { GenCertDialog QComboBox#genPGPuser {
border: 2px solid #0099cc; border: 2px solid #0099cc;
border-radius: 6px; border-radius: 6px;
background: white; background: white;
font: bold; font: bold;
} }
GenCertDialog QSpinBox#hiddenport_spinBox { GenCertDialog QSpinBox#hiddenport_spinBox {
border: 2px solid #0099cc; border: 2px solid #0099cc;
border-radius: 6px; border-radius: 6px;
background: white; background: white;
font: bold; font: bold;
} }
GenCertDialog QLineEdit#hiddenaddr_input { GenCertDialog QLineEdit#hiddenaddr_input {
border: 2px solid #0099cc; border: 2px solid #0099cc;
border-radius: 6px; border-radius: 6px;
background: white; background: white;
font: bold; font: bold;
} }
GenCertDialog QLineEdit#password2_input { GenCertDialog QLineEdit#password2_input {
border: 2px solid #0099cc; border: 2px solid #0099cc;
border-radius: 6px; border-radius: 6px;
background: white; background: white;
font: bold; font: bold;
} }
GenCertDialog QLineEdit#password_input { GenCertDialog QLineEdit#password_input {
border: 2px solid #0099cc; border: 2px solid #0099cc;
border-radius: 6px; border-radius: 6px;
background: white; background: white;
font: bold; font: bold;
} }
GenCertDialog QLineEdit#nickname_input { GenCertDialog QLineEdit#nickname_input {
border: 2px solid #0099cc; border: 2px solid #0099cc;
border-radius: 6px; border-radius: 6px;
background: white; background: white;
font: bold; font: bold;
} }
GenCertDialog QLineEdit#node_input { GenCertDialog QLineEdit#node_input {
border: 2px solid #0099cc; border: 2px solid #0099cc;
border-radius: 6px; border-radius: 6px;
background: white; background: white;
font: bold; font: bold;
} }
GenCertDialog QLineEdit#name_input { GenCertDialog QLineEdit#name_input {
border: 2px solid #0099cc; border: 2px solid #0099cc;
border-radius: 6px; border-radius: 6px;
background: white; background: white;
font: bold; font: bold;
} }
GenCertDialog QPushButton#genButton { GenCertDialog QPushButton#genButton {
border-image: url(:/images/btn_blue.png) 4; border-image: url(:/images/btn_blue.png) 4;
border-width: 4; border-width: 4;
@ -732,6 +741,10 @@ GxsForumThreadWidget QToolButton#subscribeToolButton:hover {
border-radius: 4px; border-radius: 4px;
} }
GxsForumMsgItem QFrame#frame{
background-color: white;
}
GxsChannelPostsWidget QFrame#infoFrame GxsChannelPostsWidget QFrame#infoFrame
{ {
@ -787,6 +800,10 @@ PostedItem QFrame#frame_notes {
background: white; background: white;
} }
PostedItem QFrame#mainFrame {
background-color: white;
}
PostedItem QLabel#notes { PostedItem QLabel#notes {
} }
@ -832,6 +849,11 @@ PostedCardView QFrame#voteFrame {
background: #f8f9fa; background: #f8f9fa;
} }
PostedCardView QFrame#mainFrame {
background: white;
}
GxsCommentDialog QComboBox#sortBox { GxsCommentDialog QComboBox#sortBox {
font: bold; font: bold;
color: #0099cc; color: #0099cc;
@ -870,3 +892,18 @@ WireGroupItem QWidget:hover
background-color: #7ecbfb; background-color: #7ecbfb;
} }
WireDialog QFrame#frame{
background-color: white;
}
WireDialog QWidget#scrollAreaWidgetContents_groups{
background-color: white;
}
MessagesDialog QWidget#messageTreeWidget::item {
padding: 2px;
}
GxsForumThreadWidget QWidget#threadTreeWidget::item {
padding: 2px;
}

View file

@ -57,6 +57,7 @@ RSPermissionMatrixWidget::RSPermissionMatrixWidget(QWidget *parent)
:QFrame(parent) :QFrame(parent)
{ {
_painter = new QPainter(); _painter = new QPainter();
_current_service_id = 0;
setMouseTracking(true) ; setMouseTracking(true) ;

View file

@ -91,8 +91,6 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags)
ui.tabWidget->removeTab(TAB_RELAYS) ; // remove relays. Not useful in Tor mode. ui.tabWidget->removeTab(TAB_RELAYS) ; // remove relays. Not useful in Tor mode.
ui.tabWidget->removeTab(TAB_IP_FILTERS) ; // remove IP filters. Not useful in Tor mode. ui.tabWidget->removeTab(TAB_IP_FILTERS) ; // remove IP filters. Not useful in Tor mode.
ui.hiddenServiceTab->removeTab(TAB_HIDDEN_SERVICE_I2P_BOB) ; // remove the Automatic I2P/BOB tab
ui.hiddenpage_proxyAddress_i2p->hide() ; ui.hiddenpage_proxyAddress_i2p->hide() ;
ui.hiddenpage_proxyLabel_i2p->hide() ; ui.hiddenpage_proxyLabel_i2p->hide() ;
ui.hiddenpage_proxyPort_i2p->hide() ; ui.hiddenpage_proxyPort_i2p->hide() ;
@ -109,8 +107,7 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags)
} }
else else
{ {
ui.hiddenServiceTab->removeTab(TAB_HIDDEN_SERVICE_I2P_BOB); // warning: the order of operation here is very important. ui.hiddenServiceTab->removeTab(TAB_HIDDEN_SERVICE_INCOMING); // warning: the order of operation here is very important.
ui.hiddenServiceTab->removeTab(TAB_HIDDEN_SERVICE_INCOMING);
} }
ui.filteredIpsTable->setHorizontalHeaderItem(COLUMN_RANGE,new QTableWidgetItem(tr("IP Range"))) ; ui.filteredIpsTable->setHorizontalHeaderItem(COLUMN_RANGE,new QTableWidgetItem(tr("IP Range"))) ;

View file

@ -113,10 +113,10 @@ void RshareSettings::initSettings()
#else #else
static QStringList styles = QStyleFactory::keys(); static QStringList styles = QStyleFactory::keys();
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
if (styles.contains("windowsvista", Qt::CaseInsensitive)) if (styles.contains("Fusion", Qt::CaseInsensitive))
setDefault(SETTING_STYLE, "Fusion");
else if (styles.contains("windowsvista", Qt::CaseInsensitive))
setDefault(SETTING_STYLE, "windowsvista"); setDefault(SETTING_STYLE, "windowsvista");
else if (styles.contains("windowsxp", Qt::CaseInsensitive))
setDefault(SETTING_STYLE, "windowsxp");
else else
#endif #endif
{ {

View file

@ -23,7 +23,7 @@ FriendSelectionWidget
qproperty-textColorOnline: lightBlue; qproperty-textColorOnline: lightBlue;
} }
FriendList NewFriendList
{ {
qproperty-textColorStatusOffline: white; qproperty-textColorStatusOffline: white;
qproperty-textColorStatusAway: gray; qproperty-textColorStatusAway: gray;

View file

@ -1940,7 +1940,7 @@ PlotWidget {
padding: 0px; /* to fix cut labels in plots #134 */ padding: 0px; /* to fix cut labels in plots #134 */
} }
FriendList { NewFriendList {
qproperty-textColorStatusAway: lightgray; qproperty-textColorStatusAway: lightgray;
qproperty-textColorStatusBusy: lightgray; qproperty-textColorStatusBusy: lightgray;
qproperty-textColorStatusOnline: green; qproperty-textColorStatusOnline: green;

View file

@ -833,7 +833,7 @@ QDockWidget::close-button:pressed, QDockWidget::float-button:pressed {
background: rgba(255, 255, 255, 10); background: rgba(255, 255, 255, 10);
} }
FriendList { NewFriendList {
qproperty-textColorStatusAway: lightgray; qproperty-textColorStatusAway: lightgray;
qproperty-textColorStatusBusy: lightgray; qproperty-textColorStatusBusy: lightgray;
qproperty-textColorStatusOnline: green; qproperty-textColorStatusOnline: green;

View file

@ -28,6 +28,7 @@
#include <QFontDialog> #include <QFontDialog>
#include "misc.h" #include "misc.h"
#include "util/rsdebug.h"
// return best userfriendly storage unit (B, KiB, MiB, GiB, TiB) // return best userfriendly storage unit (B, KiB, MiB, GiB, TiB)
// use Binary prefix standards from IEC 60027-2 // use Binary prefix standards from IEC 60027-2
@ -416,12 +417,17 @@ void misc::clearLayout(QLayout * layout) {
while (auto item = layout->takeAt(0)) while (auto item = layout->takeAt(0))
{ {
if (auto *widget = item->widget()) //First get all pointers, else item may be deleted when last object removed and get SIGSEGV
auto *widget = item->widget();
auto *spacer = item->spacerItem();
//Then Clear Layout
clearLayout(item->layout());
//Last clear objects
if (widget)
widget->deleteLater(); widget->deleteLater();
if (auto *spacer = item->spacerItem()) if (spacer)
delete spacer; delete spacer;
clearLayout(item->layout()); //delete item;//Auto deleted by Qt.
delete item;
} }
} }