From d35dd76ca56bf2a786a33588bae6609caca7f6de Mon Sep 17 00:00:00 2001 From: jolavillette Date: Sat, 2 May 2020 09:47:24 +0200 Subject: [PATCH 001/154] try to isolate pqistreamer mutex from pqissl mutex, step 1: pqistreamer::tick_recv() --- libretroshare/src/pqi/pqistreamer.cc | 41 ++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/libretroshare/src/pqi/pqistreamer.cc b/libretroshare/src/pqi/pqistreamer.cc index dc9ceaabc..6c3c0d180 100644 --- a/libretroshare/src/pqi/pqistreamer.cc +++ b/libretroshare/src/pqi/pqistreamer.cc @@ -288,16 +288,26 @@ int pqistreamer::tick_bio() int pqistreamer::tick_recv(uint32_t timeout) { - RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ +// Only our thread manipulates mIncoming queue and related counters. +// The lock of pqistreamer mutex is thus not needed here. +// For the moment and for safety reasons it is still kept in 3 places: +// - in pqistreamer::tick_recv before calling free_pend_locked, as I dont know what this method actually does +// - in pqistreamer::handleincomingitem_locked, as it modifies mIncoming queue +// - in pqistreamer::inReadBytes_locked, as it modifies related counters +// +// RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ if (mBio->moretoread(timeout)) { handleincoming_locked(); } - if(!(mBio->isactive())) - { - free_pend_locked(); - } + if(!(mBio->isactive())) + { + // lock only now, see comment above + RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ + + free_pend_locked(); + } return 1; } @@ -414,16 +424,20 @@ int pqistreamer::handleincomingitem_locked(RsItem *pqi,int len) // Use overloaded Contact function pqi -> PeerId(PeerId()); - mIncoming.push_back(pqi); - ++mIncomingSize ; - /*******************************************************************************************/ - // keep info for stats for a while. Only keep the items for the last two seconds. sec n is ongoing and second n-1 - // is a full statistics chunk that can be used in the GUI + // lock only now, see comment in pqistreamer::tick_recv + RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ - locked_addTrafficClue(pqi,len,mCurrentStatsChunk_In) ; + mIncoming.push_back(pqi); + ++mIncomingSize ; - /*******************************************************************************************/ + /*******************************************************************************************/ + // keep info for stats for a while. Only keep the items for the last two seconds. sec n is ongoing and second n-1 + // is a full statistics chunk that can be used in the GUI + + locked_addTrafficClue(pqi,len,mCurrentStatsChunk_In) ; + + /*******************************************************************************************/ return 1; } @@ -1241,6 +1255,9 @@ void pqistreamer::inReadBytes_locked(uint32_t inb) } #endif + // lock only now, see comment in pqistreamer::tick_recv + RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ + mTotalRead += inb; mCurrRead += inb; mAvgReadCount += inb; From d8470869118607af7dc3ad247fa11a7236063ccd Mon Sep 17 00:00:00 2001 From: jolavillette Date: Sun, 3 May 2020 20:32:17 +0200 Subject: [PATCH 002/154] finish emoving unneeded pqistreamer locks in recv part --- libretroshare/src/pqi/pqistreamer.cc | 106 +++++++++++++-------------- libretroshare/src/pqi/pqistreamer.h | 14 ++-- 2 files changed, 59 insertions(+), 61 deletions(-) diff --git a/libretroshare/src/pqi/pqistreamer.cc b/libretroshare/src/pqi/pqistreamer.cc index 6c3c0d180..45b48228e 100644 --- a/libretroshare/src/pqi/pqistreamer.cc +++ b/libretroshare/src/pqi/pqistreamer.cc @@ -159,7 +159,7 @@ pqistreamer::~pqistreamer() if (mRsSerialiser) delete mRsSerialiser; - free_pend_locked() ; + free_pend() ; // clean up incoming. while (!mIncoming.empty()) @@ -199,14 +199,12 @@ RsItem *pqistreamer::GetItem() pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::GetItem()"); #endif - RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ - if(mIncoming.empty()) return NULL; RsItem *osr = mIncoming.front() ; - mIncoming.pop_front() ; - --mIncomingSize; + mIncoming.pop_front() ; + --mIncomingSize; return osr; } @@ -288,25 +286,26 @@ int pqistreamer::tick_bio() int pqistreamer::tick_recv(uint32_t timeout) { -// Only our thread manipulates mIncoming queue and related counters. -// The lock of pqistreamer mutex is thus not needed here. -// For the moment and for safety reasons it is still kept in 3 places: -// - in pqistreamer::tick_recv before calling free_pend_locked, as I dont know what this method actually does -// - in pqistreamer::handleincomingitem_locked, as it modifies mIncoming queue -// - in pqistreamer::inReadBytes_locked, as it modifies related counters +// Apart from a few exceptions that are atomic (mLastIncomingTs, mIncomingSize), only this pqi thread reads/writes mIncoming queue and related counters. +// The lock of pqistreamer mutex is thus not needed. +// The mutex lock is still needed before calling locked_addTrafficClue because this method is also used by the thread pushing packets in mOutPkts // -// RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ +// The following methods have been renamed by removing the 'locked' part of the name: +// - handleincoming_locked +// - handleincomingitem_locked +// - inReadBytes_locked +// - inAllowedBytes_locked +// - addPartialPacket_locked +// - allocate_rpend_locked +// - free_pend_locked; if (mBio->moretoread(timeout)) { - handleincoming_locked(); + handleincoming(); } if(!(mBio->isactive())) { - // lock only now, see comment above - RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ - - free_pend_locked(); + free_pend(); } return 1; } @@ -319,7 +318,7 @@ int pqistreamer::tick_send(uint32_t timeout) /* short circuit everything is bio isn't active */ if (!(mBio->isactive())) { - free_pend_locked(); + free_pend(); return 0; } @@ -413,11 +412,11 @@ int pqistreamer::queue_outpqi_locked(RsItem *pqi,uint32_t& pktsize) return 1; // keep error internal. } -int pqistreamer::handleincomingitem_locked(RsItem *pqi,int len) +int pqistreamer::handleincomingitem(RsItem *pqi,int len) { #ifdef DEBUG_PQISTREAMER - pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::handleincomingitem_locked()"); + pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::handleincomingitem()"); #endif // timestamp last received packet. mLastIncomingTs = time(NULL); @@ -425,9 +424,6 @@ int pqistreamer::handleincomingitem_locked(RsItem *pqi,int len) // Use overloaded Contact function pqi -> PeerId(PeerId()); - // lock only now, see comment in pqistreamer::tick_recv - RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ - mIncoming.push_back(pqi); ++mIncomingSize ; @@ -435,6 +431,8 @@ int pqistreamer::handleincomingitem_locked(RsItem *pqi,int len) // keep info for stats for a while. Only keep the items for the last two seconds. sec n is ongoing and second n-1 // is a full statistics chunk that can be used in the GUI + RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ + locked_addTrafficClue(pqi,len,mCurrentStatsChunk_In) ; /*******************************************************************************************/ @@ -470,8 +468,8 @@ void pqistreamer::locked_addTrafficClue(const RsItem *pqi,uint32_t pktsize,std:: rstime_t pqistreamer::getLastIncomingTS() { - RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ - +// This is the only case where another thread (rs main for pqiperson) will access our data +// Still a mutex lock is not needed because the operation is atomic return mLastIncomingTs; } @@ -707,23 +705,23 @@ int pqistreamer::handleoutgoing_locked() /* Handles reading from input stream. */ -int pqistreamer::handleincoming_locked() +int pqistreamer::handleincoming() { int readbytes = 0; static const int max_failed_read_attempts = 2000 ; #ifdef DEBUG_PQISTREAMER - pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::handleincoming_locked()"); + pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::handleincoming()"); #endif if(!(mBio->isactive())) { mReading_state = reading_state_initial ; - free_pend_locked(); + free_pend(); return 0; } else - allocate_rpend_locked(); + allocate_rpend(); // enough space to read any packet. uint32_t maxlen = mPkt_rpend_size; @@ -732,7 +730,7 @@ int pqistreamer::handleincoming_locked() // initial read size: basic packet. int blen = getRsPktBaseSize(); // this is valid for both packet slices and normal un-sliced packets (same header size) - int maxin = inAllowedBytes_locked(); + int maxin = inAllowedBytes(); #ifdef DEBUG_PQISTREAMER std::cerr << "[" << (void*)pthread_self() << "] " << "reading state = " << mReading_state << std::endl ; @@ -981,19 +979,19 @@ continue_packet: std::cerr << "Inputing partial packet " << RsUtil::BinToHex((char*)block,8) << std::endl; #endif uint32_t packet_length = 0 ; - pkt = addPartialPacket_locked(block,pktlen,slice_packet_id,is_packet_starting,is_packet_ending,packet_length) ; + pkt = addPartialPacket(block,pktlen,slice_packet_id,is_packet_starting,is_packet_ending,packet_length) ; pktlen = packet_length ; } else pkt = mRsSerialiser->deserialise(block, &pktlen); - if ((pkt != NULL) && (0 < handleincomingitem_locked(pkt,pktlen))) + if ((pkt != NULL) && (0 < handleincomingitem(pkt,pktlen))) { #ifdef DEBUG_PQISTREAMER pqioutput(PQL_DEBUG_BASIC, pqistreamerzone, "Successfully Read a Packet!"); #endif - inReadBytes_locked(pktlen); // only count deserialised packets, because that's what is actually been transfered. + inReadBytes(pktlen); // only count deserialised packets, because that's what is actually been transfered. } else if (!is_partial_packet) { @@ -1026,7 +1024,7 @@ continue_packet: return 0; } -RsItem *pqistreamer::addPartialPacket_locked(const void *block, uint32_t len, uint32_t slice_packet_id, bool is_packet_starting, bool is_packet_ending, uint32_t &total_len) +RsItem *pqistreamer::addPartialPacket(const void *block, uint32_t len, uint32_t slice_packet_id, bool is_packet_starting, bool is_packet_ending, uint32_t &total_len) { #ifdef DEBUG_PACKET_SLICING std::cerr << "Receiving partial packet. size=" << len << ", ID=" << std::hex << slice_packet_id << std::dec << ", starting:" << is_packet_starting << ", ending:" << is_packet_ending ; @@ -1170,7 +1168,7 @@ int pqistreamer::outAllowedBytes_locked() return quota; } -int pqistreamer::inAllowedBytes_locked() +int pqistreamer::inAllowedBytes() { double t = getCurrentTS(); // in sec, with high accuracy @@ -1208,7 +1206,7 @@ int pqistreamer::inAllowedBytes_locked() #ifdef DEBUG_PQISTREAMER uint64_t t_now = 1000 * getCurrentTS(); - std::cerr << std::dec << t_now << " DEBUG_PQISTREAMER pqistreamer::inAllowedBytes_locked PeerId " << this->PeerId().toStdString() << " dt " << (int)(1000 * dt) << "ms, mAvgDtIn " << (int)(1000 * mAvgDtIn) << "ms, maxin " << (int)(maxin) << " bytes/s, mCurrRead " << mCurrRead << " bytes, quota " << (int)(quota) << " bytes" << std::endl; + std::cerr << std::dec << t_now << " DEBUG_PQISTREAMER pqistreamer::inAllowedBytes PeerId " << this->PeerId().toStdString() << " dt " << (int)(1000 * dt) << "ms, mAvgDtIn " << (int)(1000 * mAvgDtIn) << "ms, maxin " << (int)(maxin) << " bytes/s, mCurrRead " << mCurrRead << " bytes, quota " << (int)(quota) << " bytes" << std::endl; #endif return quota; @@ -1245,7 +1243,7 @@ void pqistreamer::outSentBytes_locked(uint32_t outb) return; } -void pqistreamer::inReadBytes_locked(uint32_t inb) +void pqistreamer::inReadBytes(uint32_t inb) { #ifdef DEBUG_PQISTREAMER { @@ -1255,9 +1253,6 @@ void pqistreamer::inReadBytes_locked(uint32_t inb) } #endif - // lock only now, see comment in pqistreamer::tick_recv - RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ - mTotalRead += inb; mCurrRead += inb; mAvgReadCount += inb; @@ -1265,7 +1260,7 @@ void pqistreamer::inReadBytes_locked(uint32_t inb) return; } -void pqistreamer::allocate_rpend_locked() +void pqistreamer::allocate_rpend() { if(mPkt_rpending) return; @@ -1288,17 +1283,17 @@ int pqistreamer::reset() #ifdef DEBUG_PQISTREAMER std::cerr << "pqistreamer::reset()" << std::endl; #endif - free_pend_locked(); + free_pend(); return 1 ; } -void pqistreamer::free_pend_locked() +void pqistreamer::free_pend() { if(mPkt_rpending) { #ifdef DEBUG_PQISTREAMER - std::cerr << "pqistreamer::free_pend_locked(): pending input packet buffer" << std::endl; + std::cerr << "pqistreamer::free_pend(): pending input packet buffer" << std::endl; #endif free(mPkt_rpending); mPkt_rpending = 0; @@ -1308,7 +1303,7 @@ void pqistreamer::free_pend_locked() if (mPkt_wpending) { #ifdef DEBUG_PQISTREAMER - std::cerr << "pqistreamer::free_pend_locked(): pending output packet buffer" << std::endl; + std::cerr << "pqistreamer::free_pend(): pending output packet buffer" << std::endl; #endif free(mPkt_wpending); mPkt_wpending = NULL; @@ -1317,7 +1312,7 @@ void pqistreamer::free_pend_locked() #ifdef DEBUG_PQISTREAMER if(!mPartialPackets.empty()) - std::cerr << "pqistreamer::free_pend_locked(): " << mPartialPackets.size() << " pending input partial packets" << std::endl; + std::cerr << "pqistreamer::free_pend(): " << mPartialPackets.size() << " pending input partial packets" << std::endl; #endif // also delete any incoming partial packet for(std::map::iterator it(mPartialPackets.begin());it!=mPartialPackets.end();++it) @@ -1335,23 +1330,27 @@ int pqistreamer::gatherStatistics(std::list& outqueue_lst,std return locked_gatherStatistics(outqueue_lst,inqueue_lst); } + int pqistreamer::getQueueSize(bool in) { - RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ - if (in) - return mIncomingSize; - else - return locked_out_queue_size(); +// no mutex is needed here because this is atomic + return mIncomingSize; + else + { + RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ + return locked_out_queue_size(); + } } void pqistreamer::getRates(RsBwRates &rates) { RateInterface::getRates(rates); - RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ +// no mutex is needed here because this is atomic + rates.mQueueIn = mIncomingSize; - rates.mQueueIn = mIncomingSize; + RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ rates.mQueueOut = locked_out_queue_size(); } @@ -1417,4 +1416,3 @@ void *pqistreamer::locked_pop_out_data(uint32_t /*max_slice_size*/, uint32_t &si return res ; } - diff --git a/libretroshare/src/pqi/pqistreamer.h b/libretroshare/src/pqi/pqistreamer.h index c5b2bc983..1589448c9 100644 --- a/libretroshare/src/pqi/pqistreamer.h +++ b/libretroshare/src/pqi/pqistreamer.h @@ -104,12 +104,12 @@ class pqistreamer: public PQInterface private: int queue_outpqi_locked(RsItem *i,uint32_t& serialized_size); - int handleincomingitem_locked(RsItem *i, int len); + int handleincomingitem(RsItem *i, int len); // ticked regularly (manages out queues and sending // via above interfaces. virtual int handleoutgoing_locked(); - virtual int handleincoming_locked(); + virtual int handleincoming(); // Bandwidth/Streaming Management. float outTimeSlice_locked(); @@ -117,11 +117,11 @@ class pqistreamer: public PQInterface int outAllowedBytes_locked(); void outSentBytes_locked(uint32_t ); - int inAllowedBytes_locked(); - void inReadBytes_locked(uint32_t ); + int inAllowedBytes(); + void inReadBytes(uint32_t ); // cleans up everything that's pending / half finished. - void free_pend_locked(); + void free_pend(); // RsSerialiser - determines which packets can be serialised. RsSerialiser *mRsSerialiser; @@ -129,7 +129,7 @@ class pqistreamer: public PQInterface void *mPkt_wpending; // storage for pending packet to write. uint32_t mPkt_wpending_size; // ... and its size. - void allocate_rpend_locked(); // use these two functions to allocate/free the buffer below + void allocate_rpend(); // use these two functions to allocate/free the buffer below int mPkt_rpend_size; // size of pkt_rpending. void *mPkt_rpending; // storage for read in pending packets. @@ -177,7 +177,7 @@ class pqistreamer: public PQInterface bool mAcceptsPacketSlicing ; rstime_t mLastSentPacketSlicingProbe ; void locked_addTrafficClue(const RsItem *pqi, uint32_t pktsize, std::list &lst); - RsItem *addPartialPacket_locked(const void *block, uint32_t len, uint32_t slice_packet_id,bool packet_starting,bool packet_ending,uint32_t& total_len); + RsItem *addPartialPacket(const void *block, uint32_t len, uint32_t slice_packet_id,bool packet_starting,bool packet_ending,uint32_t& total_len); std::map mPartialPackets ; }; From 28458bf10a1b1cc7c30738d0b9570babfa5943fc Mon Sep 17 00:00:00 2001 From: jolavillette Date: Mon, 4 May 2020 08:11:57 +0200 Subject: [PATCH 003/154] tick_send: remove unneeded lock around mBio->cansend --- libretroshare/src/pqi/pqistreamer.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libretroshare/src/pqi/pqistreamer.cc b/libretroshare/src/pqi/pqistreamer.cc index 45b48228e..393f2ac70 100644 --- a/libretroshare/src/pqi/pqistreamer.cc +++ b/libretroshare/src/pqi/pqistreamer.cc @@ -313,17 +313,16 @@ int pqistreamer::tick_recv(uint32_t timeout) int pqistreamer::tick_send(uint32_t timeout) { - RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ - - /* short circuit everything is bio isn't active */ + /* short circuit everything if bio isn't active */ if (!(mBio->isactive())) { - free_pend(); + free_pend(); return 0; } if (mBio->cansend(timeout)) { + RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ handleoutgoing_locked(); } From 757e922c4f7626a475586ca807e8031681a81776 Mon Sep 17 00:00:00 2001 From: sehraf Date: Mon, 4 May 2020 15:13:39 +0200 Subject: [PATCH 004/154] Fix unix_fcntl_nonblock() to not overwrite any existing flags. --- libretroshare/src/pqi/pqinetwork.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libretroshare/src/pqi/pqinetwork.cc b/libretroshare/src/pqi/pqinetwork.cc index e2251ed6a..18fe71fc0 100644 --- a/libretroshare/src/pqi/pqinetwork.cc +++ b/libretroshare/src/pqi/pqinetwork.cc @@ -413,9 +413,10 @@ int unix_fcntl_nonblock(int fd) { int ret; -/******************* WINDOWS SPECIFIC PART ******************/ +/******************* OS SPECIFIC PART ******************/ #ifndef WINDOWS_SYS // ie UNIX - ret = fcntl(fd, F_SETFL, O_NONBLOCK); + int flags = fcntl(fd, F_GETFL); + ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK); #ifdef NET_DEBUG std::cerr << "unix_fcntl_nonblock():" << ret << " errno:" << errno << std::endl; From 7113d1935fa9b21506413c8f0c789078836d19be Mon Sep 17 00:00:00 2001 From: jolavillette Date: Mon, 4 May 2020 22:42:18 +0200 Subject: [PATCH 005/154] finish removing pqistreamer locks, clean rates methods --- libretroshare/src/pqi/pqistreamer.cc | 155 ++++++++++++++++----------- libretroshare/src/pqi/pqistreamer.h | 39 ++++--- 2 files changed, 113 insertions(+), 81 deletions(-) diff --git a/libretroshare/src/pqi/pqistreamer.cc b/libretroshare/src/pqi/pqistreamer.cc index 393f2ac70..62b4d7f84 100644 --- a/libretroshare/src/pqi/pqistreamer.cc +++ b/libretroshare/src/pqi/pqistreamer.cc @@ -1,5 +1,5 @@ /******************************************************************************* - * libretroshare/src/pqi: pqistreamer.h * + * libretroshare/src/pqi: pqistreamer.cc * * * * libretroshare: retroshare core library * * * @@ -102,38 +102,39 @@ pqistreamer::pqistreamer(RsSerialiser *rss, const RsPeerId& id, BinInterface *bi mAvgDtOut(0), mAvgDtIn(0) { - // 100 B/s (minimal) - setMaxRate(true, 0.1); - setMaxRate(false, 0.1); - setRate(true, 0); // needs to be off-mutex - setRate(false, 0); + // 100 B/s (minimal) + setMaxRate(true, 0.1); + setMaxRate(false, 0.1); + setRate(true, 0); // needs to be off-mutex + setRate(false, 0); - RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ + RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ - mAcceptsPacketSlicing = false ; // by default. Will be turned into true when everyone's ready. - mLastSentPacketSlicingProbe = 0 ; + mAcceptsPacketSlicing = false ; // by default. Will be turned into true when everyone's ready. + mLastSentPacketSlicingProbe = 0 ; - mAvgLastUpdate = mCurrSentTS = mCurrReadTS = getCurrentTS(); + mAvgLastUpdate = mCurrSentTS = mCurrReadTS = getCurrentTS(); - mIncomingSize = 0 ; + mIncomingSize = 0 ; + mIncomingSize_bytes = 0; - mStatisticsTimeStamp = 0 ; - /* allocated once */ - mPkt_rpend_size = 0; - mPkt_rpending = 0; - mReading_state = reading_state_initial ; + mStatisticsTimeStamp = 0 ; + /* allocated once */ + mPkt_rpend_size = 0; + mPkt_rpending = 0; + mReading_state = reading_state_initial ; - pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::pqistreamer() Initialisation!"); + pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::pqistreamer() Initialisation!"); - if (!bio_in) - { - pqioutput(PQL_ALERT, pqistreamerzone, "pqistreamer::pqistreamer() NULL bio, FATAL ERROR!"); - exit(1); - } + if (!bio_in) + { + pqioutput(PQL_ALERT, pqistreamerzone, "pqistreamer::pqistreamer() NULL bio, FATAL ERROR!"); + exit(1); + } - mFailed_read_attempts = 0; // reset failed read, as no packet is still read. + mFailed_read_attempts = 0; // reset failed read, as no packet is still read. - return; + return; } pqistreamer::~pqistreamer() @@ -177,6 +178,7 @@ pqistreamer::~pqistreamer() // Get/Send Items. +// This is the entry poing for methods willing to send items through our out queue int pqistreamer::SendItem(RsItem *si,uint32_t& out_size) { #ifdef RSITEM_DEBUG @@ -205,10 +207,24 @@ RsItem *pqistreamer::GetItem() RsItem *osr = mIncoming.front() ; mIncoming.pop_front() ; --mIncomingSize; +// for future use +// mIncomingSize_bytes -= return osr; } + +float pqistreamer::getMaxRate(bool b) +{ + RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ + return getMaxRate_locked(b); +} + +float pqistreamer::getMaxRate_locked(bool b) +{ + return RateInterface::getMaxRate(b) ; +} + float pqistreamer::getRate(bool b) { RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ @@ -217,26 +233,28 @@ float pqistreamer::getRate(bool b) void pqistreamer::setMaxRate(bool b,float f) { - RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ - RateInterface::setMaxRate(b,f) ; + RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ + setMaxRate_locked(b,f); } + +void pqistreamer::setMaxRate_locked(bool b,float f) +{ + RateInterface::setMaxRate(b,f) ; +} + void pqistreamer::setRate(bool b,float f) { RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ RateInterface::setRate(b,f) ; } + void pqistreamer::updateRates() { - // update rates both ways. + // update actual rates both ways. double t = getCurrentTS(); // get current timestamp. - double diff ; - - { - RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ - diff = t - mAvgLastUpdate ; - } + double diff = t - mAvgLastUpdate; if (diff > PQISTREAM_AVG_PERIOD) { @@ -261,10 +279,11 @@ void pqistreamer::updateRates() setRate(false, 0); } + mAvgLastUpdate = t; + mAvgReadCount = 0; + { RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ - mAvgLastUpdate = t; - mAvgReadCount = 0; mAvgSentCount = 0; } } @@ -275,7 +294,7 @@ int pqistreamer::tick_bio() RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ mBio->tick(); - /* short circuit everything is bio isn't active */ + /* short circuit everything if bio isn't active */ if (!(mBio->isactive())) { return 0; @@ -283,21 +302,12 @@ int pqistreamer::tick_bio() return 1; } - int pqistreamer::tick_recv(uint32_t timeout) { // Apart from a few exceptions that are atomic (mLastIncomingTs, mIncomingSize), only this pqi thread reads/writes mIncoming queue and related counters. -// The lock of pqistreamer mutex is thus not needed. -// The mutex lock is still needed before calling locked_addTrafficClue because this method is also used by the thread pushing packets in mOutPkts -// -// The following methods have been renamed by removing the 'locked' part of the name: -// - handleincoming_locked -// - handleincomingitem_locked -// - inReadBytes_locked -// - inAllowedBytes_locked -// - addPartialPacket_locked -// - allocate_rpend_locked -// - free_pend_locked; +// The lock of pqistreamer mutex is thus not needed here. +// The mutex lock is still needed before calling locked_addTrafficClue because this method is also used by the thread pushing packets in mOutPkts. +// Locks around rates are provided internally. if (mBio->moretoread(timeout)) { @@ -310,7 +320,6 @@ int pqistreamer::tick_recv(uint32_t timeout) return 1; } - int pqistreamer::tick_send(uint32_t timeout) { /* short circuit everything if bio isn't active */ @@ -348,12 +357,11 @@ int pqistreamer::status() return 0; } +// this method is overloaded by pqiqosstreamer void pqistreamer::locked_storeInOutputQueue(void *ptr,int,int) { mOutPkts.push_back(ptr); } -// -/**************** HANDLE OUTGOING TRANSLATION + TRANSMISSION ******/ int pqistreamer::queue_outpqi_locked(RsItem *pqi,uint32_t& pktsize) { @@ -362,7 +370,6 @@ int pqistreamer::queue_outpqi_locked(RsItem *pqi,uint32_t& pktsize) std::cerr << "pqistreamer::queue_outpqi() called." << std::endl; #endif - /* decide which type of packet it is */ pktsize = mRsSerialiser->size(pqi); @@ -370,7 +377,6 @@ int pqistreamer::queue_outpqi_locked(RsItem *pqi,uint32_t& pktsize) if(ptr == NULL) return 0 ; - #ifdef DEBUG_PQISTREAMER std::cerr << "pqistreamer::queue_outpqi() serializing packet with packet size : " << pktsize << std::endl; @@ -424,16 +430,17 @@ int pqistreamer::handleincomingitem(RsItem *pqi,int len) pqi -> PeerId(PeerId()); mIncoming.push_back(pqi); - ++mIncomingSize ; + ++mIncomingSize; + // for future use + // mIncomingSize_bytes += len; /*******************************************************************************************/ // keep info for stats for a while. Only keep the items for the last two seconds. sec n is ongoing and second n-1 // is a full statistics chunk that can be used in the GUI - - RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ - - locked_addTrafficClue(pqi,len,mCurrentStatsChunk_In) ; - + { + RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ + locked_addTrafficClue(pqi,len,mCurrentStatsChunk_In) ; + } /*******************************************************************************************/ return 1; @@ -467,8 +474,8 @@ void pqistreamer::locked_addTrafficClue(const RsItem *pqi,uint32_t pktsize,std:: rstime_t pqistreamer::getLastIncomingTS() { -// This is the only case where another thread (rs main for pqiperson) will access our data -// Still a mutex lock is not needed because the operation is atomic + // This is the only case where another thread (rs main for pqiperson) will access our data + // Still a mutex lock is not needed because the operation is atomic return mLastIncomingTs; } @@ -1145,7 +1152,7 @@ int pqistreamer::outAllowedBytes_locked() // low pass filter on mAvgDtOut mAvgDtOut = PQISTREAM_AVG_DT_FRAC * mAvgDtOut + (1 - PQISTREAM_AVG_DT_FRAC) * dt; - double maxout = getMaxRate(false) * 1024.0; + double maxout = getMaxRate_locked(false) * 1024.0; // this is used to take into account a possible excess of data sent during the previous round mCurrSent -= int(dt * maxout); @@ -1330,6 +1337,7 @@ int pqistreamer::gatherStatistics(std::list& outqueue_lst,std return locked_gatherStatistics(outqueue_lst,inqueue_lst); } +// this method is overloaded by pqiqosstreamer int pqistreamer::getQueueSize(bool in) { if (in) @@ -1342,6 +1350,19 @@ int pqistreamer::getQueueSize(bool in) } } +int pqistreamer::getQueueSize_bytes(bool in) +{ + if (in) +// no mutex is needed here because this is atomic +// for future use, mIncomingSize_bytes is not updated yet + return mIncomingSize_bytes; + else + { + RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ + return locked_compute_out_pkt_size(); + } +} + void pqistreamer::getRates(RsBwRates &rates) { RateInterface::getRates(rates); @@ -1349,10 +1370,13 @@ void pqistreamer::getRates(RsBwRates &rates) // no mutex is needed here because this is atomic rates.mQueueIn = mIncomingSize; - RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ - rates.mQueueOut = locked_out_queue_size(); + { + RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ + rates.mQueueOut = locked_out_queue_size(); + } } +// this method is overloaded by pqiqosstreamer int pqistreamer::locked_out_queue_size() const { // Warning: because out_pkt is a list, calling size @@ -1362,6 +1386,7 @@ int pqistreamer::locked_out_queue_size() const return mOutPkts.size() ; } +// this method is overloaded by pqiqosstreamer void pqistreamer::locked_clear_out_queue() { for(std::list::iterator it = mOutPkts.begin(); it != mOutPkts.end(); ) @@ -1376,6 +1401,7 @@ void pqistreamer::locked_clear_out_queue() } } +// this method is overloaded by pqiqosstreamer int pqistreamer::locked_compute_out_pkt_size() const { int total = 0 ; @@ -1394,6 +1420,7 @@ int pqistreamer::locked_gatherStatistics(std::list& out_lst,std:: return 1 ; } +// this method is overloaded by pqiqosstreamer void *pqistreamer::locked_pop_out_data(uint32_t /*max_slice_size*/, uint32_t &size, bool &starts, bool &ends, uint32_t &packet_id) { size = 0 ; diff --git a/libretroshare/src/pqi/pqistreamer.h b/libretroshare/src/pqi/pqistreamer.h index 1589448c9..0e7f6b815 100644 --- a/libretroshare/src/pqi/pqistreamer.h +++ b/libretroshare/src/pqi/pqistreamer.h @@ -38,8 +38,8 @@ class RsSerialiser; struct PartialPacketRecord { - void *mem ; - uint32_t size ; + void *mem ; + uint32_t size ; }; /** @@ -65,18 +65,23 @@ class pqistreamer: public PQInterface virtual RsItem *GetItem(); virtual int status(); - rstime_t getLastIncomingTS(); // Time of last data packet, for checking a connection is alive. + rstime_t getLastIncomingTS(); // Time of last data packet, for checking a connection is alive. virtual void getRates(RsBwRates &rates); virtual int getQueueSize(bool in); // extracting data. + virtual int getQueueSize_bytes(bool in); // size of incoming queue in bytes virtual int gatherStatistics(std::list& outqueue_stats,std::list& inqueue_stats); // extracting data. // mutex protected versions of RateInterface calls. virtual void setRate(bool b,float f) ; virtual void setMaxRate(bool b,float f) ; - virtual float getRate(bool b) ; + virtual void setMaxRate_locked(bool b,float f) ; - protected: - virtual int reset() ; + virtual float getRate(bool b) ; + virtual float getMaxRate(bool b) ; + virtual float getMaxRate_locked(bool b); + + protected: + virtual int reset() ; int tick_bio(); int tick_send(uint32_t timeout); @@ -129,13 +134,12 @@ class pqistreamer: public PQInterface void *mPkt_wpending; // storage for pending packet to write. uint32_t mPkt_wpending_size; // ... and its size. - void allocate_rpend(); // use these two functions to allocate/free the buffer below + void allocate_rpend(); // use these two functions to allocate/free the buffer below int mPkt_rpend_size; // size of pkt_rpending. void *mPkt_rpending; // storage for read in pending packets. - enum {reading_state_packet_started=1, - reading_state_initial=0 } ; + enum {reading_state_packet_started=1, reading_state_initial=0 } ; int mReading_state ; int mFailed_read_attempts ; @@ -144,7 +148,8 @@ class pqistreamer: public PQInterface std::list mOutPkts; // Cntrl / Search / Results queue std::list mIncoming; - uint32_t mIncomingSize; // size of mIncoming. To avoid calling linear cost std::list::size() + uint32_t mIncomingSize; // size of mIncoming. To avoid calling linear cost std::list::size() + uint32_t mIncomingSize_bytes; // size of Incoming in btyes // data for network stats. int mTotalRead; @@ -154,8 +159,8 @@ class pqistreamer: public PQInterface int mCurrRead; int mCurrSent; - double mCurrReadTS; // TS from which these are measured. - double mCurrSentTS; + double mCurrReadTS; // TS from which these are measured. + double mCurrSentTS; double mAvgLastUpdate; // TS from which these are measured. uint32_t mAvgReadCount; @@ -174,12 +179,12 @@ class pqistreamer: public PQInterface std::list mCurrentStatsChunk_Out ; rstime_t mStatisticsTimeStamp ; - bool mAcceptsPacketSlicing ; - rstime_t mLastSentPacketSlicingProbe ; - void locked_addTrafficClue(const RsItem *pqi, uint32_t pktsize, std::list &lst); - RsItem *addPartialPacket(const void *block, uint32_t len, uint32_t slice_packet_id,bool packet_starting,bool packet_ending,uint32_t& total_len); + bool mAcceptsPacketSlicing ; + rstime_t mLastSentPacketSlicingProbe ; + void locked_addTrafficClue(const RsItem *pqi, uint32_t pktsize, std::list &lst); + RsItem *addPartialPacket(const void *block, uint32_t len, uint32_t slice_packet_id,bool packet_starting,bool packet_ending,uint32_t& total_len); - std::map mPartialPackets ; + std::map mPartialPackets ; }; #endif //MRK_PQI_STREAMER_HEADER From 2c1238db2c397adf4539893480e9e0500716e478 Mon Sep 17 00:00:00 2001 From: jolavillette Date: Wed, 6 May 2020 12:11:54 +0200 Subject: [PATCH 006/154] remove unneeded lock of p3ServiceServer mutex --- libretroshare/src/pqi/pqiservice.cc | 120 +++++++++++----------------- 1 file changed, 48 insertions(+), 72 deletions(-) diff --git a/libretroshare/src/pqi/pqiservice.cc b/libretroshare/src/pqi/pqiservice.cc index 35a4fac64..86336631a 100644 --- a/libretroshare/src/pqi/pqiservice.cc +++ b/libretroshare/src/pqi/pqiservice.cc @@ -1,5 +1,5 @@ /******************************************************************************* - * libretroshare/src/pqi: pqiservice.h * + * libretroshare/src/pqi: pqiservice.cc * * * * libretroshare: retroshare core library * * * @@ -23,6 +23,22 @@ #include "util/rsdebug.h" #include "util/rsstring.h" +#include +#include +static double getCurrentTS() +{ +#ifndef WINDOWS_SYS + struct timeval cts_tmp; + gettimeofday(&cts_tmp, NULL); + double cts = (cts_tmp.tv_sec) + ((double) cts_tmp.tv_usec) / 1000000.0; +#else + struct _timeb timebuf; + _ftime( &timebuf); + double cts = (timebuf.time) + ((double) timebuf.millitm) / 1000.0; +#endif + return cts; +} + #ifdef SERVICE_DEBUG const int pqiservicezone = 60478; #endif @@ -44,7 +60,7 @@ bool pqiService::send(RsRawItem *item) p3ServiceServer::p3ServiceServer(pqiPublisher *pub, p3ServiceControl *ctrl) : mPublisher(pub), mServiceControl(ctrl), srvMtx("p3ServiceServer") { - RsStackMutex stack(srvMtx); /********* LOCKED *********/ + RS_STACK_MUTEX(srvMtx); /********* LOCKED *********/ #ifdef SERVICE_DEBUG pqioutput(PQL_DEBUG_BASIC, pqiservicezone, @@ -56,7 +72,7 @@ p3ServiceServer::p3ServiceServer(pqiPublisher *pub, p3ServiceControl *ctrl) : mP int p3ServiceServer::addService(pqiService *ts, bool defaultOn) { - RsStackMutex stack(srvMtx); /********* LOCKED *********/ + RS_STACK_MUTEX(srvMtx); /********* LOCKED *********/ #ifdef SERVICE_DEBUG pqioutput(PQL_DEBUG_BASIC, pqiservicezone, @@ -84,7 +100,7 @@ int p3ServiceServer::addService(pqiService *ts, bool defaultOn) bool p3ServiceServer::getServiceItemNames(uint32_t service_type,std::map& names) { - RsStackMutex stack(srvMtx); /********* LOCKED *********/ + RS_STACK_MUTEX(srvMtx); /********* LOCKED *********/ std::map::iterator it=services.find(service_type) ; @@ -99,7 +115,7 @@ bool p3ServiceServer::getServiceItemNames(uint32_t service_type,std::map PacketId(), (item -> PacketId() & 0xffffff00)); - item -> print_string(out); - std::cerr << out; - std::cerr << std::endl; - } -#endif - // Packet Filtering. // This doesn't need to be in Mutex. if (!mServiceControl->checkFilter(item->PacketId() & 0xffffff00, item->PeerId())) { -#ifdef SERVICE_DEBUG - std::cerr << "p3ServiceServer::recvItem() Fails Filtering " << std::endl; -#endif delete item; return false; } + pqiService *s = NULL; - std::map::iterator it; - it = services.find(item -> PacketId() & 0xffffff00); - if (it == services.end()) + // access the service map under mutex lock { -#ifdef SERVICE_DEBUG - std::cerr << "p3ServiceServer::incoming() Service: No Service - deleting"; - std::cerr << std::endl; -#endif - delete item; - return false; + RS_STACK_MUTEX(srvMtx); + auto it = services.find(item -> PacketId() & 0xffffff00); + if (it == services.end()) + { + delete item; + return false; + } + s = it->second; } - { -#ifdef SERVICE_DEBUG - std::cerr << "p3ServiceServer::incoming() Sending to : " << (void *) it -> second; - std::cerr << std::endl; -#endif - - return (it->second) -> recv(item); - } - - delete item; - return false; + // then call recv off mutex + bool result = s->recv(item); + return result; } - - bool p3ServiceServer::sendItem(RsRawItem *item) { #ifdef SERVICE_DEBUG @@ -204,40 +193,27 @@ bool p3ServiceServer::sendItem(RsRawItem *item) } mPublisher->sendItem(item); + return true; } - - int p3ServiceServer::tick() { - mServiceControl->tick(); - RsStackMutex stack(srvMtx); /********* LOCKED *********/ - -#ifdef SERVICE_DEBUG - pqioutput(PQL_DEBUG_ALL, pqiservicezone, - "p3ServiceServer::tick()"); -#endif - - std::map::iterator it; - - // from the beginning to where we started. - for(it = services.begin();it != services.end(); ++it) - { - -#ifdef SERVICE_DEBUG - std::string out; - rs_sprintf(out, "p3ServiceServer::service id: %u -> Service: %p", it -> first, it -> second); - pqioutput(PQL_DEBUG_ALL, pqiservicezone, out); -#endif - - // now we should actually tick the service. - (it -> second) -> tick(); + // make a copy of the service map + std::map local_map; + { + RS_STACK_MUTEX(srvMtx); + local_map=services; } + + // tick all services off mutex + for(auto it(local_map.begin());it!=local_map.end();++it) + { + (it->second)->tick(); + } + return 1; + } - - - From 4ead639e8cabdc51e4bdd7db540d7cca1123b112 Mon Sep 17 00:00:00 2001 From: jolavillette Date: Wed, 6 May 2020 21:29:46 +0200 Subject: [PATCH 007/154] remove unneeded pqithreadstreamer and pqissl mutex locks --- libretroshare/src/pqi/pqissl.cc | 9 ++++++--- libretroshare/src/pqi/pqithreadstreamer.cc | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/libretroshare/src/pqi/pqissl.cc b/libretroshare/src/pqi/pqissl.cc index 0ef930fc2..07993a4eb 100644 --- a/libretroshare/src/pqi/pqissl.cc +++ b/libretroshare/src/pqi/pqissl.cc @@ -372,9 +372,11 @@ int pqissl::status() // tick...... int pqissl::tick() { - RsStackMutex stack(mSslMtx); /**** LOCKED MUTEX ****/ + // there is no reason to lock pqissl mutex now + // we will lock the mutex later if we actually need to call to ConnectAttempt + // RsStackMutex stack(mSslMtx); /**** LOCKED MUTEX ****/ - //pqistreamer::tick(); + // pqistreamer::tick(); // continue existing connection attempt. if (!active) @@ -385,7 +387,8 @@ int pqissl::tick() #ifdef PQISSL_LOG_DEBUG rslog(RSL_DEBUG_BASIC, pqisslzone, "pqissl::tick() Continuing Connection Attempt!"); #endif - + // now lock pqissl mutex, that will take up to 10 ms + RsStackMutex stack(mSslMtx); /**** LOCKED MUTEX ****/ ConnectAttempt(); return 1; } diff --git a/libretroshare/src/pqi/pqithreadstreamer.cc b/libretroshare/src/pqi/pqithreadstreamer.cc index 857075ef3..6a84a2e0b 100644 --- a/libretroshare/src/pqi/pqithreadstreamer.cc +++ b/libretroshare/src/pqi/pqithreadstreamer.cc @@ -43,8 +43,10 @@ bool pqithreadstreamer::RecvItem(RsItem *item) int pqithreadstreamer::tick() { - RsStackMutex stack(mThreadMutex); - tick_bio(); +// pqithreadstreamer mutex lock is not needed here +// we are only checking if the connection is active, and if not active we will try to establish it +// RsStackMutex stack(mThreadMutex); + tick_bio(); return 0; } From 7c2efbc630d6ac0a0035d514b67cd1bb6b8cb7b7 Mon Sep 17 00:00:00 2001 From: jolavillette Date: Sat, 9 May 2020 20:35:20 +0200 Subject: [PATCH 008/154] reduce cpu load by increasing sleep before ticking pqi and core --- libretroshare/src/pqi/pqithreadstreamer.cc | 90 +++++++++++---------- libretroshare/src/rsserver/p3face-server.cc | 19 +++-- 2 files changed, 58 insertions(+), 51 deletions(-) diff --git a/libretroshare/src/pqi/pqithreadstreamer.cc b/libretroshare/src/pqi/pqithreadstreamer.cc index 6a84a2e0b..6745dc864 100644 --- a/libretroshare/src/pqi/pqithreadstreamer.cc +++ b/libretroshare/src/pqi/pqithreadstreamer.cc @@ -23,17 +23,17 @@ #include "pqi/pqithreadstreamer.h" #include -#define DEFAULT_STREAMER_TIMEOUT 10000 // 10 ms. -#define DEFAULT_STREAMER_SLEEP 1000 // 1 ms. +#define DEFAULT_STREAMER_TIMEOUT 10000 // 10 ms +#define DEFAULT_STREAMER_SLEEP 30000 // 30 ms #define DEFAULT_STREAMER_IDLE_SLEEP 1000000 // 1 sec -//#define PQISTREAMER_DEBUG +// #define PQISTREAMER_DEBUG pqithreadstreamer::pqithreadstreamer(PQInterface *parent, RsSerialiser *rss, const RsPeerId& id, BinInterface *bio_in, int bio_flags_in) :pqistreamer(rss, id, bio_in, bio_flags_in), mParent(parent), mTimeout(0), mThreadMutex("pqithreadstreamer") { - mTimeout = DEFAULT_STREAMER_TIMEOUT; - mSleepPeriod = DEFAULT_STREAMER_SLEEP; + mTimeout = DEFAULT_STREAMER_TIMEOUT; + mSleepPeriod = DEFAULT_STREAMER_SLEEP; } bool pqithreadstreamer::RecvItem(RsItem *item) @@ -43,9 +43,8 @@ bool pqithreadstreamer::RecvItem(RsItem *item) int pqithreadstreamer::tick() { -// pqithreadstreamer mutex lock is not needed here -// we are only checking if the connection is active, and if not active we will try to establish it -// RsStackMutex stack(mThreadMutex); + // pqithreadstreamer mutex lock is not needed here + // we will only check if the connection is active, and if not we will try to establish it tick_bio(); return 0; @@ -53,47 +52,50 @@ int pqithreadstreamer::tick() void pqithreadstreamer::threadTick() { - uint32_t recv_timeout = 0; - uint32_t sleep_period = 0; - bool isactive = false; - { - RsStackMutex stack(mStreamerMtx); - recv_timeout = mTimeout; - sleep_period = mSleepPeriod; - isactive = mBio->isactive(); - } + uint32_t recv_timeout = 0; + uint32_t sleep_period = 0; + bool isactive = false; + + { + RsStackMutex stack(mStreamerMtx); + recv_timeout = mTimeout; + sleep_period = mSleepPeriod; + isactive = mBio->isactive(); + } - updateRates() ; + // update the connection rates + updateRates() ; - if (!isactive) - { - rstime::rs_usleep(DEFAULT_STREAMER_IDLE_SLEEP); - return ; - } + // if the connection est not active, long sleep then return + if (!isactive) + { + rstime::rs_usleep(DEFAULT_STREAMER_IDLE_SLEEP); + return ; + } - { - RsStackMutex stack(mThreadMutex); - tick_recv(recv_timeout); - } + // fill incoming queue with items from SSL + { + RsStackMutex stack(mThreadMutex); + tick_recv(recv_timeout); + } - // Push Items, Outside of Mutex. - RsItem *incoming = NULL; - while((incoming = GetItem())) - { - RecvItem(incoming); - } + // move items to appropriate service queue or shortcut to fast service + RsItem *incoming = NULL; + while((incoming = GetItem())) + { + RecvItem(incoming); + } - { - RsStackMutex stack(mThreadMutex); - tick_send(0); - } + // parse the outgoing queue and send items to SSL + { + RsStackMutex stack(mThreadMutex); + tick_send(0); + } - if (sleep_period) - { - rstime::rs_usleep(sleep_period); - } + // sleep + if (sleep_period) + { + rstime::rs_usleep(sleep_period); + } } - - - diff --git a/libretroshare/src/rsserver/p3face-server.cc b/libretroshare/src/rsserver/p3face-server.cc index 0ed2f698c..9426b0471 100644 --- a/libretroshare/src/rsserver/p3face-server.cc +++ b/libretroshare/src/rsserver/p3face-server.cc @@ -143,13 +143,14 @@ void RsServer::threadTick() // if there is time left, we sleep double timeToSleep = mTickInterval - mAvgRunDuration; - if (timeToSleep > 0) - { +// never sleep less than 50 ms + if (timeToSleep < 0.050) + timeToSleep = 0.050; + #ifdef TICK_DEBUG - RsDbg() << "TICK_DEBUG will sleep " << timeToSleep << " ms" << std::endl; + RsDbg() << "TICK_DEBUG will sleep " << (int) (1000 * timeToSleep) << " ms" << std::endl; #endif - rstime::rs_usleep(timeToSleep * 1000000); - } + rstime::rs_usleep(timeToSleep * 1000000); double ts = getCurrentTS(); mLastts = ts; @@ -229,12 +230,16 @@ void RsServer::threadTick() // ticking is done, now compute new values of mLastRunDuration, mAvgRunDuration and mTickInterval ts = getCurrentTS(); mLastRunDuration = ts - mLastts; + +// low-pass filter and don't let mAvgRunDuration exceeds maxTickInterval mAvgRunDuration = 0.1 * mLastRunDuration + 0.9 * mAvgRunDuration; + if (mAvgRunDuration > maxTickInterval) + mAvgRunDuration = maxTickInterval; #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; + RsDbg() << "TICK_DEBUG excessively long cycle time " << mLastRunDuration << std::endl; #endif // if the core has returned that there is more to tick we decrease the ticking interval, else we increse it @@ -250,7 +255,7 @@ void RsServer::threadTick() RsDbg() << "TICK_DEBUG new tick interval " << mTickInterval << std::endl; #endif -// keep the tick interval within allowed limits +// keep the tick interval target within allowed limits if (mTickInterval < minTickInterval) mTickInterval = minTickInterval; else if (mTickInterval > maxTickInterval) From 51ba879bb72f272679f8545a2a2a19ed667444ff Mon Sep 17 00:00:00 2001 From: jolavillette Date: Thu, 14 May 2020 23:28:20 +0200 Subject: [PATCH 009/154] bandwidth control improvement --- libretroshare/src/ft/fttransfermodule.cc | 6 +- libretroshare/src/pqi/pqihandler.cc | 173 +++++++++-------------- 2 files changed, 71 insertions(+), 108 deletions(-) diff --git a/libretroshare/src/ft/fttransfermodule.cc b/libretroshare/src/ft/fttransfermodule.cc index 8c6ae1f08..ab9900762 100644 --- a/libretroshare/src/ft/fttransfermodule.cc +++ b/libretroshare/src/ft/fttransfermodule.cc @@ -789,16 +789,16 @@ bool ftTransferModule::locked_tickPeerTransfer(peerInfo &info) std::cerr << std::endl; #endif - if (next_req > info.desiredRate * 1.1) + // cap next_req to desiredRate in order to respect the bandwidth limit and to avoid clogging our outqueue + if (next_req > info.desiredRate) { - next_req = info.desiredRate * 1.1; + next_req = info.desiredRate; #ifdef FT_DEBUG std::cerr << "locked_tickPeerTransfer() Reached MaxRate: next_req: " << next_req; std::cerr << std::endl; #endif } - if (next_req > FT_TM_MAX_PEER_RATE) { next_req = FT_TM_MAX_PEER_RATE; diff --git a/libretroshare/src/pqi/pqihandler.cc b/libretroshare/src/pqi/pqihandler.cc index 1e86fa9d1..72d7dbf9d 100644 --- a/libretroshare/src/pqi/pqihandler.cc +++ b/libretroshare/src/pqi/pqihandler.cc @@ -42,39 +42,19 @@ using std::dec; #include #endif -//#define PQI_HDL_DEBUG_UR 1 - -#ifdef PQI_HDL_DEBUG_UR -static double getCurrentTS() -{ - -#ifndef WINDOWS_SYS - struct timeval cts_tmp; - gettimeofday(&cts_tmp, NULL); - double cts = (cts_tmp.tv_sec) + ((double) cts_tmp.tv_usec) / 1000000.0; -#else - struct _timeb timebuf; - _ftime( &timebuf); - double cts = (timebuf.time) + ((double) timebuf.millitm) / 1000.0; -#endif - return cts; -} -#endif - struct RsLog::logInfo pqihandlerzoneInfo = {RsLog::Default, "pqihandler"}; #define pqihandlerzone &pqihandlerzoneInfo //static const int PQI_HANDLER_NB_PRIORITY_LEVELS = 10 ; //static const float PQI_HANDLER_NB_PRIORITY_RATIO = 2 ; -/**** -#define DEBUG_TICK 1 -#define RSITEM_DEBUG 1 -****/ +//#define UPDATE_RATES_DEBUG 1 +// #define DEBUG_TICK 1 +// #define RSITEM_DEBUG 1 pqihandler::pqihandler() : coreMtx("pqihandler") { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ // setup minimal total+individual rates. rateIndiv_out = 0.01; @@ -97,7 +77,7 @@ int pqihandler::tick() int moreToTick = 0; { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ // tick all interfaces... std::map::iterator it; @@ -127,9 +107,13 @@ int pqihandler::tick() if(now > mLastRateCapUpdate + 5) { + std::map rateMap; + std::map::iterator it; + + // every 5 secs, update the max rates for all modules - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ for(std::map::iterator it = mods.begin(); it != mods.end(); ++it) { // This is rather inelegant, but pqihandler has searchModules that are dynamically allocated, so the max rates @@ -149,7 +133,7 @@ int pqihandler::tick() bool pqihandler::queueOutRsItem(RsItem *item) { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ uint32_t size ; locked_HandleRsItem(item, size); @@ -166,7 +150,7 @@ bool pqihandler::queueOutRsItem(RsItem *item) int pqihandler::status() { std::map::iterator it; - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ { // for output std::string out = "pqihandler::status() Active Modules:\n"; @@ -192,7 +176,7 @@ int pqihandler::status() bool pqihandler::AddSearchModule(SearchModule *mod) { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ // if peerid used -> error. //std::map::iterator it; if (mod->peerid != mod->pqi->PeerId()) @@ -223,7 +207,7 @@ bool pqihandler::AddSearchModule(SearchModule *mod) bool pqihandler::RemoveSearchModule(SearchModule *mod) { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ std::map::iterator it; for(it = mods.begin(); it != mods.end(); ++it) { @@ -313,7 +297,7 @@ int pqihandler::ExtractRates(std::map &ratemap, RsBwRat total.mQueueOut = 0; /* Lock once rates have been retrieved */ - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ std::map::iterator it; for(it = mods.begin(); it != mods.end(); ++it) @@ -340,10 +324,6 @@ int pqihandler::ExtractRates(std::map &ratemap, RsBwRat // internal fn to send updates int pqihandler::UpdateRates() { -#ifdef PQI_HDL_DEBUG_UR - uint64_t t_now; -#endif - std::map::iterator it; float avail_in = getMaxRate(true); @@ -353,18 +333,15 @@ int pqihandler::UpdateRates() float used_bw_out = 0; /* Lock once rates have been retrieved */ - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ int num_sm = mods.size(); float used_bw_in_table[num_sm]; /* table of in bandwidth currently used by each module */ float used_bw_out_table[num_sm]; /* table of out bandwidth currently used by each module */ - int effectiveUploadsSm = 0; - int effectiveDownloadsSm = 0; - - // loop through modules to get the used bandwith and the number of modules that are affectively transfering -#ifdef PQI_HDL_DEBUG_UR - std::cerr << "Looping through modules" << std::endl; + // loop through modules to get the used bandwidth +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates Looping through modules" << std::endl; #endif int index = 0; @@ -372,49 +349,33 @@ int pqihandler::UpdateRates() for(it = mods.begin(); it != mods.end(); ++it) { SearchModule *mod = (it -> second); - float crate_in = mod -> pqi -> getRate(true); traffInSum += mod -> pqi -> getTraffic(true); traffOutSum += mod -> pqi -> getTraffic(false); -#ifdef PQI_HDL_DEBUG_UR - if(crate_in > 0.0) - std::cerr << " got in rate for peer " << it->first << " : " << crate_in << std::endl; -#endif - - if ((crate_in > 0.01 * avail_in) || (crate_in > 0.1)) - { - ++effectiveDownloadsSm; - } - + float crate_in = mod -> pqi -> getRate(true); float crate_out = mod -> pqi -> getRate(false); - if ((crate_out > 0.01 * avail_out) || (crate_out > 0.1)) - { - ++effectiveUploadsSm; - } used_bw_in += crate_in; used_bw_out += crate_out; - /* fill the table of bandwidth */ + /* fill the table of used bandwidths */ used_bw_in_table[index] = crate_in; used_bw_out_table[index] = crate_out; + ++index; } -#ifdef PQI_HDL_DEBUG_UR - t_now = 1000 * getCurrentTS(); - std::cerr << dec << t_now << " pqihandler::UpdateRates(): Sorting used_bw_out_table: " << num_sm << " entries" << std::endl; +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates Sorting used_bw_out_table: " << num_sm << " entries" << std::endl; #endif /* Sort the used bw in/out table in ascending order */ std::sort(used_bw_in_table, used_bw_in_table + num_sm); std::sort(used_bw_out_table, used_bw_out_table + num_sm); -#ifdef PQI_HDL_DEBUG_UR - t_now = 1000 * getCurrentTS(); - std::cerr << dec << t_now << " pqihandler::UpdateRates(): Done." << std::endl; - std::cerr << dec << t_now << " pqihandler::UpdateRates(): used_bw_out " << used_bw_out << std::endl; +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates used_bw_out " << used_bw_out << std::endl; #endif /* Calculate the optimal out_max value, taking into account avail_out and the out bw requested by modules */ @@ -441,9 +402,8 @@ int pqihandler::UpdateRates() } } -#ifdef PQI_HDL_DEBUG_UR - t_now = 1000 * getCurrentTS(); - std::cerr << dec << t_now << " pqihandler::UpdateRates(): mod_index " << mod_index << " out_max_bw " << out_max_bw << " remaining out bw " << out_remaining_bw << std::endl; +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates mod_index " << mod_index << " out_max_bw " << out_max_bw << " remaining out bw " << out_remaining_bw << std::endl; #endif /* Allocate only half the remaining out bw, if any, to make it smoother */ @@ -473,67 +433,70 @@ int pqihandler::UpdateRates() } } -#ifdef PQI_HDL_DEBUG_UR - t_now = 1000 * getCurrentTS(); - std::cerr << dec << t_now << " pqihandler::UpdateRates(): mod_index " << mod_index << " in_max_bw " << in_max_bw << " remaining in bw " << in_remaining_bw << std::endl; +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates mod_index " << mod_index << " in_max_bw " << in_max_bw << " remaining in bw " << in_remaining_bw << std::endl; #endif /* Allocate only half the remaining in bw, if any, to make it smoother */ in_max_bw = in_max_bw + in_remaining_bw / 2; - -#ifdef DEBUG_QOS -// std::cerr << "Totals (In) Used B/W " << used_bw_in; -// std::cerr << " Available B/W " << avail_in; -// std::cerr << " Effective transfers " << effectiveDownloadsSm << std::endl; -// std::cerr << "Totals (Out) Used B/W " << used_bw_out; -// std::cerr << " Available B/W " << avail_out; -// std::cerr << " Effective transfers " << effectiveUploadsSm << std::endl; -#endif - + // store current total in and ou used bw locked_StoreCurrentRates(used_bw_in, used_bw_out); - //computing average rates for effective transfers - float max_in_effective = avail_in / num_sm; - if (effectiveDownloadsSm != 0) { - max_in_effective = avail_in / effectiveDownloadsSm; - } - float max_out_effective = avail_out / num_sm; - if (effectiveUploadsSm != 0) { - max_out_effective = avail_out / effectiveUploadsSm; - } - - //modify the in and out limit -#ifdef PQI_HDL_DEBUG_UR - t_now = 1000 * getCurrentTS(); - std::cerr << dec << t_now << " pqihandler::UpdateRates(): setting new out_max " << out_max_bw << " in_max " << in_max_bw << std::endl; +#ifdef UPDATE_RATES_DEBUG + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates setting new out_max " << out_max_bw << " in_max " << in_max_bw << std::endl; #endif + // retrieve down (from peer point of view) bandwidth limits set by peers in their own settings + std::map rateMap; + rsConfig->getAllBandwidthRates(rateMap); + std::map::iterator rateMap_it; + +#ifdef UPDATE_RATES_DEBUG + // Dump RsConfigurationDataRates + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates RsConfigDataRates dump" << std::endl; + for (rateMap_it = rateMap.begin(); rateMap_it != rateMap.end(); rateMap_it++) + RsDbg () << "UPDATE_RATES pqihandler::UpdateRates PeerId " << rateMap_it->first.toStdString() << " mAllowedOut " << rateMap_it->second.mAllowedOut << std::endl; +#endif + + // update max rates taking into account the limits set by peers in their own settings for(it = mods.begin(); it != mods.end(); ++it) { SearchModule *mod = (it -> second); - - mod -> pqi -> setMaxRate(true, in_max_bw); - mod -> pqi -> setMaxRate(false, out_max_bw); + + // for our down bandwidth we set the max to the calculated value without taking into account the max set by peers: they will control their up bw on their side + mod -> pqi -> setMaxRate(true, in_max_bw); + + // for our up bandwidth we limit to the maximum down bw provided by peers via BwCtrl because we don't want to clog our outqueues, the SSL buffers, and our friends inbound queues + if ((rateMap_it = rateMap.find(mod->pqi->PeerId())) != rateMap.end()) + { + if (rateMap_it->second.mAllowedOut > 0) + { + if (out_max_bw > rateMap_it->second.mAllowedOut) + mod -> pqi -> setMaxRate(false, rateMap_it->second.mAllowedOut); + else + mod -> pqi -> setMaxRate(false, out_max_bw); + } + else + mod -> pqi -> setMaxRate(false, out_max_bw); + } } - - //cap the rates +#ifdef UPDATE_RATES_DEBUG + // dump maxRates for(it = mods.begin(); it != mods.end(); ++it) { SearchModule *mod = (it -> second); - if (mod -> pqi -> getMaxRate(false) < max_out_effective) mod -> pqi -> setMaxRate(false, max_out_effective); - if (mod -> pqi -> getMaxRate(false) > avail_out) mod -> pqi -> setMaxRate(false, avail_out); - if (mod -> pqi -> getMaxRate(true) < max_in_effective) mod -> pqi -> setMaxRate(true, max_in_effective); - if (mod -> pqi -> getMaxRate(true) > avail_in) mod -> pqi -> setMaxRate(true, avail_in); + RsDbg() << "UPDATE_RATES pqihandler::UpdateRates PeerID " << (mod ->pqi -> PeerId()).toStdString() << " new bandwidth limits up " << mod -> pqi -> getMaxRate(false) << " down " << mod -> pqi -> getMaxRate(true) << std::endl; } +#endif return 1; } void pqihandler::getCurrentRates(float &in, float &out) { - RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/ + RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/ in = rateTotal_in; out = rateTotal_out; From e5e468b083059cbbb091c5e8ffc7605c5ec54e60 Mon Sep 17 00:00:00 2001 From: Phenom Date: Tue, 12 May 2020 19:52:49 +0200 Subject: [PATCH 010/154] Fix AutoLogin --- libretroshare/src/libretroshare.pro | 2 ++ libretroshare/src/rsserver/rsloginhandler.cc | 10 +++++++++- libretroshare/src/use_libretroshare.pri | 5 +++++ retroshare-gui/src/retroshare-gui.pro | 4 ++++ retroshare-service/src/retroshare-service.pro | 10 ++++++++++ 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index c7b38ce0b..495caf4b2 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -327,6 +327,8 @@ INCLUDEPATH *= $${OPENPGPSDK_DIR} PRE_TARGETDEPS *= $${OPENPGPSDK_DIR}/lib/libops.a LIBS *= $${OPENPGPSDK_DIR}/lib/libops.a -lbz2 +################################### HEADERS & SOURCES ############################# + HEADERS += ft/ftchunkmap.h \ ft/ftcontroller.h \ ft/ftdata.h \ diff --git a/libretroshare/src/rsserver/rsloginhandler.cc b/libretroshare/src/rsserver/rsloginhandler.cc index 8a0469e1d..dbe023235 100644 --- a/libretroshare/src/rsserver/rsloginhandler.cc +++ b/libretroshare/src/rsserver/rsloginhandler.cc @@ -26,6 +26,7 @@ #include "rsloginhandler.h" #include "util/rsdir.h" #include "retroshare/rsinit.h" +#include "util/rsdebug.h" //#define DEBUG_RSLOGINHANDLER 1 @@ -497,8 +498,15 @@ bool RsLoginHandler::enableAutoLogin(const RsPeerId& ssl_id,const std::string& s NULL); if (error) { + RsErr() << __PRETTY_FUNCTION__ + << " Could not store passwd using libsecret with" + << " error.code=" << error->code + << " error.domain=" << error->domain + << " error.message=\"" << error->message << "\"" << std::endl; + if (error->code == 2) + RsErr() << "Do have a key wallet installed?" << std::endl + << "Like gnome-keyring or other using \"Secret Service\" by DBus." << std::endl; g_error_free (error); - std::cerr << "Could not store passwd using libsecret" << std::endl; return false; } std::cout << "Stored passwd " << "************************" << " using libsecret" << std::endl; diff --git a/libretroshare/src/use_libretroshare.pri b/libretroshare/src/use_libretroshare.pri index 681805a7f..eb7a4e470 100644 --- a/libretroshare/src/use_libretroshare.pri +++ b/libretroshare/src/use_libretroshare.pri @@ -102,3 +102,8 @@ android-* { CONFIG *= qt QT *= network } + +################################### Pkg-Config Stuff ############################# + +LIBS *= $$system(pkg-config --libs $$PKGCONFIG) + diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index a5d6838ae..68f2987c0 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -344,12 +344,16 @@ openbsd-* { LIBS *= -rdynamic } +################################### COMMON stuff ################################## + wikipoos { PRE_TARGETDEPS *= $$OUT_PWD/../../supportlibs/pegmarkdown/lib/libpegmarkdown.a LIBS *= $$OUT_PWD/../../supportlibs/pegmarkdown/lib/libpegmarkdown.a LIBS *= -lglib-2.0 } +################################### HEADERS & SOURCES ############################# + # Tor controller HEADERS += TorControl/AddOnionCommand.h \ diff --git a/retroshare-service/src/retroshare-service.pro b/retroshare-service/src/retroshare-service.pro index 75cb0b581..ae3b38049 100644 --- a/retroshare-service/src/retroshare-service.pro +++ b/retroshare-service/src/retroshare-service.pro @@ -29,6 +29,8 @@ QT -= gui SOURCES += retroshare-service.cc +################################# Linux ########################################## + android-* { QT += androidextras @@ -56,11 +58,14 @@ appimage { INSTALLS += desktop_files } + unix { target.path = "$${RS_BIN_DIR}" INSTALLS += target } +################################# MacOSX ########################################## + macx { # ENABLE THIS OPTION FOR Univeral Binary BUILD. #CONFIG += ppc x86 @@ -81,6 +86,8 @@ macx { INCLUDEPATH += . $$INC_DIR } +################################# Windows ########################################## + win32-g++ { CONFIG(debug, debug|release) { # show console output @@ -130,3 +137,6 @@ win32-g++ { QMAKE_PRE_LINK = $(CHK_DIR_EXISTS) lib || $(MKDIR) lib } } + +################################### COMMON stuff ################################## + From ea827b180a29806e80f916e437c370f526c48c76 Mon Sep 17 00:00:00 2001 From: jolavillette Date: Sat, 23 May 2020 22:20:49 +0200 Subject: [PATCH 011/154] restore 1.1 factor in ft/fttransfermodule --- libretroshare/src/ft/fttransfermodule.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libretroshare/src/ft/fttransfermodule.cc b/libretroshare/src/ft/fttransfermodule.cc index ab9900762..8c6ae1f08 100644 --- a/libretroshare/src/ft/fttransfermodule.cc +++ b/libretroshare/src/ft/fttransfermodule.cc @@ -789,16 +789,16 @@ bool ftTransferModule::locked_tickPeerTransfer(peerInfo &info) std::cerr << std::endl; #endif - // cap next_req to desiredRate in order to respect the bandwidth limit and to avoid clogging our outqueue - if (next_req > info.desiredRate) + if (next_req > info.desiredRate * 1.1) { - next_req = info.desiredRate; + next_req = info.desiredRate * 1.1; #ifdef FT_DEBUG std::cerr << "locked_tickPeerTransfer() Reached MaxRate: next_req: " << next_req; std::cerr << std::endl; #endif } + if (next_req > FT_TM_MAX_PEER_RATE) { next_req = FT_TM_MAX_PEER_RATE; From ebf32bf955a3a1ab0e80f14a3edea65763aca694 Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 27 May 2020 22:27:30 +0200 Subject: [PATCH 012/154] moved parts of the GrpMeta cache into a template to also handle MsgMeta --- libretroshare/src/gxs/rsdataservice.cc | 138 ++++++++----------------- libretroshare/src/gxs/rsdataservice.h | 106 ++++++++++++++++++- 2 files changed, 142 insertions(+), 102 deletions(-) diff --git a/libretroshare/src/gxs/rsdataservice.cc b/libretroshare/src/gxs/rsdataservice.cc index 6bdc924ed..8bf848a38 100644 --- a/libretroshare/src/gxs/rsdataservice.cc +++ b/libretroshare/src/gxs/rsdataservice.cc @@ -110,8 +110,6 @@ const std::string RsGeneralDataService::MSG_META_STATUS = KEY_MSG_STATUS; const uint32_t RsGeneralDataService::GXS_MAX_ITEM_SIZE = 1572864; // 1.5 Mbytes -static const uint32_t CACHE_ENTRY_GRACE_PERIOD = 600 ; // 10 minutes - static int addColumn(std::list &list, const std::string &attribute) { list.push_back(attribute); @@ -123,7 +121,6 @@ RsDataService::RsDataService(const std::string &serviceDir, const std::string &d : RsGeneralDataService(), mDbMutex("RsDataService"), mServiceDir(serviceDir), mDbName(dbName), mDbPath(mServiceDir + "/" + dbName), mServType(serviceType), mDb(NULL) { bool isNewDatabase = !RsDirUtil::fileExists(mDbPath); - mGrpMetaDataCache_ContainsAllDatabase = false ; mDb = new RetroDb(mDbPath, RetroDb::OPEN_READWRITE_CREATE, key); @@ -488,8 +485,7 @@ bool RsDataService::finishReleaseUpdate(int release, bool result) RsGxsGrpMetaData* RsDataService::locked_getGrpMeta(RetroCursor &c, int colOffset,bool use_cache) { #ifdef RS_DATA_SERVICE_DEBUG - std::cerr << "RsDataService::locked_getGrpMeta()"; - std::cerr << std::endl; + std::cerr << "RsDataService::locked_getGrpMeta()" << std::endl; #endif bool ok = true; @@ -507,20 +503,13 @@ RsGxsGrpMetaData* RsDataService::locked_getGrpMeta(RetroCursor &c, int colOffset RsGxsGroupId grpId(tempId) ; if(use_cache) - { - auto it = mGrpMetaDataCache.find(grpId) ; - - if(it != mGrpMetaDataCache.end()) - grpMeta = it->second ; - else - { - grpMeta = new RsGxsGrpMetaData(); - mGrpMetaDataCache[grpId] = grpMeta ; - } - } + grpMeta = mGrpMetaDataCache.getOrCreateMeta(grpId); else grpMeta = new RsGxsGrpMetaData(); + // if(!grpMeta->mGroupId.isNull()) // the grpMeta is already initialized because it comes from the cache + // return grpMeta; + grpMeta->mGroupId = RsGxsGroupId(tempId); c.getString(mColGrpMeta_NxsIdentity + colOffset, tempId); grpMeta->mAuthorId = RsGxsId(tempId); @@ -653,24 +642,38 @@ RsNxsGrp* RsDataService::locked_getGroup(RetroCursor &c) return NULL; } -RsGxsMsgMetaData* RsDataService::locked_getMsgMeta(RetroCursor &c, int colOffset) +RsGxsMsgMetaData* RsDataService::locked_getMsgMeta(RetroCursor &c, int colOffset,bool use_cache) { - RsGxsMsgMetaData* msgMeta = new RsGxsMsgMetaData(); - bool ok = true; uint32_t data_len = 0, offset = 0; char* data = NULL; + RsGxsGroupId group_id; + RsGxsMessageId msg_id; + std::string gId; c.getString(mColMsgMeta_GrpId + colOffset, gId); - msgMeta->mGroupId = RsGxsGroupId(gId); + group_id = RsGxsGroupId(gId); std::string temp; c.getString(mColMsgMeta_MsgId + colOffset, temp); - msgMeta->mMsgId = RsGxsMessageId(temp); + msg_id = RsGxsMessageId(temp); // without these, a msg is meaningless - ok &= (!msgMeta->mGroupId.isNull()) && (!msgMeta->mMsgId.isNull()); + ok &= (!group_id.isNull()) && (!msg_id.isNull()); + + RsGxsMsgMetaData* msgMeta = nullptr; + +// if(use_cache) +// msgMeta = mMsgMetaDataCache[group_id].getOrCreateMeta(msg_id); +// else + msgMeta = new RsGxsMsgMetaData(); + + //if(!msgMeta->mGroupId.isNull()) // we cannot do that because the cursor needs to advance. Is there a method to skip some data in the db? + // return msgMeta; + + msgMeta->mGroupId = group_id; + msgMeta->mMsgId = msg_id; c.getString(mColMsgMeta_OrigMsgId + colOffset, temp); msgMeta->mOrigMsgId = RsGxsMessageId(temp); @@ -704,7 +707,7 @@ RsGxsMsgMetaData* RsDataService::locked_getMsgMeta(RetroCursor &c, int colOffset if(ok) return msgMeta; - else + else if(!use_cache) delete msgMeta; return NULL; @@ -834,7 +837,7 @@ int RsDataService::storeMessage(const std::list& msg) // This is needed so that mLastPost is correctly updated in the group meta when it is re-loaded. - locked_clearGrpMetaCache(msgMetaPtr->mGroupId); + mGrpMetaDataCache.clear(msgMetaPtr->mGroupId); } // finish transaction @@ -926,7 +929,7 @@ int RsDataService::storeGroup(const std::list& grp) cv.put(KEY_GRP_STATUS, (int32_t)grpMetaPtr->mGroupStatus); cv.put(KEY_GRP_LAST_POST, (int32_t)grpMetaPtr->mLastPost); - locked_updateGrpMetaCache(*grpMetaPtr); + mGrpMetaDataCache.updateMeta(grpMetaPtr->mGroupId,*grpMetaPtr); if (!mDb->sqlInsert(GRP_TABLE_NAME, "", cv)) { @@ -942,54 +945,6 @@ int RsDataService::storeGroup(const std::list& grp) return ret; } -void RsDataService::locked_updateGrpMetaCache(const RsGxsGrpMetaData& meta) -{ - auto it = mGrpMetaDataCache.find(meta.mGroupId) ; - - if(it != mGrpMetaDataCache.end()) - *(it->second) = meta ; - else - mGrpMetaDataCache[meta.mGroupId] = new RsGxsGrpMetaData(meta) ; -} - -void RsDataService::locked_clearGrpMetaCache(const RsGxsGroupId& gid) -{ - rstime_t now = time(NULL) ; - auto it = mGrpMetaDataCache.find(gid) ; - - // We dont actually delete the item, because it might be used by a calling client. - // In this case, the memory will not be used for long, so we keep it into a list for a safe amount - // of time and delete it later. Using smart pointers here would be more elegant, but that would need - // to be implemented thread safe, which is difficult in this case. - - if(it != mGrpMetaDataCache.end()) - { -#ifdef RS_DATA_SERVICE_DEBUG - std::cerr << "(II) moving database cache entry " << (void*)(*it).second << " to dead list." << std::endl; -#endif - - mOldCachedItems.push_back(std::make_pair(now,it->second)) ; - - mGrpMetaDataCache.erase(it) ; - mGrpMetaDataCache_ContainsAllDatabase = false; - } - - // We also take that opportunity to delete old entries. - - auto it2(mOldCachedItems.begin()); - - while(it2!=mOldCachedItems.end() && (*it2).first + CACHE_ENTRY_GRACE_PERIOD < now) - { -#ifdef RS_DATA_SERVICE_DEBUG - std::cerr << "(II) deleting old GXS database cache entry " << (void*)(*it2).second << ", " << now - (*it2).first << " seconds old." << std::endl; -#endif - - delete (*it2).second ; - it2 = mOldCachedItems.erase(it2) ; - } - -} - int RsDataService::updateGroup(const std::list &grp) { @@ -1058,7 +1013,7 @@ int RsDataService::updateGroup(const std::list &grp) mDb->sqlUpdate(GRP_TABLE_NAME, "grpId='" + grpPtr->grpId.toStdString() + "'", cv); - locked_updateGrpMetaCache(*grpMetaPtr); + mGrpMetaDataCache.updateMeta(grpMetaPtr->mGroupId,*grpMetaPtr); } // finish transaction bool ret = mDb->commitTransaction(); @@ -1275,7 +1230,7 @@ void RsDataService::locked_retrieveMessages(RetroCursor *c, std::vectormetaData = locked_getMsgMeta(*c, metaOffset); + m->metaData = locked_getMsgMeta(*c, metaOffset,false); } msgs.push_back(m); } @@ -1357,7 +1312,7 @@ void RsDataService::locked_retrieveMsgMeta(RetroCursor *c, std::vectormoveToFirst(); while(valid){ - RsGxsMsgMetaData* m = locked_getMsgMeta(*c, 0); + RsGxsMsgMetaData* m = locked_getMsgMeta(*c, 0,true); if(m != NULL) msgMeta.push_back(m); @@ -1385,13 +1340,13 @@ int RsDataService::retrieveGxsGrpMetaData(RsGxsGrpMetaTemporaryMap& grp) if(grp.empty()) { - if(mGrpMetaDataCache_ContainsAllDatabase) // grab all the stash from the cache, so as to avoid decryption costs. + if(mGrpMetaDataCache.isCacheUpToDate()) // grab all the stash from the cache, so as to avoid decryption costs. { #ifdef RS_DATA_SERVICE_DEBUG_CACHE std::cerr << (void*)this << ": RsDataService::retrieveGxsGrpMetaData() retrieving all from cache!" << std::endl; #endif - grp = mGrpMetaDataCache ; + grp = mGrpMetaDataCache.getFullMetaMap() ; } else { @@ -1426,9 +1381,8 @@ int RsDataService::retrieveGxsGrpMetaData(RsGxsGrpMetaTemporaryMap& grp) delete c; } - mGrpMetaDataCache_ContainsAllDatabase = true ; + mGrpMetaDataCache.setCacheUpToDate(true); } - } else { @@ -1436,15 +1390,10 @@ int RsDataService::retrieveGxsGrpMetaData(RsGxsGrpMetaTemporaryMap& grp) for(; mit != grp.end(); ++mit) { - std::map::const_iterator itt = mGrpMetaDataCache.find(mit->first) ; + RsGxsGrpMetaData *meta = mGrpMetaDataCache.getMeta(mit->first) ; - if(itt != mGrpMetaDataCache.end()) - { -#ifdef RS_DATA_SERVICE_DEBUG_CACHE - std::cerr << mDbName << ": Retrieving Grp metadata grpId=" << mit->first << " from cache!" << std::endl; -#endif - grp[mit->first] = itt->second ; - } + if(meta) + grp[mit->first] = meta; else { #ifdef RS_DATA_SERVICE_DEBUG_CACHE @@ -1538,7 +1487,7 @@ int RsDataService::updateGroupMetaData(GrpLocMetaData &meta) std::cerr << (void*)this << ": erasing old entry from cache." << std::endl; #endif - locked_clearGrpMetaCache(meta.grpId); + mGrpMetaDataCache.clear(meta.grpId); return mDb->sqlUpdate(GRP_TABLE_NAME, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", meta.val) ? 1 : 0; } @@ -1698,23 +1647,18 @@ bool RsDataService::locked_removeGroupEntries(const std::vector& g // start a transaction bool ret = mDb->beginTransaction(); - std::vector::const_iterator vit = grpIds.begin(); - - for(; vit != grpIds.end(); ++vit) + for(auto grpId:grpIds) { - - const RsGxsGroupId& grpId = *vit; mDb->sqlDelete(GRP_TABLE_NAME, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", ""); // also remove the group meta from cache. - locked_clearGrpMetaCache(*vit) ; + mGrpMetaDataCache.clear(grpId) ; } ret &= mDb->commitTransaction(); - - mGrpMetaDataCache_ContainsAllDatabase = false ; return ret; } + uint32_t RsDataService::cacheSize() const { return 0; } diff --git a/libretroshare/src/gxs/rsdataservice.h b/libretroshare/src/gxs/rsdataservice.h index 8b4e2aac9..5babb59ce 100644 --- a/libretroshare/src/gxs/rsdataservice.h +++ b/libretroshare/src/gxs/rsdataservice.h @@ -35,6 +35,104 @@ public: ContentValue cv; }; +template class t_MetaDataCache +{ +public: + t_MetaDataCache() : mCache_ContainsAllMetas(false) {} + + bool isCacheUpToDate() const { return mCache_ContainsAllMetas ; } + void setCacheUpToDate(bool b) { mCache_ContainsAllMetas = b; } + const std::map getFullMetaMap() const { return mMetas ; } + + MetaDataClass *getMeta(const ID& id) + { + auto itt = mMetas.find(id); + + if(itt != mMetas.end()) + return itt->second ; + else + return NULL; + } + + MetaDataClass *getOrCreateMeta(const ID& id) + { + MetaDataClass *meta = nullptr; + auto it = mMetas.find(id) ; + + if(it != mMetas.end()) + { +#ifdef RS_DATA_SERVICE_DEBUG + RsDbg() << __PRETTY_FUNCTION__ << ": getting group meta " << grpId << " from cache." << std::endl; +#endif + meta = it->second ; + } + else + { +#ifdef RS_DATA_SERVICE_DEBUG + RsDbg() << __PRETTY_FUNCTION__ << ": group meta " << grpId << " not in cache. Loading it from DB..." << std::endl; +#endif + meta = new MetaDataClass(); + mMetas[id] = meta ; + } + + return meta; + } + + void updateMeta(const ID& id,const MetaDataClass& meta) + { + auto it = mMetas.find(id) ; + + if(it != mMetas.end()) + *(it->second) = meta ; + else + mMetas[id] = new MetaDataClass(meta) ; + } + + void clear(const ID& id) + { + rstime_t now = time(NULL) ; + auto it = mMetas.find(id) ; + + // We dont actually delete the item, because it might be used by a calling client. + // In this case, the memory will not be used for long, so we keep it into a list for a safe amount + // of time and delete it later. Using smart pointers here would be more elegant, but that would need + // to be implemented thread safe, which is difficult in this case. + + if(it != mMetas.end()) + { +#ifdef RS_DATA_SERVICE_DEBUG + std::cerr << "(II) moving database cache entry " << (void*)(*it).second << " to dead list." << std::endl; +#endif + + mOldCachedItems.push_back(std::make_pair(now,it->second)) ; + + mMetas.erase(it) ; + mCache_ContainsAllMetas = false; + } + + // We also take that opportunity to delete old entries. + + auto it2(mOldCachedItems.begin()); + + while(it2!=mOldCachedItems.end() && (*it2).first + CACHE_ENTRY_GRACE_PERIOD < now) + { +#ifdef RS_DATA_SERVICE_DEBUG + std::cerr << "(II) deleting old GXS database cache entry " << (void*)(*it2).second << ", " << now - (*it2).first << " seconds old." << std::endl; +#endif + delete (*it2).second ; + it2 = mOldCachedItems.erase(it2) ; + } + } + +private: + std::map mMetas; + std::list > mOldCachedItems ; // dead list, where items get deleted after being unused for a while. This is due to not using smart ptrs. + + static const uint32_t CACHE_ENTRY_GRACE_PERIOD = 600 ; // 10 minutes + + bool mCache_ContainsAllMetas ; +}; + class RsDataService : public RsGeneralDataService { public: @@ -202,7 +300,7 @@ private: * extracts a msg meta item from a cursor at its * current position */ - RsGxsMsgMetaData* locked_getMsgMeta(RetroCursor& c, int colOffset); + RsGxsMsgMetaData* locked_getMsgMeta(RetroCursor& c, int colOffset, bool use_cache); /*! * extracts a grp meta item from a cursor at its @@ -348,10 +446,8 @@ private: void locked_clearGrpMetaCache(const RsGxsGroupId& gid); void locked_updateGrpMetaCache(const RsGxsGrpMetaData& meta); - std::map mGrpMetaDataCache ; - std::list > mOldCachedItems ; - - bool mGrpMetaDataCache_ContainsAllDatabase ; + t_MetaDataCache mGrpMetaDataCache; + std::map > mMsgMetaDataCache; }; #endif // RSDATASERVICE_H From eb6af15b1a0f67088f90c28b40905b6a6ffe4a7c Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 28 May 2020 15:11:14 +0200 Subject: [PATCH 013/154] enabled MsgMetaData cache in rsgxsdataaccess.cc and witched metas to const, and removed deletion of retrieved metas since now the cache handles it --- libretroshare/src/gxs/rsdataservice.cc | 314 +++++++++++++---------- libretroshare/src/gxs/rsdataservice.h | 21 +- libretroshare/src/gxs/rsgds.h | 4 +- libretroshare/src/gxs/rsgenexchange.cc | 22 +- libretroshare/src/gxs/rsgxs.h | 4 +- libretroshare/src/gxs/rsgxsdata.cc | 2 +- libretroshare/src/gxs/rsgxsdata.h | 2 +- libretroshare/src/gxs/rsgxsdataaccess.cc | 92 ++++--- libretroshare/src/gxs/rsgxsdataaccess.h | 12 +- libretroshare/src/gxs/rsgxsnetservice.cc | 25 +- libretroshare/src/gxs/rsgxsnetservice.h | 2 +- libretroshare/src/gxs/rsgxsutil.cc | 6 +- 12 files changed, 277 insertions(+), 229 deletions(-) diff --git a/libretroshare/src/gxs/rsdataservice.cc b/libretroshare/src/gxs/rsdataservice.cc index 8bf848a38..b09e62c99 100644 --- a/libretroshare/src/gxs/rsdataservice.cc +++ b/libretroshare/src/gxs/rsdataservice.cc @@ -507,8 +507,8 @@ RsGxsGrpMetaData* RsDataService::locked_getGrpMeta(RetroCursor &c, int colOffset else grpMeta = new RsGxsGrpMetaData(); - // if(!grpMeta->mGroupId.isNull()) // the grpMeta is already initialized because it comes from the cache - // return grpMeta; + if(!grpMeta->mGroupId.isNull()) // the grpMeta is already initialized because it comes from the cache + return grpMeta; grpMeta->mGroupId = RsGxsGroupId(tempId); c.getString(mColGrpMeta_NxsIdentity + colOffset, tempId); @@ -664,13 +664,13 @@ RsGxsMsgMetaData* RsDataService::locked_getMsgMeta(RetroCursor &c, int colOffset RsGxsMsgMetaData* msgMeta = nullptr; -// if(use_cache) -// msgMeta = mMsgMetaDataCache[group_id].getOrCreateMeta(msg_id); -// else + if(use_cache) + msgMeta = mMsgMetaDataCache[group_id].getOrCreateMeta(msg_id); + else msgMeta = new RsGxsMsgMetaData(); - //if(!msgMeta->mGroupId.isNull()) // we cannot do that because the cursor needs to advance. Is there a method to skip some data in the db? - // return msgMeta; + if(!msgMeta->mGroupId.isNull()) // we cannot do that because the cursor needs to advance. Is there a method to skip some data in the db? + return msgMeta; msgMeta->mGroupId = group_id; msgMeta->mMsgId = msg_id; @@ -838,6 +838,7 @@ int RsDataService::storeMessage(const std::list& msg) // This is needed so that mLastPost is correctly updated in the group meta when it is re-loaded. mGrpMetaDataCache.clear(msgMetaPtr->mGroupId); + mMsgMetaDataCache[msgMetaPtr->mGroupId].updateMeta(msgMetaPtr->mMsgId,*msgMetaPtr); } // finish transaction @@ -1240,7 +1241,7 @@ void RsDataService::locked_retrieveMessages(RetroCursor *c, std::vectorfirst; + const std::set& msgIdV = mit->second; // if vector empty then request all messages - const std::set& msgIdV = mit->second; - std::vector metaSet; - if(msgIdV.empty()){ - RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, mMsgMetaColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", ""); + t_MetaDataCache& cache(mMsgMetaDataCache[grpId]); - if (c) - { - locked_retrieveMsgMeta(c, metaSet); + if(msgIdV.empty()) + { + if(cache.isCacheUpToDate()) + cache.getFullMetaList(msgMeta[grpId]); + else + { + RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, mMsgMetaColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", ""); + + if (c) + { + locked_retrieveMsgMetaList(c, msgMeta[grpId]); #ifdef RS_DATA_SERVICE_DEBUG_CACHE - std::cerr << mDbName << ": Retrieving (all) Msg metadata grpId=" << grpId << ", " << std::dec << metaSet.size() << " messages" << std::endl; + std::cerr << mDbName << ": Retrieving (all) Msg metadata grpId=" << grpId << ", " << std::dec << metaSet.size() << " messages" << std::endl; #endif - } - }else{ - - // request each grp - std::set::const_iterator sit = msgIdV.begin(); - - for(; sit!=msgIdV.end(); ++sit){ - const RsGxsMessageId& msgId = *sit; - RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, mMsgMetaColumns, KEY_GRP_ID+ "='" + grpId.toStdString() - + "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", ""); - - if (c) - { - locked_retrieveMsgMeta(c, metaSet); -#ifdef RS_DATA_SERVICE_DEBUG_CACHE - std::cerr << mDbName << ": Retrieving Msg metadata grpId=" << grpId << ", " << std::dec << metaSet.size() << " messages" << std::endl; -#endif - } - } + cache.setCacheUpToDate(true); + } + delete c; + } } + else + { + // request each msg meta + auto& metaSet(msgMeta[grpId]); -#ifdef RS_DATA_SERVICE_DEBUG_TIME - resultCount += metaSet.size(); + for(auto sit(msgIdV.begin()); sit!=msgIdV.end(); ++sit) + { + const RsGxsMessageId& msgId = *sit; + + RsGxsMsgMetaData *meta = cache.getMeta(msgId); + + if(meta) + metaSet.push_back(meta); + else + { + RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, mMsgMetaColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", ""); + + c->moveToFirst(); + RsGxsMsgMetaData* meta = locked_getMsgMeta(*c, 0,true); + + if(meta) + metaSet.push_back(meta); + + delete c; + +#ifdef RS_DATA_SERVICE_DEBUG_CACHE + std::cerr << mDbName << ": Retrieving Msg metadata grpId=" << grpId << ", " << std::dec << metaSet.size() << " messages" << std::endl; #endif - - msgMeta[grpId] = metaSet; + } + } + } } #ifdef RS_DATA_SERVICE_DEBUG_TIME @@ -1305,22 +1320,43 @@ int RsDataService::retrieveGxsMsgMetaData(const GxsMsgReq& reqIds, GxsMsgMetaRes return 1; } -void RsDataService::locked_retrieveMsgMeta(RetroCursor *c, std::vector &msgMeta) +void RsDataService::locked_retrieveGrpMetaList(RetroCursor *c, std::map& grpMeta) { + if(!c) + { + RsErr() << __PRETTY_FUNCTION__ << ": attempt to retrieve Group Meta data from the DB with null cursor!" << std::endl; + return; + } - if(c) - { - bool valid = c->moveToFirst(); - while(valid){ - RsGxsMsgMetaData* m = locked_getMsgMeta(*c, 0,true); + bool valid = c->moveToFirst(); - if(m != NULL) - msgMeta.push_back(m); + while(valid) + { + RsGxsGrpMetaData* m = locked_getGrpMeta(*c, 0,true); - valid = c->moveToNext(); - } - delete c; - } + if(m) + grpMeta[m->mGroupId] = m; + + valid = c->moveToNext(); + } +} +void RsDataService::locked_retrieveMsgMetaList(RetroCursor *c, std::vector& msgMeta) +{ + if(!c) + { + RsErr() << __PRETTY_FUNCTION__ << ": attempt to retrieve Msg Meta data from the DB with null cursor!" << std::endl; + return; + } + + bool valid = c->moveToFirst(); + while(valid){ + const RsGxsMsgMetaData* m = locked_getMsgMeta(*c, 0,true); + + if(m != NULL) + msgMeta.push_back(m); + + valid = c->moveToNext(); + } } int RsDataService::retrieveGxsGrpMetaData(RsGxsGrpMetaTemporaryMap& grp) @@ -1346,7 +1382,7 @@ int RsDataService::retrieveGxsGrpMetaData(RsGxsGrpMetaTemporaryMap& grp) std::cerr << (void*)this << ": RsDataService::retrieveGxsGrpMetaData() retrieving all from cache!" << std::endl; #endif - grp = mGrpMetaDataCache.getFullMetaMap() ; + mGrpMetaDataCache.getFullMetaList(grp) ; } else { @@ -1357,87 +1393,99 @@ int RsDataService::retrieveGxsGrpMetaData(RsGxsGrpMetaTemporaryMap& grp) RetroCursor* c = mDb->sqlQuery(GRP_TABLE_NAME, mGrpMetaColumns, "", ""); - if(c) + if(c) { - bool valid = c->moveToFirst(); + locked_retrieveGrpMetaList(c,grp); - while(valid) - { - RsGxsGrpMetaData* g = locked_getGrpMeta(*c, 0,true); - - if(g) - { - grp[g->mGroupId] = g; -#ifdef RS_DATA_SERVICE_DEBUG_CACHE - std::cerr << (void *)this << " " << mDbName << ": Retrieving (all) Grp metadata grpId=" << g->mGroupId << std::endl; -#endif - } - valid = c->moveToNext(); - -#ifdef RS_DATA_SERVICE_DEBUG_TIME - ++resultCount; -#endif - } - delete c; + mGrpMetaDataCache.setCacheUpToDate(true); } + delete c; - mGrpMetaDataCache.setCacheUpToDate(true); +// if(c) +// { +// bool valid = c->moveToFirst(); +// +// while(valid) +// { +// RsGxsGrpMetaData* g = locked_getGrpMeta(*c, 0,true); +// +// if(g) +// { +// grp[g->mGroupId] = g; +//#ifdef RS_DATA_SERVICE_DEBUG_CACHE +// std::cerr << (void *)this << " " << mDbName << ": Retrieving (all) Grp metadata grpId=" << g->mGroupId << std::endl; +//#endif +// } +// valid = c->moveToNext(); +// +//#ifdef RS_DATA_SERVICE_DEBUG_TIME +// ++resultCount; +//#endif +// } +// delete c; +// } } } else - { - std::map::iterator mit = grp.begin(); + { + for(auto mit(grp.begin()); mit != grp.end(); ++mit) + { + RsGxsGrpMetaData *meta = mGrpMetaDataCache.getMeta(mit->first) ; - for(; mit != grp.end(); ++mit) - { - RsGxsGrpMetaData *meta = mGrpMetaDataCache.getMeta(mit->first) ; - - if(meta) - grp[mit->first] = meta; - else - { + if(meta) + grp[mit->first] = meta; + else + { #ifdef RS_DATA_SERVICE_DEBUG_CACHE - std::cerr << mDbName << ": Retrieving Grp metadata grpId=" << mit->first ; + std::cerr << mDbName << ": Retrieving Grp metadata grpId=" << mit->first ; #endif - const RsGxsGroupId& grpId = mit->first; - RetroCursor* c = mDb->sqlQuery(GRP_TABLE_NAME, mGrpMetaColumns, "grpId='" + grpId.toStdString() + "'", ""); + const RsGxsGroupId& grpId = mit->first; + RetroCursor* c = mDb->sqlQuery(GRP_TABLE_NAME, mGrpMetaColumns, "grpId='" + grpId.toStdString() + "'", ""); - if(c) - { - bool valid = c->moveToFirst(); + c->moveToFirst(); + RsGxsGrpMetaData* meta = locked_getGrpMeta(*c, 0,true); + if(meta) + grp[mit->first] = meta; + + delete c; + + // if(c) + // { + // bool valid = c->moveToFirst(); + // + //#ifdef RS_DATA_SERVICE_DEBUG_CACHE + // if(!valid) + // std::cerr << " Empty query! GrpId " << grpId << " is not in database" << std::endl; + //#endif + // while(valid) + // { + // RsGxsGrpMetaData* g = locked_getGrpMeta(*c, 0,true); + // + // if(g) + // { + // grp[g->mGroupId] = g; + //#ifdef RS_DATA_SERVICE_DEBUG_CACHE + // std::cerr << ". Got it. Updating cache." << std::endl; + //#endif + // } + // valid = c->moveToNext(); + // + //#ifdef RS_DATA_SERVICE_DEBUG_TIME + // ++resultCount; + //#endif + // } + // delete c; + // } #ifdef RS_DATA_SERVICE_DEBUG_CACHE - if(!valid) - std::cerr << " Empty query! GrpId " << grpId << " is not in database" << std::endl; + else + std::cerr << ". not found!" << std::endl; #endif - while(valid) - { - RsGxsGrpMetaData* g = locked_getGrpMeta(*c, 0,true); + } + } - if(g) - { - grp[g->mGroupId] = g; -#ifdef RS_DATA_SERVICE_DEBUG_CACHE - std::cerr << ". Got it. Updating cache." << std::endl; -#endif - } - valid = c->moveToNext(); - -#ifdef RS_DATA_SERVICE_DEBUG_TIME - ++resultCount; -#endif - } - delete c; - } -#ifdef RS_DATA_SERVICE_DEBUG_CACHE - else - std::cerr << ". not found!" << std::endl; -#endif - } - } - - } + } #ifdef RS_DATA_SERVICE_DEBUG_TIME std::cerr << "RsDataService::retrieveGxsGrpMetaData() " << mDbName << ", Requests: " << requestedGroups << ", Results: " << resultCount << ", Time: " << timer.duration() << std::endl; @@ -1474,14 +1522,14 @@ int RsDataService::resetDataStore() return 1; } -int RsDataService::updateGroupMetaData(GrpLocMetaData &meta) +int RsDataService::updateGroupMetaData(const GrpLocMetaData& meta) { #ifdef RS_DATA_SERVICE_DEBUG_CACHE std::cerr << (void*)this << ": Updating Grp Meta data: grpId = " << meta.grpId << std::endl; #endif RsStackMutex stack(mDbMutex); - RsGxsGroupId& grpId = meta.grpId; + const RsGxsGroupId& grpId = meta.grpId; #ifdef RS_DATA_SERVICE_DEBUG_CACHE std::cerr << (void*)this << ": erasing old entry from cache." << std::endl; @@ -1492,17 +1540,19 @@ int RsDataService::updateGroupMetaData(GrpLocMetaData &meta) return mDb->sqlUpdate(GRP_TABLE_NAME, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", meta.val) ? 1 : 0; } -int RsDataService::updateMessageMetaData(MsgLocMetaData &metaData) +int RsDataService::updateMessageMetaData(const MsgLocMetaData& metaData) { #ifdef RS_DATA_SERVICE_DEBUG_CACHE std::cerr << (void*)this << ": Updating Msg Meta data: grpId = " << metaData.msgId.first << " msgId = " << metaData.msgId.second << std::endl; #endif RsStackMutex stack(mDbMutex); - RsGxsGroupId& grpId = metaData.msgId.first; - RsGxsMessageId& msgId = metaData.msgId.second; - return mDb->sqlUpdate(MSG_TABLE_NAME, KEY_GRP_ID+ "='" + grpId.toStdString() - + "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", metaData.val) ? 1 : 0; + const RsGxsGroupId& grpId = metaData.msgId.first; + const RsGxsMessageId& msgId = metaData.msgId.second; + + mMsgMetaDataCache[grpId].clear(msgId); + + return mDb->sqlUpdate(MSG_TABLE_NAME, KEY_GRP_ID+ "='" + grpId.toStdString() + "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", metaData.val) ? 1 : 0; } int RsDataService::removeMsgs(const GxsMsgReq& msgIds) @@ -1627,13 +1677,13 @@ bool RsDataService::locked_removeMessageEntries(const GxsMsgReq& msgIds) { const RsGxsGroupId& grpId = mit->first; const std::set& msgsV = mit->second; - std::set::const_iterator vit = msgsV.begin(); + auto& cache(mMsgMetaDataCache[grpId]); - for(; vit != msgsV.end(); ++vit) + for(auto& msgId:msgsV) { - const RsGxsMessageId& msgId = *vit; - mDb->sqlDelete(MSG_TABLE_NAME, KEY_GRP_ID+ "='" + grpId.toStdString() - + "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", ""); + mDb->sqlDelete(MSG_TABLE_NAME, KEY_GRP_ID+ "='" + grpId.toStdString() + "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", ""); + + cache.clear(msgId); } } diff --git a/libretroshare/src/gxs/rsdataservice.h b/libretroshare/src/gxs/rsdataservice.h index 5babb59ce..35234be9e 100644 --- a/libretroshare/src/gxs/rsdataservice.h +++ b/libretroshare/src/gxs/rsdataservice.h @@ -42,7 +42,9 @@ public: bool isCacheUpToDate() const { return mCache_ContainsAllMetas ; } void setCacheUpToDate(bool b) { mCache_ContainsAllMetas = b; } - const std::map getFullMetaMap() const { return mMetas ; } + + void getFullMetaList(std::map& mp) const { mp = mMetas ; } + void getFullMetaList(std::vector& mp) const { for(auto& m:mMetas) mp.push_back(m.second) ; } MetaDataClass *getMeta(const ID& id) { @@ -128,7 +130,7 @@ private: std::map mMetas; std::list > mOldCachedItems ; // dead list, where items get deleted after being unused for a while. This is due to not using smart ptrs. - static const uint32_t CACHE_ENTRY_GRACE_PERIOD = 600 ; // 10 minutes + static const uint32_t CACHE_ENTRY_GRACE_PERIOD = 600 ; // Unused items are deleted 10 minutes after last usage. bool mCache_ContainsAllMetas ; }; @@ -245,13 +247,13 @@ public: * @param metaData The meta data item to update * @return error code */ - int updateMessageMetaData(MsgLocMetaData& metaData); + int updateMessageMetaData(const MsgLocMetaData& metaData); /*! * @param metaData The meta data item to update * @return error code */ - int updateGroupMetaData(GrpLocMetaData& meta); + int updateGroupMetaData(const GrpLocMetaData &meta); /*! * Completely clear out data stored in @@ -292,9 +294,16 @@ private: /*! * Retrieves all the msg meta results from a cursor * @param c cursor to result set - * @param metaSet message metadata retrieved from cursor are stored here + * @param msgMeta message metadata retrieved from cursor are stored here */ - void locked_retrieveMsgMeta(RetroCursor* c, std::vector& msgMeta); + void locked_retrieveMsgMetaList(RetroCursor* c, std::vector& msgMeta); + + /*! + * Retrieves all the grp meta results from a cursor + * @param c cursor to result set + * @param grpMeta group metadata retrieved from cursor are stored here + */ + void locked_retrieveGrpMetaList(RetroCursor *c, std::map& grpMeta); /*! * extracts a msg meta item from a cursor at its diff --git a/libretroshare/src/gxs/rsgds.h b/libretroshare/src/gxs/rsgds.h index 04c2b17e7..fb985b9f7 100644 --- a/libretroshare/src/gxs/rsgds.h +++ b/libretroshare/src/gxs/rsgds.h @@ -239,12 +239,12 @@ public: /*! * @param metaData */ - virtual int updateMessageMetaData(MsgLocMetaData& metaData) = 0; + virtual int updateMessageMetaData(const MsgLocMetaData& metaData) = 0; /*! * @param metaData */ - virtual int updateGroupMetaData(GrpLocMetaData& meta) = 0; + virtual int updateGroupMetaData(const GrpLocMetaData& meta) = 0; virtual int updateGroupKeys(const RsGxsGroupId& grpId,const RsTlvSecurityKeySet& keys,uint32_t subscribed_flags) = 0 ; diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index 8debf99f4..bfc1bbd23 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -1274,18 +1274,18 @@ bool RsGenExchange::getMsgMeta(const uint32_t &token, for(; mit != result.end(); ++mit) { - std::vector& metaV = mit->second; + std::vector& metaV = mit->second; std::vector& msgInfoV = msgInfo[mit->first]; - std::vector::iterator vit = metaV.begin(); + std::vector::iterator vit = metaV.begin(); RsMsgMetaData meta; for(; vit != metaV.end(); ++vit) { - RsGxsMsgMetaData& m = *(*vit); + const RsGxsMsgMetaData& m = *(*vit); meta = m; msgInfoV.push_back(meta); - delete *vit; + //delete *vit; } metaV.clear(); } @@ -1302,18 +1302,18 @@ bool RsGenExchange::getMsgRelatedMeta(const uint32_t &token, GxsMsgRelatedMetaMa for(; mit != result.end(); ++mit) { - std::vector& metaV = mit->second; + std::vector& metaV = mit->second; std::vector& msgInfoV = msgMeta[mit->first]; - std::vector::iterator vit = metaV.begin(); + std::vector::iterator vit = metaV.begin(); RsMsgMetaData meta; for(; vit != metaV.end(); ++vit) { - RsGxsMsgMetaData& m = *(*vit); + const RsGxsMsgMetaData& m = *(*vit); meta = m; msgInfoV.push_back(meta); - delete *vit; + //delete *vit; } metaV.clear(); } @@ -2016,15 +2016,15 @@ void RsGenExchange::processMsgMetaChanges() if(mit != result.end()) { - std::vector& msgMetaV = mit->second; + std::vector& msgMetaV = mit->second; if(!msgMetaV.empty()) { - RsGxsMsgMetaData* meta = *(msgMetaV.begin()); + const RsGxsMsgMetaData* meta = *(msgMetaV.begin()); value = (meta->mMsgStatus & ~mask) | (mask & value); changed = (static_cast(meta->mMsgStatus) != value); m.val.put(RsGeneralDataService::MSG_META_STATUS, value); - delete meta; + //delete meta; ok = true; } } diff --git a/libretroshare/src/gxs/rsgxs.h b/libretroshare/src/gxs/rsgxs.h index 3f25b087b..fd7f693f9 100644 --- a/libretroshare/src/gxs/rsgxs.h +++ b/libretroshare/src/gxs/rsgxs.h @@ -29,8 +29,8 @@ /* data types used throughout Gxs from netservice to genexchange */ -typedef std::map > GxsMsgMetaResult; -typedef std::map > MsgRelatedMetaResult; +typedef std::map > GxsMsgMetaResult; +typedef std::map > MsgRelatedMetaResult; // Default values that are used throughout GXS code diff --git a/libretroshare/src/gxs/rsgxsdata.cc b/libretroshare/src/gxs/rsgxsdata.cc index 0ec61de8e..c3c9b9f08 100644 --- a/libretroshare/src/gxs/rsgxsdata.cc +++ b/libretroshare/src/gxs/rsgxsdata.cc @@ -209,7 +209,7 @@ RsGxsMsgMetaData::~RsGxsMsgMetaData(){ return; } -uint32_t RsGxsMsgMetaData::serial_size() +uint32_t RsGxsMsgMetaData::serial_size() const { uint32_t s = 8; // header size diff --git a/libretroshare/src/gxs/rsgxsdata.h b/libretroshare/src/gxs/rsgxsdata.h index 282f063fb..6ef5b0c28 100644 --- a/libretroshare/src/gxs/rsgxsdata.h +++ b/libretroshare/src/gxs/rsgxsdata.h @@ -94,7 +94,7 @@ public: ~RsGxsMsgMetaData(); bool deserialise(void *data, uint32_t *size); bool serialise(void* data, uint32_t *size); - uint32_t serial_size(); + uint32_t serial_size() const; void clear(); void operator =(const RsMsgMetaData& rMeta); diff --git a/libretroshare/src/gxs/rsgxsdataaccess.cc b/libretroshare/src/gxs/rsgxsdataaccess.cc index 6104b0b56..a695672f9 100644 --- a/libretroshare/src/gxs/rsgxsdataaccess.cc +++ b/libretroshare/src/gxs/rsgxsdataaccess.cc @@ -1028,7 +1028,7 @@ bool RsGxsDataAccess::getMsgMetaDataList( const GxsMsgReq& msgIds, const RsTokRe //auto& filter( metaFilter[grpId] ); // does the initialization of metaFilter[grpId] and avoids further O(log(n)) calls - std::vector& metaV = meta_it->second; + std::vector& metaV = meta_it->second; if (onlyLatestMsgs) // if we only consider latest messages, we need to first filter out messages with "children" { @@ -1062,7 +1062,7 @@ bool RsGxsDataAccess::getMsgMetaDataList( const GxsMsgReq& msgIds, const RsTokRe for(uint32_t i=0;imParentId.isNull()) { - delete msgMeta; + //delete msgMeta; metaV[i] = nullptr; continue; } if (onlyOrigMsgs && !msgMeta->mOrigMsgId.isNull() && msgMeta->mMsgId != msgMeta->mOrigMsgId) { - delete msgMeta; + //delete msgMeta; metaV[i] = nullptr; continue; } @@ -1187,7 +1187,7 @@ bool RsGxsDataAccess::getMsgIdList( const GxsMsgReq& msgIds, const RsTokReqOptio } // delete meta data - cleanseMsgMetaMap(result); + //cleanseMsgMetaMap(result); return true; } @@ -1296,9 +1296,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) return true; } - std::vector::iterator vit_msgIds = req->mMsgIds.begin(); - - for(; vit_msgIds != req->mMsgIds.end(); ++vit_msgIds) + for(auto vit_msgIds(req->mMsgIds.begin()); vit_msgIds != req->mMsgIds.end(); ++vit_msgIds) { MsgMetaFilter filterMap; @@ -1310,8 +1308,8 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) GxsMsgReq msgIds; msgIds.insert(std::make_pair(grpMsgIdPair.first, std::set())); mDataStore->retrieveGxsMsgMetaData(msgIds, result); - std::vector& metaV = result[grpMsgIdPair.first]; - std::vector::iterator vit_meta; + std::vector& metaV = result[grpMsgIdPair.first]; + std::vector::iterator vit_meta; // msg id to relate to const RsGxsMessageId& msgId = grpMsgIdPair.second; @@ -1319,10 +1317,11 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) std::set outMsgIds; - RsGxsMsgMetaData* origMeta = nullptr; + const RsGxsMsgMetaData* origMeta = nullptr; + for(vit_meta = metaV.begin(); vit_meta != metaV.end(); ++vit_meta) { - RsGxsMsgMetaData* meta = *vit_meta; + const RsGxsMsgMetaData* meta = *vit_meta; if(msgId == meta->mMsgId) { @@ -1337,12 +1336,11 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) RsDbg() << "RsGxsDataAccess::getMsgRelatedInfo(): Cannot find meta of msgId (to relate to)!" << std::endl; #endif - cleanseMsgMetaMap(result); return false; } const RsGxsMessageId& origMsgId = origMeta->mOrigMsgId; - std::map& metaMap = filterMap[grpId]; + std::map& metaMap = filterMap[grpId]; if (onlyLatestMsgs) { @@ -1354,7 +1352,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) for(vit_meta = metaV.begin(); vit_meta != metaV.end(); ++vit_meta) { - RsGxsMsgMetaData* meta = *vit_meta; + const RsGxsMsgMetaData* meta = *vit_meta; // skip msgs that aren't children. if (onlyChildMsgs) @@ -1422,11 +1420,11 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) /* first guess is potentially better than Orig (can't be worse!) */ rstime_t latestTs = 0; RsGxsMessageId latestMsgId; - RsGxsMsgMetaData* latestMeta=nullptr; + const RsGxsMsgMetaData* latestMeta=nullptr; for(vit_meta = metaV.begin(); vit_meta != metaV.end(); ++vit_meta) { - RsGxsMsgMetaData* meta = *vit_meta; + const RsGxsMsgMetaData* meta = *vit_meta; if (meta->mOrigMsgId == origMsgId) { @@ -1446,7 +1444,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) { for(vit_meta = metaV.begin(); vit_meta != metaV.end(); ++vit_meta) { - RsGxsMsgMetaData* meta = *vit_meta; + const RsGxsMsgMetaData* meta = *vit_meta; if (meta->mOrigMsgId == origMsgId) { @@ -1482,8 +1480,6 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req) outMsgIds.clear(); filteredOutMsgIds.clear(); - - cleanseMsgMetaMap(result); } return true; } @@ -1496,7 +1492,7 @@ bool RsGxsDataAccess::getGroupStatistic(GroupStatisticRequest *req) GxsMsgMetaResult metaResult; mDataStore->retrieveGxsMsgMetaData(metaReq, metaResult); - const std::vector& msgMetaV = metaResult[req->mGrpId]; + const std::vector& msgMetaV = metaResult[req->mGrpId]; req->mGroupStatistic.mGrpId = req->mGrpId; req->mGroupStatistic.mNumMsgs = msgMetaV.size(); @@ -1514,7 +1510,7 @@ bool RsGxsDataAccess::getGroupStatistic(GroupStatisticRequest *req) for(uint32_t i = 0; i < msgMetaV.size(); ++i) { - RsGxsMsgMetaData* m = msgMetaV[i]; + const RsGxsMsgMetaData* m = msgMetaV[i]; req->mGroupStatistic.mTotalSizeOfMsgs += m->mMsgSize + m->serial_size(); if(obsolete_msgs.find(m->mMsgId) != obsolete_msgs.end()) // skip obsolete messages. @@ -1540,7 +1536,7 @@ bool RsGxsDataAccess::getGroupStatistic(GroupStatisticRequest *req) } } - cleanseMsgMetaMap(metaResult); + //cleanseMsgMetaMap(metaResult); return true; } @@ -1595,21 +1591,19 @@ bool RsGxsDataAccess::getMsgIdList(MsgIdReq* req) mDataStore->retrieveGxsMsgMetaData(req->mMsgIds, result); - GxsMsgMetaResult::iterator mit = result.begin(), mit_end = result.end(); for(; mit != mit_end; ++mit) { const RsGxsGroupId grpId = mit->first; - std::vector& metaV = mit->second; - std::vector::iterator vit = metaV.begin(), + std::vector& metaV = mit->second; + std::vector::iterator vit = metaV.begin(), vit_end = metaV.end(); for(; vit != vit_end; ++vit) { - RsGxsMsgMetaData* meta = *vit; + const RsGxsMsgMetaData* meta = *vit; req->mMsgIdResult[grpId].insert(meta->mMsgId); - delete meta; // discard meta data mem } } @@ -1622,24 +1616,24 @@ bool RsGxsDataAccess::getMsgIdList(MsgIdReq* req) return true; } -void RsGxsDataAccess::cleanseMsgMetaMap(GxsMsgMetaResult& result) -{ - GxsMsgMetaResult::iterator mit = result.begin(); - - for(; mit !=result.end(); ++mit) - { - - std::vector& msgMetaV = mit->second; - std::vector::iterator vit = msgMetaV.begin(); - for(; vit != msgMetaV.end(); ++vit) - { - delete *vit; - } - } - - result.clear(); - return; -} +// void RsGxsDataAccess::cleanseMsgMetaMap(GxsMsgMetaResult& result) +// { +// GxsMsgMetaResult::iterator mit = result.begin(); +// +// for(; mit !=result.end(); ++mit) +// { +// +// std::vector& msgMetaV = mit->second; +// std::vector::iterator vit = msgMetaV.begin(); +// for(; vit != msgMetaV.end(); ++vit) +// { +// delete *vit; +// } +// } +// +// result.clear(); +// return; +// } void RsGxsDataAccess::filterMsgIdList( GxsMsgIdResult& resultsMap, const RsTokReqOptions& opts, const MsgMetaFilter& msgMetas ) const { @@ -1659,11 +1653,11 @@ void RsGxsDataAccess::filterMsgIdList( GxsMsgIdResult& resultsMap, const RsTokRe for( std::set::iterator msgIdIt = msgsIdSet.begin(); msgIdIt != msgsIdSet.end(); ) { const RsGxsMessageId& msgId(*msgIdIt); - const std::map& msgsMetaMap = + const std::map& msgsMetaMap = cit->second; bool keep = false; - std::map::const_iterator msgsMetaMapIt; + std::map::const_iterator msgsMetaMapIt; if( (msgsMetaMapIt = msgsMetaMap.find(msgId)) != msgsMetaMap.end() ) { diff --git a/libretroshare/src/gxs/rsgxsdataaccess.h b/libretroshare/src/gxs/rsgxsdataaccess.h index 21cb89b24..727ebe605 100644 --- a/libretroshare/src/gxs/rsgxsdataaccess.h +++ b/libretroshare/src/gxs/rsgxsdataaccess.h @@ -28,7 +28,7 @@ #include "rsgds.h" -typedef std::map< RsGxsGroupId, std::map > MsgMetaFilter; +typedef std::map< RsGxsGroupId, std::map > MsgMetaFilter; typedef std::map< RsGxsGroupId, RsGxsGrpMetaData* > GrpMetaFilter; bool operator<(const std::pair& p1,const std::pair& p2); @@ -328,11 +328,11 @@ private: */ void tokenList(std::list &tokens); - /*! - * Convenience function to delete the ids - * @param filter the meta filter to clean - */ - void cleanseMsgMetaMap(GxsMsgMetaResult& result); + // /*! + // * Convenience function to delete the ids + // * @param filter the meta filter to clean + // */ + // void cleanseMsgMetaMap(GxsMsgMetaResult& result); public: diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index 3259a060c..484ad466b 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -953,7 +953,7 @@ void RsGxsNetService::handleRecvSyncGrpStatistics(RsNxsSyncGrpStatsItem *grs) #endif mDataStore->retrieveGxsMsgMetaData(reqIds, result); - const std::vector& vec(result[grs->grpId]) ; + const std::vector& vec(result[grs->grpId]) ; if(vec.empty()) // that means we don't have any, or there isn't any, but since the default is always 0, no need to send. return ; @@ -970,12 +970,9 @@ void RsGxsNetService::handleRecvSyncGrpStatistics(RsNxsSyncGrpStatsItem *grs) // be used to discard groups that are not used. for(uint32_t i=0;ilast_post_TS < vec[i]->mPublishTs) grs_resp->last_post_TS = vec[i]->mPublishTs; - delete vec[i] ; - } #ifdef NXS_NET_DEBUG_6 GXSNETDEBUG_PG(grs->PeerId(),grs->grpId) << " sending back statistics item with " << vec.size() << " elements." << std::endl; #endif @@ -2953,21 +2950,19 @@ void RsGxsNetService::locked_genReqMsgTransaction(NxsTransaction* tr) reqIds[grpId] = std::set(); GxsMsgMetaResult result; mDataStore->retrieveGxsMsgMetaData(reqIds, result); - std::vector &msgMetaV = result[grpId]; + std::vector &msgMetaV = result[grpId]; #ifdef NXS_NET_DEBUG_1 GXSNETDEBUG_PG(item->PeerId(),grpId) << " retrieving grp message list..." << std::endl; GXSNETDEBUG_PG(item->PeerId(),grpId) << " grp locally contains " << msgMetaV.size() << " messsages." << std::endl; #endif - std::vector::const_iterator vit = msgMetaV.begin(); + std::vector::const_iterator vit = msgMetaV.begin(); std::set msgIdSet; // put ids in set for each searching for(; vit != msgMetaV.end(); ++vit) - { msgIdSet.insert((*vit)->mMsgId); - delete(*vit); - } + msgMetaV.clear(); #ifdef NXS_NET_DEBUG_1 @@ -4367,7 +4362,7 @@ void RsGxsNetService::handleRecvSyncMessage(RsNxsSyncMsgReqItem *item,bool item_ GxsMsgMetaResult metaResult; mDataStore->retrieveGxsMsgMetaData(req, metaResult); - std::vector& msgMetas = metaResult[item->grpId]; + std::vector& msgMetas = metaResult[item->grpId]; #ifdef NXS_NET_DEBUG_0 GXSNETDEBUG_PG(item->PeerId(),item->grpId) << " retrieving message meta data." << std::endl; @@ -4395,9 +4390,9 @@ void RsGxsNetService::handleRecvSyncMessage(RsNxsSyncMsgReqItem *item,bool item_ if(canSendMsgIds(msgMetas, *grpMeta, peer, should_encrypt_to_this_circle_id)) { - for(std::vector::iterator vit = msgMetas.begin();vit != msgMetas.end(); ++vit) + for(auto vit = msgMetas.begin();vit != msgMetas.end(); ++vit) { - RsGxsMsgMetaData* m = *vit; + const RsGxsMsgMetaData* m = *vit; // Check reputation @@ -4497,8 +4492,8 @@ void RsGxsNetService::handleRecvSyncMessage(RsNxsSyncMsgReqItem *item,bool item_ // release meta resource - for(std::vector::iterator vit = msgMetas.begin(); vit != msgMetas.end(); ++vit) - delete *vit; + // for(std::vector::iterator vit = msgMetas.begin(); vit != msgMetas.end(); ++vit) + // delete *vit; } void RsGxsNetService::locked_pushMsgRespFromList(std::list& itemL, const RsPeerId& sslId, const RsGxsGroupId& grp_id,const uint32_t& transN) @@ -4542,7 +4537,7 @@ void RsGxsNetService::locked_pushMsgRespFromList(std::list& itemL, c } } -bool RsGxsNetService::canSendMsgIds(std::vector& msgMetas, const RsGxsGrpMetaData& grpMeta, const RsPeerId& sslId,RsGxsCircleId& should_encrypt_id) +bool RsGxsNetService::canSendMsgIds(std::vector& msgMetas, const RsGxsGrpMetaData& grpMeta, const RsPeerId& sslId,RsGxsCircleId& should_encrypt_id) { #ifdef NXS_NET_DEBUG_4 GXSNETDEBUG_PG(sslId,grpMeta.mGroupId) << "RsGxsNetService::canSendMsgIds() CIRCLE VETTING" << std::endl; diff --git a/libretroshare/src/gxs/rsgxsnetservice.h b/libretroshare/src/gxs/rsgxsnetservice.h index 39fd2982e..e4056bb06 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.h +++ b/libretroshare/src/gxs/rsgxsnetservice.h @@ -395,7 +395,7 @@ private: * @return false, if you cannot send to this peer, true otherwise */ bool canSendGrpId(const RsPeerId& sslId, const RsGxsGrpMetaData& grpMeta, std::vector& toVet, bool &should_encrypt); - bool canSendMsgIds(std::vector& msgMetas, const RsGxsGrpMetaData&, const RsPeerId& sslId, RsGxsCircleId &should_encrypt_id); + bool canSendMsgIds(std::vector& msgMetas, const RsGxsGrpMetaData&, const RsPeerId& sslId, RsGxsCircleId &should_encrypt_id); /*! * \brief checkPermissionsForFriendGroup diff --git a/libretroshare/src/gxs/rsgxsutil.cc b/libretroshare/src/gxs/rsgxsutil.cc index 2396618a8..951476403 100644 --- a/libretroshare/src/gxs/rsgxsutil.cc +++ b/libretroshare/src/gxs/rsgxsutil.cc @@ -85,7 +85,7 @@ bool RsGxsMessageCleanUp::clean() for(; mit != result.end(); ++mit) { - std::vector& metaV = mit->second; + std::vector& metaV = mit->second; // First, make a map of which message have a child message. This allows to only delete messages that dont have child messages. // A more accurate way to go would be to compute the time of the oldest message and possibly delete all the branch, but in the @@ -99,7 +99,7 @@ bool RsGxsMessageCleanUp::clean() for( uint32_t i=0;imMsgId)!=messages_with_kids.end()); @@ -132,7 +132,7 @@ bool RsGxsMessageCleanUp::clean() std::cerr << std::endl; #endif - delete meta; + //delete meta; } } From a17f5a21f822dba9cd7b246358db5a5b0f8bc144 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 28 May 2020 15:55:49 +0200 Subject: [PATCH 014/154] re-enabled resultCOunt --- libretroshare/src/gxs/rsdataservice.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libretroshare/src/gxs/rsdataservice.cc b/libretroshare/src/gxs/rsdataservice.cc index b09e62c99..6834444ae 100644 --- a/libretroshare/src/gxs/rsdataservice.cc +++ b/libretroshare/src/gxs/rsdataservice.cc @@ -1400,6 +1400,9 @@ int RsDataService::retrieveGxsGrpMetaData(RsGxsGrpMetaTemporaryMap& grp) mGrpMetaDataCache.setCacheUpToDate(true); } delete c; +#ifdef RS_DATA_SERVICE_DEBUG_TIME + resultCount += grp.size(); +#endif // if(c) // { @@ -1418,9 +1421,6 @@ int RsDataService::retrieveGxsGrpMetaData(RsGxsGrpMetaTemporaryMap& grp) // } // valid = c->moveToNext(); // -//#ifdef RS_DATA_SERVICE_DEBUG_TIME -// ++resultCount; -//#endif // } // delete c; // } @@ -1449,6 +1449,10 @@ int RsDataService::retrieveGxsGrpMetaData(RsGxsGrpMetaTemporaryMap& grp) if(meta) grp[mit->first] = meta; +#ifdef RS_DATA_SERVICE_DEBUG_TIME + ++resultCount; +#endif + delete c; // if(c) From 1a362f1cc00bd1835e93da00d5d94f5115026be5 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 28 May 2020 16:06:31 +0200 Subject: [PATCH 015/154] moved a debug output to the right place --- libretroshare/src/gxs/rsdataservice.cc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/libretroshare/src/gxs/rsdataservice.cc b/libretroshare/src/gxs/rsdataservice.cc index 6834444ae..23d59d231 100644 --- a/libretroshare/src/gxs/rsdataservice.cc +++ b/libretroshare/src/gxs/rsdataservice.cc @@ -1271,13 +1271,13 @@ int RsDataService::retrieveGxsMsgMetaData(const GxsMsgReq& reqIds, GxsMsgMetaRes if (c) { locked_retrieveMsgMetaList(c, msgMeta[grpId]); -#ifdef RS_DATA_SERVICE_DEBUG_CACHE - std::cerr << mDbName << ": Retrieving (all) Msg metadata grpId=" << grpId << ", " << std::dec << metaSet.size() << " messages" << std::endl; -#endif cache.setCacheUpToDate(true); } delete c; } +#ifdef RS_DATA_SERVICE_DEBUG_CACHE + std::cerr << mDbName << ": Retrieving (all) Msg metadata grpId=" << grpId << ", " << std::dec << metaSet.size() << " messages" << std::endl; +#endif } else { @@ -1303,12 +1303,11 @@ int RsDataService::retrieveGxsMsgMetaData(const GxsMsgReq& reqIds, GxsMsgMetaRes metaSet.push_back(meta); delete c; - -#ifdef RS_DATA_SERVICE_DEBUG_CACHE - std::cerr << mDbName << ": Retrieving Msg metadata grpId=" << grpId << ", " << std::dec << metaSet.size() << " messages" << std::endl; -#endif } } +#ifdef RS_DATA_SERVICE_DEBUG_CACHE + std::cerr << mDbName << ": Retrieving Msg metadata grpId=" << grpId << ", " << std::dec << metaSet.size() << " messages" << std::endl; +#endif } } From 31e6e02a919debb29e193617ab7689add22477ac Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 28 May 2020 17:07:33 +0200 Subject: [PATCH 016/154] removed MsgMeta delete that was left --- libretroshare/src/gxs/rsgxsnetservice.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index 484ad466b..72a078075 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -4604,7 +4604,7 @@ bool RsGxsNetService::canSendMsgIds(std::vector& msgMet GXSNETDEBUG_PG(sslId,grpMeta.mGroupId) << " deleting MsgMeta entry for msg ID " << msgMetas[i]->mMsgId << " signed by " << msgMetas[i]->mAuthorId << " who is not in group circle " << circleId << std::endl; #endif - delete msgMetas[i] ; + //delete msgMetas[i] ; msgMetas[i] = msgMetas[msgMetas.size()-1] ; msgMetas.pop_back() ; } From 1dbc0c1fcff2f23cbdac3691f59de60035ecfb1a Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 28 May 2020 23:58:07 +0200 Subject: [PATCH 017/154] fixed long-term bug due to sending an empty list of destkeys for GXSSecurity to encrypt an item --- libretroshare/src/gxs/gxssecurity.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libretroshare/src/gxs/gxssecurity.cc b/libretroshare/src/gxs/gxssecurity.cc index 6dedf1dff..d5b377328 100644 --- a/libretroshare/src/gxs/gxssecurity.cc +++ b/libretroshare/src/gxs/gxssecurity.cc @@ -651,6 +651,9 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u try { + if(keys.empty()) + throw std::runtime_error("EVP_SealInit will not be called with 0 keys. GxsSecurity::encrypt() was called with an empty set of destination keys!") ; + for(uint32_t i=0;i Date: Fri, 29 May 2020 09:49:07 +0200 Subject: [PATCH 018/154] added method to print cache size --- libretroshare/src/gxs/rsdataservice.cc | 35 ++++++++++++++++++++++++++ libretroshare/src/gxs/rsdataservice.h | 12 +++++++++ libretroshare/src/gxs/rsgxsdata.h | 1 + 3 files changed, 48 insertions(+) diff --git a/libretroshare/src/gxs/rsdataservice.cc b/libretroshare/src/gxs/rsdataservice.cc index 23d59d231..bd22a8aa9 100644 --- a/libretroshare/src/gxs/rsdataservice.cc +++ b/libretroshare/src/gxs/rsdataservice.cc @@ -1721,3 +1721,38 @@ int RsDataService::setCacheSize(uint32_t /* size */) return 0; } +void RsDataService::debug_printCacheSize() const +{ + uint32_t nb_items,nb_items_on_deadlist; + uint64_t total_size,total_size_of_deadlist; + + mGrpMetaDataCache.debug_computeSize(nb_items, nb_items_on_deadlist, total_size,total_size_of_deadlist); + + RsDbg() << "Cache size: " << std::endl; + RsDbg() << " Groups: " << " total: " << nb_items << " (dead: " << nb_items_on_deadlist << "), size: " << total_size << " (Dead: " << total_size_of_deadlist << ")" << std::endl; + + nb_items = 0,nb_items_on_deadlist = 0; + total_size = 0,total_size_of_deadlist = 0; + + for(auto it:mMsgMetaDataCache) + { + uint32_t tmp_nb_items,tmp_nb_items_on_deadlist; + uint64_t tmp_total_size,tmp_total_size_of_deadlist; + + it.second.debug_computeSize(tmp_nb_items, tmp_nb_items_on_deadlist, tmp_total_size,tmp_total_size_of_deadlist); + + nb_items += tmp_nb_items; + nb_items_on_deadlist += tmp_nb_items_on_deadlist; + total_size += tmp_total_size; + total_size_of_deadlist += tmp_total_size_of_deadlist; + } + RsDbg() << " Msgs: " << " total: " << nb_items << " (dead: " << nb_items_on_deadlist << "), size: " << total_size << " (Dead: " << total_size_of_deadlist << ")" << std::endl; +} + + + + + + + + diff --git a/libretroshare/src/gxs/rsdataservice.h b/libretroshare/src/gxs/rsdataservice.h index 35234be9e..56dc8dea6 100644 --- a/libretroshare/src/gxs/rsdataservice.h +++ b/libretroshare/src/gxs/rsdataservice.h @@ -126,6 +126,16 @@ public: } } + void debug_computeSize(uint32_t& nb_items, uint32_t& nb_items_on_deadlist, uint64_t& total_size,uint64_t& total_size_of_deadlist) const + { + nb_items = mMetas.size(); + nb_items_on_deadlist = mOldCachedItems.size(); + total_size = 0; + total_size_of_deadlist = 0; + + for(auto it:mMetas) total_size += it.second->serial_size(); + for(auto it:mOldCachedItems) total_size_of_deadlist += it.second->serial_size(); + } private: std::map mMetas; std::list > mOldCachedItems ; // dead list, where items get deleted after being unused for a while. This is due to not using smart ptrs. @@ -274,6 +284,8 @@ public: int updateGroupKeys(const RsGxsGroupId& grpId,const RsTlvSecurityKeySet& keys, uint32_t subscribe_flags) ; + void debug_printCacheSize() const; + private: /*! diff --git a/libretroshare/src/gxs/rsgxsdata.h b/libretroshare/src/gxs/rsgxsdata.h index 6ef5b0c28..2102a8254 100644 --- a/libretroshare/src/gxs/rsgxsdata.h +++ b/libretroshare/src/gxs/rsgxsdata.h @@ -48,6 +48,7 @@ public: bool deserialise(void *data, uint32_t &pktsize); bool serialise(void* data, uint32_t &pktsize, uint32_t api_version); uint32_t serial_size(uint32_t api_version) const; + uint32_t serial_size() const { return serial_size(RS_GXS_GRP_META_DATA_CURRENT_API_VERSION); } void clear(); void operator =(const RsGroupMetaData& rMeta); From aef87fb1f89630660f63918c2d599c01d4acfa9b Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Mon, 1 Jun 2020 00:43:44 +0200 Subject: [PATCH 019/154] Multiple improvements in debugging helpers Add variadic style macro helpers that make debugging code disappear completely (also the paramethers evaluation) when debugging level is lower Chained style << is now atomic like variadic style, still can't benefit of paramethers eveluation stripping Reduced to minimum the difference between Android and other platform debugging code Port debugging code to new helpers, expecially a few corner cases to test it, and as examples of how to use it. --- libretroshare/src/jsonapi/jsonapi.cpp | 8 +- libretroshare/src/libretroshare.pro | 7 +- .../src/retroshare/rsgxsifacehelper.h | 16 +- .../src/serialiser/rstypeserializer.cc | 3 +- .../src/serialiser/rstypeserializer.h | 41 ++- libretroshare/src/util/rsdebug.h | 285 +++++++----------- libretroshare/src/util/rsdebuglevel0.h | 42 +++ libretroshare/src/util/rsdebuglevel1.h | 42 +++ libretroshare/src/util/rsdebuglevel2.h | 42 +++ libretroshare/src/util/rsdebuglevel3.h | 42 +++ libretroshare/src/util/rsdebuglevel4.h | 42 +++ 11 files changed, 365 insertions(+), 205 deletions(-) create mode 100644 libretroshare/src/util/rsdebuglevel0.h create mode 100644 libretroshare/src/util/rsdebuglevel1.h create mode 100644 libretroshare/src/util/rsdebuglevel2.h create mode 100644 libretroshare/src/util/rsdebuglevel3.h create mode 100644 libretroshare/src/util/rsdebuglevel4.h diff --git a/libretroshare/src/jsonapi/jsonapi.cpp b/libretroshare/src/jsonapi/jsonapi.cpp index 338782a01..abb68478a 100644 --- a/libretroshare/src/jsonapi/jsonapi.cpp +++ b/libretroshare/src/jsonapi/jsonapi.cpp @@ -467,18 +467,18 @@ void JsonApiServer::registerHandler( const std::function)>& callback ) { /* Declare outside the lambda to avoid returning a dangling - * reference on Android */ + * reference */ RsWarn tWarn; const auto authFail = - [&](int status) -> RsWarn::stream_type& + [&](int status) -> std::ostream& { /* Capture session by reference as it is cheaper then copying * shared_ptr by value which is not needed in this case */ session->close(status, corsOptionsHeaders); return tWarn << "JsonApiServer authentication handler " - "blocked an attempt to call JSON API " - "authenticated method: " << path; + "blocked an attempt to call JSON API " + "authenticated method: " << path; }; if(session->get_request()->get_method() == "OPTIONS") diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 3f9dde680..e3ff086a1 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -468,7 +468,12 @@ HEADERS += turtle/p3turtle.h \ turtle/turtleclientservice.h HEADERS += util/folderiterator.h \ - util/rsdebug.h \ + util/rsdebug.h \ + util/rsdebuglevel0.h \ + util/rsdebuglevel1.h \ + util/rsdebuglevel2.h \ + util/rsdebuglevel3.h \ + util/rsdebuglevel4.h \ util/rskbdinput.h \ util/rsmemory.h \ util/smallobject.h \ diff --git a/libretroshare/src/retroshare/rsgxsifacehelper.h b/libretroshare/src/retroshare/rsgxsifacehelper.h index d2f588623..7db596873 100644 --- a/libretroshare/src/retroshare/rsgxsifacehelper.h +++ b/libretroshare/src/retroshare/rsgxsifacehelper.h @@ -507,25 +507,27 @@ private: std::map mActiveTokens; +#ifdef DEBUG_GXSIFACEHELPER void locked_dumpTokens() { const uint16_t service_id = mGxs.serviceType(); const auto countSize = static_cast(TokenRequestType::__MAX); uint32_t count[countSize] = {0}; - RsDbg() << __PRETTY_FUNCTION__ << "Service 0x" << std::hex << service_id - << " (" << rsServiceControl->getServiceName( - RsServiceInfo::RsServiceInfoUIn16ToFullServiceId(service_id) ) - << ") this=0x" << static_cast(this) - << ") Active tokens (per type): "; + RsDbg rsdbg; + rsdbg << __PRETTY_FUNCTION__ << " Service 0x" << std::hex << service_id + << " (" << rsServiceControl->getServiceName( + RsServiceInfo::RsServiceInfoUIn16ToFullServiceId(service_id) ) + << ") this=0x" << static_cast(this) + << ") Active tokens (per type): "; // let's count how many token of each type we've got. for(auto& it: mActiveTokens) ++count[static_cast(it.second)]; for(uint32_t i=0; i < countSize; ++i) - RsDbg().uStream() /* << i << ":" */ << count[i] << " "; - RsDbg().uStream() << std::endl; + rsdbg /* << i << ":" */ << count[i] << " "; } +#endif // def DEBUG_GXSIFACEHELPER RS_SET_CONTEXT_DEBUG_LEVEL(1) }; diff --git a/libretroshare/src/serialiser/rstypeserializer.cc b/libretroshare/src/serialiser/rstypeserializer.cc index 7cf799d0f..0c7bfc435 100644 --- a/libretroshare/src/serialiser/rstypeserializer.cc +++ b/libretroshare/src/serialiser/rstypeserializer.cc @@ -235,8 +235,7 @@ template<> bool RsTypeSerializer::from_JSON( \ \ if(!ret) \ { \ - Dbg3() << __PRETTY_FUNCTION__ << " " << memberName << " not found" \ - << std::endl; \ + RS_DBG3(memberName, " not found"); \ return false; \ } \ \ diff --git a/libretroshare/src/serialiser/rstypeserializer.h b/libretroshare/src/serialiser/rstypeserializer.h index 3c8af510e..6474f6971 100644 --- a/libretroshare/src/serialiser/rstypeserializer.h +++ b/libretroshare/src/serialiser/rstypeserializer.h @@ -39,7 +39,7 @@ #include "serialiser/rsserializer.h" #include "serialiser/rsserializable.h" #include "util/rsjson.h" -#include "util/rsdebug.h" +#include "util/rsdebuglevel1.h" #include "util/cxx14retrocompat.h" @@ -715,12 +715,9 @@ struct RsTypeSerializer E& member, const std::string& memberName ) { -#ifdef RSSERIAL_DEBUG - std::cerr << __PRETTY_FUNCTION__ << " processing enum: " - << typeid(E).name() << " as " - << typeid(typename std::underlying_type::type).name() - << std::endl; -#endif + RS_DBG4( "processing enum: ", typeid(E).name(), " as ", + typeid(typename std::underlying_type::type).name() ); + serial_process( j, ctx, reinterpret_cast::type&>(member), @@ -1004,14 +1001,16 @@ protected: uint8_t data[], uint32_t size, uint32_t &offset, T member ) { std::decay_t backupMember = member; +#if RS_DEBUG_LEVEL >= 3 uint32_t offsetBackup = offset; +#endif bool ok = true; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wbool-compare" /* Check with < and not with <= here as we write last byte after * the loop. Order of && operands very important here! */ - while(member > 127 && (ok = offset < size)) + while(member > 127 && (ok = (offset < size))) { // | 128: Set the next byte flag data[offset++] = (static_cast(member & 127)) | 128; @@ -1036,13 +1035,13 @@ protected: data[offset++] = static_cast(member & 127); - Dbg3() << __PRETTY_FUNCTION__ << " backupMember: " << backupMember - << " offsetBackup: " << offsetBackup << " offeset: " << offset - << " serialized as: "; +#if RS_DEBUG_LEVEL >= 3 + RsDbg tdbg( __PRETTY_FUNCTION__, " backupMember: ", backupMember, + " offsetBackup: ", offsetBackup, " offeset: ", offset, + " serialized as: " ); for(; offsetBackup < offset; ++offsetBackup) - Dbg3().uStream() << " " << std::bitset<8>(data[offsetBackup]); - Dbg3().uStream() << std::endl; - + tdbg << " " << std::bitset<8>(data[offsetBackup]); +#endif return ok; } @@ -1082,13 +1081,13 @@ protected: /* If return is not triggered inside the for loop, either the buffer * ended before we encountered the end of the number, or the number * is VLQ encoded improperly */ - RsErr() << __PRETTY_FUNCTION__ << std::errc::illegal_byte_sequence - << " size: " << size - << " offsetBackup: " << offsetBackup - << " offset: " << offset << " bytes: "; + RsErr rserr; + rserr << __PRETTY_FUNCTION__ << std::errc::illegal_byte_sequence + << " size: " << size + << " offsetBackup: " << offsetBackup + << " offset: " << offset << " bytes: "; for(; offsetBackup < offset; ++offsetBackup) - RsErr().uStream() << " " << std::bitset<8>(data[offsetBackup]); - RsErr().uStream() << std::endl; + rserr << " " << std::bitset<8>(data[offsetBackup]); print_stacktrace(); return false; @@ -1151,7 +1150,7 @@ protected: struct ErrConditionWrapper : RsSerializable { - ErrConditionWrapper(const std::error_condition& ec): mec(ec) {} + explicit ErrConditionWrapper(const std::error_condition& ec): mec(ec) {} /** supports only TO_JSON if a different SerializeJob is passed it will * explode at runtime */ diff --git a/libretroshare/src/util/rsdebug.h b/libretroshare/src/util/rsdebug.h index 73d5a2132..4a88d8c90 100644 --- a/libretroshare/src/util/rsdebug.h +++ b/libretroshare/src/util/rsdebug.h @@ -21,19 +21,23 @@ *******************************************************************************/ #pragma once -#include +#include +#include #include -/** Stream helper for std::error_condition */ -std::ostream &operator<<(std::ostream& out, const std::error_condition& err); - #ifdef __ANDROID__ # include -# include -# include +#else // def __ANDROID__ +# include +# include +# include +#endif // def __ANDROID__ -# include "util/rsjson.h" +#include "util/rsjson.h" + + +#ifdef __ANDROID__ enum class RsLoggerCategories { DEBUG = ANDROID_LOG_DEBUG, @@ -42,72 +46,7 @@ enum class RsLoggerCategories ERROR = ANDROID_LOG_ERROR, FATAL = ANDROID_LOG_FATAL }; - -template -struct t_RsLogger -{ - inline t_RsLogger() = default; - - /** Offer variadic style too, as a benefit this has better atomicity then - * << style, but doesn't supports manipulators and things like std::endl - * @see https://stackoverflow.com/a/27375675 */ - template - inline t_RsLogger(Arg&& arg, Args&&... args) - { - ostr << std::forward(arg); - using expander = int[]; - (void)expander{0, (void(ostr << std::forward(args)), 0)...}; - mFlush(); - } - - /** On other platforms expose the type of underlying stream. - * On Android it cannot work like that so return the class type itself - * just for code compatibility with other platforms */ - using stream_type = t_RsLogger; - - template - inline stream_type& operator<<(const T& val) - { ostr << val; return *this; } - - template - inline stream_type& operator<<(const RsJson& val) - { ostr << val; return *this; } - - /// needed for manipulators and things like std::endl - stream_type& operator<<(std::ostream& (*pf)(std::ostream&)) - { - if(pf == static_cast( - &std::endl< char, std::char_traits > )) - mFlush(); - else ostr << pf; - - return *this; - } - - /** On other platforms return underlying stream to write avoiding additional - * prefixes. On Android it cannot work like that so return the object itself - * just for code compatibility with other platforms */ - inline stream_type& uStream() { return *this; } - -private: - std::ostringstream ostr; - - void mFlush() - { - __android_log_write( - static_cast(CATEGORY), - "RetroShare", ostr.str().c_str() ); - ostr.str() = ""; - } -}; - #else // def __ANDROID__ - -#include -#include -#include -#include - enum class RsLoggerCategories { DEBUG = 'D', @@ -116,90 +55,101 @@ enum class RsLoggerCategories ERROR = 'E', FATAL = 'F' }; +#endif // def __ANDROID__ + + +/** Stream helper for std::error_condition */ +std::ostream &operator<<(std::ostream& out, const std::error_condition& err); + template -struct t_RsLogger +struct t_RsLogger : std::ostringstream { - /// Expose the type of underlying stream - using stream_type = decltype(std::cerr); + t_RsLogger() { setPrefix(); } + ~t_RsLogger() { flush(); } - /// Return underlying stream to write avoiding additional prefixes - static inline stream_type& uStream() { return std::cerr; } - - inline t_RsLogger() = default; - - /** Offer variadic style too, as a benefit this has better atomicity then - * << style, but doesn't supports manipulators and things like std::endl - * @see https://stackoverflow.com/a/27375675 */ - template - inline t_RsLogger(Arg&& arg, Args&&... args) + /** Offer variadic style, this doesn't supports things like std::endl as + * paramether but when used toghether with conditional debugging macros + * reduces binary size as paramethers of suppressed calls are not evaluated + * and literally disappear in preprocessing fase @see RsDbg */ + template + explicit inline t_RsLogger(Args&&... args) { - std::ostringstream ostr; - ostr << getPrefix() << std::forward(arg); - using expander = int[]; - (void)expander{0, (void(ostr << std::forward(args)), 0)...}; - ostr << std::endl; - uStream() << ostr.str(); + setPrefix(); + + /* Combine initializer list and comma operator so the compiler unpack + * template arguments and feed our own stream without recursion + * see https://stackoverflow.com/a/27375675 */ + using expander = char[]; + (void) expander {0, (void((*this) << std::forward(args)), 0)...}; } - template - inline stream_type& operator<<(const T& val) - { return uStream() << getPrefix() << val; } - - /// needed for manipulators and things like std::endl - stream_type& operator<<(std::ostream& (*pf)(std::ostream&)) - { return uStream() << pf; } + /** Dump buffer stream to log */ + void flush() + { +#ifdef __ANDROID__ + __android_log_write( + static_cast(CATEGORY), + "RetroShare", str().c_str() ); +#else // def __ANDROID__ + (*this) << std::endl; + std::cerr << str(); +#endif // def __ANDROID__ + str() = ""; + } private: - std::string getPrefix() +#ifdef __ANDROID__ + inline void setPrefix() {} +#else // def __ANDROID__ + void setPrefix() { using namespace std::chrono; const auto now = system_clock::now(); const auto sec = time_point_cast(now); const auto msec = duration_cast(now - sec); - std::ostringstream tstream; - tstream << static_cast(CATEGORY) << " " + (*this) << static_cast(CATEGORY) << " " << sec.time_since_epoch().count() << "." - << std::setfill('0') << std::setw(3) << msec.count() - << " "; - return tstream.str(); + << std::setfill('0') << std::setw(3) << msec.count() << " "; } -}; #endif // def __ANDROID__ +}; /** - * Comfortable debug message logging, supports chaining like std::cerr but can - * be easly and selectively disabled at compile time to reduce generated binary - * size and performance impact without too many \#ifdef around. + * Comfortable debug message logging, supports both variadic style and chaining + * style like std::cerr. + * Can be easly and selectively disabled at compile time. + * To reduce generated binary size and performance impact when debugging is + * disabled without too many \#ifdef around the code combining the variadic + * style with the leveled debugging macros is the way to go. * - * To selectively debug your context you can just add something like this in - * in that context, as an example for a class you can just add a line like this - * inside class declaration: + * To selectively debug your file you just need to include the header of desired + * debugging level (0 to 4) @code{.cpp} -RS_SET_CONTEXT_DEBUG_LEVEL(2) +#include "util/rsdebuglevel2.h" @endcode - * And the you can write debug messages around the code of the class like this: + * Then where you want to print debug messages use @code{.cpp} -Dbg1() << "Level 1 debug message example, this will be compiled and " - << "printed" << std::endl; -Dbg2() << "Level 2 debug message example, this will be compiled and " - << "printed" << std::endl; -Dbg3() << "Level 3 debug message example, this will not be compiled and " - << "printed, and without #ifdef around!!" << std::endl; -Dbg4() << "Level 4 debug message example, this will not be compiled and " - << "printed, and without #ifdef around!!" << std::endl; +RS_DBG0("Hello 0 ", "my debug ", my_variable) << " message " << variable2; +RS_DBG1("Hello 1 ", "my debug ", my_variable) << " message " << variable2; +RS_DBG2("Hello 2 ", "my debug ", my_variable) << " message " << variable2; +RS_DBG3("Hello 3 ", "my debug ", my_variable) << " message " << variable2; +RS_DBG4("Hello 4 ", "my debug ", my_variable) << " message " << variable2; @endcode - * To change the debugging level, for example to completely disable debug - * messages you can change it to 0 -@code{.cpp} -RS_SET_CONTEXT_DEBUG_LEVEL(0) -@endcode - * While to set it to maximim level you have to pass 4. + * To change the debugging level just include a different level header like + * `util/rsdebuglevel1.h`, debug messages with lower or equal level then the + * included header will be printed, the others will not. + * Remember then on messages with debug level higher then the included the + * paramethers you pass as macro arguments (variadic style) will disappear in + * the preprocessing phase, so their evaluation will not be included in the + * final binary and not executed at runtime, instead the paramether passed with + * `<<` (chaining style) will be in the compiled binary and evaluated at runtime + * even if are not printed, due to how C++ is made it is not possible to avoid + * this, so we suggest to use variadic style for debug messages. */ using RsDbg = t_RsLogger; - /** * Comfortable log information reporting helper, supports chaining like * std::cerr. @@ -220,6 +170,7 @@ using RsErr = t_RsLogger; * to terminate) messages */ using RsFatal = t_RsLogger; + /** * Keeps compatible syntax with RsDbg but explicitely do nothing in a way that * any modern compiler should be smart enough to optimize out all the function @@ -228,27 +179,32 @@ using RsFatal = t_RsLogger; struct RsNoDbg { inline RsNoDbg() = default; - - template inline RsNoDbg(T, Args...) {} - - /** Defined as the type itself just for code compatibility with other - * logging classes */ - using stream_type = RsNoDbg; + template inline explicit RsNoDbg(Args...) {} /** This match most of the types, but might be not enough for templated * types */ template - inline stream_type& operator<<(const T&) { return *this; } + inline RsNoDbg& operator<<(const T&) { return *this; } /// needed for manipulators and things like std::endl - inline stream_type& operator<<(std::ostream& (*/*pf*/)(std::ostream&)) + inline RsNoDbg& operator<<(std::ostream& (*/*pf*/)(std::ostream&)) { return *this; } - /** Return the object itself just for code compatibility with other - * logging classes */ - inline stream_type& uStream() { return *this; } + /** Do nothing. Just for code compatibility with other logging classes */ + inline void flush() {} }; + + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// All the following lines are DEPRECATED!! + +#include "util/rsdeprecate.h" + /** * Concatenate preprocessor tokens A and B without expanding macro definitions * (however, if invoked from a macro, macro arguments are expanded). @@ -267,41 +223,30 @@ struct RsNoDbg // A bunch of boilerplate, but just in one place #define RS_SET_CONTEXT_DEBUG_LEVEL0 \ - using Dbg1 = RsNoDbg; \ - using Dbg2 = RsNoDbg; \ - using Dbg3 = RsNoDbg; \ - using Dbg4 = RsNoDbg; + using Dbg1 RS_DEPRECATED_FOR(RS_DBG1) = RsNoDbg; \ + using Dbg2 RS_DEPRECATED_FOR(RS_DBG2) = RsNoDbg; \ + using Dbg3 RS_DEPRECATED_FOR(RS_DBG3) = RsNoDbg; \ + using Dbg4 RS_DEPRECATED_FOR(RS_DBG4) = RsNoDbg; #define RS_SET_CONTEXT_DEBUG_LEVEL1 \ - using Dbg1 = RsDbg; \ - using Dbg2 = RsNoDbg; \ - using Dbg3 = RsNoDbg; \ - using Dbg4 = RsNoDbg; + using Dbg1 RS_DEPRECATED_FOR(RS_DBG1) = RsDbg; \ + using Dbg2 RS_DEPRECATED_FOR(RS_DBG2) = RsNoDbg; \ + using Dbg3 RS_DEPRECATED_FOR(RS_DBG3) = RsNoDbg; \ + using Dbg4 RS_DEPRECATED_FOR(RS_DBG4) = RsNoDbg; #define RS_SET_CONTEXT_DEBUG_LEVEL2 \ - using Dbg1 = RsDbg; \ - using Dbg2 = RsDbg; \ - using Dbg3 = RsNoDbg; \ - using Dbg4 = RsNoDbg; + using Dbg1 RS_DEPRECATED_FOR(RS_DBG1) = RsDbg; \ + using Dbg2 RS_DEPRECATED_FOR(RS_DBG2) = RsDbg; \ + using Dbg3 RS_DEPRECATED_FOR(RS_DBG3) = RsNoDbg; \ + using Dbg4 RS_DEPRECATED_FOR(RS_DBG4) = RsNoDbg; #define RS_SET_CONTEXT_DEBUG_LEVEL3 \ - using Dbg1 = RsDbg; \ - using Dbg2 = RsDbg; \ - using Dbg3 = RsDbg; \ - using Dbg4 = RsNoDbg; + using Dbg1 RS_DEPRECATED_FOR(RS_DBG1) = RsDbg; \ + using Dbg2 RS_DEPRECATED_FOR(RS_DBG2) = RsDbg; \ + using Dbg3 RS_DEPRECATED_FOR(RS_DBG3) = RsDbg; \ + using Dbg4 RS_DEPRECATED_FOR(RS_DBG4) = RsNoDbg; #define RS_SET_CONTEXT_DEBUG_LEVEL4 \ - using Dbg1 = RsDbg; \ - using Dbg2 = RsDbg; \ - using Dbg3 = RsDbg; \ - using Dbg4 = RsDbg; - - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -/// All the following lines are DEPRECATED!! - -#include - -#include "util/rsdeprecate.h" + using Dbg1 RS_DEPRECATED_FOR(RS_DBG1) = RsDbg; \ + using Dbg2 RS_DEPRECATED_FOR(RS_DBG2) = RsDbg; \ + using Dbg3 RS_DEPRECATED_FOR(RS_DBG3) = RsDbg; \ + using Dbg4 RS_DEPRECATED_FOR(RS_DBG4) = RsDbg; namespace RsLog { enum RS_DEPRECATED_FOR("RsErr, RsDbg, RsNoDbg") logLvl { diff --git a/libretroshare/src/util/rsdebuglevel0.h b/libretroshare/src/util/rsdebuglevel0.h new file mode 100644 index 000000000..5c68ec0be --- /dev/null +++ b/libretroshare/src/util/rsdebuglevel0.h @@ -0,0 +1,42 @@ +/******************************************************************************* + * RetroShare debugging level * + * * + * Copyright (C) 2020 Gioacchino Mazzurco * + * Copyright (C) 2020 Asociación Civil Altermundi * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +// #pragma once // This is commented out on purpose! + +#include + +#undef RS_DEBUG_LEVEL +#define RS_DEBUG_LEVEL 0 + +#undef RS_DBG0 +#define RS_DBG0(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__) + +#undef RS_DBG1 +#define RS_DBG1(...) RsNoDbg("") + +#undef RS_DBG2 +#define RS_DBG2(...) RsNoDbg("") + +#undef RS_DBG3 +#define RS_DBG3(...) RsNoDbg("") + +#undef RS_DBG4 +#define RS_DBG4(...) RsNoDbg("") diff --git a/libretroshare/src/util/rsdebuglevel1.h b/libretroshare/src/util/rsdebuglevel1.h new file mode 100644 index 000000000..7e968e402 --- /dev/null +++ b/libretroshare/src/util/rsdebuglevel1.h @@ -0,0 +1,42 @@ +/******************************************************************************* + * RetroShare debugging level * + * * + * Copyright (C) 2020 Gioacchino Mazzurco * + * Copyright (C) 2020 Asociación Civil Altermundi * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +// #pragma once // This is commented out on purpose! + +#include + +#undef RS_DEBUG_LEVEL +#define RS_DEBUG_LEVEL 1 + +#undef RS_DBG0 +#define RS_DBG0(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__) + +#undef RS_DBG1 +#define RS_DBG1(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__) + +#undef RS_DBG2 +#define RS_DBG2(...) RsNoDbg() + +#undef RS_DBG3 +#define RS_DBG3(...) RsNoDbg() + +#undef RS_DBG4 +#define RS_DBG4(...) RsNoDbg() diff --git a/libretroshare/src/util/rsdebuglevel2.h b/libretroshare/src/util/rsdebuglevel2.h new file mode 100644 index 000000000..2cbf1a224 --- /dev/null +++ b/libretroshare/src/util/rsdebuglevel2.h @@ -0,0 +1,42 @@ +/******************************************************************************* + * RetroShare debugging level * + * * + * Copyright (C) 2020 Gioacchino Mazzurco * + * Copyright (C) 2020 Asociación Civil Altermundi * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +// #pragma once // This is commented out on purpose! + +#include + +#undef RS_DEBUG_LEVEL +#define RS_DEBUG_LEVEL 2 + +#undef RS_DBG0 +#define RS_DBG0(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__) + +#undef RS_DBG1 +#define RS_DBG1(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__) + +#undef RS_DBG2 +#define RS_DBG2(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__) + +#undef RS_DBG3 +#define RS_DBG3(...) RsNoDbg() + +#undef RS_DBG4 +#define RS_DBG4(...) RsNoDbg() diff --git a/libretroshare/src/util/rsdebuglevel3.h b/libretroshare/src/util/rsdebuglevel3.h new file mode 100644 index 000000000..53bcbfe9f --- /dev/null +++ b/libretroshare/src/util/rsdebuglevel3.h @@ -0,0 +1,42 @@ +/******************************************************************************* + * RetroShare debugging level * + * * + * Copyright (C) 2020 Gioacchino Mazzurco * + * Copyright (C) 2020 Asociación Civil Altermundi * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +// #pragma once // This is commented out on purpose! + +#include + +#undef RS_DEBUG_LEVEL +#define RS_DEBUG_LEVEL 3 + +#undef RS_DBG0 +#define RS_DBG0(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__) + +#undef RS_DBG1 +#define RS_DBG1(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__) + +#undef RS_DBG2 +#define RS_DBG2(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__) + +#undef RS_DBG3 +#define RS_DBG3(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__) + +#undef RS_DBG4 +#define RS_DBG4(...) RsNoDbg() diff --git a/libretroshare/src/util/rsdebuglevel4.h b/libretroshare/src/util/rsdebuglevel4.h new file mode 100644 index 000000000..f8697cad8 --- /dev/null +++ b/libretroshare/src/util/rsdebuglevel4.h @@ -0,0 +1,42 @@ +/******************************************************************************* + * RetroShare debugging level * + * * + * Copyright (C) 2020 Gioacchino Mazzurco * + * Copyright (C) 2020 Asociación Civil Altermundi * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +// #pragma once // This is commented out on purpose! + +#include + +#undef RS_DEBUG_LEVEL +#define RS_DEBUG_LEVEL 4 + +#undef RS_DBG0 +#define RS_DBG0(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__) + +#undef RS_DBG1 +#define RS_DBG1(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__) + +#undef RS_DBG2 +#define RS_DBG2(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__) + +#undef RS_DBG3 +#define RS_DBG3(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__) + +#undef RS_DBG4 +#define RS_DBG4(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__) From 198733a763d927bcf4fc7ae2ba50489d4de7a772 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 1 Jun 2020 22:00:49 +0200 Subject: [PATCH 020/154] started implementing an abstract item model for channels --- .../src/gui/gxschannels/GxsChannelDialog.cpp | 4 +- .../gui/gxschannels/GxsChannelFilesWidget.cpp | 11 +- .../gui/gxschannels/GxsChannelPostsWidget.cpp | 4 - .../gui/gxschannels/GxsChannelPostsWidget.h | 2 +- .../GxsChannelPostsWidgetWithModel.cpp | 953 ++++++++++++++++++ .../GxsChannelPostsWidgetWithModel.h | 130 +++ .../GxsChannelPostsWidgetWithModel.ui | 563 +++++++++++ retroshare-gui/src/retroshare-gui.pro | 8 +- 8 files changed, 1666 insertions(+), 9 deletions(-) create mode 100644 retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp create mode 100644 retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h create mode 100644 retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp index 8e25e4ea0..23e0854a6 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp @@ -26,7 +26,7 @@ #include "GxsChannelDialog.h" #include "GxsChannelGroupDialog.h" -#include "GxsChannelPostsWidget.h" +#include "GxsChannelPostsWidgetWithModel.h" #include "CreateGxsChannelMsg.h" #include "GxsChannelUserNotify.h" #include "gui/gxs/GxsGroupShareKey.h" @@ -204,7 +204,7 @@ int GxsChannelDialog::shareKeyType() GxsMessageFrameWidget *GxsChannelDialog::createMessageFrameWidget(const RsGxsGroupId &groupId) { - return new GxsChannelPostsWidget(groupId); + return new GxsChannelPostsWidgetWithModel(groupId,this); } void GxsChannelDialog::setDefaultDirectory() diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesWidget.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesWidget.cpp index 3aa6ccae9..3afb4e645 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesWidget.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesWidget.cpp @@ -80,13 +80,22 @@ GxsChannelFilesWidget::GxsChannelFilesWidget(QWidget *parent) : ui->treeWidget->setColumnWidth(COLUMN_PUBLISHED, 150); } +GxsChannelFilesWidget::paintEvent() +{ + QWidget::paintEvent(); + + if(!mLoaded) + { + } +} + GxsChannelFilesWidget::~GxsChannelFilesWidget() { delete(mCompareRole); delete ui; } -void GxsChannelFilesWidget::addFiles(const RsGxsChannelPost &post, bool related) +void GxsChannelFilesWidget::addFiles(const RsGxsChannelPost& post, bool related) { if (related) { removeItems(post.mMeta.mGroupId, post.mMeta.mMsgId); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp index d4e6192e2..5d6974442 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp @@ -551,13 +551,9 @@ void GxsChannelPostsWidget::createPostItem(const RsGxsChannelPost& post, bool re ui->feedWidget->addFeedItem(item, ROLE_PUBLISH, QDateTime::fromTime_t(meta.mPublishTs)); } -#ifdef TODO ui->fileWidget->addFiles(post, related); -#endif } - - void GxsChannelPostsWidget::fillThreadCreatePost(const QVariant &post, bool related, int current, int count) { /* show fill progress */ diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h index 025d933bf..28a521944 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h @@ -98,7 +98,7 @@ private: int viewMode(); void insertChannelDetails(const RsGxsChannelGroup &group); - void insertChannelPosts(std::vector &posts, GxsMessageFramePostThread *thread, bool related); + void insertChannelPosts(std::vector &posts); void createPostItem(const RsGxsChannelPost &post, bool related); void handleEvent_main_thread(std::shared_ptr event); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp new file mode 100644 index 000000000..bc3c564e3 --- /dev/null +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -0,0 +1,953 @@ +/******************************************************************************* + * retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp * + * * + * Copyright 2013 by Robert Fernie * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include +#include + +#include "retroshare/rsgxscircles.h" + +#include "GxsChannelPostsWidgetWithModel.h" +#include "ui_GxsChannelPostsWidget.h" +#include "gui/feeds/GxsChannelPostItem.h" +#include "gui/gxs/GxsIdDetails.h" +#include "gui/gxschannels/CreateGxsChannelMsg.h" +#include "gui/common/UIStateHelper.h" +#include "gui/settings/rsharesettings.h" +#include "gui/feeds/SubFileItem.h" +#include "gui/notifyqt.h" +#include "gui/RetroShareLink.h" +#include "util/HandleRichText.h" +#include "util/DateTime.h" +#include "util/qtthreadsutils.h" + +#include + +#define CHAN_DEFAULT_IMAGE ":/icons/png/channels.png" + +#define ROLE_PUBLISH FEED_TREEWIDGET_SORTROLE + +/**** + * #define DEBUG_CHANNEL + ***/ + +/* View mode */ +#define VIEW_MODE_FEEDS 1 +#define VIEW_MODE_FILES 2 + +/** Constructor */ +GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupId &channelId, QWidget *parent) : + GxsMessageFramePostWidget(rsGxsChannels, parent), + ui(new Ui::GxsChannelPostsWidget) +{ + /* Invoke the Qt Designer generated object setup routine */ + ui->setupUi(this); + + ui->postsTree->setModel(new RsGxsChannelPostsModel()); + + /* Setup UI helper */ + + mStateHelper->addWidget(mTokenTypeAllPosts, ui->progressBar, UISTATE_LOADING_VISIBLE); + mStateHelper->addWidget(mTokenTypeAllPosts, ui->loadingLabel, UISTATE_LOADING_VISIBLE); + mStateHelper->addWidget(mTokenTypeAllPosts, ui->filterLineEdit); + + mStateHelper->addWidget(mTokenTypePosts, ui->loadingLabel, UISTATE_LOADING_VISIBLE); + + mStateHelper->addLoadPlaceholder(mTokenTypeGroupData, ui->nameLabel); + + mStateHelper->addWidget(mTokenTypeGroupData, ui->postButton); + mStateHelper->addWidget(mTokenTypeGroupData, ui->logoLabel); + mStateHelper->addWidget(mTokenTypeGroupData, ui->subscribeToolButton); + + /* Connect signals */ + connect(ui->postButton, SIGNAL(clicked()), this, SLOT(createMsg())); + connect(ui->subscribeToolButton, SIGNAL(subscribe(bool)), this, SLOT(subscribeGroup(bool))); + connect(NotifyQt::getInstance(), SIGNAL(settingsChanged()), this, SLOT(settingsChanged())); + + ui->postButton->setText(tr("Add new post")); + + /* add filter actions */ + ui->filterLineEdit->addFilter(QIcon(), tr("Title"), FILTER_TITLE, tr("Search Title")); + ui->filterLineEdit->addFilter(QIcon(), tr("Message"), FILTER_MSG, tr("Search Message")); + ui->filterLineEdit->addFilter(QIcon(), tr("Filename"), FILTER_FILE_NAME, tr("Search Filename")); +#ifdef TODO + connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), ui->feedWidget, SLOT(setFilterText(QString))); + connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), ui->fileWidget, SLOT(setFilterText(QString))); +#endif + connect(ui->filterLineEdit, SIGNAL(filterChanged(int)), this, SLOT(filterChanged(int))); + + /* Initialize view button */ + //setViewMode(VIEW_MODE_FEEDS); see processSettings + ui->infoWidget->hide(); + + QSignalMapper *signalMapper = new QSignalMapper(this); + connect(ui->feedToolButton, SIGNAL(clicked()), signalMapper, SLOT(map())); + connect(ui->fileToolButton, SIGNAL(clicked()), signalMapper, SLOT(map())); + signalMapper->setMapping(ui->feedToolButton, VIEW_MODE_FEEDS); + signalMapper->setMapping(ui->fileToolButton, VIEW_MODE_FILES); + connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(setViewMode(int))); + + /*************** Setup Left Hand Side (List of Channels) ****************/ + + ui->loadingLabel->hide(); + ui->progressBar->hide(); + + ui->nameLabel->setMinimumWidth(20); + + /* Initialize feed widget */ + ui->feedWidget->setSortRole(ROLE_PUBLISH, Qt::DescendingOrder); + ui->feedWidget->setFilterCallback(filterItem); + + /* load settings */ + processSettings(true); + + /* Initialize subscribe button */ + QIcon icon; + icon.addPixmap(QPixmap(":/images/redled.png"), QIcon::Normal, QIcon::On); + icon.addPixmap(QPixmap(":/images/start.png"), QIcon::Normal, QIcon::Off); + mAutoDownloadAction = new QAction(icon, "", this); + mAutoDownloadAction->setCheckable(true); + connect(mAutoDownloadAction, SIGNAL(triggered()), this, SLOT(toggleAutoDownload())); + + ui->subscribeToolButton->addSubscribedAction(mAutoDownloadAction); + + /* Initialize GUI */ + setAutoDownload(false); + settingsChanged(); + + mThreadModel->updateChannel(channelId); + + mEventHandlerId = 0; + // Needs to be asynced because this function is called by another thread! + rsEvents->registerEventsHandler( + [this](std::shared_ptr event) + { RsQThreadUtils::postToObject([=](){ handleEvent_main_thread(event); }, this ); }, + mEventHandlerId, RsEventType::GXS_CHANNELS ); +} + +void GxsChannelPostsWidget::handleEvent_main_thread(std::shared_ptr event) +{ + const RsGxsChannelEvent *e = dynamic_cast(event.get()); + + if(!e) + return; + + switch(e->mChannelEventCode) + { + case RsChannelEventCode::NEW_CHANNEL: // [[fallthrough]]; + case RsChannelEventCode::UPDATED_CHANNEL: // [[fallthrough]]; + case RsChannelEventCode::NEW_MESSAGE: // [[fallthrough]]; + case RsChannelEventCode::UPDATED_MESSAGE: + if(e->mChannelGroupId == groupId()) + updateDisplay(true); + break; + case RsChannelEventCode::READ_STATUS_CHANGED: + if (FeedItem *feedItem = ui->feedWidget->findFeedItem(GxsChannelPostItem::computeIdentifier(e->mChannelMsgId))) + if (GxsChannelPostItem *channelPostItem = dynamic_cast(feedItem)) + channelPostItem->setReadStatus(false,!channelPostItem->isUnread()); + //channelPostItem->setReadStatus(false,e->Don't get read status. Will be more easier and accurate); + break; + default: + break; + } +} + +GxsChannelPostsWidget::~GxsChannelPostsWidget() +{ + rsEvents->unregisterEventsHandler(mEventHandlerId); + // save settings + processSettings(false); + + delete(mAutoDownloadAction); + + delete ui; +} + +void GxsChannelPostsWidget::processSettings(bool load) +{ + Settings->beginGroup(QString("ChannelPostsWidget")); + + if (load) { + // load settings + + /* Filter */ + ui->filterLineEdit->setCurrentFilter(Settings->value("filter", FILTER_TITLE).toInt()); + + /* View mode */ + setViewMode(Settings->value("viewMode", VIEW_MODE_FEEDS).toInt()); + } else { + // save settings + + /* Filter */ + Settings->setValue("filter", ui->filterLineEdit->currentFilter()); + + /* View mode */ + Settings->setValue("viewMode", viewMode()); + } + + Settings->endGroup(); +} + +void GxsChannelPostsWidget::settingsChanged() +{ + mUseThread = Settings->getChannelLoadThread(); + + mStateHelper->setWidgetVisible(ui->progressBar, mUseThread); +} + +void GxsChannelPostsWidget::groupNameChanged(const QString &name) +{ + if (groupId().isNull()) { + ui->nameLabel->setText(tr("No Channel Selected")); + ui->logoLabel->setPixmap(QPixmap(":/icons/png/channels.png")); + } else { + ui->nameLabel->setText(name); + } +} + +QIcon GxsChannelPostsWidget::groupIcon() +{ + if (mStateHelper->isLoading(mTokenTypeGroupData) || mStateHelper->isLoading(mTokenTypeAllPosts)) { + return QIcon(":/images/kalarm.png"); + } + +// if (mNewCount) { +// return QIcon(":/images/message-state-new.png"); +// } + + return QIcon(); +} + +/*************************************************************************************/ +/*************************************************************************************/ +/*************************************************************************************/ + +QScrollArea *GxsChannelPostsWidget::getScrollArea() +{ + return NULL; +} + +void GxsChannelPostsWidget::deleteFeedItem(FeedItem *feedItem, uint32_t /*type*/) +{ + if (!feedItem) + return; + + ui->feedWidget->removeFeedItem(feedItem); +} + +void GxsChannelPostsWidget::openChat(const RsPeerId & /*peerId*/) +{ +} + +// Callback from Widget->FeedHolder->ServiceDialog->CommentContainer->CommentDialog, +void GxsChannelPostsWidget::openComments(uint32_t /*type*/, const RsGxsGroupId &groupId, const QVector& msg_versions,const RsGxsMessageId &msgId, const QString &title) +{ + emit loadComment(groupId, msg_versions,msgId, title); +} + +void GxsChannelPostsWidget::createMsg() +{ + if (groupId().isNull()) { + return; + } + + if (!IS_GROUP_SUBSCRIBED(subscribeFlags())) { + return; + } + + CreateGxsChannelMsg *msgDialog = new CreateGxsChannelMsg(groupId()); + msgDialog->show(); + + /* window will destroy itself! */ +} + +void GxsChannelPostsWidget::insertChannelDetails(const RsGxsChannelGroup &group) +{ + /* IMAGE */ + QPixmap chanImage; + if (group.mImage.mData != NULL) { + GxsIdDetails::loadPixmapFromData(group.mImage.mData, group.mImage.mSize, chanImage,GxsIdDetails::ORIGINAL); + } else { + chanImage = QPixmap(CHAN_DEFAULT_IMAGE); + } + ui->logoLabel->setPixmap(chanImage); + + if (group.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_PUBLISH) + { + mStateHelper->setWidgetEnabled(ui->postButton, true); + } + else + { + mStateHelper->setWidgetEnabled(ui->postButton, false); + } + + ui->subscribeToolButton->setSubscribed(IS_GROUP_SUBSCRIBED(group.mMeta.mSubscribeFlags)); + mStateHelper->setWidgetEnabled(ui->subscribeToolButton, true); + + + bool autoDownload ; + rsGxsChannels->getChannelAutoDownload(group.mMeta.mGroupId,autoDownload); + setAutoDownload(autoDownload); + + RetroShareLink link; + + if (IS_GROUP_SUBSCRIBED(group.mMeta.mSubscribeFlags)) { + ui->feedToolButton->setEnabled(true); + + ui->fileToolButton->setEnabled(true); + ui->infoWidget->hide(); + setViewMode(viewMode()); + + ui->subscribeToolButton->setText(tr("Subscribed") + " " + QString::number(group.mMeta.mPop) ); + + + ui->infoPosts->clear(); + ui->infoDescription->clear(); + } else { + ui->infoPosts->setText(QString::number(group.mMeta.mVisibleMsgCount)); + if(group.mMeta.mLastPost==0) + ui->infoLastPost->setText(tr("Never")); + else + ui->infoLastPost->setText(DateTime::formatLongDateTime(group.mMeta.mLastPost)); + QString formatDescription = QString::fromUtf8(group.mDescription.c_str()); + + unsigned int formatFlag = RSHTML_FORMATTEXT_EMBED_LINKS; + + // embed smileys ? + if (Settings->valueFromGroup(QString("ChannelPostsWidget"), QString::fromUtf8("Emoteicons_ChannelDecription"), true).toBool()) { + formatFlag |= RSHTML_FORMATTEXT_EMBED_SMILEYS; + } + + formatDescription = RsHtml().formatText(NULL, formatDescription, formatFlag); + + ui->infoDescription->setText(formatDescription); + + ui->infoAdministrator->setId(group.mMeta.mAuthorId) ; + + link = RetroShareLink::createMessage(group.mMeta.mAuthorId, ""); + ui->infoAdministrator->setText(link.toHtml()); + + ui->infoCreated->setText(DateTime::formatLongDateTime(group.mMeta.mPublishTs)); + + QString distrib_string ( "[unknown]" ); + + switch(group.mMeta.mCircleType) + { + case GXS_CIRCLE_TYPE_PUBLIC: distrib_string = tr("Public") ; + break ; + case GXS_CIRCLE_TYPE_EXTERNAL: + { + RsGxsCircleDetails det ; + + // !! What we need here is some sort of CircleLabel, which loads the circle and updates the label when done. + + if(rsGxsCircles->getCircleDetails(group.mMeta.mCircleId,det)) + distrib_string = tr("Restricted to members of circle \"")+QString::fromUtf8(det.mCircleName.c_str()) +"\""; + else + distrib_string = tr("Restricted to members of circle ")+QString::fromStdString(group.mMeta.mCircleId.toStdString()) ; + } + break ; + case GXS_CIRCLE_TYPE_YOUR_EYES_ONLY: distrib_string = tr("Your eyes only"); + break ; + case GXS_CIRCLE_TYPE_LOCAL: distrib_string = tr("You and your friend nodes"); + break ; + default: + std::cerr << "(EE) badly initialised group distribution ID = " << group.mMeta.mCircleType << std::endl; + } + + ui->infoDistribution->setText(distrib_string); + +#ifdef TODO + ui->infoWidget->show(); + ui->feedWidget->hide(); + ui->fileWidget->hide(); +#endif + + ui->feedToolButton->setEnabled(false); + ui->fileToolButton->setEnabled(false); + + ui->subscribeToolButton->setText(tr("Subscribe ") + " " + QString::number(group.mMeta.mPop) ); + + } +} + +int GxsChannelPostsWidget::viewMode() +{ + if (ui->feedToolButton->isChecked()) { + return VIEW_MODE_FEEDS; + } else if (ui->fileToolButton->isChecked()) { + return VIEW_MODE_FILES; + } + + /* Default */ + return VIEW_MODE_FEEDS; +} + +void GxsChannelPostsWidget::setViewMode(int viewMode) +{ +#ifdef TODO + switch (viewMode) { + case VIEW_MODE_FEEDS: + ui->feedWidget->show(); + ui->fileWidget->hide(); + + ui->feedToolButton->setChecked(true); + ui->fileToolButton->setChecked(false); + + break; + case VIEW_MODE_FILES: + ui->feedWidget->hide(); + ui->fileWidget->show(); + + ui->feedToolButton->setChecked(false); + ui->fileToolButton->setChecked(true); + + break; + default: + setViewMode(VIEW_MODE_FEEDS); + return; + } +#endif +} + +void GxsChannelPostsWidget::filterChanged(int filter) +{ +#ifdef TODO + ui->feedWidget->setFilterType(filter); + ui->fileWidget->setFilterType(filter); +#endif +} + +/*static*/ bool GxsChannelPostsWidget::filterItem(FeedItem *feedItem, const QString &text, int filter) +{ + GxsChannelPostItem *item = dynamic_cast(feedItem); + if (!item) { + return true; + } + + bool bVisible = text.isEmpty(); + + if (!bVisible) + { + switch(filter) + { + case FILTER_TITLE: + bVisible = item->getTitleLabel().contains(text,Qt::CaseInsensitive); + break; + case FILTER_MSG: + bVisible = item->getMsgLabel().contains(text,Qt::CaseInsensitive); + break; + case FILTER_FILE_NAME: + { + std::list fileItems = item->getFileItems(); + std::list::iterator lit; + for(lit = fileItems.begin(); lit != fileItems.end(); ++lit) + { + SubFileItem *fi = *lit; + QString fileName = QString::fromUtf8(fi->FileName().c_str()); + bVisible = (bVisible || fileName.contains(text,Qt::CaseInsensitive)); + } + break; + } + default: + bVisible = true; + break; + } + } + + return bVisible; +} + +#ifdef TODO +void GxsChannelPostsWidget::createPostItemFromMetaData(const RsGxsMsgMetaData& meta,bool related) +{ + GxsChannelPostItem *item = NULL; + RsGxsChannelPost post; + + if(!meta.mOrigMsgId.isNull()) + { + FeedItem *feedItem = ui->feedWidget->findFeedItem(GxsChannelPostItem::computeIdentifier(meta.mOrigMsgId)) ; + item = dynamic_cast(feedItem); + + if(item) + { + post = feedItem->post(); + ui->feedWidget->removeFeedItem(item) ; + + post.mOlderVersions.insert(post.mMeta.mMsgId); + + GxsChannelPostItem *item = new GxsChannelPostItem(this, 0, post, true, false,post.mOlderVersions); + ui->feedWidget->addFeedItem(item, ROLE_PUBLISH, QDateTime::fromTime_t(post.mMeta.mPublishTs)); + + return ; + } + } + + if (related) + { + FeedItem *feedItem = ui->feedWidget->findFeedItem(GxsChannelPostItem::computeIdentifier(meta.mMsgId)) ; + item = dynamic_cast(feedItem); + } + if (item) + { + item->setPost(post); + ui->feedWidget->setSort(item, ROLE_PUBLISH, QDateTime::fromTime_t(meta.mPublishTs)); + } + else + { + GxsChannelPostItem *item = new GxsChannelPostItem(this, 0, meta.mGroupId,meta.mMsgId, true, true); + ui->feedWidget->addFeedItem(item, ROLE_PUBLISH, QDateTime::fromTime_t(post.mMeta.mPublishTs)); + } +#ifdef TODO + ui->fileWidget->addFiles(post, related); +#endif +} +#endif + +void GxsChannelPostsWidget::insertChannelPosts(std::vector& posts) +{ + mModel->setPosts(posts); +} + +#ifdef TODO +void GxsChannelPostsWidget::createPostItem(const RsGxsChannelPost& post, bool related) +{ + GxsChannelPostItem *item = NULL; + + const RsMsgMetaData& meta(post.mMeta); + + if(!meta.mOrigMsgId.isNull()) + { + FeedItem *feedItem = ui->feedWidget->findFeedItem(GxsChannelPostItem::computeIdentifier(meta.mOrigMsgId)) ; + item = dynamic_cast(feedItem); + + if(item) + { + std::set older_versions(item->olderVersions()); // we make a copy because the item will be deleted + ui->feedWidget->removeFeedItem(item) ; + + older_versions.insert(meta.mMsgId); + + GxsChannelPostItem *item = new GxsChannelPostItem(this, 0, mGroup.mMeta,meta.mMsgId, true, false,older_versions); + ui->feedWidget->addFeedItem(item, ROLE_PUBLISH, QDateTime::fromTime_t(meta.mPublishTs)); + + return ; + } + } + + if (related) + { + FeedItem *feedItem = ui->feedWidget->findFeedItem(GxsChannelPostItem::computeIdentifier(meta.mMsgId)) ; + item = dynamic_cast(feedItem); + } + if (item) + { + item->setPost(post); + ui->feedWidget->setSort(item, ROLE_PUBLISH, QDateTime::fromTime_t(meta.mPublishTs)); + } + else + { + GxsChannelPostItem *item = new GxsChannelPostItem(this, 0, mGroup.mMeta,meta.mMsgId, true, true); + ui->feedWidget->addFeedItem(item, ROLE_PUBLISH, QDateTime::fromTime_t(meta.mPublishTs)); + } + + ui->fileWidget->addFiles(post, related); +} + +void GxsChannelPostsWidget::fillThreadCreatePost(const QVariant &post, bool related, int current, int count) +{ + /* show fill progress */ + if (count) { + ui->progressBar->setValue(current * ui->progressBar->maximum() / count); + } + + if (!post.canConvert()) { + return; + } + + createPostItem(post.value(), related); +} + +void GxsChannelPostsWidget::insertChannelPosts(std::vector& posts, GxsMessageFramePostThread *thread, bool related) +{ + if (related && thread) { + std::cerr << "GxsChannelPostsWidget::insertChannelPosts fill only related posts as thread is not possible" << std::endl; + return; + } + + int count = posts.size(); + int pos = 0; + + if (!thread) { + ui->feedWidget->setSortingEnabled(false); + } + + // collect new versions of posts if any + +#ifdef DEBUG_CHANNEL + std::cerr << "Inserting channel posts" << std::endl; +#endif + + std::vector new_versions ; + for (uint32_t i=0;i search_map ; + for (uint32_t i=0;i versions ; + std::map::const_iterator vit ; + + while(search_map.end() != (vit=search_map.find(posts[current_index].mMeta.mOrigMsgId))) + { +#ifdef DEBUG_CHANNEL + std::cerr << " post at index " << current_index << " replaces a post at position " << vit->second ; +#endif + + // Now replace the post only if the new versionis more recent. It may happen indeed that the same post has been corrected multiple + // times. In this case, we only need to replace the post with the newest version + + //uint32_t prev_index = current_index ; + current_index = vit->second ; + + if(posts[current_index].mMeta.mMsgId.isNull()) // This handles the branching situation where this post has been already erased. No need to go down further. + { +#ifdef DEBUG_CHANNEL + std::cerr << " already erased. Stopping." << std::endl; +#endif + break ; + } + + if(posts[current_index].mMeta.mPublishTs < posts[source_index].mMeta.mPublishTs) + { +#ifdef DEBUG_CHANNEL + std::cerr << " and is more recent => following" << std::endl; +#endif + for(std::set::const_iterator itt(posts[current_index].mOlderVersions.begin());itt!=posts[current_index].mOlderVersions.end();++itt) + posts[source_index].mOlderVersions.insert(*itt); + + posts[source_index].mOlderVersions.insert(posts[current_index].mMeta.mMsgId); + posts[current_index].mMeta.mMsgId.clear(); // clear the msg Id so the post will be ignored + } +#ifdef DEBUG_CHANNEL + else + std::cerr << " but is older -> Stopping" << std::endl; +#endif + } + } + } + +#ifdef DEBUG_CHANNEL + std::cerr << "Now adding posts..." << std::endl; +#endif + + for (std::vector::const_reverse_iterator it = posts.rbegin(); it != posts.rend(); ++it) + { +#ifdef DEBUG_CHANNEL + std::cerr << " adding post: " << (*it).mMeta.mMsgId ; +#endif + + if(!(*it).mMeta.mMsgId.isNull()) + { +#ifdef DEBUG_CHANNEL + std::cerr << " added" << std::endl; +#endif + + if (thread && thread->stopped()) + break; + + if (thread) + thread->emitAddPost(QVariant::fromValue(*it), related, ++pos, count); + else + createPostItem(*it, related); + } +#ifdef DEBUG_CHANNEL + else + std::cerr << " skipped" << std::endl; +#endif + } + + if (!thread) { + ui->feedWidget->setSortingEnabled(true); + } +} + +void GxsChannelPostsWidget::clearPosts() +{ + ui->feedWidget->clear(); + ui->fileWidget->clear(); +} +#endif + +void GxsChannelPostsWidget::blank() +{ + mStateHelper->setWidgetEnabled(ui->postButton, false); + mStateHelper->setWidgetEnabled(ui->subscribeToolButton, false); + + clearPosts(); + + groupNameChanged(QString()); + + ui->infoWidget->hide(); + ui->feedWidget->show(); + ui->fileWidget->hide(); +} + +bool GxsChannelPostsWidget::navigatePostItem(const RsGxsMessageId &msgId) +{ + FeedItem *feedItem = ui->feedWidget->findFeedItem(GxsChannelPostItem::computeIdentifier(msgId)); + if (!feedItem) { + return false; + } + + return ui->feedWidget->scrollTo(feedItem, true); +} + +void GxsChannelPostsWidget::subscribeGroup(bool subscribe) +{ + RsGxsGroupId grpId(groupId()); + if (grpId.isNull()) return; + + RsThread::async([=]() + { + rsGxsChannels->subscribeToChannel(grpId, subscribe); + } ); +} + +void GxsChannelPostsWidget::setAutoDownload(bool autoDl) +{ + mAutoDownloadAction->setChecked(autoDl); + mAutoDownloadAction->setText(autoDl ? tr("Disable Auto-Download") : tr("Enable Auto-Download")); +} + +void GxsChannelPostsWidget::toggleAutoDownload() +{ + RsGxsGroupId grpId = groupId(); + if (grpId.isNull()) { + return; + } + + bool autoDownload; + if(!rsGxsChannels->getChannelAutoDownload(grpId, autoDownload)) + { + std::cerr << __PRETTY_FUNCTION__ << " failed to get autodownload value " + << "for channel: " << grpId.toStdString() << std::endl; + return; + } + + RsThread::async([this, grpId, autoDownload]() + { + if(!rsGxsChannels->setChannelAutoDownload(grpId, !autoDownload)) + { + std::cerr << __PRETTY_FUNCTION__ << " failed to set autodownload " + << "for channel: " << grpId.toStdString() << std::endl; + return; + } + +// RsQThreadUtils::postToObject( [=]() +// { +// /* Here it goes any code you want to be executed on the Qt Gui +// * thread, for example to update the data model with new information +// * after a blocking call to RetroShare API complete, note that +// * Qt::QueuedConnection is important! +// */ +// +// std::cerr << __PRETTY_FUNCTION__ << " Has been executed on GUI " +// << "thread but was scheduled by async thread" << std::endl; +// }, this ); + }); +} + +bool GxsChannelPostsWidget::insertGroupData(const RsGxsGenericGroupData *data) +{ + const RsGxsChannelGroup *d = dynamic_cast(data); + + if(!d) + { + RsErr() << __PRETTY_FUNCTION__ << " Cannot dynamic cast input data (" << (void*)data << " to RsGxsGenericGroupData. Something bad happenned." << std::endl; + return false; + } + + insertChannelDetails(*d); + return true; +} + +void GxsChannelPostsWidget::getMsgData(const std::set& msgIds,std::vector& psts) +{ + std::vector posts; + std::vector comments; + std::vector votes; + + rsGxsChannels->getChannelContent( groupId(),msgIds,posts,comments,votes ); + + psts.clear(); + + for(auto& post: posts) + psts.push_back(new RsGxsChannelPost(post)); +} + +void GxsChannelPostsWidget::getAllMsgData(std::vector& psts) +{ + std::vector posts; + std::vector comments; + std::vector votes; + + rsGxsChannels->getChannelAllContent( groupId(),posts,comments,votes ); + + psts.clear(); + + for(auto& post: posts) + psts.push_back(new RsGxsChannelPost(post)); +} + +bool GxsChannelPostsWidget::getGroupData(RsGxsGenericGroupData *& data) +{ + if(groupId().isNull()) + { + RsErr() << __PRETTY_FUNCTION__ << " Trying to get data about null group!!" << std::endl; + return false; + } + std::vector groups; + + if(rsGxsChannels->getChannelsInfo(std::list({groupId()}),groups) && groups.size()==1) + { + data = new RsGxsChannelGroup(groups[0]); + + mGroup = groups[0]; // make a local copy to pass on to items + return true; + } + else + { + RsGxsChannelGroup distant_group; + + if(rsGxsChannels->retrieveDistantGroup(groupId(),distant_group)) + { + insertChannelDetails(distant_group); + data = new RsGxsChannelGroup(distant_group); + mGroup = distant_group; // make a local copy to pass on to items + return true ; + } + } + + return false; +} + +#ifdef TODO +void GxsChannelPostsWidget::insertAllPosts(const std::vector& posts, GxsMessageFramePostThread *thread) +{ + std::vector cposts; + + for(auto post: posts) // This is not so nice but we have somehow to convert to RsGxsChannelPost at some time, and the cposts list is being modified in the insert method. + cposts.push_back(*static_cast(post)); + + insertChannelPosts(cposts, thread, false); +} +#endif + +void GxsChannelPostsWidget::insertPosts(const std::vector& posts) +{ + std::vector cposts; + + for(auto post: posts) // This is not so nice but we have somehow to convert to RsGxsChannelPost at some timer, and the cposts list is being modified in the insert method. + cposts.push_back(*static_cast(post)); + + insertChannelPosts(cposts); +} + +class GxsChannelPostsReadData +{ +public: + GxsChannelPostsReadData(bool read) + { + mRead = read; + mLastToken = 0; + } + +public: + bool mRead; + uint32_t mLastToken; +}; + +static void setAllMessagesReadCallback(FeedItem *feedItem, void *data) +{ + GxsChannelPostItem *channelPostItem = dynamic_cast(feedItem); + if (!channelPostItem) { + return; + } + + GxsChannelPostsReadData *readData = (GxsChannelPostsReadData*) data; + bool isRead = !channelPostItem->isUnread() ; + + if(channelPostItem->isLoaded() && (isRead == readData->mRead)) + return ; + + RsGxsGrpMsgIdPair msgPair = std::make_pair(channelPostItem->groupId(), channelPostItem->messageId()); + rsGxsChannels->setMessageReadStatus(readData->mLastToken, msgPair, readData->mRead); +} + +void GxsChannelPostsWidget::setAllMessagesReadDo(bool read, uint32_t &token) +{ + if (groupId().isNull() || !IS_GROUP_SUBSCRIBED(subscribeFlags())) { + return; + } + + GxsChannelPostsReadData data(read); + ui->feedWidget->withAll(setAllMessagesReadCallback, &data); + + token = data.mLastToken; +} diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h new file mode 100644 index 000000000..31fe597a1 --- /dev/null +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -0,0 +1,130 @@ +/******************************************************************************* + * retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h * + * * + * Copyright 2013 by Robert Fernie * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#ifndef _GXS_CHANNELPOSTSWIDGET_H +#define _GXS_CHANNELPOSTSWIDGET_H + +#include + +#include "gui/gxs/GxsMessageFramePostWidget.h" + +#include "gui/feeds/FeedHolder.h" + +namespace Ui { +class GxsChannelPostsWidget; +} + +class GxsChannelPostItem; +class QTreeWidgetItem; +class FeedItem; +class RsGxsChannelPostsModel; + +class GxsChannelPostsWidgetWithModel: public QWidget, public GxsMessageFrameWidget +{ + Q_OBJECT + +public: + /* Filters */ + enum Filter { + FILTER_TITLE = 1, + FILTER_MSG = 2, + FILTER_FILE_NAME = 3 + }; + +public: + /** Default Constructor */ + GxsChannelPostsWidgetWithModel(const RsGxsGroupId &channelId, QWidget *parent = 0); + /** Default Destructor */ + ~GxsChannelPostsWidgetWithModel(); + + /* GxsMessageFrameWidget */ + virtual QIcon groupIcon(); + virtual void groupIdChanged() override; + virtual QString groupName(bool) override; + virtual bool navigate(const RsGxsMessageId&) override; + +#ifdef TODO + /* FeedHolder */ + virtual QScrollArea *getScrollArea(); + virtual void deleteFeedItem(FeedItem *feedItem, uint32_t type); + virtual void openChat(const RsPeerId& peerId); + virtual void openComments(uint32_t type, const RsGxsGroupId &groupId, const QVector &msg_versions, const RsGxsMessageId &msgId, const QString &title); +#endif + +protected: + /* GxsMessageFramePostWidget */ + virtual void groupNameChanged(const QString &name); +#ifdef TODO + virtual bool insertGroupData(const RsGxsGenericGroupData *data) override; +#endif + virtual void clearPosts(); + virtual bool useThread() { return mUseThread; } + virtual void fillThreadCreatePost(const QVariant &post, bool related, int current, int count); + virtual bool navigatePostItem(const RsGxsMessageId& msgId); + virtual void blank() ; + +#ifdef TODO + virtual bool getGroupData(RsGxsGenericGroupData *& data) override; + virtual void getMsgData(const std::set& msgIds,std::vector& posts) override; + virtual void getAllMsgData(std::vector& posts) override; + virtual void insertPosts(const std::vector& posts) override; + virtual void insertAllPosts(const std::vector& posts, GxsMessageFramePostThread *thread) override; +#endif + + /* GxsMessageFrameWidget */ + virtual void setAllMessagesReadDo(bool read, uint32_t &token); + +private slots: + void createMsg(); + void toggleAutoDownload(); + void subscribeGroup(bool subscribe); + void filterChanged(int filter); + void setViewMode(int viewMode); + void settingsChanged(); + +private: + void processSettings(bool load); + + void setAutoDownload(bool autoDl); + static bool filterItem(FeedItem *feedItem, const QString &text, int filter); + + int viewMode(); + + void insertChannelDetails(const RsGxsChannelGroup &group); + void insertChannelPosts(std::vector &posts, GxsMessageFramePostThread *thread, bool related); + + void createPostItem(const RsGxsChannelPost &post, bool related); + void handleEvent_main_thread(std::shared_ptr event); + +private: + QAction *mAutoDownloadAction; + + RsGxsChannelGroup mGroup; + bool mUseThread; + RsEventsHandlerId_t mEventHandlerId ; + + RsGxsChannelPostsModel *mThreadModel; + UIStateHelper *mStateHelper; + + /* UI - from Designer */ + Ui::GxsChannelPostsWidget *ui; +}; + +#endif diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui new file mode 100644 index 000000000..c1bc74996 --- /dev/null +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -0,0 +1,563 @@ + + + GxsChannelPostsWidgetWithModel + + + + 0 + 0 + 977 + 628 + + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::Box + + + QFrame::Sunken + + + + 4 + + + 4 + + + 4 + + + 4 + + + + + + 64 + 64 + + + + + 64 + 64 + + + + + + + :/images/channels.png + + + true + + + + + + + + + + + + + + Channel Name + + + + + + + + + + QFrame::Box + + + QFrame::Sunken + + + + 4 + + + 2 + + + 6 + + + 2 + + + + + + 0 + 0 + + + + Subscribe + + + + 16 + 16 + + + + QToolButton::MenuButtonPopup + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Qt::NoFocus + + + Post to Channel + + + Add new post + + + + :/icons/png/add.png:/icons/png/add.png + + + + 32 + 16 + + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 0 + 0 + + + + + + + + Loading + + + + + + + + 0 + 0 + + + + + 16777215 + 10 + + + + 1000 + + + 0 + + + + + + + 0 + + + + + Show feeds + + + + :/images/view-feeds.png:/images/view-feeds.png + + + true + + + true + + + + + + + Show files + + + + :/images/view-files.png:/images/view-files.png + + + true + + + true + + + + + + + + + + 0 + 0 + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + Search channels + + + true + + + + + + + + + + + + + + 3 + + + 0 + + + 3 + + + 3 + + + + + false + + + QFrame::NoFrame + + + QFrame::Plain + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + Channel details + + + + 9 + + + 9 + + + 9 + + + 9 + + + + + + 0 + 0 + + + + + 75 + true + + + + Last Post: + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Description</span></p></body></html> + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + true + + + true + + + + + + + + 75 + true + + + + Description: + + + + + + + + 75 + true + + + + Created: + + + + + + + + 75 + true + + + + Administrator: + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Posts: + + + + + + + + 75 + true + + + + Distribution: + + + + + + + unknown + + + + + + + unknown + + + + + + + unknown + + + true + + + + + + + unknown + + + + + + + 0 + + + + + + + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + + + + + + + Feeds + + + + + Files + + + toolBarFrame + headFrame + infoWidget + postsTree + + + + GxsIdLabel + QLabel +
gui/gxs/GxsIdLabel.h
+
+ + SubscribeToolButton + QToolButton +
gui/common/SubscribeToolButton.h
+
+ + StyledElidedLabel + QLabel +
gui/common/StyledElidedLabel.h
+
+ + LineEditClear + QLineEdit +
gui/common/LineEditClear.h
+
+
+ + + + + +
diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index a5d6838ae..8a1133e02 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -1333,13 +1333,17 @@ gxschannels { gui/gxschannels/GxsChannelGroupDialog.h \ gui/gxschannels/CreateGxsChannelMsg.h \ gui/gxschannels/GxsChannelPostsWidget.h \ + gui/gxschannels/GxsChannelPostsWidgetWithModel.h \ + gui/gxschannels/GxsChannelPostsModel.h \ gui/gxschannels/GxsChannelFilesWidget.h \ gui/gxschannels/GxsChannelFilesStatusWidget.h \ gui/feeds/GxsChannelGroupItem.h \ gui/feeds/GxsChannelPostItem.h \ gui/gxschannels/GxsChannelUserNotify.h - FORMS += gui/gxschannels/GxsChannelPostsWidget.ui \ + FORMS += \ + gui/gxschannels/GxsChannelPostsWidgetWithModel.ui \ + gui/gxschannels/GxsChannelPostsWidget.ui \ gui/gxschannels/GxsChannelFilesWidget.ui \ gui/gxschannels/GxsChannelFilesStatusWidget.ui \ gui/gxschannels/CreateGxsChannelMsg.ui \ @@ -1348,6 +1352,8 @@ gxschannels { SOURCES += gui/gxschannels/GxsChannelDialog.cpp \ gui/gxschannels/GxsChannelPostsWidget.cpp \ + gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp \ + gui/gxschannels/GxsChannelPostsModel.cpp \ gui/gxschannels/GxsChannelFilesWidget.cpp \ gui/gxschannels/GxsChannelFilesStatusWidget.cpp \ gui/gxschannels/GxsChannelGroupDialog.cpp \ From 5a6c8de0056fb7fd40e7de30c647e2001d04cbda Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 2 Jun 2020 22:22:36 +0200 Subject: [PATCH 021/154] fixed abstract item model for channels. Display still missing --- .../gui/gxschannels/GxsChannelFilesWidget.cpp | 9 - .../gui/gxschannels/GxsChannelPostsWidget.h | 2 +- .../GxsChannelPostsWidgetWithModel.cpp | 271 ++++++++---------- .../GxsChannelPostsWidgetWithModel.h | 19 +- .../gui/gxsforums/GxsForumThreadWidget.cpp | 1 + 5 files changed, 134 insertions(+), 168 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesWidget.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesWidget.cpp index 3afb4e645..5ae905cea 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesWidget.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesWidget.cpp @@ -80,15 +80,6 @@ GxsChannelFilesWidget::GxsChannelFilesWidget(QWidget *parent) : ui->treeWidget->setColumnWidth(COLUMN_PUBLISHED, 150); } -GxsChannelFilesWidget::paintEvent() -{ - QWidget::paintEvent(); - - if(!mLoaded) - { - } -} - GxsChannelFilesWidget::~GxsChannelFilesWidget() { delete(mCompareRole); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h index 28a521944..dded41491 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h @@ -98,7 +98,7 @@ private: int viewMode(); void insertChannelDetails(const RsGxsChannelGroup &group); - void insertChannelPosts(std::vector &posts); + void insertChannelPosts(std::vector& posts, GxsMessageFramePostThread *thread, bool related); void createPostItem(const RsGxsChannelPost &post, bool related); void handleEvent_main_thread(std::shared_ptr event); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index bc3c564e3..dd2c8cccc 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -24,7 +24,8 @@ #include "retroshare/rsgxscircles.h" #include "GxsChannelPostsWidgetWithModel.h" -#include "ui_GxsChannelPostsWidget.h" +#include "GxsChannelPostsModel.h" +#include "ui_GxsChannelPostsWidgetWithModel.h" #include "gui/feeds/GxsChannelPostItem.h" #include "gui/gxs/GxsIdDetails.h" #include "gui/gxschannels/CreateGxsChannelMsg.h" @@ -53,27 +54,27 @@ /** Constructor */ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupId &channelId, QWidget *parent) : - GxsMessageFramePostWidget(rsGxsChannels, parent), - ui(new Ui::GxsChannelPostsWidget) + GxsMessageFrameWidget(rsGxsChannels, parent), + ui(new Ui::GxsChannelPostsWidgetWithModel) { /* Invoke the Qt Designer generated object setup routine */ ui->setupUi(this); - ui->postsTree->setModel(new RsGxsChannelPostsModel()); + ui->postsTree->setModel(mThreadModel = new RsGxsChannelPostsModel()); /* Setup UI helper */ - mStateHelper->addWidget(mTokenTypeAllPosts, ui->progressBar, UISTATE_LOADING_VISIBLE); - mStateHelper->addWidget(mTokenTypeAllPosts, ui->loadingLabel, UISTATE_LOADING_VISIBLE); - mStateHelper->addWidget(mTokenTypeAllPosts, ui->filterLineEdit); + //mStateHelper->addWidget(mTokenTypeAllPosts, ui->progressBar, UISTATE_LOADING_VISIBLE); + //mStateHelper->addWidget(mTokenTypeAllPosts, ui->loadingLabel, UISTATE_LOADING_VISIBLE); + //mStateHelper->addWidget(mTokenTypeAllPosts, ui->filterLineEdit); - mStateHelper->addWidget(mTokenTypePosts, ui->loadingLabel, UISTATE_LOADING_VISIBLE); + //mStateHelper->addWidget(mTokenTypePosts, ui->loadingLabel, UISTATE_LOADING_VISIBLE); - mStateHelper->addLoadPlaceholder(mTokenTypeGroupData, ui->nameLabel); + //mStateHelper->addLoadPlaceholder(mTokenTypeGroupData, ui->nameLabel); - mStateHelper->addWidget(mTokenTypeGroupData, ui->postButton); - mStateHelper->addWidget(mTokenTypeGroupData, ui->logoLabel); - mStateHelper->addWidget(mTokenTypeGroupData, ui->subscribeToolButton); + //mStateHelper->addWidget(mTokenTypeGroupData, ui->postButton); + //mStateHelper->addWidget(mTokenTypeGroupData, ui->logoLabel); + //mStateHelper->addWidget(mTokenTypeGroupData, ui->subscribeToolButton); /* Connect signals */ connect(ui->postButton, SIGNAL(clicked()), this, SLOT(createMsg())); @@ -111,8 +112,8 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->nameLabel->setMinimumWidth(20); /* Initialize feed widget */ - ui->feedWidget->setSortRole(ROLE_PUBLISH, Qt::DescendingOrder); - ui->feedWidget->setFilterCallback(filterItem); + //ui->feedWidget->setSortRole(ROLE_PUBLISH, Qt::DescendingOrder); + //ui->feedWidget->setFilterCallback(filterItem); /* load settings */ processSettings(true); @@ -141,7 +142,7 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI mEventHandlerId, RsEventType::GXS_CHANNELS ); } -void GxsChannelPostsWidget::handleEvent_main_thread(std::shared_ptr event) +void GxsChannelPostsWidgetWithModel::handleEvent_main_thread(std::shared_ptr event) { const RsGxsChannelEvent *e = dynamic_cast(event.get()); @@ -157,29 +158,90 @@ void GxsChannelPostsWidget::handleEvent_main_thread(std::shared_ptrmChannelGroupId == groupId()) updateDisplay(true); break; - case RsChannelEventCode::READ_STATUS_CHANGED: - if (FeedItem *feedItem = ui->feedWidget->findFeedItem(GxsChannelPostItem::computeIdentifier(e->mChannelMsgId))) - if (GxsChannelPostItem *channelPostItem = dynamic_cast(feedItem)) - channelPostItem->setReadStatus(false,!channelPostItem->isUnread()); - //channelPostItem->setReadStatus(false,e->Don't get read status. Will be more easier and accurate); - break; +// case RsChannelEventCode::READ_STATUS_CHANGED: +// if (FeedItem *feedItem = ui->feedWidget->findFeedItem(GxsChannelPostItem::computeIdentifier(e->mChannelMsgId))) +// if (GxsChannelPostItem *channelPostItem = dynamic_cast(feedItem)) +// channelPostItem->setReadStatus(false,!channelPostItem->isUnread()); +// //channelPostItem->setReadStatus(false,e->Don't get read status. Will be more easier and accurate); +// break; default: break; } } -GxsChannelPostsWidget::~GxsChannelPostsWidget() +void GxsChannelPostsWidgetWithModel::updateGroupData() +{ + if(groupId().isNull()) + return; + + RsThread::async([this]() + { + std::vector groups; + + if(!rsGxsChannels->getChannelsInfo(std::list{ groupId() }, groups)) + { + std::cerr << __PRETTY_FUNCTION__ << " failed to get autodownload value for channel: " << groupId() << std::endl; + return; + } + + if(groups.size() != 1) + { + RsErr() << __PRETTY_FUNCTION__ << " cannot retrieve channel data for group ID " << groupId() << ": ERROR." << std::endl; + return; + } + + RsQThreadUtils::postToObject( [this,groups]() + { + mGroup = groups[0]; + mThreadModel->updateChannel(groupId()); + } ); + }); +} + +void GxsChannelPostsWidgetWithModel::updateDisplay(bool complete) +{ +#ifdef DEBUG_CHANNEL + std::cerr << "udateDisplay: groupId()=" << groupId()<< std::endl; +#endif + if(groupId().isNull()) + { +#ifdef DEBUG_CHANNEL + std::cerr << " group_id=0. Return!"<< std::endl; +#endif + return; + } + + if(mGroup.mMeta.mGroupId.isNull() && !groupId().isNull()) + { +#ifdef DEBUG_FORUMS + std::cerr << " inconsistent group data. Reloading!"<< std::endl; +#endif + complete = true; + } + if(complete) // need to update the group data, reload the messages etc. + { +#warning todo + //saveExpandedItems(mSavedExpandedMessages); + + //if(mGroupId != mThreadModel->currentGroupId()) + // mThreadId.clear(); + + updateGroupData(); + + return; + } +} +GxsChannelPostsWidgetWithModel::~GxsChannelPostsWidgetWithModel() { rsEvents->unregisterEventsHandler(mEventHandlerId); // save settings processSettings(false); delete(mAutoDownloadAction); - delete ui; } -void GxsChannelPostsWidget::processSettings(bool load) +void GxsChannelPostsWidgetWithModel::processSettings(bool load) { Settings->beginGroup(QString("ChannelPostsWidget")); @@ -204,14 +266,19 @@ void GxsChannelPostsWidget::processSettings(bool load) Settings->endGroup(); } -void GxsChannelPostsWidget::settingsChanged() +void GxsChannelPostsWidgetWithModel::settingsChanged() { mUseThread = Settings->getChannelLoadThread(); - mStateHelper->setWidgetVisible(ui->progressBar, mUseThread); + //mStateHelper->setWidgetVisible(ui->progressBar, mUseThread); } -void GxsChannelPostsWidget::groupNameChanged(const QString &name) +QString GxsChannelPostsWidgetWithModel::groupName(bool) +{ + return "Group name" ; +} + +void GxsChannelPostsWidgetWithModel::groupNameChanged(const QString &name) { if (groupId().isNull()) { ui->nameLabel->setText(tr("No Channel Selected")); @@ -221,11 +288,11 @@ void GxsChannelPostsWidget::groupNameChanged(const QString &name) } } -QIcon GxsChannelPostsWidget::groupIcon() +QIcon GxsChannelPostsWidgetWithModel::groupIcon() { - if (mStateHelper->isLoading(mTokenTypeGroupData) || mStateHelper->isLoading(mTokenTypeAllPosts)) { - return QIcon(":/images/kalarm.png"); - } +// if (mStateHelper->isLoading(mTokenTypeGroupData) || mStateHelper->isLoading(mTokenTypeAllPosts)) { +// return QIcon(":/images/kalarm.png"); +// } // if (mNewCount) { // return QIcon(":/images/message-state-new.png"); @@ -238,36 +305,19 @@ QIcon GxsChannelPostsWidget::groupIcon() /*************************************************************************************/ /*************************************************************************************/ -QScrollArea *GxsChannelPostsWidget::getScrollArea() -{ - return NULL; -} - -void GxsChannelPostsWidget::deleteFeedItem(FeedItem *feedItem, uint32_t /*type*/) -{ - if (!feedItem) - return; - - ui->feedWidget->removeFeedItem(feedItem); -} - -void GxsChannelPostsWidget::openChat(const RsPeerId & /*peerId*/) -{ -} - // Callback from Widget->FeedHolder->ServiceDialog->CommentContainer->CommentDialog, -void GxsChannelPostsWidget::openComments(uint32_t /*type*/, const RsGxsGroupId &groupId, const QVector& msg_versions,const RsGxsMessageId &msgId, const QString &title) +void GxsChannelPostsWidgetWithModel::openComments(uint32_t /*type*/, const RsGxsGroupId &groupId, const QVector& msg_versions,const RsGxsMessageId &msgId, const QString &title) { emit loadComment(groupId, msg_versions,msgId, title); } -void GxsChannelPostsWidget::createMsg() +void GxsChannelPostsWidgetWithModel::createMsg() { if (groupId().isNull()) { return; } - if (!IS_GROUP_SUBSCRIBED(subscribeFlags())) { + if (!IS_GROUP_SUBSCRIBED(mGroup.mMeta.mSubscribeFlags)) { return; } @@ -277,7 +327,7 @@ void GxsChannelPostsWidget::createMsg() /* window will destroy itself! */ } -void GxsChannelPostsWidget::insertChannelDetails(const RsGxsChannelGroup &group) +void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGroup &group) { /* IMAGE */ QPixmap chanImage; @@ -387,7 +437,7 @@ void GxsChannelPostsWidget::insertChannelDetails(const RsGxsChannelGroup &group) } } -int GxsChannelPostsWidget::viewMode() +int GxsChannelPostsWidgetWithModel::viewMode() { if (ui->feedToolButton->isChecked()) { return VIEW_MODE_FEEDS; @@ -399,7 +449,7 @@ int GxsChannelPostsWidget::viewMode() return VIEW_MODE_FEEDS; } -void GxsChannelPostsWidget::setViewMode(int viewMode) +void GxsChannelPostsWidgetWithModel::setViewMode(int viewMode) { #ifdef TODO switch (viewMode) { @@ -426,7 +476,7 @@ void GxsChannelPostsWidget::setViewMode(int viewMode) #endif } -void GxsChannelPostsWidget::filterChanged(int filter) +void GxsChannelPostsWidgetWithModel::filterChanged(int filter) { #ifdef TODO ui->feedWidget->setFilterType(filter); @@ -434,7 +484,8 @@ void GxsChannelPostsWidget::filterChanged(int filter) #endif } -/*static*/ bool GxsChannelPostsWidget::filterItem(FeedItem *feedItem, const QString &text, int filter) +#ifdef TODO +/*static*/ bool GxsChannelPostsWidgetWithModel::filterItem(FeedItem *feedItem, const QString &text, int filter) { GxsChannelPostItem *item = dynamic_cast(feedItem); if (!item) { @@ -474,7 +525,6 @@ void GxsChannelPostsWidget::filterChanged(int filter) return bVisible; } -#ifdef TODO void GxsChannelPostsWidget::createPostItemFromMetaData(const RsGxsMsgMetaData& meta,bool related) { GxsChannelPostItem *item = NULL; @@ -518,14 +568,7 @@ void GxsChannelPostsWidget::createPostItemFromMetaData(const RsGxsMsgMetaData& m ui->fileWidget->addFiles(post, related); #endif } -#endif -void GxsChannelPostsWidget::insertChannelPosts(std::vector& posts) -{ - mModel->setPosts(posts); -} - -#ifdef TODO void GxsChannelPostsWidget::createPostItem(const RsGxsChannelPost& post, bool related) { GxsChannelPostItem *item = NULL; @@ -734,31 +777,25 @@ void GxsChannelPostsWidget::clearPosts() } #endif -void GxsChannelPostsWidget::blank() +void GxsChannelPostsWidgetWithModel::blank() { - mStateHelper->setWidgetEnabled(ui->postButton, false); - mStateHelper->setWidgetEnabled(ui->subscribeToolButton, false); + //mStateHelper->setWidgetEnabled(ui->postButton, false); + //mStateHelper->setWidgetEnabled(ui->subscribeToolButton, false); - clearPosts(); - + mThreadModel->clear(); groupNameChanged(QString()); ui->infoWidget->hide(); - ui->feedWidget->show(); - ui->fileWidget->hide(); } -bool GxsChannelPostsWidget::navigatePostItem(const RsGxsMessageId &msgId) +bool GxsChannelPostsWidgetWithModel::navigate(const RsGxsMessageId &msgId) { - FeedItem *feedItem = ui->feedWidget->findFeedItem(GxsChannelPostItem::computeIdentifier(msgId)); - if (!feedItem) { - return false; - } - - return ui->feedWidget->scrollTo(feedItem, true); +#warning TODO + //return ui->feedWidget->scrollTo(feedItem, true); + return true; } -void GxsChannelPostsWidget::subscribeGroup(bool subscribe) +void GxsChannelPostsWidgetWithModel::subscribeGroup(bool subscribe) { RsGxsGroupId grpId(groupId()); if (grpId.isNull()) return; @@ -769,13 +806,13 @@ void GxsChannelPostsWidget::subscribeGroup(bool subscribe) } ); } -void GxsChannelPostsWidget::setAutoDownload(bool autoDl) +void GxsChannelPostsWidgetWithModel::setAutoDownload(bool autoDl) { mAutoDownloadAction->setChecked(autoDl); mAutoDownloadAction->setText(autoDl ? tr("Disable Auto-Download") : tr("Enable Auto-Download")); } -void GxsChannelPostsWidget::toggleAutoDownload() +void GxsChannelPostsWidgetWithModel::toggleAutoDownload() { RsGxsGroupId grpId = groupId(); if (grpId.isNull()) { @@ -813,7 +850,8 @@ void GxsChannelPostsWidget::toggleAutoDownload() }); } -bool GxsChannelPostsWidget::insertGroupData(const RsGxsGenericGroupData *data) +#ifdef TODO +bool GxsChannelPostsWidgetWithModel::insertGroupData(const RsGxsGenericGroupData *data) { const RsGxsChannelGroup *d = dynamic_cast(data); @@ -827,67 +865,6 @@ bool GxsChannelPostsWidget::insertGroupData(const RsGxsGenericGroupData *data) return true; } -void GxsChannelPostsWidget::getMsgData(const std::set& msgIds,std::vector& psts) -{ - std::vector posts; - std::vector comments; - std::vector votes; - - rsGxsChannels->getChannelContent( groupId(),msgIds,posts,comments,votes ); - - psts.clear(); - - for(auto& post: posts) - psts.push_back(new RsGxsChannelPost(post)); -} - -void GxsChannelPostsWidget::getAllMsgData(std::vector& psts) -{ - std::vector posts; - std::vector comments; - std::vector votes; - - rsGxsChannels->getChannelAllContent( groupId(),posts,comments,votes ); - - psts.clear(); - - for(auto& post: posts) - psts.push_back(new RsGxsChannelPost(post)); -} - -bool GxsChannelPostsWidget::getGroupData(RsGxsGenericGroupData *& data) -{ - if(groupId().isNull()) - { - RsErr() << __PRETTY_FUNCTION__ << " Trying to get data about null group!!" << std::endl; - return false; - } - std::vector groups; - - if(rsGxsChannels->getChannelsInfo(std::list({groupId()}),groups) && groups.size()==1) - { - data = new RsGxsChannelGroup(groups[0]); - - mGroup = groups[0]; // make a local copy to pass on to items - return true; - } - else - { - RsGxsChannelGroup distant_group; - - if(rsGxsChannels->retrieveDistantGroup(groupId(),distant_group)) - { - insertChannelDetails(distant_group); - data = new RsGxsChannelGroup(distant_group); - mGroup = distant_group; // make a local copy to pass on to items - return true ; - } - } - - return false; -} - -#ifdef TODO void GxsChannelPostsWidget::insertAllPosts(const std::vector& posts, GxsMessageFramePostThread *thread) { std::vector cposts; @@ -897,7 +874,6 @@ void GxsChannelPostsWidget::insertAllPosts(const std::vector& posts) { @@ -908,6 +884,7 @@ void GxsChannelPostsWidget::insertPosts(const std::vector& insertChannelPosts(cposts); } +#endif class GxsChannelPostsReadData { @@ -940,14 +917,14 @@ static void setAllMessagesReadCallback(FeedItem *feedItem, void *data) rsGxsChannels->setMessageReadStatus(readData->mLastToken, msgPair, readData->mRead); } -void GxsChannelPostsWidget::setAllMessagesReadDo(bool read, uint32_t &token) +void GxsChannelPostsWidgetWithModel::setAllMessagesReadDo(bool read, uint32_t &token) { - if (groupId().isNull() || !IS_GROUP_SUBSCRIBED(subscribeFlags())) { + if (groupId().isNull() || !IS_GROUP_SUBSCRIBED(mGroup.mMeta.mSubscribeFlags)) { return; } GxsChannelPostsReadData data(read); - ui->feedWidget->withAll(setAllMessagesReadCallback, &data); + //ui->feedWidget->withAll(setAllMessagesReadCallback, &data); token = data.mLastToken; } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index 31fe597a1..64478a112 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -28,7 +28,7 @@ #include "gui/feeds/FeedHolder.h" namespace Ui { -class GxsChannelPostsWidget; +class GxsChannelPostsWidgetWithModel; } class GxsChannelPostItem; @@ -36,7 +36,7 @@ class QTreeWidgetItem; class FeedItem; class RsGxsChannelPostsModel; -class GxsChannelPostsWidgetWithModel: public QWidget, public GxsMessageFrameWidget +class GxsChannelPostsWidgetWithModel: public GxsMessageFrameWidget { Q_OBJECT @@ -56,17 +56,19 @@ public: /* GxsMessageFrameWidget */ virtual QIcon groupIcon(); - virtual void groupIdChanged() override; + virtual void groupIdChanged() { updateDisplay(true); } virtual QString groupName(bool) override; virtual bool navigate(const RsGxsMessageId&) override; + void updateDisplay(bool complete); + #ifdef TODO /* FeedHolder */ virtual QScrollArea *getScrollArea(); virtual void deleteFeedItem(FeedItem *feedItem, uint32_t type); virtual void openChat(const RsPeerId& peerId); - virtual void openComments(uint32_t type, const RsGxsGroupId &groupId, const QVector &msg_versions, const RsGxsMessageId &msgId, const QString &title); #endif + virtual void openComments(uint32_t type, const RsGxsGroupId &groupId, const QVector &msg_versions, const RsGxsMessageId &msgId, const QString &title); protected: /* GxsMessageFramePostWidget */ @@ -74,10 +76,7 @@ protected: #ifdef TODO virtual bool insertGroupData(const RsGxsGenericGroupData *data) override; #endif - virtual void clearPosts(); virtual bool useThread() { return mUseThread; } - virtual void fillThreadCreatePost(const QVariant &post, bool related, int current, int count); - virtual bool navigatePostItem(const RsGxsMessageId& msgId); virtual void blank() ; #ifdef TODO @@ -92,6 +91,7 @@ protected: virtual void setAllMessagesReadDo(bool read, uint32_t &token); private slots: + void updateGroupData(); void createMsg(); void toggleAutoDownload(); void subscribeGroup(bool subscribe); @@ -108,9 +108,6 @@ private: int viewMode(); void insertChannelDetails(const RsGxsChannelGroup &group); - void insertChannelPosts(std::vector &posts, GxsMessageFramePostThread *thread, bool related); - - void createPostItem(const RsGxsChannelPost &post, bool related); void handleEvent_main_thread(std::shared_ptr event); private: @@ -124,7 +121,7 @@ private: UIStateHelper *mStateHelper; /* UI - from Designer */ - Ui::GxsChannelPostsWidget *ui; + Ui::GxsChannelPostsWidgetWithModel *ui; }; #endif diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 02eb74334..5e7e481b3 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -498,6 +498,7 @@ void GxsForumThreadWidget::recursRestoreExpandedItems(const QModelIndex& /*index ui->threadTreeWidget->setExpanded( mThreadProxyModel->mapFromSource(mThreadModel->getIndexOfMessage(*it)) ,true) ; } + void GxsForumThreadWidget::updateDisplay(bool complete) { #ifdef DEBUG_FORUMS From 3586fa78e62a60bf7bfbfbb2fe5f977e14b6c957 Mon Sep 17 00:00:00 2001 From: Klaus Eisentraut <2080545+keisentraut@users.noreply.github.com> Date: Tue, 2 Jun 2020 23:18:34 +0200 Subject: [PATCH 022/154] cherrypicked missing include from https://github.com/public/OpenPGP-SDK/pull/3 by @agl --- openpgpsdk/src/openpgpsdk/openssl_crypto.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openpgpsdk/src/openpgpsdk/openssl_crypto.c b/openpgpsdk/src/openpgpsdk/openssl_crypto.c index d1573437d..086dad77a 100644 --- a/openpgpsdk/src/openpgpsdk/openssl_crypto.c +++ b/openpgpsdk/src/openpgpsdk/openssl_crypto.c @@ -22,6 +22,7 @@ /** \file */ +#include #include #include #include From 58a4eafcc2e03d59310f53f4b9dd6ed05b424d73 Mon Sep 17 00:00:00 2001 From: defnax Date: Wed, 3 Jun 2020 12:24:58 +0200 Subject: [PATCH 023/154] Added reputation check for board posts * Added reputation check for board posts * Added show author feature for the menu --- .../src/gui/Posted/PostedCardView.cpp | 182 +++++++++------- retroshare-gui/src/gui/Posted/PostedItem.cpp | 202 +++++++++++------- retroshare-gui/src/gui/Posted/PostedItem.h | 1 + 3 files changed, 222 insertions(+), 163 deletions(-) diff --git a/retroshare-gui/src/gui/Posted/PostedCardView.cpp b/retroshare-gui/src/gui/Posted/PostedCardView.cpp index e75c2fb62..75a01557a 100644 --- a/retroshare-gui/src/gui/Posted/PostedCardView.cpp +++ b/retroshare-gui/src/gui/Posted/PostedCardView.cpp @@ -146,6 +146,8 @@ void PostedCardView::setup() QAction *CopyLinkAction = new QAction(QIcon(""),tr("Copy RetroShare Link"), this); connect(CopyLinkAction, SIGNAL(triggered()), this, SLOT(copyMessageLink())); + QAction *showInPeopleAct = new QAction(QIcon(), tr("Show author in people tab"), this); + connect(showInPeopleAct, SIGNAL(triggered()), this, SLOT(showAuthorInPeople())); int S = QFontMetricsF(font()).height() ; @@ -157,6 +159,8 @@ void PostedCardView::setup() QMenu *menu = new QMenu(); menu->addAction(CopyLinkAction); + menu->addSeparator(); + menu->addAction(showInPeopleAct); ui->shareButton->setMenu(menu); ui->clearButton->hide(); @@ -172,90 +176,106 @@ void PostedCardView::fill() // return; // } - QPixmap sqpixmap2 = QPixmap(":/images/thumb-default.png"); + RsReputationLevel overall_reputation = rsReputations->overallReputationLevel(mPost.mMeta.mAuthorId); + bool redacted = (overall_reputation == RsReputationLevel::LOCALLY_NEGATIVE); - mInFill = true; - int desired_height = 1.5*(ui->voteDownButton->height() + ui->voteUpButton->height() + ui->scoreLabel->height()); - int desired_width = sqpixmap2.width()*desired_height/(float)sqpixmap2.height(); - - QDateTime qtime; - qtime.setTime_t(mPost.mMeta.mPublishTs); - QString timestamp = qtime.toString("hh:mm dd-MMM-yyyy"); - QString timestamp2 = misc::timeRelativeToNow(mPost.mMeta.mPublishTs); - ui->dateLabel->setText(timestamp2); - ui->dateLabel->setToolTip(timestamp); - - ui->fromLabel->setId(mPost.mMeta.mAuthorId); - - // Use QUrl to check/parse our URL - // The only combination that seems to work: load as EncodedUrl, extract toEncoded(). - QByteArray urlarray(mPost.mLink.c_str()); - QUrl url = QUrl::fromEncoded(urlarray.trimmed()); - QString urlstr = "Invalid Link"; - QString sitestr = "Invalid Link"; - - bool urlOkay = url.isValid(); - if (urlOkay) - { - QString scheme = url.scheme(); - if ((scheme != "https") - && (scheme != "http") - && (scheme != "ftp") - && (scheme != "retroshare")) - { - urlOkay = false; - sitestr = "Invalid Link Scheme"; - } - } - - if (urlOkay) - { - urlstr = QString(" "); - urlstr += messageName(); - urlstr += QString(" "); - - QString siteurl = url.toEncoded(); - sitestr = QString(" %2 ").arg(siteurl).arg(siteurl); - - ui->titleLabel->setText(urlstr); - }else - { - ui->titleLabel->setText(messageName()); - - } - - if (urlarray.isEmpty()) - { - ui->siteLabel->hide(); - } - - ui->siteLabel->setText(sitestr); - - if(mPost.mImage.mData != NULL) - { - QPixmap pixmap; - GxsIdDetails::loadPixmapFromData(mPost.mImage.mData, mPost.mImage.mSize, pixmap,GxsIdDetails::ORIGINAL); - // Wiping data - as its been passed to thumbnail. - - QPixmap scaledpixmap; - if(pixmap.width() > 800){ - QPixmap scaledpixmap = pixmap.scaledToWidth(800, Qt::SmoothTransformation); - ui->pictureLabel->setPixmap(scaledpixmap); - }else{ - ui->pictureLabel->setPixmap(pixmap); - } - } - else if (mPost.mImage.mData == NULL) - { + if(redacted) { + ui->commentButton->setDisabled(true); + ui->voteUpButton->setDisabled(true); + ui->voteDownButton->setDisabled(true); ui->picture_frame->hide(); - } - else - { - ui->picture_frame->show(); - } + ui->fromLabel->setId(mPost.mMeta.mAuthorId); + ui->titleLabel->setText(tr( "

The author of this message (with ID %1) is banned.").arg(QString::fromStdString(mPost.mMeta.mAuthorId.toStdString()))) ; + QDateTime qtime; + qtime.setTime_t(mPost.mMeta.mPublishTs); + QString timestamp = qtime.toString("hh:mm dd-MMM-yyyy"); + ui->dateLabel->setText(timestamp); + } else { + QPixmap sqpixmap2 = QPixmap(":/images/thumb-default.png"); + + mInFill = true; + int desired_height = 1.5*(ui->voteDownButton->height() + ui->voteUpButton->height() + ui->scoreLabel->height()); + int desired_width = sqpixmap2.width()*desired_height/(float)sqpixmap2.height(); + + QDateTime qtime; + qtime.setTime_t(mPost.mMeta.mPublishTs); + QString timestamp = qtime.toString("hh:mm dd-MMM-yyyy"); + QString timestamp2 = misc::timeRelativeToNow(mPost.mMeta.mPublishTs); + ui->dateLabel->setText(timestamp2); + ui->dateLabel->setToolTip(timestamp); + + ui->fromLabel->setId(mPost.mMeta.mAuthorId); + + // Use QUrl to check/parse our URL + // The only combination that seems to work: load as EncodedUrl, extract toEncoded(). + QByteArray urlarray(mPost.mLink.c_str()); + QUrl url = QUrl::fromEncoded(urlarray.trimmed()); + QString urlstr = "Invalid Link"; + QString sitestr = "Invalid Link"; + + bool urlOkay = url.isValid(); + if (urlOkay) + { + QString scheme = url.scheme(); + if ((scheme != "https") + && (scheme != "http") + && (scheme != "ftp") + && (scheme != "retroshare")) + { + urlOkay = false; + sitestr = "Invalid Link Scheme"; + } + } + + if (urlOkay) + { + urlstr = QString(" "); + urlstr += messageName(); + urlstr += QString(" "); + + QString siteurl = url.toEncoded(); + sitestr = QString(" %2 ").arg(siteurl).arg(siteurl); + + ui->titleLabel->setText(urlstr); + }else + { + ui->titleLabel->setText(messageName()); + + } + + if (urlarray.isEmpty()) + { + ui->siteLabel->hide(); + } + + ui->siteLabel->setText(sitestr); + + if(mPost.mImage.mData != NULL) + { + QPixmap pixmap; + GxsIdDetails::loadPixmapFromData(mPost.mImage.mData, mPost.mImage.mSize, pixmap,GxsIdDetails::ORIGINAL); + // Wiping data - as its been passed to thumbnail. + + QPixmap scaledpixmap; + if(pixmap.width() > 800){ + QPixmap scaledpixmap = pixmap.scaledToWidth(800, Qt::SmoothTransformation); + ui->pictureLabel->setPixmap(scaledpixmap); + }else{ + ui->pictureLabel->setPixmap(pixmap); + } + } + else if (mPost.mImage.mData == NULL) + { + ui->picture_frame->hide(); + } + else + { + ui->picture_frame->show(); + } + } //QString score = "Hot" + QString::number(post.mHotScore); //score += " Top" + QString::number(post.mTopScore); diff --git a/retroshare-gui/src/gui/Posted/PostedItem.cpp b/retroshare-gui/src/gui/Posted/PostedItem.cpp index 751f68ee5..46de8a1e6 100644 --- a/retroshare-gui/src/gui/Posted/PostedItem.cpp +++ b/retroshare-gui/src/gui/Posted/PostedItem.cpp @@ -32,6 +32,8 @@ #include "gui/common/FilesDefs.h" #include "util/qtthreadsutils.h" #include "util/HandleRichText.h" +#include "gui/MainWindow.h" +#include "gui/Identity/IdDialog.h" #include "PhotoView.h" #include "ui_PostedItem.h" @@ -338,6 +340,24 @@ void BasePostedItem::viewPicture() /* window will destroy itself! */ } +void BasePostedItem::showAuthorInPeople() +{ + if(mPost.mMeta.mAuthorId.isNull()) + { + std::cerr << "(EE) GxsForumThreadWidget::loadMsgData_showAuthorInPeople() ERROR Missing Message Data..."; + std::cerr << std::endl; + } + + /* window will destroy itself! */ + IdDialog *idDialog = dynamic_cast(MainWindow::getPage(MainWindow::People)); + + if (!idDialog) + return ; + + MainWindow::showWindow(MainWindow::People); + idDialog->navigate(RsGxsId(mPost.mMeta.mAuthorId)); +} + //======================================================================================== // PostedItem // //======================================================================================== @@ -394,6 +414,8 @@ void PostedItem::setup() QAction *CopyLinkAction = new QAction(QIcon(""),tr("Copy RetroShare Link"), this); connect(CopyLinkAction, SIGNAL(triggered()), this, SLOT(copyMessageLink())); + QAction *showInPeopleAct = new QAction(QIcon(), tr("Show author in people tab"), this); + connect(showInPeopleAct, SIGNAL(triggered()), this, SLOT(showAuthorInPeople())); int S = QFontMetricsF(font()).height() ; @@ -407,6 +429,8 @@ void PostedItem::setup() QMenu *menu = new QMenu(); menu->addAction(CopyLinkAction); + menu->addSeparator(); + menu->addAction(showInPeopleAct); ui->shareButton->setMenu(menu); ui->clearButton->hide(); @@ -438,8 +462,6 @@ void PostedItem::makeUpVote() emit vote(msgId, true); } - - void PostedItem::setComment(const RsGxsComment& cmt) { ui->newCommentLabel->show(); @@ -459,97 +481,115 @@ void PostedItem::setCommentsSize(int comNb) void PostedItem::fill() { - RetroShareLink link = RetroShareLink::createGxsGroupLink(RetroShareLink::TYPE_POSTED, mGroupMeta.mGroupId, groupName()); - ui->nameLabel->setText(link.toHtml()); + RsReputationLevel overall_reputation = rsReputations->overallReputationLevel(mPost.mMeta.mAuthorId); + bool redacted = (overall_reputation == RsReputationLevel::LOCALLY_NEGATIVE); - QPixmap sqpixmap2 = QPixmap(":/images/thumb-default.png"); + if(redacted) { + ui->expandButton->setDisabled(true); + ui->commentButton->setDisabled(true); + ui->voteUpButton->setDisabled(true); + ui->voteDownButton->setDisabled(true); - mInFill = true; - int desired_height = 1.5*(ui->voteDownButton->height() + ui->voteUpButton->height() + ui->scoreLabel->height()); - int desired_width = sqpixmap2.width()*desired_height/(float)sqpixmap2.height(); + ui->thumbnailLabel->setPixmap( QPixmap(":/images/thumb-default.png")); + ui->fromLabel->setId(mPost.mMeta.mAuthorId); + ui->titleLabel->setText(tr( "

The author of this message (with ID %1) is banned.").arg(QString::fromStdString(mPost.mMeta.mAuthorId.toStdString()))) ; + QDateTime qtime; + qtime.setTime_t(mPost.mMeta.mPublishTs); + QString timestamp = qtime.toString("hh:mm dd-MMM-yyyy"); + ui->dateLabel->setText(timestamp); + } else { + RetroShareLink link = RetroShareLink::createGxsGroupLink(RetroShareLink::TYPE_POSTED, mGroupMeta.mGroupId, groupName()); + ui->nameLabel->setText(link.toHtml()); - QDateTime qtime; - qtime.setTime_t(mPost.mMeta.mPublishTs); - QString timestamp = qtime.toString("hh:mm dd-MMM-yyyy"); - QString timestamp2 = misc::timeRelativeToNow(mPost.mMeta.mPublishTs); - ui->dateLabel->setText(timestamp2); - ui->dateLabel->setToolTip(timestamp); + QPixmap sqpixmap2 = QPixmap(":/images/thumb-default.png"); - ui->fromLabel->setId(mPost.mMeta.mAuthorId); + mInFill = true; + int desired_height = 1.5*(ui->voteDownButton->height() + ui->voteUpButton->height() + ui->scoreLabel->height()); + int desired_width = sqpixmap2.width()*desired_height/(float)sqpixmap2.height(); - // Use QUrl to check/parse our URL - // The only combination that seems to work: load as EncodedUrl, extract toEncoded(). - QByteArray urlarray(mPost.mLink.c_str()); - QUrl url = QUrl::fromEncoded(urlarray.trimmed()); - QString urlstr = "Invalid Link"; - QString sitestr = "Invalid Link"; + QDateTime qtime; + qtime.setTime_t(mPost.mMeta.mPublishTs); + QString timestamp = qtime.toString("hh:mm dd-MMM-yyyy"); + QString timestamp2 = misc::timeRelativeToNow(mPost.mMeta.mPublishTs); + ui->dateLabel->setText(timestamp2); + ui->dateLabel->setToolTip(timestamp); - bool urlOkay = url.isValid(); - if (urlOkay) - { - QString scheme = url.scheme(); - if ((scheme != "https") - && (scheme != "http") - && (scheme != "ftp") - && (scheme != "retroshare")) + ui->fromLabel->setId(mPost.mMeta.mAuthorId); + + // Use QUrl to check/parse our URL + // The only combination that seems to work: load as EncodedUrl, extract toEncoded(). + QByteArray urlarray(mPost.mLink.c_str()); + QUrl url = QUrl::fromEncoded(urlarray.trimmed()); + QString urlstr = "Invalid Link"; + QString sitestr = "Invalid Link"; + + bool urlOkay = url.isValid(); + if (urlOkay) { - urlOkay = false; - sitestr = "Invalid Link Scheme"; + QString scheme = url.scheme(); + if ((scheme != "https") + && (scheme != "http") + && (scheme != "ftp") + && (scheme != "retroshare")) + { + urlOkay = false; + sitestr = "Invalid Link Scheme"; + } } - } - if (urlOkay) - { - urlstr = QString(" "); - urlstr += messageName(); - urlstr += QString(" "); + if (urlOkay) + { + urlstr = QString(" "); + urlstr += messageName(); + urlstr += QString(" "); - QString siteurl = url.toEncoded(); - sitestr = QString(" %2 ").arg(siteurl).arg(siteurl); + QString siteurl = url.toEncoded(); + sitestr = QString(" %2 ").arg(siteurl).arg(siteurl); - ui->titleLabel->setText(urlstr); - }else - { - ui->titleLabel->setText(messageName()); + ui->titleLabel->setText(urlstr); + }else + { + ui->titleLabel->setText(messageName()); - } - - if (urlarray.isEmpty()) - { - ui->siteLabel->hide(); - } - - ui->siteLabel->setText(sitestr); - - if(mPost.mImage.mData != NULL) - { - QPixmap pixmap; - GxsIdDetails::loadPixmapFromData(mPost.mImage.mData, mPost.mImage.mSize, pixmap,GxsIdDetails::ORIGINAL); - // Wiping data - as its been passed to thumbnail. - - QPixmap sqpixmap = pixmap.scaled(desired_width,desired_height, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - ui->thumbnailLabel->setPixmap(sqpixmap); - ui->thumbnailLabel->setToolTip(tr("Click to view Picture")); - - QPixmap scaledpixmap; - if(pixmap.width() > 800){ - QPixmap scaledpixmap = pixmap.scaledToWidth(800, Qt::SmoothTransformation); - ui->pictureLabel->setPixmap(scaledpixmap); - }else{ - ui->pictureLabel->setPixmap(pixmap); } - } - else if (urlOkay && (mPost.mImage.mData == NULL)) - { - ui->expandButton->setDisabled(true); - ui->thumbnailLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(LINK_IMAGE)); - } - else - { - ui->expandButton->setDisabled(true); - ui->thumbnailLabel->setPixmap(sqpixmap2); + + if (urlarray.isEmpty()) + { + ui->siteLabel->hide(); + } + + ui->siteLabel->setText(sitestr); + + if(mPost.mImage.mData != NULL) + { + QPixmap pixmap; + GxsIdDetails::loadPixmapFromData(mPost.mImage.mData, mPost.mImage.mSize, pixmap,GxsIdDetails::ORIGINAL); + // Wiping data - as its been passed to thumbnail. + + QPixmap sqpixmap = pixmap.scaled(desired_width,desired_height, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); + ui->thumbnailLabel->setPixmap(sqpixmap); + ui->thumbnailLabel->setToolTip(tr("Click to view Picture")); + + QPixmap scaledpixmap; + if(pixmap.width() > 800){ + QPixmap scaledpixmap = pixmap.scaledToWidth(800, Qt::SmoothTransformation); + ui->pictureLabel->setPixmap(scaledpixmap); + }else{ + ui->pictureLabel->setPixmap(pixmap); + } + } + else if (urlOkay && (mPost.mImage.mData == NULL)) + { + ui->expandButton->setDisabled(true); + ui->thumbnailLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(LINK_IMAGE)); + } + else + { + ui->expandButton->setDisabled(true); + ui->thumbnailLabel->setPixmap(sqpixmap2); + } } @@ -701,5 +741,3 @@ void PostedItem::toggleNotes() } } - - diff --git a/retroshare-gui/src/gui/Posted/PostedItem.h b/retroshare-gui/src/gui/Posted/PostedItem.h index 7debd9d75..d726cf830 100644 --- a/retroshare-gui/src/gui/Posted/PostedItem.h +++ b/retroshare-gui/src/gui/Posted/PostedItem.h @@ -55,6 +55,7 @@ private slots: void readAndClearItem(); void copyMessageLink(); void viewPicture(); + void showAuthorInPeople(); signals: void vote(const RsGxsGrpMsgIdPair& msgId, bool up); From bbaad838572b5fba6109bc7d3b5c55c2c68e6cdc Mon Sep 17 00:00:00 2001 From: Phenom Date: Mon, 1 Jun 2020 13:44:43 +0200 Subject: [PATCH 024/154] Fix build with Qt 5.15+ --- retroshare-gui/src/gui/elastic/elnode.h | 8 +++++--- .../src/gui/gxs/GxsCommentTreeWidget.cpp | 16 ++++++++------- retroshare-gui/src/gui/gxs/GxsIdDetails.cpp | 20 ++++++++++--------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/retroshare-gui/src/gui/elastic/elnode.h b/retroshare-gui/src/gui/elastic/elnode.h index 1e0edd1a8..33043ddab 100644 --- a/retroshare-gui/src/gui/elastic/elnode.h +++ b/retroshare-gui/src/gui/elastic/elnode.h @@ -23,6 +23,10 @@ #ifndef ELNODE_H #define ELNODE_H +#include "graphwidget.h" + +#include + #include #if QT_VERSION >= 0x040600 #include @@ -30,9 +34,7 @@ #include #endif #include - -#include -#include "graphwidget.h" +#include class Edge; QT_BEGIN_NAMESPACE diff --git a/retroshare-gui/src/gui/gxs/GxsCommentTreeWidget.cpp b/retroshare-gui/src/gui/gxs/GxsCommentTreeWidget.cpp index 14413963f..a1f824e9a 100644 --- a/retroshare-gui/src/gui/gxs/GxsCommentTreeWidget.cpp +++ b/retroshare-gui/src/gui/gxs/GxsCommentTreeWidget.cpp @@ -18,6 +18,14 @@ * * *******************************************************************************/ +#include "GxsCommentTreeWidget.h" + +#include "gui/common/FilesDefs.h" +#include "gui/common/RSElidedItemDelegate.h" +#include "gui/common/RSTreeWidgetItem.h" +#include "gui/gxs/GxsCreateCommentDialog.h" +#include "gui/gxs/GxsIdTreeWidgetItem.h" + #include #include #include @@ -25,15 +33,9 @@ #include #include #include +#include #include -#include "gui/common/RSElidedItemDelegate.h" -#include "gui/common/FilesDefs.h" -#include "gui/gxs/GxsCommentTreeWidget.h" -#include "gui/gxs/GxsCreateCommentDialog.h" -#include "gui/gxs/GxsIdTreeWidgetItem.h" -#include "gui/common/RSTreeWidgetItem.h" - #include #define PCITEM_COLUMN_COMMENT 0 diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp index 22469575f..701a9153d 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp @@ -18,21 +18,23 @@ * * *******************************************************************************/ -#include -#include -#include -#include - -#include -#include -#include "gui/common/AvatarDialog.h" #include "GxsIdDetails.h" + +#include "gui/common/AvatarDialog.h" #include "retroshare-gui/RsAutoUpdatePage.h" #include +#include + +#include +#include +#include +#include +#include +#include #include -#include +#include /* Images for tag icons */ #define IMAGE_LOADING ":/images/folder-draft.png" From da968379d6f56a33cad0811970b2418641609f27 Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 3 Jun 2020 21:06:37 +0200 Subject: [PATCH 025/154] improved design: moved channel details+posts into tabs, and added tabs for comments+post details --- .../GxsChannelPostsWidgetWithModel.cpp | 113 +++- .../GxsChannelPostsWidgetWithModel.h | 22 +- .../GxsChannelPostsWidgetWithModel.ui | 501 ++++++++---------- 3 files changed, 332 insertions(+), 304 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index dd2c8cccc..ad695136d 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -20,6 +20,7 @@ #include #include +#include #include "retroshare/rsgxscircles.h" @@ -52,6 +53,86 @@ #define VIEW_MODE_FEEDS 1 #define VIEW_MODE_FILES 2 +Q_DECLARE_METATYPE(RsGxsChannelPost*) + +void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const +{ + QString byteUnits[4] = {tr("B"), tr("KB"), tr("MB"), tr("GB")}; + QStyleOptionViewItem opt = option; + QStyleOptionProgressBarV2 newopt; + QRect pixmapRect; + QPixmap pixmap; + qlonglong fileSize; + double dlspeed, multi; + int seconds,minutes, hours, days; + qlonglong remaining; + QString temp ; + qlonglong completed; + qlonglong downloadtime; + qint64 qi64Value; + + // prepare + painter->save(); + painter->setClipRect(opt.rect); + + RsGxsChannelPost post = index.data(Qt::UserRole).value() ; + //const RsGxsChannelPost& post(*pinfo); + + QVariant value = index.data(Qt::TextColorRole); + + if(value.isValid() && qvariant_cast(value).isValid()) + opt.palette.setColor(QPalette::Text, qvariant_cast(value)); + + QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; + + if(option.state & QStyle::State_Selected) + painter->setPen(opt.palette.color(cg, QPalette::HighlightedText)); + else + painter->setPen(opt.palette.color(cg, QPalette::Text)); + + //painter->drawText(option.rect, Qt::AlignRight, QString("TODO")); + + QPixmap thumbnail; + GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL); + + QFontMetricsF fm(opt.font); + + int W = IMAGE_SIZE_FACTOR_W * fm.height() * IMAGE_ZOOM_FACTOR; + int H = IMAGE_SIZE_FACTOR_H * fm.height() * IMAGE_ZOOM_FACTOR; + + int w = fm.width("X") ; + int h = fm.height() ; + + float img_coord_x = IMAGE_MARGIN_FACTOR*0.5*w; + float img_coord_y = IMAGE_MARGIN_FACTOR*0.5*h; + + QPoint img_pos(img_coord_x,img_coord_y); + QPoint img_size(W,H); + + QPoint txt_pos(0,img_coord_y + H + h); + + painter->drawPixmap(QRect(opt.rect.topLeft() + img_pos,opt.rect.topLeft()+img_pos+img_size),thumbnail.scaled(W,H,Qt::KeepAspectRatio,Qt::SmoothTransformation)); + painter->drawText(QRect(option.rect.topLeft() + txt_pos,option.rect.bottomRight()),Qt::AlignCenter,QString::fromStdString(post.mMeta.mMsgName)); +} + +QSize ChannelPostDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + RsGxsChannelPost post = index.data(Qt::UserRole).value() ; + + //QPixmap thumbnail; + //GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL); + + QFontMetricsF fm(option.font); + + int W = IMAGE_SIZE_FACTOR_W * fm.height() * IMAGE_ZOOM_FACTOR; + int H = IMAGE_SIZE_FACTOR_H * fm.height() * IMAGE_ZOOM_FACTOR; + + int h = fm.height() ; + int w = fm.width("X") ; + + return QSize(W+IMAGE_MARGIN_FACTOR*w,H + 2*h); +} + /** Constructor */ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupId &channelId, QWidget *parent) : GxsMessageFrameWidget(rsGxsChannels, parent), @@ -61,6 +142,9 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->setupUi(this); ui->postsTree->setModel(mThreadModel = new RsGxsChannelPostsModel()); + ui->postsTree->setItemDelegate(new ChannelPostDelegate()); + + connect(ui->postsTree->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),this,SLOT(showPostDetails())); /* Setup UI helper */ @@ -95,7 +179,7 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI /* Initialize view button */ //setViewMode(VIEW_MODE_FEEDS); see processSettings - ui->infoWidget->hide(); + //ui->infoWidget->hide(); QSignalMapper *signalMapper = new QSignalMapper(this); connect(ui->feedToolButton, SIGNAL(clicked()), signalMapper, SLOT(map())); @@ -109,7 +193,7 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->loadingLabel->hide(); ui->progressBar->hide(); - ui->nameLabel->setMinimumWidth(20); + //ui->nameLabel->setMinimumWidth(20); /* Initialize feed widget */ //ui->feedWidget->setSortRole(ROLE_PUBLISH, Qt::DescendingOrder); @@ -169,6 +253,13 @@ void GxsChannelPostsWidgetWithModel::handleEvent_main_thread(std::shared_ptrpostsTree->selectionModel()->currentIndex(); + + std::cerr << "Showing details about selected index : "<< selected_index.row() << "," << selected_index.column() << std::endl; +} + void GxsChannelPostsWidgetWithModel::updateGroupData() { if(groupId().isNull()) @@ -280,12 +371,12 @@ QString GxsChannelPostsWidgetWithModel::groupName(bool) void GxsChannelPostsWidgetWithModel::groupNameChanged(const QString &name) { - if (groupId().isNull()) { - ui->nameLabel->setText(tr("No Channel Selected")); - ui->logoLabel->setPixmap(QPixmap(":/icons/png/channels.png")); - } else { - ui->nameLabel->setText(name); - } +// if (groupId().isNull()) { +// ui->nameLabel->setText(tr("No Channel Selected")); +// ui->logoLabel->setPixmap(QPixmap(":/icons/png/channels.png")); +// } else { +// ui->nameLabel->setText(name); +// } } QIcon GxsChannelPostsWidgetWithModel::groupIcon() @@ -336,7 +427,7 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou } else { chanImage = QPixmap(CHAN_DEFAULT_IMAGE); } - ui->logoLabel->setPixmap(chanImage); + //ui->logoLabel->setPixmap(chanImage); if (group.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_PUBLISH) { @@ -361,7 +452,7 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou ui->feedToolButton->setEnabled(true); ui->fileToolButton->setEnabled(true); - ui->infoWidget->hide(); + //ui->infoWidget->hide(); setViewMode(viewMode()); ui->subscribeToolButton->setText(tr("Subscribed") + " " + QString::number(group.mMeta.mPop) ); @@ -785,7 +876,7 @@ void GxsChannelPostsWidgetWithModel::blank() mThreadModel->clear(); groupNameChanged(QString()); - ui->infoWidget->hide(); + //ui->infoWidget->hide(); } bool GxsChannelPostsWidgetWithModel::navigate(const RsGxsMessageId &msgId) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index 64478a112..246be0715 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -23,8 +23,9 @@ #include -#include "gui/gxs/GxsMessageFramePostWidget.h" +#include +#include "gui/gxs/GxsMessageFramePostWidget.h" #include "gui/feeds/FeedHolder.h" namespace Ui { @@ -36,6 +37,24 @@ class QTreeWidgetItem; class FeedItem; class RsGxsChannelPostsModel; +class ChannelPostDelegate: public QAbstractItemDelegate +{ + Q_OBJECT + + public: + ChannelPostDelegate(QObject *parent=0) : QAbstractItemDelegate(parent){} + virtual ~ChannelPostDelegate(){} + + void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const override; + QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override; + + private: + static constexpr float IMAGE_MARGIN_FACTOR = 1.0; + static constexpr float IMAGE_SIZE_FACTOR_W = 4.0 ; + static constexpr float IMAGE_SIZE_FACTOR_H = 6.0 ; + static constexpr float IMAGE_ZOOM_FACTOR = 1.0; +}; + class GxsChannelPostsWidgetWithModel: public GxsMessageFrameWidget { Q_OBJECT @@ -91,6 +110,7 @@ protected: virtual void setAllMessagesReadDo(bool read, uint32_t &token); private slots: + void showPostDetails(); void updateGroupData(); void createMsg(); void toggleAutoDownload(); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index c1bc74996..2ae7ecac8 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -26,69 +26,6 @@ 0 - - - - QFrame::Box - - - QFrame::Sunken - - - - 4 - - - 4 - - - 4 - - - 4 - - - - - - 64 - 64 - - - - - 64 - 64 - - - - - - - :/images/channels.png - - - true - - - - - - - - - - - - - - Channel Name - - - - - - @@ -285,237 +222,226 @@ - - - + + + 0 - - - 3 - - - 0 - - - 3 - - - 3 - - - - - false - - - QFrame::NoFrame - - - QFrame::Plain - - - - 6 + + + Channel details + + + + + + Channel details - - 6 - - - 6 - - - 6 - - - - - Channel details - - - - 9 + + + 9 + + + 9 + + + 9 + + + 9 + + + + + + 0 + 0 + - - 9 + + + 75 + true + - - 9 + + Last Post: - - 9 - - - - - - 0 - 0 - - - - - 75 - true - - - - Last Post: - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Description</span></p></body></html> - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - true - - - true - - - - - - - - 75 - true - - - - Description: - - - - - - - - 75 - true - - - - Created: - - - - - - - - 75 - true - - - - Administrator: - - - - - - - - 0 - 0 - - - - - 75 - true - - - - Posts: - - - - - - - - 75 - true - - - - Distribution: - - - - - - - unknown - - - - - - - unknown - - - - - - - unknown - - - true - - - - - - - unknown - - - - - - - 0 - - - - - - - - - - - - - Qt::Vertical - - - - 0 - 0 - - - - - + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + true + + + true + + + + + + + + 75 + true + + + + Description: + + + + + + + + 75 + true + + + + Created: + + + + + + + + 75 + true + + + + Administrator: + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Posts: + + + + + + + + 75 + true + + + + Distribution: + + + + + + + unknown + + + + + + + unknown + + + + + + + unknown + + + true + + + + + + + unknown + + + + + + + 0 + + + + + + + + + + + Posts + + + + + + QAbstractItemView::SelectItems + + + false + + + + + - + + + 0 + + + + Details + + + + + + + + + + Comments + + + @@ -528,10 +454,6 @@ p, li { white-space: pre-wrap; } Files - toolBarFrame - headFrame - infoWidget - postsTree @@ -544,11 +466,6 @@ p, li { white-space: pre-wrap; } QToolButton

gui/common/SubscribeToolButton.h
- - StyledElidedLabel - QLabel -
gui/common/StyledElidedLabel.h
-
LineEditClear QLineEdit @@ -556,8 +473,8 @@ p, li { white-space: pre-wrap; } - + From a38d5aba141ae8f1930a090dd898eed7f39c13c3 Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 3 Jun 2020 22:49:13 +0200 Subject: [PATCH 026/154] added missing files --- .../gui/gxschannels/GxsChannelPostsModel.cpp | 1104 +++++++++++++++++ .../gui/gxschannels/GxsChannelPostsModel.h | 227 ++++ 2 files changed, 1331 insertions(+) create mode 100644 retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp create mode 100644 retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.h diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp new file mode 100644 index 000000000..5d82110d5 --- /dev/null +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -0,0 +1,1104 @@ +/******************************************************************************* + * retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp * + * * + * Copyright 2020 by Cyril Soler * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include +#include +#include +#include + +#include "gui/common/FilesDefs.h" +#include "util/qtthreadsutils.h" +#include "util/HandleRichText.h" +#include "util/DateTime.h" +#include "GxsChannelPostsModel.h" +#include "retroshare/rsgxsflags.h" +#include "retroshare/rsgxschannels.h" +#include "retroshare/rsexpr.h" + +#define DEBUG_CHANNEL_MODEL + +Q_DECLARE_METATYPE(RsMsgMetaData) + +Q_DECLARE_METATYPE(RsGxsChannelPost) + +std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsewhere + +const QString RsGxsChannelPostsModel::FilterString("filtered"); + +RsGxsChannelPostsModel::RsGxsChannelPostsModel(QObject *parent) + : QAbstractItemModel(parent), mTreeMode(TREE_MODE_PLAIN), mColumns(6) +{ + initEmptyHierarchy(mPosts); +} + +void RsGxsChannelPostsModel::initEmptyHierarchy(std::vector& posts) +{ + preMods(); + + posts.resize(1); // adds a sentinel item + posts[0].mMeta.mMsgName = "Root sentinel post" ; + + postMods(); +} + +void RsGxsChannelPostsModel::preMods() +{ + //emit layoutAboutToBeChanged(); //Generate SIGSEGV when click on button move next/prev. + + beginResetModel(); +} +void RsGxsChannelPostsModel::postMods() +{ + endResetModel(); + + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mPosts.size(),mColumns-1,(void*)NULL)); +} + +void RsGxsChannelPostsModel::setTreeMode(TreeMode mode) +{ + if(mode == mTreeMode) + return; + + preMods(); + + // We're not removing/adding rows here. We're simply asking for re-draw. + + mTreeMode = mode; + postMods(); +} + +#ifdef TODO +void RsGxsChannelPostsModel::setSortMode(SortMode mode) +{ + preMods(); + + mSortMode = mode; + + postMods(); +} + +void RsGxsForumModel::initEmptyHierarchy(std::vector& posts) +{ + preMods(); + + posts.resize(1); // adds a sentinel item + posts[0].mTitle = "Root sentinel post" ; + posts[0].mParent = 0; + + postMods(); +} +#endif + +int RsGxsChannelPostsModel::rowCount(const QModelIndex& parent) const +{ + if(parent.column() > 0) + return 0; + + if(mPosts.empty()) // security. Should never happen. + return 0; + + if(!parent.isValid()) + return (getChildrenCount(0) + mColumns-1)/mColumns; + + RsErr() << __PRETTY_FUNCTION__ << " rowCount cannot figure out the porper number of rows." << std::endl; + return 0; + + //else + // return getChildrenCount(parent.internalId()); +} + +int RsGxsChannelPostsModel::columnCount(const QModelIndex &/*parent*/) const +{ + return mColumns ; +} + +// std::vector > RsGxsChannelPostsModel::getPostVersions(const RsGxsMessageId& mid) const +// { +// auto it = mPostVersions.find(mid); +// +// if(it != mPostVersions.end()) +// return it->second; +// else +// return std::vector >(); +// } + +bool RsGxsChannelPostsModel::getPostData(const QModelIndex& i,RsGxsChannelPost& fmpe) const +{ + if(!i.isValid()) + return true; + + quintptr ref = i.internalId(); + uint32_t entry = 0; + + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) + return false ; + + fmpe = mPosts[entry]; + + return true; + +} + +bool RsGxsChannelPostsModel::hasChildren(const QModelIndex &parent) const +{ + if(!parent.isValid()) + return true; + + return false; // by default, no channel post has children +} + +bool RsGxsChannelPostsModel::convertTabEntryToRefPointer(uint32_t entry,quintptr& ref) +{ + // the pointer is formed the following way: + // + // [ 32 bits ] + // + // This means that the whole software has the following build-in limitation: + // * 4 B simultaenous posts. Should be enough ! + + ref = (intptr_t)entry; + + return true; +} + +bool RsGxsChannelPostsModel::convertRefPointerToTabEntry(quintptr ref, uint32_t& entry) +{ + intptr_t val = (intptr_t)ref; + + if(val > (1<<30)) // make sure the pointer is an int that fits in 32bits and not too big which would look suspicious + { + RsErr() << "(EE) trying to make a ChannelPostsModelIndex out of a number that is larger than 2^32-1 !" << std::endl; + return false ; + } + entry = quintptr(val); + + return true; +} + +QModelIndex RsGxsChannelPostsModel::index(int row, int column, const QModelIndex & parent) const +{ + if(row < 0 || column < 0 || column >= mColumns) + return QModelIndex(); + + quintptr ref = getChildRef(parent.internalId(),row + column*mColumns); + +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << "index-3(" << row << "," << column << " parent=" << parent << ") : " << createIndex(row,column,ref) << std::endl; +#endif + return createIndex(row,column,ref) ; +} + +QModelIndex RsGxsChannelPostsModel::parent(const QModelIndex& index) const +{ + if(!index.isValid()) + return QModelIndex(); + + return QModelIndex(); // there's no hierarchy here. So nothing to do! +} + +Qt::ItemFlags RsGxsChannelPostsModel::flags(const QModelIndex& index) const +{ + if (!index.isValid()) + return 0; + + return QAbstractItemModel::flags(index); +} + +quintptr RsGxsChannelPostsModel::getChildRef(quintptr ref,int index) const +{ + if (index < 0) + return 0; + + ChannelPostsModelIndex entry ; + + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) + return 0 ; + + if(entry == 0) + { + quintptr new_ref; + convertTabEntryToRefPointer(index+1,new_ref); + return new_ref; + } + else + return 0 ; +} + +quintptr RsGxsChannelPostsModel::getParentRow(quintptr ref,int& row) const +{ + ChannelPostsModelIndex ref_entry; + + if(!convertRefPointerToTabEntry(ref,ref_entry) || ref_entry >= mPosts.size()) + return 0 ; + + if(ref_entry == 0) + { + RsErr() << "getParentRow() shouldn't be asked for the parent of NULL" << std::endl; + row = 0; + } + else + row = ref_entry-1; + + return 0; +} + +int RsGxsChannelPostsModel::getChildrenCount(quintptr ref) const +{ + uint32_t entry = 0 ; + + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) + return 0 ; + + if(entry == 0) + { +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << "Children count (flat mode): " << mPosts.size()-1 << std::endl; +#endif + return ((int)mPosts.size())-1; + } + else + return 0; +} + +QVariant RsGxsChannelPostsModel::data(const QModelIndex &index, int role) const +{ +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << "calling data(" << index << ") role=" << role << std::endl; +#endif + + if(!index.isValid()) + return QVariant(); + + switch(role) + { + case Qt::SizeHintRole: return sizeHintRole(index.column()) ; + case Qt::StatusTipRole:return QVariant(); + default: break; + } + + quintptr ref = (index.isValid())?index.internalId():0 ; + uint32_t entry = 0; + +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << "data(" << index << ")" ; +#endif + + if(!ref) + { +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << " [empty]" << std::endl; +#endif + return QVariant() ; + } + + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) + { +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << "Bad pointer: " << (void*)ref << std::endl; +#endif + return QVariant() ; + } + + const RsGxsChannelPost& fmpe(mPosts[entry]); + +#ifdef TODO + if(role == Qt::FontRole) + { + QFont font ; + font.setBold( (fmpe.mPostFlags & (ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN | ForumModelPostEntry::FLAG_POST_IS_PINNED)) || IS_MSG_UNREAD(fmpe.mMsgStatus)); + return QVariant(font); + } + + if(role == UnreadChildrenRole) + return bool(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN); + +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << " [ok]" << std::endl; +#endif +#endif + + switch(role) + { + case Qt::DisplayRole: return displayRole (fmpe,index.column()) ; + case Qt::UserRole: return userRole (fmpe,index.column()) ; +#ifdef TODO + case Qt::DecorationRole: return decorationRole(fmpe,index.column()) ; + case Qt::ToolTipRole: return toolTipRole (fmpe,index.column()) ; + case Qt::TextColorRole: return textColorRole (fmpe,index.column()) ; + case Qt::BackgroundRole: return backgroundRole(fmpe,index.column()) ; + + case FilterRole: return filterRole (fmpe,index.column()) ; + case ThreadPinnedRole: return pinnedRole (fmpe,index.column()) ; + case MissingRole: return missingRole (fmpe,index.column()) ; + case StatusRole: return statusRole (fmpe,index.column()) ; + case SortRole: return sortRole (fmpe,index.column()) ; +#endif + default: + return QVariant(); + } +} + +#ifdef TODO +QVariant RsGxsForumModel::textColorRole(const ForumModelPostEntry& fmpe,int /*column*/) const +{ + if( (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING)) + return QVariant(mTextColorMissing); + + if(IS_MSG_UNREAD(fmpe.mMsgStatus) || (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED)) + return QVariant(mTextColorUnread); + else + return QVariant(mTextColorRead); + + return QVariant(); +} + +QVariant RsGxsForumModel::statusRole(const ForumModelPostEntry& fmpe,int column) const +{ + if(column != COLUMN_THREAD_DATA) + return QVariant(); + + return QVariant(fmpe.mMsgStatus); +} + +QVariant RsGxsForumModel::filterRole(const ForumModelPostEntry& fmpe,int /*column*/) const +{ + if(!mFilteringEnabled || (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER)) + return QVariant(FilterString); + + return QVariant(QString()); +} + +uint32_t RsGxsForumModel::recursUpdateFilterStatus(ForumModelIndex i,int column,const QStringList& strings) +{ + QString s ; + uint32_t count = 0; + + switch(column) + { + default: + case COLUMN_THREAD_DATE: + case COLUMN_THREAD_TITLE: s = displayRole(mPosts[i],column).toString(); + break; + case COLUMN_THREAD_AUTHOR: + { + QString comment ; + QList icons; + + GxsIdDetails::MakeIdDesc(mPosts[i].mAuthorId, false,s, icons, comment,GxsIdDetails::ICON_TYPE_NONE); + } + break; + } + + if(!strings.empty()) + { + mPosts[i].mPostFlags &= ~(ForumModelPostEntry::FLAG_POST_PASSES_FILTER | ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER); + + for(auto iter(strings.begin()); iter != strings.end(); ++iter) + if(s.contains(*iter,Qt::CaseInsensitive)) + { + mPosts[i].mPostFlags |= ForumModelPostEntry::FLAG_POST_PASSES_FILTER | ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER; + + count++; + break; + } + } + else + { + mPosts[i].mPostFlags |= ForumModelPostEntry::FLAG_POST_PASSES_FILTER |ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER; + count++; + } + + for(uint32_t j=0;j 0) + mPosts[i].mPostFlags |= ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER; + } + + return count; +} + + +void RsGxsForumModel::setFilter(int column,const QStringList& strings,uint32_t& count) +{ + preMods(); + + if(!strings.empty()) + { + count = recursUpdateFilterStatus(ForumModelIndex(0),column,strings); + mFilteringEnabled = true; + } + else + { + count=0; + mFilteringEnabled = false; + } + + postMods(); +} + +QVariant RsGxsForumModel::missingRole(const ForumModelPostEntry& fmpe,int /*column*/) const +{ + if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING) + return QVariant(true); + else + return QVariant(false); +} + +QVariant RsGxsForumModel::toolTipRole(const ForumModelPostEntry& fmpe,int column) const +{ + if(column == COLUMN_THREAD_DISTRIBUTION) + switch(fmpe.mReputationWarningLevel) + { + case 3: return QVariant(tr("Information for this identity is currently missing.")) ; + case 2: return QVariant(tr("You have banned this ID. The message will not be\ndisplayed nor forwarded to your friends.")) ; + case 1: return QVariant(tr("You have not set an opinion for this person,\n and your friends do not vote positively: Spam regulation \nprevents the message to be forwarded to your friends.")) ; + case 0: return QVariant(tr("Message will be forwarded to your friends.")) ; + default: + return QVariant("[ERROR: missing reputation level information - contact the developers]"); + } + + if(column == COLUMN_THREAD_AUTHOR) + { + QString str,comment ; + QList icons; + + if(!GxsIdDetails::MakeIdDesc(fmpe.mAuthorId, true, str, icons, comment,GxsIdDetails::ICON_TYPE_AVATAR)) + return QVariant(); + + int S = QFontMetricsF(QApplication::font()).height(); + QImage pix( (*icons.begin()).pixmap(QSize(4*S,4*S)).toImage()); + + QString embeddedImage; + if(RsHtml::makeEmbeddedImage(pix.scaled(QSize(4*S,4*S), Qt::KeepAspectRatio, Qt::SmoothTransformation), embeddedImage, 8*S * 8*S)) + comment = "
" + embeddedImage + "" + comment + "
"; + + return comment; + } + + return QVariant(); +} + +QVariant RsGxsForumModel::pinnedRole(const ForumModelPostEntry& fmpe,int /*column*/) const +{ + if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) + return QVariant(true); + else + return QVariant(false); +} + +QVariant RsGxsForumModel::backgroundRole(const ForumModelPostEntry& fmpe,int /*column*/) const +{ + if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) + return QVariant(QBrush(QColor(255,200,180))); + + if(mFilteringEnabled && (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_PASSES_FILTER)) + return QVariant(QBrush(QColor(255,240,210))); + + return QVariant(); +} +#endif + +QVariant RsGxsChannelPostsModel::sizeHintRole(int col) const +{ + float factor = QFontMetricsF(QApplication::font()).height()/14.0f ; + + return QVariant( QSize(factor * 170, factor*14 )); +#ifdef TODO + switch(col) + { + default: + case COLUMN_THREAD_TITLE: return QVariant( QSize(factor * 170, factor*14 )); + case COLUMN_THREAD_DATE: return QVariant( QSize(factor * 75 , factor*14 )); + case COLUMN_THREAD_AUTHOR: return QVariant( QSize(factor * 75 , factor*14 )); + case COLUMN_THREAD_DISTRIBUTION: return QVariant( QSize(factor * 15 , factor*14 )); + } +#endif +} + +#ifdef TODO +QVariant RsGxsForumModel::authorRole(const ForumModelPostEntry& fmpe,int column) const +{ + if(column == COLUMN_THREAD_DATA) + return QVariant(QString::fromStdString(fmpe.mAuthorId.toStdString())); + + return QVariant(); +} + +QVariant RsGxsForumModel::sortRole(const ForumModelPostEntry& fmpe,int column) const +{ + switch(column) + { + case COLUMN_THREAD_DATE: if(mSortMode == SORT_MODE_PUBLISH_TS) + return QVariant(QString::number(fmpe.mPublishTs)); // we should probably have leading zeroes here + else + return QVariant(QString::number(fmpe.mMostRecentTsInThread)); // we should probably have leading zeroes here + + case COLUMN_THREAD_READ: return QVariant((bool)IS_MSG_UNREAD(fmpe.mMsgStatus)); + case COLUMN_THREAD_DISTRIBUTION: return decorationRole(fmpe,column); + case COLUMN_THREAD_AUTHOR: + { + QString str,comment ; + QList icons; + GxsIdDetails::MakeIdDesc(fmpe.mAuthorId, false, str, icons, comment,GxsIdDetails::ICON_TYPE_NONE); + + return QVariant(str); + } + default: + return displayRole(fmpe,column); + } +} +#endif + +QVariant RsGxsChannelPostsModel::displayRole(const RsGxsChannelPost& fmpe,int col) const +{ + switch(col) + { + default: + return QString::fromUtf8(fmpe.mMeta.mMsgName.c_str()); +#ifdef TODO + case COLUMN_THREAD_TITLE: if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_REDACTED) + return QVariant(tr("[ ... Redacted message ... ]")); + else if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) + return QVariant(tr("[PINNED] ") + QString::fromUtf8(fmpe.mTitle.c_str())); + else + return QVariant(QString::fromUtf8(fmpe.mTitle.c_str())); + + case COLUMN_THREAD_READ:return QVariant(); + case COLUMN_THREAD_DATE:{ + if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING) + return QVariant(QString()); + + QDateTime qtime; + qtime.setTime_t(fmpe.mPublishTs); + + return QVariant(DateTime::formatDateTime(qtime)); + } + + case COLUMN_THREAD_DISTRIBUTION: + 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(); +#endif +#ifdef TODO + if (filterColumn == COLUMN_THREAD_CONTENT) { + // need content for filter + QTextDocument doc; + doc.setHtml(QString::fromUtf8(msg.mMsg.c_str())); + item->setText(COLUMN_THREAD_CONTENT, doc.toPlainText().replace(QString("\n"), QString(" "))); + } +#endif + } + + + return QVariant("[ERROR]"); +} + +QVariant RsGxsChannelPostsModel::userRole(const RsGxsChannelPost& fmpe,int col) const +{ + switch(col) + { + default: + return QVariant::fromValue(fmpe); + } +} + +#ifdef TODO +QVariant RsGxsForumModel::decorationRole(const ForumModelPostEntry& fmpe,int col) const +{ + bool exist=false; + switch(col) + { + case COLUMN_THREAD_DISTRIBUTION: + return QVariant(fmpe.mReputationWarningLevel); + 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(); +} +#endif + +const RsGxsGroupId& RsGxsChannelPostsModel::currentGroupId() const +{ + return mChannelGroup.mMeta.mGroupId; +} + +void RsGxsChannelPostsModel::updateChannel(const RsGxsGroupId& channel_group_id) +{ + if(channel_group_id.isNull()) + return; + + update_posts(channel_group_id); +} + +void RsGxsChannelPostsModel::clear() +{ + preMods(); + + mPosts.clear(); + initEmptyHierarchy(mPosts); + + postMods(); + emit channelLoaded(); +} + +void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vector& posts) +{ + preMods(); + + beginRemoveRows(QModelIndex(),0,mPosts.size()-1); + endRemoveRows(); + + mPosts.clear(); + mChannelGroup = group; + + createPostsArray(posts); + +#ifdef TODO + recursUpdateReadStatusAndTimes(0,has_unread_below,has_read_below) ; + recursUpdateFilterStatus(0,0,QStringList()); +#endif + +#ifdef DEBUG_CHANNEL_MODEL + // debug_dump(); +#endif + + beginInsertRows(QModelIndex(),0,mPosts.size()-1); + endInsertRows(); + + postMods(); + + emit channelLoaded(); +} + +void RsGxsChannelPostsModel::update_posts(const RsGxsGroupId& group_id) +{ + if(group_id.isNull()) + return; + + RsThread::async([this, group_id]() + { + // 1 - get message data from p3GxsChannels + + std::list channelIds; + std::vector msg_metas; + std::vector groups; + + channelIds.push_back(group_id); + + if(!rsGxsChannels->getChannelsInfo(channelIds,groups) || groups.size() != 1) + { + std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve channel group info for channel " << group_id << std::endl; + return; + } + + RsGxsChannelGroup group = groups[0]; + + // We use the heap because the arrays need to be stored accross async + + std::vector *posts = new std::vector(); + std::vector *comments = new std::vector(); + std::vector *votes = new std::vector(); + + if(!rsGxsChannels->getChannelAllContent(group_id, *posts,*comments,*votes)) + { + std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve channel messages for channel " << group_id << std::endl; + return; + } + + // 2 - update the model in the UI thread. + + RsQThreadUtils::postToObject( [group,posts,comments,votes,this]() + { + /* Here it goes any code you want to be executed on the Qt Gui + * thread, for example to update the data model with new information + * after a blocking call to RetroShare API complete, note that + * Qt::QueuedConnection is important! + */ + + setPosts(group,*posts) ; + + delete posts; + delete comments; + delete votes; + + }, this ); + + }); +} + +//ChannelPostsModelIndex RsGxsChannelPostsModel::addEntry(std::vector& posts,const ChannelPostsModelPostEntry& entry) +//{ +// uint32_t N = posts.size(); +// posts.push_back(entry); +// +//#ifdef DEBUG_FORUMMODEL +// std::cerr << "Added new entry " << N << " children of " << parent << std::endl; +//#endif +// if(N == parent) +// std::cerr << "(EE) trying to add a post as its own parent!" << std::endl; +// +// return ChannelPostsModelIndex(N); +//} + +//void RsGxsChannelPostsModel::convertMsgToPostEntry(const RsGxsChannelGroup& mChannelGroup,const RsMsgMetaData& msg, bool /*useChildTS*/, ChannelPostsModelPostEntry& fentry) +//{ +// fentry.mTitle = msg.mMsgName; +// fentry.mMsgId = msg.mMsgId; +// fentry.mPublishTs = msg.mPublishTs; +// fentry.mPostFlags = 0; +// fentry.mMsgStatus = msg.mMsgStatus; +// +// // Early check for a message that should be hidden because its author +// // is flagged with a bad reputation +//} + +static bool decreasing_time_comp(const std::pair& e1,const std::pair& e2) { return e2.first < e1.first ; } + +void RsGxsChannelPostsModel::createPostsArray(std::vector& posts) +{ + // collect new versions of posts if any + +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << "Inserting channel posts" << std::endl; +#endif + + std::vector new_versions ; + for (uint32_t i=0;i search_map ; + for (uint32_t i=0;i versions ; + std::map::const_iterator vit ; + + while(search_map.end() != (vit=search_map.find(posts[current_index].mMeta.mOrigMsgId))) + { +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << " post at index " << current_index << " replaces a post at position " << vit->second ; +#endif + + // Now replace the post only if the new versionis more recent. It may happen indeed that the same post has been corrected multiple + // times. In this case, we only need to replace the post with the newest version + + //uint32_t prev_index = current_index ; + current_index = vit->second ; + + if(posts[current_index].mMeta.mMsgId.isNull()) // This handles the branching situation where this post has been already erased. No need to go down further. + { +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << " already erased. Stopping." << std::endl; +#endif + break ; + } + + if(posts[current_index].mMeta.mPublishTs < posts[source_index].mMeta.mPublishTs) + { +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << " and is more recent => following" << std::endl; +#endif + for(std::set::const_iterator itt(posts[current_index].mOlderVersions.begin());itt!=posts[current_index].mOlderVersions.end();++itt) + posts[source_index].mOlderVersions.insert(*itt); + + posts[source_index].mOlderVersions.insert(posts[current_index].mMeta.mMsgId); + posts[current_index].mMeta.mMsgId.clear(); // clear the msg Id so the post will be ignored + } +#ifdef DEBUG_CHANNEL_MODEL + else + std::cerr << " but is older -> Stopping" << std::endl; +#endif + } + } + } + +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << "Now adding " << posts.size() << " posts into array structure..." << std::endl; +#endif + + mPosts.clear(); + + for (std::vector::const_reverse_iterator it = posts.rbegin(); it != posts.rend(); ++it) + { +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << " adding post: " << (*it).mMeta.mMsgId ; +#endif + + if(!(*it).mMeta.mMsgId.isNull()) + { +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << " added" << std::endl; +#endif + mPosts.push_back(*it); + } +#ifdef DEBUG_CHANNEL_MODEL + else + std::cerr << " skipped" << std::endl; +#endif + } +} + +void RsGxsChannelPostsModel::setMsgReadStatus(const QModelIndex& i,bool read_status,bool with_children) +{ + if(!i.isValid()) + return ; + + // no need to call preMods()/postMods() here because we'renot changing the model + + quintptr ref = i.internalId(); + uint32_t entry = 0; + + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) + return ; + +#warning TODO +// bool has_unread_below, has_read_below; +// recursSetMsgReadStatus(entry,read_status,with_children) ; +// recursUpdateReadStatusAndTimes(0,has_unread_below,has_read_below); + +} + +#ifdef TODO +void RsGxsForumModel::recursSetMsgReadStatus(ForumModelIndex i,bool read_status,bool with_children) +{ + int newStatus = (read_status ? mPosts[i].mMsgStatus & ~static_cast(GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD) + : mPosts[i].mMsgStatus | static_cast(GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD)); + bool bChanged = (mPosts[i].mMsgStatus != newStatus); + mPosts[i].mMsgStatus = newStatus; + //Remove Unprocessed and New flags + mPosts[i].mMsgStatus &= ~(GXS_SERV::GXS_MSG_STATUS_UNPROCESSED | GXS_SERV::GXS_MSG_STATUS_GUI_NEW); + + if (bChanged) + { + //Don't recurs post versions as this should be done before, if no change. + uint32_t token; + auto s = getPostVersions(mPosts[i].mMsgId) ; + + if(!s.empty()) + for(auto it(s.begin());it!=s.end();++it) + { + rsGxsForums->setMessageReadStatus(token,std::make_pair( mForumGroup.mMeta.mGroupId, it->second ), read_status); + std::cerr << "Setting version " << it->second << " of post " << mPosts[i].mMsgId << " as read." << std::endl; + } + else + rsGxsForums->setMessageReadStatus(token,std::make_pair( mForumGroup.mMeta.mGroupId, mPosts[i].mMsgId ), read_status); + + QModelIndex itemIndex = createIndex(i - 1, 0, &mPosts[i]); + emit dataChanged(itemIndex, itemIndex); + } + + if(!with_children) + return; + + for(uint32_t j=0;j& entries,ForumModelIndex index,int depth) +{ + const ForumModelPostEntry& e(entries[index]); + + QDateTime qtime; + qtime.setTime_t(e.mPublishTs); + + std::cerr << std::string(depth*2,' ') << index << " : " << e.mAuthorId.toStdString() << " " + << QString("%1").arg((uint32_t)e.mPostFlags,8,16,QChar('0')).toStdString() << " " + << QString("%1").arg((uint32_t)e.mMsgStatus,8,16,QChar('0')).toStdString() << " " + << qtime.toString().toStdString() << " \"" << e.mTitle << "\"" << std::endl; + + for(uint32_t i=0;i= mPosts.size()) + return ; + + std::cerr << "Setting own opinion for author " << mPosts[entry].mAuthorId + << " to " << static_cast(op) << std::endl; + RsGxsId author_id = mPosts[entry].mAuthorId; + + rsReputations->setOwnOpinion(author_id,op) ; + + // update opinions and distribution flags. No need to re-load all posts. + + for(uint32_t i=0;i * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include "retroshare/rsgxschannels.h" +#include "retroshare/rsgxsifacetypes.h" +#include +#include + +// This class holds the actual hierarchy of posts, represented by identifiers +// It is responsible for auto-updating when necessary and holds a mutex to allow the Model to +// safely access the data. + +// The model contains a post in place 0 that is the parent of all posts. + +typedef uint32_t ChannelPostsModelIndex; + +// struct ChannelPostsModelPostEntry +// { +// ChannelPostsModelPostEntry() : mPublishTs(0),mPostFlags(0),mMsgStatus(0),prow(0) {} +// +// enum { // flags for display of posts. To be used in mPostFlags +// FLAG_POST_IS_PINNED = 0x0001, +// FLAG_POST_IS_MISSING = 0x0002, +// FLAG_POST_IS_REDACTED = 0x0004, +// FLAG_POST_HAS_UNREAD_CHILDREN = 0x0008, +// FLAG_POST_HAS_READ_CHILDREN = 0x0010, +// FLAG_POST_PASSES_FILTER = 0x0020, +// FLAG_POST_CHILDREN_PASSES_FILTER = 0x0040, +// }; +// +// std::string mTitle ; +// RsGxsMessageId mMsgId; +// uint32_t mPublishTs; +// uint32_t mPostFlags; +// int mMsgStatus; +// +// int prow ;// parent row, which basically means position in the array of posts +// }; + +// This class is the item model used by Qt to display the information + +class RsGxsChannelPostsModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit RsGxsChannelPostsModel(QObject *parent = NULL); + ~RsGxsChannelPostsModel(){} + + static const int COLUMN_THREAD_NB_COLUMNS = 0x01; + +#ifdef TODO + enum Columns { + COLUMN_THREAD_TITLE =0x00, + COLUMN_THREAD_READ =0x01, + COLUMN_THREAD_DATE =0x02, + COLUMN_THREAD_DISTRIBUTION =0x03, + COLUMN_THREAD_AUTHOR =0x04, + COLUMN_THREAD_CONTENT =0x05, + COLUMN_THREAD_MSGID =0x06, + COLUMN_THREAD_DATA =0x07, + }; + + enum Roles{ SortRole = Qt::UserRole+1, + ThreadPinnedRole = Qt::UserRole+2, + MissingRole = Qt::UserRole+3, + StatusRole = Qt::UserRole+4, + UnreadChildrenRole = Qt::UserRole+5, + FilterRole = Qt::UserRole+6, + }; +#endif + + enum TreeMode{ TREE_MODE_UNKWN = 0x00, + TREE_MODE_PLAIN = 0x01, + TREE_MODE_FILES = 0x02, + }; + +#ifdef TODO + enum SortMode{ SORT_MODE_PUBLISH_TS = 0x00, + SORT_MODE_CHILDREN_PUBLISH_TS = 0x01, + }; +#endif + + QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;} + QModelIndex getIndexOfMessage(const RsGxsMessageId& mid) const; + + static const QString FilterString ; + + std::vector > getPostVersions(const RsGxsMessageId& mid) const; + + // This method will asynchroneously update the data + void updateChannel(const RsGxsGroupId& channel_group_id); + const RsGxsGroupId& currentGroupId() const; + + void setTreeMode(TreeMode mode) ; +#ifdef TODO + void setSortMode(SortMode mode) ; + + void setTextColorRead (QColor color) { mTextColorRead = color;} + void setTextColorUnread (QColor color) { mTextColorUnread = color;} + void setTextColorUnreadChildren(QColor color) { mTextColorUnreadChildren = color;} + void setTextColorNotSubscribed (QColor color) { mTextColorNotSubscribed = color;} + void setTextColorMissing (QColor color) { mTextColorMissing = color;} +#endif + + void setMsgReadStatus(const QModelIndex &i, bool read_status, bool with_children); +#ifdef TODO + void setFilter(int column, const QStringList &strings, uint32_t &count) ; + void setAuthorOpinion(const QModelIndex& indx,RsOpinion op); +#endif + + // Helper functions + + bool getPostData(const QModelIndex& i,RsGxsChannelPost& fmpe) const ; + void clear() ; + + // AbstractItemModel functions. + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; + + QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex& child) const override; + Qt::ItemFlags flags(const QModelIndex& index) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + // Custom item roles + + QVariant sizeHintRole (int col) const; + QVariant displayRole (const RsGxsChannelPost& fmpe, int col) const; + QVariant toolTipRole (const RsGxsChannelPost& fmpe, int col) const; + QVariant userRole (const RsGxsChannelPost& fmpe, int col) const; +#ifdef TODO + QVariant decorationRole(const ForumModelPostEntry& fmpe, int col) const; + QVariant pinnedRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant missingRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant statusRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant authorRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant sortRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant fontRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant filterRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant textColorRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant backgroundRole(const ForumModelPostEntry& fmpe, int col) const; +#endif + + /*! + * \brief debug_dump + * Dumps the hierarchy of posts in the terminal, to allow checking whether the internal representation is correct. + */ + void debug_dump(); + +signals: + void channelLoaded(); // emitted after the posts have been set. Can be used to updated the UI. + +private: + RsGxsChannelGroup mChannelGroup; + +#ifdef TODO + bool mUseChildTS; + bool mFilteringEnabled; + SortMode mSortMode; +#endif + TreeMode mTreeMode; + + uint32_t mColumns; + + void preMods() ; + void postMods() ; + + quintptr getParentRow(quintptr ref,int& row) const; + quintptr getChildRef(quintptr ref, int index) const; + int getChildrenCount(quintptr ref) const; + + static bool convertTabEntryToRefPointer(uint32_t entry, quintptr &ref); + static bool convertRefPointerToTabEntry(quintptr ref,uint32_t& entry); + static void computeReputationLevel(uint32_t forum_sign_flags, RsGxsChannelPost& entry); + + void update_posts(const RsGxsGroupId& group_id); + +#ifdef TODO + void setForumMessageSummary(const std::vector& messages); +#endif + void recursUpdateReadStatusAndTimes(ChannelPostsModelIndex i,bool& has_unread_below,bool& has_read_below); + uint32_t recursUpdateFilterStatus(ChannelPostsModelIndex i,int column,const QStringList& strings); + void recursSetMsgReadStatus(ChannelPostsModelIndex i,bool read_status,bool with_children); + +#ifdef TODO + static void generateMissingItem(const RsGxsMessageId &msgId,ChannelPostsModelPostEntry& entry); +#endif + //static ChannelModelIndex addEntry(std::vector& posts,const ChannelModelPostEntry& entry,ChannelModelIndex parent); + //static void convertMsgToPostEntry(const RsGxsChannelGroup &mChannelGroup, const RsMsgMetaData &msg, bool useChildTS, ChannelModelPostEntry& fentry); + + //void computeMessagesHierarchy(const RsGxsChannelGroup& forum_group, const std::vector &msgs_array, std::vector &posts, std::map > > &mPostVersions); + void createPostsArray(std::vector &posts); + void setPosts(const RsGxsChannelGroup& group, std::vector &posts); + void initEmptyHierarchy(std::vector& posts); + + std::vector mPosts ; // store the list of posts updated from rsForums. + //std::map > > mPostVersions; // stores versions of posts + + QColor mTextColorRead ; + QColor mTextColorUnread ; + QColor mTextColorUnreadChildren; + QColor mTextColorNotSubscribed ; + QColor mTextColorMissing ; + + friend class const_iterator; +}; From f75a6424b5e04e5b93f4ff39a80ca60eb0d167db Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 28 May 2020 23:58:07 +0200 Subject: [PATCH 027/154] fixed long-term bug due to sending an empty list of destkeys for GXSSecurity to encrypt an item --- libretroshare/src/gxs/gxssecurity.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libretroshare/src/gxs/gxssecurity.cc b/libretroshare/src/gxs/gxssecurity.cc index 6dedf1dff..d5b377328 100644 --- a/libretroshare/src/gxs/gxssecurity.cc +++ b/libretroshare/src/gxs/gxssecurity.cc @@ -651,6 +651,9 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u try { + if(keys.empty()) + throw std::runtime_error("EVP_SealInit will not be called with 0 keys. GxsSecurity::encrypt() was called with an empty set of destination keys!") ; + for(uint32_t i=0;i Date: Thu, 4 Jun 2020 19:38:46 +0200 Subject: [PATCH 028/154] Enabled sorting for gxs transport statistics, view details & small changes * Enabled sorting for gxs transport statistics * Context menu to view author details on gxs transport groups * ui layout fixes for view boards details * Display counting for people tree --- retroshare-gui/src/gui/Identity/IdDialog.cpp | 8 + .../src/gui/Posted/PostedListWidget.ui | 387 +++++++++--------- .../gui/statistics/GxsTransportStatistics.cpp | 63 ++- .../gui/statistics/GxsTransportStatistics.h | 3 + .../gui/statistics/GxsTransportStatistics.ui | 15 +- 5 files changed, 270 insertions(+), 206 deletions(-) diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index 2fd243c20..1a585d532 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -1575,6 +1575,14 @@ void IdDialog::loadIdentities(const std::map& ids_set /* count items */ int itemCount = contactsItem->childCount() + allItem->childCount() + ownItem->childCount(); ui->label_count->setText( "(" + QString::number( itemCount ) + ")" ); + + int contactsCount = contactsItem->childCount() ; + int allCount = allItem->childCount() ; + int ownCount = ownItem->childCount(); + + contactsItem->setText(0, tr("My contacts") + " (" + QString::number( contactsCount ) + ")" ); + allItem->setText(0, tr("All") + " (" + QString::number( allCount ) + ")" ); + ownItem->setText(0, tr("My own identities") + " (" + QString::number( ownCount ) + ")" ); navigate(RsGxsId(oldCurrentId)); filterIds(); diff --git a/retroshare-gui/src/gui/Posted/PostedListWidget.ui b/retroshare-gui/src/gui/Posted/PostedListWidget.ui index c4a6d51cd..3fa7069e6 100644 --- a/retroshare-gui/src/gui/Posted/PostedListWidget.ui +++ b/retroshare-gui/src/gui/Posted/PostedListWidget.ui @@ -298,199 +298,10 @@ false - - - - - - - 64 - 64 - - - - - 64 - 64 - - - - :/icons/png/postedlinks.png - - - true - - - - - - - - 14 - - - - TextLabel - - - - - - - - - 6 - - - - - - 75 - true - - - - Popularity - - - - - - - - 75 - true - - - - 0 - - - - - - - - 0 - 0 - - - - - 75 - true - - - - Posts - - - - - - - - 75 - true - - - - 0 - - - - - - - - 75 - true - - - - Created - - - - - - - unknown - - - - - - - - 75 - true - - - - Administrator: - - - - - - - unknown - - - true - - - - - - - - 75 - true - - - - Distribution: - - - - - - - unknown - - - - - - - - 0 - 0 - - - - - 75 - true - - - - Last Post: - - - - - - - unknown - - - - - - + + 6 + + Qt::Horizontal @@ -503,7 +314,7 @@ - + @@ -526,6 +337,194 @@ p, li { white-space: pre-wrap; } + + + + 0 + + + + + + 75 + true + + + + Popularity + + + + + + + + 75 + true + + + + 0 + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Posts + + + + + + + + 75 + true + + + + 0 + + + + + + + + 75 + true + + + + Created + + + + + + + unknown + + + + + + + + 75 + true + + + + Administrator: + + + + + + + unknown + + + true + + + + + + + + 75 + true + + + + Distribution: + + + + + + + unknown + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Last Post: + + + + + + + unknown + + + + + + + + 64 + 64 + + + + + 64 + 64 + + + + :/icons/png/postedlinks.png + + + true + + + + + + + + 14 + + + + TextLabel + + + + + diff --git a/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp b/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp index 10663a735..4b3ddf5e8 100644 --- a/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp +++ b/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp @@ -49,6 +49,8 @@ #include "gui/gxs/GxsIdLabel.h" #include "gui/gxs/GxsIdDetails.h" #include "gui/gxs/GxsIdTreeWidgetItem.h" +#include "gui/Identity/IdDialog.h" +#include "gui/MainWindow.h" #define COL_PENDING_ID 0 #define COL_PENDING_DESTINATION 1 @@ -61,11 +63,13 @@ #define COL_PENDING_DESTINATION_ID 8 #define COL_GROUP_GRP_ID 0 -#define COL_GROUP_NUM_MSGS 1 -#define COL_GROUP_SIZE_MSGS 2 -#define COL_GROUP_SUBSCRIBED 3 -#define COL_GROUP_POPULARITY 4 -#define COL_GROUP_UNIQUE_ID 5 +#define COL_GROUP_PUBLISHTS 1 +#define COL_GROUP_NUM_MSGS 2 +#define COL_GROUP_SIZE_MSGS 3 +#define COL_GROUP_SUBSCRIBED 4 +#define COL_GROUP_POPULARITY 5 +#define COL_GROUP_UNIQUE_ID 6 +#define COL_GROUP_AUTHOR_ID 7 //static const int PARTIAL_VIEW_SIZE = 9 ; //static const int MAX_TUNNEL_REQUESTS_DISPLAY = 10 ; @@ -94,8 +98,10 @@ GxsTransportStatistics::GxsTransportStatistics(QWidget *parent) QHeaderView_setSectionResizeMode(groupTreeWidget->header(), QHeaderView::ResizeToContents); connect(treeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(CustomPopupMenu(QPoint))); - - treeWidget->setColumnHidden(COL_PENDING_DESTINATION_ID,true); + connect(groupTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(CustomPopupMenuGroups(QPoint))); + + treeWidget->setColumnHidden(COL_PENDING_DESTINATION_ID,true); + groupTreeWidget->setColumnHidden(COL_GROUP_AUTHOR_ID,true); // load settings processSettings(true); @@ -146,6 +152,19 @@ void GxsTransportStatistics::CustomPopupMenu( QPoint ) contextMnu.exec(QCursor::pos()); } +void GxsTransportStatistics::CustomPopupMenuGroups( QPoint ) +{ + QMenu contextMnu( this ); + + QTreeWidgetItem *item = groupTreeWidget->currentItem(); + if (item) { + contextMnu.addAction(QIcon(":/images/info16.png"), tr("View details"), this, SLOT(showAuthorInPeople())); + + } + + contextMnu.exec(QCursor::pos()); +} + void GxsTransportStatistics::updateDisplay(bool) { time_t now = time(NULL) ; @@ -275,9 +294,10 @@ void GxsTransportStatistics::updateContent() groupTreeWidget->addTopLevelItem(item); groupTreeWidget->setItemExpanded(item,openned_groups.find(it->first) != openned_groups.end()); - QString msg_time_string = (stat.last_publish_TS>0)?QString(" (Last msg: %1)").arg(QDateTime::fromTime_t((uint)stat.last_publish_TS).toString()):"" ; + QString msg_time_string = (stat.last_publish_TS>0)?QString("(Last msg: %1)").arg(QDateTime::fromTime_t((uint)stat.last_publish_TS).toString()):"" ; - item->setData(COL_GROUP_NUM_MSGS, Qt::DisplayRole, QString::number(stat.mNumMsgs) + msg_time_string) ; + item->setData(COL_GROUP_PUBLISHTS, Qt::DisplayRole, msg_time_string) ; + item->setData(COL_GROUP_NUM_MSGS, Qt::DisplayRole, QString::number(stat.mNumMsgs) ) ; item->setData(COL_GROUP_GRP_ID, Qt::DisplayRole, QString::fromStdString(it->first.toStdString())) ; item->setData(COL_GROUP_SIZE_MSGS, Qt::DisplayRole, QString::number(stat.mTotalSizeOfMsgs)) ; item->setData(COL_GROUP_SUBSCRIBED,Qt::DisplayRole, stat.subscribed?tr("Yes"):tr("No")) ; @@ -308,6 +328,8 @@ void GxsTransportStatistics::updateContent() rsIdentity->getIdDetails(meta.mAuthorId,idDetails); QPixmap pixmap ; + QDateTime qdatetime; + qdatetime.setTime_t(meta.mPublishTs); if(idDetails.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idDetails.mAvatar.mData, idDetails.mAvatar.mSize, pixmap,GxsIdDetails::SMALL)) pixmap = GxsIdDetails::makeDefaultIcon(meta.mAuthorId,GxsIdDetails::SMALL); @@ -315,7 +337,9 @@ void GxsTransportStatistics::updateContent() sitem->setIcon(COL_GROUP_GRP_ID, QIcon(pixmap)); sitem->setData(COL_GROUP_UNIQUE_ID, Qt::DisplayRole,QString::fromStdString(meta.mMsgId.toStdString())); - sitem->setData(COL_GROUP_NUM_MSGS,Qt::DisplayRole, QDateTime::fromTime_t(meta.mPublishTs).toString()); + sitem->setData(COL_GROUP_AUTHOR_ID, Qt::DisplayRole, QString::fromStdString(meta.mAuthorId.toStdString())) ; + sitem->setText(COL_GROUP_PUBLISHTS, QDateTime::fromTime_t(meta.mPublishTs).toString()); + sitem->setData(COL_GROUP_PUBLISHTS, Qt::UserRole, qdatetime); } } } @@ -333,6 +357,25 @@ void GxsTransportStatistics::personDetails() dialog->show(); } +void GxsTransportStatistics::showAuthorInPeople() +{ + QTreeWidgetItem *item = groupTreeWidget->currentItem(); + std::string id = item->text(COL_GROUP_AUTHOR_ID).toStdString(); + + if (id.empty()) { + return; + } + + /* window will destroy itself! */ + IdDialog *idDialog = dynamic_cast(MainWindow::getPage(MainWindow::People)); + + if (!idDialog) + return ; + + MainWindow::showWindow(MainWindow::People); + idDialog->navigate(RsGxsId(id)); +} + #ifdef TO_REMOVE void GxsTransportStatistics::loadGroupMeta(const std::vector& groupInfo) { diff --git a/retroshare-gui/src/gui/statistics/GxsTransportStatistics.h b/retroshare-gui/src/gui/statistics/GxsTransportStatistics.h index 01a31e776..d23fdaa0f 100644 --- a/retroshare-gui/src/gui/statistics/GxsTransportStatistics.h +++ b/retroshare-gui/src/gui/statistics/GxsTransportStatistics.h @@ -51,7 +51,10 @@ public: private slots: /** Create the context popup menu and it's submenus */ void CustomPopupMenu( QPoint point ); + void CustomPopupMenuGroups( QPoint point ) ; + void personDetails(); + void showAuthorInPeople(); private: void updateDisplay(bool complete) ; diff --git a/retroshare-gui/src/gui/statistics/GxsTransportStatistics.ui b/retroshare-gui/src/gui/statistics/GxsTransportStatistics.ui index e2c7449c0..8ce780e81 100644 --- a/retroshare-gui/src/gui/statistics/GxsTransportStatistics.ui +++ b/retroshare-gui/src/gui/statistics/GxsTransportStatistics.ui @@ -41,7 +41,7 @@ true - false + true @@ -108,6 +108,12 @@ Qt::CustomContextMenu + + true + + + true + Group ID / Author @@ -115,7 +121,12 @@ - Number of messages / Publish TS + Publish TS + + + + + Number of messages From e0cf9768fce3c21936a619d6c57befc441cc4c0d Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 4 Jun 2020 19:50:34 +0200 Subject: [PATCH 029/154] improved layout --- .../GxsChannelPostsWidgetWithModel.cpp | 168 ++++---- .../GxsChannelPostsWidgetWithModel.ui | 401 +++++++++--------- 2 files changed, 295 insertions(+), 274 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index ad695136d..0bd08b9d0 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -49,6 +49,10 @@ * #define DEBUG_CHANNEL ***/ +static const int mTokenTypeGroupData = 1; +static const int CHANNEL_TABS_DETAILS= 0; +static const int CHANNEL_TABS_POSTS = 1; + /* View mode */ #define VIEW_MODE_FEEDS 1 #define VIEW_MODE_FILES 2 @@ -255,9 +259,18 @@ void GxsChannelPostsWidgetWithModel::handleEvent_main_thread(std::shared_ptrpostsTree->selectionModel()->currentIndex(); + QModelIndex index = ui->postsTree->selectionModel()->currentIndex(); - std::cerr << "Showing details about selected index : "<< selected_index.row() << "," << selected_index.column() << std::endl; + if(!index.isValid()) + { + ui->postDetails_TE->clear(); + return; + } + RsGxsChannelPost post = index.data(Qt::UserRole).value() ; + + std::cerr << "Showing details about selected index : "<< index.row() << "," << index.column() << std::endl; + + ui->postDetails_TE->setText(RsHtml().formatText(NULL, QString::fromUtf8(post.mMsg.c_str()), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); } void GxsChannelPostsWidgetWithModel::updateGroupData() @@ -285,6 +298,7 @@ void GxsChannelPostsWidgetWithModel::updateGroupData() { mGroup = groups[0]; mThreadModel->updateChannel(groupId()); + insertChannelDetails(mGroup); } ); }); } @@ -427,105 +441,99 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou } else { chanImage = QPixmap(CHAN_DEFAULT_IMAGE); } - //ui->logoLabel->setPixmap(chanImage); + ui->logoLabel->setPixmap(chanImage); + ui->logoLabel->setFixedSize(QSize(ui->logoLabel->height()*chanImage.width()/(float)chanImage.height(),ui->logoLabel->height())); // make the logo have the same aspect ratio than the original image - if (group.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_PUBLISH) - { - mStateHelper->setWidgetEnabled(ui->postButton, true); - } - else - { - mStateHelper->setWidgetEnabled(ui->postButton, false); - } + ui->postButton->setEnabled(bool(group.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_PUBLISH)); ui->subscribeToolButton->setSubscribed(IS_GROUP_SUBSCRIBED(group.mMeta.mSubscribeFlags)); - mStateHelper->setWidgetEnabled(ui->subscribeToolButton, true); + ui->subscribeToolButton->setEnabled(true); - bool autoDownload ; - rsGxsChannels->getChannelAutoDownload(group.mMeta.mGroupId,autoDownload); + bool autoDownload ; + rsGxsChannels->getChannelAutoDownload(group.mMeta.mGroupId,autoDownload); setAutoDownload(autoDownload); - + RetroShareLink link; - if (IS_GROUP_SUBSCRIBED(group.mMeta.mSubscribeFlags)) { - ui->feedToolButton->setEnabled(true); - - ui->fileToolButton->setEnabled(true); - //ui->infoWidget->hide(); - setViewMode(viewMode()); - + if (IS_GROUP_SUBSCRIBED(group.mMeta.mSubscribeFlags)) + { ui->subscribeToolButton->setText(tr("Subscribed") + " " + QString::number(group.mMeta.mPop) ); + ui->feedToolButton->setEnabled(true); + ui->fileToolButton->setEnabled(true); + ui->channel_TW->setTabEnabled(CHANNEL_TABS_POSTS,true); + ui->details_TW->setEnabled(true); + } + else + { + ui->details_TW->setEnabled(false); + ui->channel_TW->setTabEnabled(CHANNEL_TABS_POSTS,false); + } - ui->infoPosts->clear(); - ui->infoDescription->clear(); - } else { - ui->infoPosts->setText(QString::number(group.mMeta.mVisibleMsgCount)); - if(group.mMeta.mLastPost==0) - ui->infoLastPost->setText(tr("Never")); - else - ui->infoLastPost->setText(DateTime::formatLongDateTime(group.mMeta.mLastPost)); - QString formatDescription = QString::fromUtf8(group.mDescription.c_str()); + ui->infoPosts->setText(QString::number(group.mMeta.mVisibleMsgCount)); + if(group.mMeta.mLastPost==0) + ui->infoLastPost->setText(tr("Never")); + else + ui->infoLastPost->setText(DateTime::formatLongDateTime(group.mMeta.mLastPost)); + QString formatDescription = QString::fromUtf8(group.mDescription.c_str()); - unsigned int formatFlag = RSHTML_FORMATTEXT_EMBED_LINKS; + unsigned int formatFlag = RSHTML_FORMATTEXT_EMBED_LINKS; - // embed smileys ? - if (Settings->valueFromGroup(QString("ChannelPostsWidget"), QString::fromUtf8("Emoteicons_ChannelDecription"), true).toBool()) { - formatFlag |= RSHTML_FORMATTEXT_EMBED_SMILEYS; - } + // embed smileys ? + if (Settings->valueFromGroup(QString("ChannelPostsWidget"), QString::fromUtf8("Emoteicons_ChannelDecription"), true).toBool()) { + formatFlag |= RSHTML_FORMATTEXT_EMBED_SMILEYS; + } - formatDescription = RsHtml().formatText(NULL, formatDescription, formatFlag); + formatDescription = RsHtml().formatText(NULL, formatDescription, formatFlag); - ui->infoDescription->setText(formatDescription); - - ui->infoAdministrator->setId(group.mMeta.mAuthorId) ; - - link = RetroShareLink::createMessage(group.mMeta.mAuthorId, ""); - ui->infoAdministrator->setText(link.toHtml()); - - ui->infoCreated->setText(DateTime::formatLongDateTime(group.mMeta.mPublishTs)); + ui->infoDescription->setText(formatDescription); - QString distrib_string ( "[unknown]" ); - - switch(group.mMeta.mCircleType) - { - case GXS_CIRCLE_TYPE_PUBLIC: distrib_string = tr("Public") ; - break ; - case GXS_CIRCLE_TYPE_EXTERNAL: - { - RsGxsCircleDetails det ; + ui->infoAdministrator->setId(group.mMeta.mAuthorId) ; - // !! What we need here is some sort of CircleLabel, which loads the circle and updates the label when done. + link = RetroShareLink::createMessage(group.mMeta.mAuthorId, ""); + ui->infoAdministrator->setText(link.toHtml()); - if(rsGxsCircles->getCircleDetails(group.mMeta.mCircleId,det)) - distrib_string = tr("Restricted to members of circle \"")+QString::fromUtf8(det.mCircleName.c_str()) +"\""; - else - distrib_string = tr("Restricted to members of circle ")+QString::fromStdString(group.mMeta.mCircleId.toStdString()) ; - } - break ; - case GXS_CIRCLE_TYPE_YOUR_EYES_ONLY: distrib_string = tr("Your eyes only"); - break ; - case GXS_CIRCLE_TYPE_LOCAL: distrib_string = tr("You and your friend nodes"); - break ; - default: - std::cerr << "(EE) badly initialised group distribution ID = " << group.mMeta.mCircleType << std::endl; - } - - ui->infoDistribution->setText(distrib_string); + ui->infoCreated->setText(DateTime::formatLongDateTime(group.mMeta.mPublishTs)); + + QString distrib_string ( "[unknown]" ); + + switch(group.mMeta.mCircleType) + { + case GXS_CIRCLE_TYPE_PUBLIC: distrib_string = tr("Public") ; + break ; + case GXS_CIRCLE_TYPE_EXTERNAL: + { + RsGxsCircleDetails det ; + + // !! What we need here is some sort of CircleLabel, which loads the circle and updates the label when done. + + if(rsGxsCircles->getCircleDetails(group.mMeta.mCircleId,det)) + distrib_string = tr("Restricted to members of circle \"")+QString::fromUtf8(det.mCircleName.c_str()) +"\""; + else + distrib_string = tr("Restricted to members of circle ")+QString::fromStdString(group.mMeta.mCircleId.toStdString()) ; + } + break ; + case GXS_CIRCLE_TYPE_YOUR_EYES_ONLY: distrib_string = tr("Your eyes only"); + break ; + case GXS_CIRCLE_TYPE_LOCAL: distrib_string = tr("You and your friend nodes"); + break ; + default: + std::cerr << "(EE) badly initialised group distribution ID = " << group.mMeta.mCircleType << std::endl; + } + + ui->infoDistribution->setText(distrib_string); #ifdef TODO - ui->infoWidget->show(); - ui->feedWidget->hide(); - ui->fileWidget->hide(); + ui->infoWidget->show(); + ui->feedWidget->hide(); + ui->fileWidget->hide(); #endif - ui->feedToolButton->setEnabled(false); - ui->fileToolButton->setEnabled(false); - - ui->subscribeToolButton->setText(tr("Subscribe ") + " " + QString::number(group.mMeta.mPop) ); + ui->feedToolButton->setEnabled(false); + ui->fileToolButton->setEnabled(false); - } + ui->subscribeToolButton->setText(tr("Subscribe ") + " " + QString::number(group.mMeta.mPop) ); } int GxsChannelPostsWidgetWithModel::viewMode() @@ -870,8 +878,8 @@ void GxsChannelPostsWidget::clearPosts() void GxsChannelPostsWidgetWithModel::blank() { - //mStateHelper->setWidgetEnabled(ui->postButton, false); - //mStateHelper->setWidgetEnabled(ui->subscribeToolButton, false); + mStateHelper->setWidgetEnabled(ui->postButton, false); + mStateHelper->setWidgetEnabled(ui->subscribeToolButton, false); mThreadModel->clear(); groupNameChanged(QString()); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index 2ae7ecac8..5cea1d692 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -222,182 +222,182 @@ - + - 0 + 1 Channel details - + - - - Channel details - - - - 9 - - - 9 - - - 9 - - - 9 - - - - - - 0 - 0 - - - - - 75 - true - - - - Last Post: - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + + + TextLabel + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + unknown + + + true + + + + + + + unknown + + + + + + + + 75 + true + + + + Created: + + + + + + + unknown + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Posts: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Last Post: + + + + + + + unknown + + + + + + + + 75 + true + + + + Administrator: + + + + + + + + 75 + true + + + + Distribution: + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Description</span></p></body></html> - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - true - - - true - - - - - - - - 75 - true - - - - Description: - - - - - - - - 75 - true - - - - Created: - - - - - - - - 75 - true - - - - Administrator: - - - - - - - - 0 - 0 - - - - - 75 - true - - - - Posts: - - - - - - - - 75 - true - - - - Distribution: - - - - - - - unknown - - - - - - - unknown - - - - - - - unknown - - - true - - - - - - - unknown - - - - - - - 0 - - - - + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + true + + + true + @@ -406,43 +406,56 @@ p, li { white-space: pre-wrap; } Posts - + - - - QAbstractItemView::SelectItems + + + Qt::Vertical - - false - + + + QAbstractItemView::SelectItems + + + false + + + + + 2 + + + + Details + + + + + 9 + 9 + 955 + 181 + + + + + + + Files + + + + + Comments + + + - - - - 0 - - - - Details - - - - - - - - - - Comments - - - - From a5dd33e085be81063303105d323d3caed8970a33 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 4 Jun 2020 21:50:27 +0200 Subject: [PATCH 030/154] improved widgets. Added file list (with dump delegate), labels, etc --- .../gxschannels/GxsChannelPostFilesModel.cpp | 799 ++++++++++++++++++ .../gxschannels/GxsChannelPostFilesModel.h | 161 ++++ .../GxsChannelPostsWidgetWithModel.cpp | 102 ++- .../GxsChannelPostsWidgetWithModel.h | 18 +- .../GxsChannelPostsWidgetWithModel.ui | 66 +- retroshare-gui/src/retroshare-gui.pro | 2 + 6 files changed, 1129 insertions(+), 19 deletions(-) create mode 100644 retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp create mode 100644 retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp new file mode 100644 index 000000000..9098af57b --- /dev/null +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp @@ -0,0 +1,799 @@ +/******************************************************************************* + * retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp * + * * + * Copyright 2020 by Cyril Soler * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include +#include +#include +#include + +#include "gui/common/FilesDefs.h" +#include "util/qtthreadsutils.h" +#include "util/HandleRichText.h" +#include "util/DateTime.h" +#include "retroshare/rsgxsflags.h" +#include "retroshare/rsgxschannels.h" +#include "retroshare/rsexpr.h" + +#include "GxsChannelPostFilesModel.h" + +#define DEBUG_CHANNEL_MODEL + +Q_DECLARE_METATYPE(RsGxsFile) + +static std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsewhere + +RsGxsChannelPostFilesModel::RsGxsChannelPostFilesModel(QObject *parent) + : QAbstractItemModel(parent) +{ + initEmptyHierarchy(mFiles); +} + +void RsGxsChannelPostFilesModel::initEmptyHierarchy(std::vector& files) +{ + preMods(); + + files.resize(1); // adds a sentinel item + files[0].mName = "Root sentinel post" ; + + postMods(); +} + +void RsGxsChannelPostFilesModel::preMods() +{ + //emit layoutAboutToBeChanged(); //Generate SIGSEGV when click on button move next/prev. + + beginResetModel(); +} +void RsGxsChannelPostFilesModel::postMods() +{ + endResetModel(); + + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mFiles.size(),COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); +} + +#ifdef TODO +void RsGxsChannelPostsModel::setSortMode(SortMode mode) +{ + preMods(); + + mSortMode = mode; + + postMods(); +} + +void RsGxsForumModel::initEmptyHierarchy(std::vector& posts) +{ + preMods(); + + posts.resize(1); // adds a sentinel item + posts[0].mTitle = "Root sentinel post" ; + posts[0].mParent = 0; + + postMods(); +} +#endif + +int RsGxsChannelPostFilesModel::rowCount(const QModelIndex& parent) const +{ + if(parent.column() > 0) + return 0; + + if(mFiles.empty()) // security. Should never happen. + return 0; + + if(!parent.isValid()) + return getChildrenCount(0); + + RsErr() << __PRETTY_FUNCTION__ << " rowCount cannot figure out the porper number of rows." << std::endl; + return 0; +} + +int RsGxsChannelPostFilesModel::columnCount(const QModelIndex &/*parent*/) const +{ + return COLUMN_THREAD_NB_COLUMNS ; +} + +// std::vector > RsGxsChannelPostsModel::getPostVersions(const RsGxsMessageId& mid) const +// { +// auto it = mPostVersions.find(mid); +// +// if(it != mPostVersions.end()) +// return it->second; +// else +// return std::vector >(); +// } + +bool RsGxsChannelPostFilesModel::getFileData(const QModelIndex& i,RsGxsFile& fmpe) const +{ + if(!i.isValid()) + return true; + + quintptr ref = i.internalId(); + uint32_t entry = 0; + + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mFiles.size()) + return false ; + + fmpe = mFiles[entry]; + + return true; + +} + +bool RsGxsChannelPostFilesModel::hasChildren(const QModelIndex &parent) const +{ + if(!parent.isValid()) + return true; + + return false; // by default, no channel post has children +} + +bool RsGxsChannelPostFilesModel::convertTabEntryToRefPointer(uint32_t entry,quintptr& ref) +{ + // the pointer is formed the following way: + // + // [ 32 bits ] + // + // This means that the whole software has the following build-in limitation: + // * 4 B simultaenous posts. Should be enough ! + + ref = (intptr_t)entry; + + return true; +} + +bool RsGxsChannelPostFilesModel::convertRefPointerToTabEntry(quintptr ref, uint32_t& entry) +{ + intptr_t val = (intptr_t)ref; + + if(val > (1<<30)) // make sure the pointer is an int that fits in 32bits and not too big which would look suspicious + { + RsErr() << "(EE) trying to make a ChannelPostsModelIndex out of a number that is larger than 2^32-1 !" << std::endl; + return false ; + } + entry = quintptr(val); + + return true; +} + +QModelIndex RsGxsChannelPostFilesModel::index(int row, int column, const QModelIndex & parent) const +{ + if(row < 0 || column < 0 || column >= COLUMN_THREAD_NB_COLUMNS) + return QModelIndex(); + + quintptr ref = getChildRef(parent.internalId(),row); + +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << "index-3(" << row << "," << column << " parent=" << parent << ") : " << createIndex(row,column,ref) << std::endl; +#endif + return createIndex(row,column,ref) ; +} + +QModelIndex RsGxsChannelPostFilesModel::parent(const QModelIndex& index) const +{ + if(!index.isValid()) + return QModelIndex(); + + return QModelIndex(); // there's no hierarchy here. So nothing to do! +} + +Qt::ItemFlags RsGxsChannelPostFilesModel::flags(const QModelIndex& index) const +{ + if (!index.isValid()) + return 0; + + return QAbstractItemModel::flags(index); +} + +quintptr RsGxsChannelPostFilesModel::getChildRef(quintptr ref,int index) const +{ + if (index < 0) + return 0; + + ChannelPostFilesModelIndex entry ; + + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mFiles.size()) + return 0 ; + + if(entry == 0) + { + quintptr new_ref; + convertTabEntryToRefPointer(index+1,new_ref); + return new_ref; + } + else + return 0 ; +} + +quintptr RsGxsChannelPostFilesModel::getParentRow(quintptr ref,int& row) const +{ + ChannelPostFilesModelIndex ref_entry; + + if(!convertRefPointerToTabEntry(ref,ref_entry) || ref_entry >= mFiles.size()) + return 0 ; + + if(ref_entry == 0) + { + RsErr() << "getParentRow() shouldn't be asked for the parent of NULL" << std::endl; + row = 0; + } + else + row = ref_entry-1; + + return 0; +} + +int RsGxsChannelPostFilesModel::getChildrenCount(quintptr ref) const +{ + uint32_t entry = 0 ; + + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mFiles.size()) + return 0 ; + + if(entry == 0) + { +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << "Children count (flat mode): " << mFiles.size()-1 << std::endl; +#endif + return ((int)mFiles.size())-1; + } + else + return 0; +} + +QVariant RsGxsChannelPostFilesModel::data(const QModelIndex &index, int role) const +{ +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << "calling data(" << index << ") role=" << role << std::endl; +#endif + + if(!index.isValid()) + return QVariant(); + + switch(role) + { + case Qt::SizeHintRole: return sizeHintRole(index.column()) ; + case Qt::StatusTipRole:return QVariant(); + default: break; + } + + quintptr ref = (index.isValid())?index.internalId():0 ; + uint32_t entry = 0; + +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << "data(" << index << ")" ; +#endif + + if(!ref) + { +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << " [empty]" << std::endl; +#endif + return QVariant() ; + } + + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mFiles.size()) + { +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << "Bad pointer: " << (void*)ref << std::endl; +#endif + return QVariant() ; + } + + const RsGxsFile& fmpe(mFiles[entry]); + +#ifdef TODO + if(role == Qt::FontRole) + { + QFont font ; + font.setBold( (fmpe.mPostFlags & (ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN | ForumModelPostEntry::FLAG_POST_IS_PINNED)) || IS_MSG_UNREAD(fmpe.mMsgStatus)); + return QVariant(font); + } + + if(role == UnreadChildrenRole) + return bool(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN); + +#ifdef DEBUG_CHANNEL_MODEL + std::cerr << " [ok]" << std::endl; +#endif +#endif + + switch(role) + { + case Qt::DisplayRole: return displayRole (fmpe,index.column()) ; + case Qt::UserRole: return userRole (fmpe,index.column()) ; +#ifdef TODO + case Qt::DecorationRole: return decorationRole(fmpe,index.column()) ; + case Qt::ToolTipRole: return toolTipRole (fmpe,index.column()) ; + case Qt::TextColorRole: return textColorRole (fmpe,index.column()) ; + case Qt::BackgroundRole: return backgroundRole(fmpe,index.column()) ; + + case FilterRole: return filterRole (fmpe,index.column()) ; + case ThreadPinnedRole: return pinnedRole (fmpe,index.column()) ; + case MissingRole: return missingRole (fmpe,index.column()) ; + case StatusRole: return statusRole (fmpe,index.column()) ; + case SortRole: return sortRole (fmpe,index.column()) ; +#endif + default: + return QVariant(); + } +} + +#ifdef TODO +QVariant RsGxsForumModel::textColorRole(const ForumModelPostEntry& fmpe,int /*column*/) const +{ + if( (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING)) + return QVariant(mTextColorMissing); + + if(IS_MSG_UNREAD(fmpe.mMsgStatus) || (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED)) + return QVariant(mTextColorUnread); + else + return QVariant(mTextColorRead); + + return QVariant(); +} + +QVariant RsGxsForumModel::statusRole(const ForumModelPostEntry& fmpe,int column) const +{ + if(column != COLUMN_THREAD_DATA) + return QVariant(); + + return QVariant(fmpe.mMsgStatus); +} + +QVariant RsGxsForumModel::filterRole(const ForumModelPostEntry& fmpe,int /*column*/) const +{ + if(!mFilteringEnabled || (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER)) + return QVariant(FilterString); + + return QVariant(QString()); +} + +uint32_t RsGxsForumModel::recursUpdateFilterStatus(ForumModelIndex i,int column,const QStringList& strings) +{ + QString s ; + uint32_t count = 0; + + switch(column) + { + default: + case COLUMN_THREAD_DATE: + case COLUMN_THREAD_TITLE: s = displayRole(mPosts[i],column).toString(); + break; + case COLUMN_THREAD_AUTHOR: + { + QString comment ; + QList icons; + + GxsIdDetails::MakeIdDesc(mPosts[i].mAuthorId, false,s, icons, comment,GxsIdDetails::ICON_TYPE_NONE); + } + break; + } + + if(!strings.empty()) + { + mPosts[i].mPostFlags &= ~(ForumModelPostEntry::FLAG_POST_PASSES_FILTER | ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER); + + for(auto iter(strings.begin()); iter != strings.end(); ++iter) + if(s.contains(*iter,Qt::CaseInsensitive)) + { + mPosts[i].mPostFlags |= ForumModelPostEntry::FLAG_POST_PASSES_FILTER | ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER; + + count++; + break; + } + } + else + { + mPosts[i].mPostFlags |= ForumModelPostEntry::FLAG_POST_PASSES_FILTER |ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER; + count++; + } + + for(uint32_t j=0;j 0) + mPosts[i].mPostFlags |= ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER; + } + + return count; +} + + +void RsGxsForumModel::setFilter(int column,const QStringList& strings,uint32_t& count) +{ + preMods(); + + if(!strings.empty()) + { + count = recursUpdateFilterStatus(ForumModelIndex(0),column,strings); + mFilteringEnabled = true; + } + else + { + count=0; + mFilteringEnabled = false; + } + + postMods(); +} + +QVariant RsGxsForumModel::missingRole(const ForumModelPostEntry& fmpe,int /*column*/) const +{ + if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING) + return QVariant(true); + else + return QVariant(false); +} + +QVariant RsGxsForumModel::toolTipRole(const ForumModelPostEntry& fmpe,int column) const +{ + if(column == COLUMN_THREAD_DISTRIBUTION) + switch(fmpe.mReputationWarningLevel) + { + case 3: return QVariant(tr("Information for this identity is currently missing.")) ; + case 2: return QVariant(tr("You have banned this ID. The message will not be\ndisplayed nor forwarded to your friends.")) ; + case 1: return QVariant(tr("You have not set an opinion for this person,\n and your friends do not vote positively: Spam regulation \nprevents the message to be forwarded to your friends.")) ; + case 0: return QVariant(tr("Message will be forwarded to your friends.")) ; + default: + return QVariant("[ERROR: missing reputation level information - contact the developers]"); + } + + if(column == COLUMN_THREAD_AUTHOR) + { + QString str,comment ; + QList icons; + + if(!GxsIdDetails::MakeIdDesc(fmpe.mAuthorId, true, str, icons, comment,GxsIdDetails::ICON_TYPE_AVATAR)) + return QVariant(); + + int S = QFontMetricsF(QApplication::font()).height(); + QImage pix( (*icons.begin()).pixmap(QSize(4*S,4*S)).toImage()); + + QString embeddedImage; + if(RsHtml::makeEmbeddedImage(pix.scaled(QSize(4*S,4*S), Qt::KeepAspectRatio, Qt::SmoothTransformation), embeddedImage, 8*S * 8*S)) + comment = "
" + embeddedImage + "" + comment + "
"; + + return comment; + } + + return QVariant(); +} + +QVariant RsGxsForumModel::pinnedRole(const ForumModelPostEntry& fmpe,int /*column*/) const +{ + if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) + return QVariant(true); + else + return QVariant(false); +} + +QVariant RsGxsForumModel::backgroundRole(const ForumModelPostEntry& fmpe,int /*column*/) const +{ + if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) + return QVariant(QBrush(QColor(255,200,180))); + + if(mFilteringEnabled && (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_PASSES_FILTER)) + return QVariant(QBrush(QColor(255,240,210))); + + return QVariant(); +} +#endif + +QVariant RsGxsChannelPostFilesModel::sizeHintRole(int col) const +{ + float factor = QFontMetricsF(QApplication::font()).height()/14.0f ; + + return QVariant( QSize(factor * 170, factor*14 )); +#ifdef TODO + switch(col) + { + default: + case COLUMN_THREAD_TITLE: return QVariant( QSize(factor * 170, factor*14 )); + case COLUMN_THREAD_DATE: return QVariant( QSize(factor * 75 , factor*14 )); + case COLUMN_THREAD_AUTHOR: return QVariant( QSize(factor * 75 , factor*14 )); + case COLUMN_THREAD_DISTRIBUTION: return QVariant( QSize(factor * 15 , factor*14 )); + } +#endif +} + +#ifdef TODO +QVariant RsGxsForumModel::authorRole(const ForumModelPostEntry& fmpe,int column) const +{ + if(column == COLUMN_THREAD_DATA) + return QVariant(QString::fromStdString(fmpe.mAuthorId.toStdString())); + + return QVariant(); +} + +QVariant RsGxsForumModel::sortRole(const ForumModelPostEntry& fmpe,int column) const +{ + switch(column) + { + case COLUMN_THREAD_DATE: if(mSortMode == SORT_MODE_PUBLISH_TS) + return QVariant(QString::number(fmpe.mPublishTs)); // we should probably have leading zeroes here + else + return QVariant(QString::number(fmpe.mMostRecentTsInThread)); // we should probably have leading zeroes here + + case COLUMN_THREAD_READ: return QVariant((bool)IS_MSG_UNREAD(fmpe.mMsgStatus)); + case COLUMN_THREAD_DISTRIBUTION: return decorationRole(fmpe,column); + case COLUMN_THREAD_AUTHOR: + { + QString str,comment ; + QList icons; + GxsIdDetails::MakeIdDesc(fmpe.mAuthorId, false, str, icons, comment,GxsIdDetails::ICON_TYPE_NONE); + + return QVariant(str); + } + default: + return displayRole(fmpe,column); + } +} +#endif + +QVariant RsGxsChannelPostFilesModel::displayRole(const RsGxsFile& fmpe,int col) const +{ + switch(col) + { + case 0: return QString::fromUtf8(fmpe.mName.c_str()); + case 1: return QString::number(fmpe.mSize); + case 2: { + FileInfo finfo; + if(rsFiles->FileDetails(fmpe.mHash,RS_FILE_HINTS_DOWNLOAD,finfo)) + return qulonglong(finfo.transfered); + else + return 0; + } + default: + return QString(); +#ifdef TODO + case COLUMN_THREAD_TITLE: if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_REDACTED) + return QVariant(tr("[ ... Redacted message ... ]")); + else if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) + return QVariant(tr("[PINNED] ") + QString::fromUtf8(fmpe.mTitle.c_str())); + else + return QVariant(QString::fromUtf8(fmpe.mTitle.c_str())); + + case COLUMN_THREAD_READ:return QVariant(); + case COLUMN_THREAD_DATE:{ + if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING) + return QVariant(QString()); + + QDateTime qtime; + qtime.setTime_t(fmpe.mPublishTs); + + return QVariant(DateTime::formatDateTime(qtime)); + } + + case COLUMN_THREAD_DISTRIBUTION: + 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(); +#endif +#ifdef TODO + if (filterColumn == COLUMN_THREAD_CONTENT) { + // need content for filter + QTextDocument doc; + doc.setHtml(QString::fromUtf8(msg.mMsg.c_str())); + item->setText(COLUMN_THREAD_CONTENT, doc.toPlainText().replace(QString("\n"), QString(" "))); + } +#endif + } + + + return QVariant("[ERROR]"); +} + +QVariant RsGxsChannelPostFilesModel::userRole(const RsGxsFile& fmpe,int col) const +{ + switch(col) + { + default: + return QVariant::fromValue(fmpe); + } +} + +#ifdef TODO +QVariant RsGxsForumModel::decorationRole(const ForumModelPostEntry& fmpe,int col) const +{ + bool exist=false; + switch(col) + { + case COLUMN_THREAD_DISTRIBUTION: + return QVariant(fmpe.mReputationWarningLevel); + 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(); +} +#endif + +void RsGxsChannelPostFilesModel::clear() +{ + preMods(); + + mFiles.clear(); + initEmptyHierarchy(mFiles); + + postMods(); + emit channelLoaded(); +} + +void RsGxsChannelPostFilesModel::setFiles(const std::list& files) +{ + preMods(); + + beginRemoveRows(QModelIndex(),0,mFiles.size()-1); + endRemoveRows(); + + mFiles.clear(); + initEmptyHierarchy(mFiles); + + for(auto& file:files) + mFiles.push_back(file); + +#ifdef TODO + recursUpdateReadStatusAndTimes(0,has_unread_below,has_read_below) ; + recursUpdateFilterStatus(0,0,QStringList()); +#endif + +#ifdef DEBUG_CHANNEL_MODEL + // debug_dump(); +#endif + + beginInsertRows(QModelIndex(),0,mFiles.size()-1); + endInsertRows(); + + postMods(); + + emit channelLoaded(); +} + +//ChannelPostsModelIndex RsGxsChannelPostsModel::addEntry(std::vector& posts,const ChannelPostsModelPostEntry& entry) +//{ +// uint32_t N = posts.size(); +// posts.push_back(entry); +// +//#ifdef DEBUG_FORUMMODEL +// std::cerr << "Added new entry " << N << " children of " << parent << std::endl; +//#endif +// if(N == parent) +// std::cerr << "(EE) trying to add a post as its own parent!" << std::endl; +// +// return ChannelPostsModelIndex(N); +//} + +//void RsGxsChannelPostsModel::convertMsgToPostEntry(const RsGxsChannelGroup& mChannelGroup,const RsMsgMetaData& msg, bool /*useChildTS*/, ChannelPostsModelPostEntry& fentry) +//{ +// fentry.mTitle = msg.mMsgName; +// fentry.mMsgId = msg.mMsgId; +// fentry.mPublishTs = msg.mPublishTs; +// fentry.mPostFlags = 0; +// fentry.mMsgStatus = msg.mMsgStatus; +// +// // Early check for a message that should be hidden because its author +// // is flagged with a bad reputation +//} + +QModelIndex RsGxsChannelPostFilesModel::getIndexOfFile(const RsFileHash& hash) const +{ + // Brutal search. This is not so nice, so dont call that in a loop! If too costly, we'll use a map. + + for(uint32_t i=1;i& entries,ForumModelIndex index,int depth) +{ + const ForumModelPostEntry& e(entries[index]); + + QDateTime qtime; + qtime.setTime_t(e.mPublishTs); + + std::cerr << std::string(depth*2,' ') << index << " : " << e.mAuthorId.toStdString() << " " + << QString("%1").arg((uint32_t)e.mPostFlags,8,16,QChar('0')).toStdString() << " " + << QString("%1").arg((uint32_t)e.mMsgStatus,8,16,QChar('0')).toStdString() << " " + << qtime.toString().toStdString() << " \"" << e.mTitle << "\"" << std::endl; + + for(uint32_t i=0;i= mPosts.size()) + return ; + + std::cerr << "Setting own opinion for author " << mPosts[entry].mAuthorId + << " to " << static_cast(op) << std::endl; + RsGxsId author_id = mPosts[entry].mAuthorId; + + rsReputations->setOwnOpinion(author_id,op) ; + + // update opinions and distribution flags. No need to re-load all posts. + + for(uint32_t i=0;i * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#pragma once + +#include "retroshare/rsfiles.h" +#include "retroshare/rsgxscommon.h" + +#include +#include + +// This class holds the actual hierarchy of posts, represented by identifiers +// It is responsible for auto-updating when necessary and holds a mutex to allow the Model to +// safely access the data. + +// The model contains a post in place 0 that is the parent of all posts. + +typedef uint32_t ChannelPostFilesModelIndex; + +// This class is the item model used by Qt to display the information + +class RsGxsChannelPostFilesModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit RsGxsChannelPostFilesModel(QObject *parent = NULL); + ~RsGxsChannelPostFilesModel(){} + + static const int COLUMN_THREAD_NB_COLUMNS = 0x03; // columns for name, size, percentage completion + +#ifdef TODO + enum Columns { + COLUMN_THREAD_TITLE =0x00, + COLUMN_THREAD_READ =0x01, + COLUMN_THREAD_DATE =0x02, + COLUMN_THREAD_DISTRIBUTION =0x03, + COLUMN_THREAD_AUTHOR =0x04, + COLUMN_THREAD_CONTENT =0x05, + COLUMN_THREAD_MSGID =0x06, + COLUMN_THREAD_DATA =0x07, + }; + + enum Roles{ SortRole = Qt::UserRole+1, + ThreadPinnedRole = Qt::UserRole+2, + MissingRole = Qt::UserRole+3, + StatusRole = Qt::UserRole+4, + UnreadChildrenRole = Qt::UserRole+5, + FilterRole = Qt::UserRole+6, + }; +#endif + +#ifdef TODO + enum SortMode{ SORT_MODE_PUBLISH_TS = 0x00, + SORT_MODE_CHILDREN_PUBLISH_TS = 0x01, + }; +#endif + + QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;} + QModelIndex getIndexOfFile(const RsFileHash& hash) const; + + // This method will asynchroneously update the data + void setFiles(const std::list& files); + +#ifdef TODO + void setSortMode(SortMode mode) ; + + void setTextColorRead (QColor color) { mTextColorRead = color;} + void setTextColorUnread (QColor color) { mTextColorUnread = color;} + void setTextColorUnreadChildren(QColor color) { mTextColorUnreadChildren = color;} + void setTextColorNotSubscribed (QColor color) { mTextColorNotSubscribed = color;} + void setTextColorMissing (QColor color) { mTextColorMissing = color;} + void setFilter(int column, const QStringList &strings, uint32_t &count) ; + void setAuthorOpinion(const QModelIndex& indx,RsOpinion op); +#endif + + // Helper functions + + void clear() ; + + // AbstractItemModel functions. + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; + + QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex& child) const override; + Qt::ItemFlags flags(const QModelIndex& index) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + // Custom item roles + + QVariant sizeHintRole (int col) const; + QVariant displayRole (const RsGxsFile& fmpe, int col) const; + QVariant toolTipRole (const RsGxsFile& fmpe, int col) const; + QVariant userRole (const RsGxsFile& fmpe, int col) const; +#ifdef TODO + QVariant decorationRole(const ForumModelPostEntry& fmpe, int col) const; + QVariant pinnedRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant missingRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant statusRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant authorRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant sortRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant fontRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant filterRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant textColorRole (const ForumModelPostEntry& fmpe, int col) const; + QVariant backgroundRole(const ForumModelPostEntry& fmpe, int col) const; +#endif + + /*! + * \brief debug_dump + * Dumps the hierarchy of posts in the terminal, to allow checking whether the internal representation is correct. + */ + void debug_dump(); + +signals: + void channelLoaded(); // emitted after the posts have been set. Can be used to updated the UI. + +private: +#ifdef TODO + bool mUseChildTS; + bool mFilteringEnabled; + SortMode mSortMode; +#endif + void preMods() ; + void postMods() ; + + quintptr getParentRow(quintptr ref,int& row) const; + quintptr getChildRef(quintptr ref, int index) const; + int getChildrenCount(quintptr ref) const; + bool getFileData(const QModelIndex& i,RsGxsFile& fmpe) const; + + static bool convertTabEntryToRefPointer(uint32_t entry, quintptr& ref); + static bool convertRefPointerToTabEntry(quintptr ref,uint32_t& entry); + +#ifdef TODO + static void generateMissingItem(const RsGxsMessageId &msgId,ChannelPostsModelPostEntry& entry); +#endif + void initEmptyHierarchy(std::vector &files); + + std::vector mFiles ; // store the list of files for the post +}; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 0bd08b9d0..0ba8fc607 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -26,6 +26,7 @@ #include "GxsChannelPostsWidgetWithModel.h" #include "GxsChannelPostsModel.h" +#include "GxsChannelPostFilesModel.h" #include "ui_GxsChannelPostsWidgetWithModel.h" #include "gui/feeds/GxsChannelPostItem.h" #include "gui/gxs/GxsIdDetails.h" @@ -57,7 +58,7 @@ static const int CHANNEL_TABS_POSTS = 1; #define VIEW_MODE_FEEDS 1 #define VIEW_MODE_FILES 2 -Q_DECLARE_METATYPE(RsGxsChannelPost*) +Q_DECLARE_METATYPE(RsGxsFile) void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { @@ -137,6 +138,73 @@ QSize ChannelPostDelegate::sizeHint(const QStyleOptionViewItem& option, const QM return QSize(W+IMAGE_MARGIN_FACTOR*w,H + 2*h); } +void ChannelPostFilesDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const +{ + QString byteUnits[4] = {tr("B"), tr("KB"), tr("MB"), tr("GB")}; + + QStyleOptionViewItem opt = option; + QStyleOptionProgressBarV2 newopt; + QRect pixmapRect; + QPixmap pixmap; + qlonglong fileSize; + double dlspeed, multi; + int seconds,minutes, hours, days; + qlonglong remaining; + QString temp ; + qlonglong completed; + qlonglong downloadtime; + qint64 qi64Value; + + // prepare + painter->save(); + painter->setClipRect(opt.rect); + + RsGxsFile file = index.data(Qt::UserRole).value() ; + + QVariant value = index.data(Qt::TextColorRole); + + if(value.isValid() && qvariant_cast(value).isValid()) + opt.palette.setColor(QPalette::Text, qvariant_cast(value)); + + QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; + + if(option.state & QStyle::State_Selected) + painter->setPen(opt.palette.color(cg, QPalette::HighlightedText)); + else + painter->setPen(opt.palette.color(cg, QPalette::Text)); + + switch(index.column()) + { + case 0: painter->drawText(option.rect,Qt::AlignLeft,QString::fromUtf8(file.mName.c_str())); + break; + case 1: painter->drawText(option.rect,Qt::AlignLeft,QString::number(file.mSize)); + break; + case 2: { + FileInfo finfo; + if(rsFiles->FileDetails(file.mHash,RS_FILE_HINTS_DOWNLOAD,finfo)) + painter->drawText(option.rect,Qt::AlignLeft,QString::number(finfo.transfered)); + } + break; + default: + break; + } +} + +QSize ChannelPostFilesDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + RsGxsFile file = index.data(Qt::UserRole).value() ; + + QFontMetricsF fm(option.font); + + switch(index.column()) + { + case 0: return QSize(fm.width(QString::fromUtf8(file.mName.c_str())),fm.height()); + case 1: return QSize(fm.width(QString::number(file.mSize)),fm.height()); + default: + case 2: return QSize(fm.height() * 20,fm.height()) ; + } +} + /** Constructor */ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupId &channelId, QWidget *parent) : GxsMessageFrameWidget(rsGxsChannels, parent), @@ -145,9 +213,12 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI /* Invoke the Qt Designer generated object setup routine */ ui->setupUi(this); - ui->postsTree->setModel(mThreadModel = new RsGxsChannelPostsModel()); + ui->postsTree->setModel(mChannelPostsModel = new RsGxsChannelPostsModel()); ui->postsTree->setItemDelegate(new ChannelPostDelegate()); + ui->channelPostFiles_TV->setModel(mChannelPostFilesModel = new RsGxsChannelPostFilesModel()); + ui->channelPostFiles_TV->setItemDelegate(new ChannelPostFilesDelegate()); + connect(ui->postsTree->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),this,SLOT(showPostDetails())); /* Setup UI helper */ @@ -220,7 +291,7 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI setAutoDownload(false); settingsChanged(); - mThreadModel->updateChannel(channelId); + mChannelPostsModel->updateChannel(channelId); mEventHandlerId = 0; // Needs to be asynced because this function is called by another thread! @@ -264,13 +335,31 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() if(!index.isValid()) { ui->postDetails_TE->clear(); + ui->postLogo_LB->clear(); + mChannelPostFilesModel->clear(); return; } RsGxsChannelPost post = index.data(Qt::UserRole).value() ; + mChannelPostFilesModel->setFiles(post.mFiles); + std::cerr << "Showing details about selected index : "<< index.row() << "," << index.column() << std::endl; ui->postDetails_TE->setText(RsHtml().formatText(NULL, QString::fromUtf8(post.mMsg.c_str()), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); + + QPixmap postImage; + + if (post.mThumbnail.mData != NULL) + GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, postImage,GxsIdDetails::ORIGINAL); + else + postImage = QPixmap(CHAN_DEFAULT_IMAGE); + + int W = QFontMetricsF(font()).height() * 8; + + // Using fixed width so that the post will not displace the text when we browse. + + ui->postLogo_LB->setPixmap(postImage); + ui->postLogo_LB->setFixedSize(W,postImage.height()/(float)postImage.width()*W); } void GxsChannelPostsWidgetWithModel::updateGroupData() @@ -297,7 +386,7 @@ void GxsChannelPostsWidgetWithModel::updateGroupData() RsQThreadUtils::postToObject( [this,groups]() { mGroup = groups[0]; - mThreadModel->updateChannel(groupId()); + mChannelPostsModel->updateChannel(groupId()); insertChannelDetails(mGroup); } ); }); @@ -328,7 +417,7 @@ void GxsChannelPostsWidgetWithModel::updateDisplay(bool complete) #warning todo //saveExpandedItems(mSavedExpandedMessages); - //if(mGroupId != mThreadModel->currentGroupId()) + //if(mGroupId != mChannelPostsModel->currentGroupId()) // mThreadId.clear(); updateGroupData(); @@ -881,7 +970,7 @@ void GxsChannelPostsWidgetWithModel::blank() mStateHelper->setWidgetEnabled(ui->postButton, false); mStateHelper->setWidgetEnabled(ui->subscribeToolButton, false); - mThreadModel->clear(); + mChannelPostsModel->clear(); groupNameChanged(QString()); //ui->infoWidget->hide(); @@ -1027,3 +1116,4 @@ void GxsChannelPostsWidgetWithModel::setAllMessagesReadDo(bool read, uint32_t &t token = data.mLastToken; } + diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index 246be0715..ca37e3289 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -36,6 +36,21 @@ class GxsChannelPostItem; class QTreeWidgetItem; class FeedItem; class RsGxsChannelPostsModel; +class RsGxsChannelPostFilesModel; + +class ChannelPostFilesDelegate: public QAbstractItemDelegate +{ + Q_OBJECT + + public: + ChannelPostFilesDelegate(QObject *parent=0) : QAbstractItemDelegate(parent){} + virtual ~ChannelPostFilesDelegate(){} + + void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const override; + QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override; + + private: +}; class ChannelPostDelegate: public QAbstractItemDelegate { @@ -137,7 +152,8 @@ private: bool mUseThread; RsEventsHandlerId_t mEventHandlerId ; - RsGxsChannelPostsModel *mThreadModel; + RsGxsChannelPostsModel *mChannelPostsModel; + RsGxsChannelPostFilesModel *mChannelPostFilesModel; UIStateHelper *mStateHelper; /* UI - from Designer */ diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index 5cea1d692..adbe5fb98 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -421,28 +421,70 @@ p, li { white-space: pre-wrap; } + + + true + + - 2 + 1 Details - - - - 9 - 9 - 955 - 181 - - - + + + + + + + TextLabel + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + - + Files + + + + + + + + Download selected files + + + + diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 8a1133e02..69dfc6b85 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -1335,6 +1335,7 @@ gxschannels { gui/gxschannels/GxsChannelPostsWidget.h \ gui/gxschannels/GxsChannelPostsWidgetWithModel.h \ gui/gxschannels/GxsChannelPostsModel.h \ + gui/gxschannels/GxsChannelPostFilesModel.h \ gui/gxschannels/GxsChannelFilesWidget.h \ gui/gxschannels/GxsChannelFilesStatusWidget.h \ gui/feeds/GxsChannelGroupItem.h \ @@ -1354,6 +1355,7 @@ gxschannels { gui/gxschannels/GxsChannelPostsWidget.cpp \ gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp \ gui/gxschannels/GxsChannelPostsModel.cpp \ + gui/gxschannels/GxsChannelPostFilesModel.cpp \ gui/gxschannels/GxsChannelFilesWidget.cpp \ gui/gxschannels/GxsChannelFilesStatusWidget.cpp \ gui/gxschannels/GxsChannelGroupDialog.cpp \ From b9c41b31d407ac926accef5b84eb2dc73f6f7a46 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 5 Jun 2020 17:34:56 +0200 Subject: [PATCH 031/154] added QStyledItemDelegate based on ChannelFilesStatusWidget. Not working yet. --- .../GxsChannelFilesStatusWidget.cpp | 4 +- .../gxschannels/GxsChannelFilesStatusWidget.h | 2 +- .../gui/gxschannels/GxsChannelFilesWidget.cpp | 2 +- .../GxsChannelPostsWidgetWithModel.cpp | 69 +++++++++++++++---- .../GxsChannelPostsWidgetWithModel.h | 10 ++- .../GxsChannelPostsWidgetWithModel.ui | 27 +++++++- 6 files changed, 93 insertions(+), 21 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.cpp index 6dfe8a673..c28601fed 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.cpp @@ -30,8 +30,8 @@ #include "retroshare/rsfiles.h" -GxsChannelFilesStatusWidget::GxsChannelFilesStatusWidget(const RsGxsGroupId &groupId, const RsGxsMessageId &messageId, const RsGxsFile &file, QWidget *parent) : - QWidget(parent), mGroupId(groupId), mMessageId(messageId), mFile(file), ui(new Ui::GxsChannelFilesStatusWidget) +GxsChannelFilesStatusWidget::GxsChannelFilesStatusWidget(const RsGxsFile &file, QWidget *parent) : + QWidget(parent), mFile(file), ui(new Ui::GxsChannelFilesStatusWidget) { ui->setupUi(this); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.h b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.h index 1fc24437f..3d58cc4d7 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.h @@ -34,7 +34,7 @@ class GxsChannelFilesStatusWidget : public QWidget Q_OBJECT public: - explicit GxsChannelFilesStatusWidget(const RsGxsGroupId &groupId, const RsGxsMessageId &messageId, const RsGxsFile &file, QWidget *parent = 0); + explicit GxsChannelFilesStatusWidget(const RsGxsFile &file, QWidget *parent = 0); ~GxsChannelFilesStatusWidget(); private slots: diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesWidget.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesWidget.cpp index 5ae905cea..6a975df64 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesWidget.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesWidget.cpp @@ -113,7 +113,7 @@ void GxsChannelFilesWidget::addFiles(const RsGxsChannelPost& post, bool related) ui->treeWidget->addTopLevelItem(treeItem); - QWidget *statusWidget = new GxsChannelFilesStatusWidget(post.mMeta.mGroupId, post.mMeta.mMsgId, file); + QWidget *statusWidget = new GxsChannelFilesStatusWidget(file); ui->treeWidget->setItemWidget(treeItem, COLUMN_STATUS, statusWidget); filterItem(treeItem); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 0ba8fc607..2865e2649 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -24,12 +24,10 @@ #include "retroshare/rsgxscircles.h" -#include "GxsChannelPostsWidgetWithModel.h" -#include "GxsChannelPostsModel.h" -#include "GxsChannelPostFilesModel.h" #include "ui_GxsChannelPostsWidgetWithModel.h" #include "gui/feeds/GxsChannelPostItem.h" #include "gui/gxs/GxsIdDetails.h" +#include "util/misc.h" #include "gui/gxschannels/CreateGxsChannelMsg.h" #include "gui/common/UIStateHelper.h" #include "gui/settings/rsharesettings.h" @@ -40,6 +38,11 @@ #include "util/DateTime.h" #include "util/qtthreadsutils.h" +#include "GxsChannelPostsWidgetWithModel.h" +#include "GxsChannelPostsModel.h" +#include "GxsChannelPostFilesModel.h" +#include "GxsChannelFilesStatusWidget.h" + #include #define CHAN_DEFAULT_IMAGE ":/icons/png/channels.png" @@ -51,6 +54,7 @@ ***/ static const int mTokenTypeGroupData = 1; + static const int CHANNEL_TABS_DETAILS= 0; static const int CHANNEL_TABS_POSTS = 1; @@ -58,6 +62,10 @@ static const int CHANNEL_TABS_POSTS = 1; #define VIEW_MODE_FEEDS 1 #define VIEW_MODE_FILES 2 +#define CHANNEL_FILES_COLUMN_NAME 0 +#define CHANNEL_FILES_COLUMN_SIZE 1 +#define CHANNEL_FILES_COLUMN_FILE 2 + Q_DECLARE_METATYPE(RsGxsFile) void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const @@ -138,8 +146,31 @@ QSize ChannelPostDelegate::sizeHint(const QStyleOptionViewItem& option, const QM return QSize(W+IMAGE_MARGIN_FACTOR*w,H + 2*h); } +QWidget *ChannelPostFilesDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex& index) const +{ + RsGxsFile file = index.data(Qt::UserRole).value() ; + + if(index.column() == CHANNEL_FILES_COLUMN_FILE) + return new GxsChannelFilesStatusWidget(file,parent); + else + return NULL; +} +void ChannelPostFilesDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const +{ + editor->setGeometry(option.rect); +} + +void ChannelPostFilesDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const +{ + // nothing to do here. Is this override needed? +} + void ChannelPostFilesDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { + RsGxsFile file = index.data(Qt::UserRole).value() ; + +#ifdef TODO + QString byteUnits[4] = {tr("B"), tr("KB"), tr("MB"), tr("GB")}; QStyleOptionViewItem opt = option; @@ -154,13 +185,14 @@ void ChannelPostFilesDelegate::paint(QPainter * painter, const QStyleOptionViewI qlonglong completed; qlonglong downloadtime; qint64 qi64Value; +#endif // prepare painter->save(); - painter->setClipRect(opt.rect); + painter->setClipRect(option.rect); +#ifdef TODO RsGxsFile file = index.data(Qt::UserRole).value() ; - QVariant value = index.data(Qt::TextColorRole); if(value.isValid() && qvariant_cast(value).isValid()) @@ -172,21 +204,32 @@ void ChannelPostFilesDelegate::paint(QPainter * painter, const QStyleOptionViewI painter->setPen(opt.palette.color(cg, QPalette::HighlightedText)); else painter->setPen(opt.palette.color(cg, QPalette::Text)); +#endif switch(index.column()) { - case 0: painter->drawText(option.rect,Qt::AlignLeft,QString::fromUtf8(file.mName.c_str())); + case CHANNEL_FILES_COLUMN_NAME: painter->drawText(option.rect,Qt::AlignLeft | Qt::AlignVCenter,QString::fromUtf8(file.mName.c_str())); break; - case 1: painter->drawText(option.rect,Qt::AlignLeft,QString::number(file.mSize)); + case CHANNEL_FILES_COLUMN_SIZE: painter->drawText(option.rect,Qt::AlignLeft | Qt::AlignVCenter,misc::friendlyUnit(qulonglong(file.mSize))); break; - case 2: { + case CHANNEL_FILES_COLUMN_FILE: { + GxsChannelFilesStatusWidget w(file); + QPixmap pixmap(w.size()); + + w.render(&pixmap); + painter->drawPixmap(option.rect.topLeft(),pixmap); + +#ifdef TODO FileInfo finfo; if(rsFiles->FileDetails(file.mHash,RS_FILE_HINTS_DOWNLOAD,finfo)) painter->drawText(option.rect,Qt::AlignLeft,QString::number(finfo.transfered)); +#endif } - break; - default: break; + + default: + painter->drawText(option.rect,Qt::AlignLeft,QString("[No data]")); + break; } } @@ -198,10 +241,10 @@ QSize ChannelPostFilesDelegate::sizeHint(const QStyleOptionViewItem& option, con switch(index.column()) { - case 0: return QSize(fm.width(QString::fromUtf8(file.mName.c_str())),fm.height()); - case 1: return QSize(fm.width(QString::number(file.mSize)),fm.height()); + case CHANNEL_FILES_COLUMN_NAME: return QSize(fm.width(QString::fromUtf8(file.mName.c_str())),fm.height()); + case CHANNEL_FILES_COLUMN_SIZE: return QSize(fm.width(misc::friendlyUnit(qulonglong(file.mSize))),fm.height()); default: - case 2: return QSize(fm.height() * 20,fm.height()) ; + case CHANNEL_FILES_COLUMN_FILE: return GxsChannelFilesStatusWidget(file).size(); } } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index ca37e3289..aee073b09 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -23,7 +23,7 @@ #include -#include +#include #include "gui/gxs/GxsMessageFramePostWidget.h" #include "gui/feeds/FeedHolder.h" @@ -38,17 +38,21 @@ class FeedItem; class RsGxsChannelPostsModel; class RsGxsChannelPostFilesModel; -class ChannelPostFilesDelegate: public QAbstractItemDelegate +class ChannelPostFilesDelegate: public QStyledItemDelegate { Q_OBJECT public: - ChannelPostFilesDelegate(QObject *parent=0) : QAbstractItemDelegate(parent){} + ChannelPostFilesDelegate(QObject *parent=0) : QStyledItemDelegate(parent){} virtual ~ChannelPostFilesDelegate(){} void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const override; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override; + void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const override; + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + void setEditorData(QWidget *editor, const QModelIndex &index) const override; + private: }; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index adbe5fb98..b6dfb43d5 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -413,9 +413,27 @@ p, li { white-space: pre-wrap; } Qt::Vertical
+ + QAbstractScrollArea::AdjustToContents + QAbstractItemView::SelectItems + + 0 + + + false + + + false + + + true + + + true + false @@ -475,7 +493,14 @@ p, li { white-space: pre-wrap; } - + + + QAbstractItemView::CurrentChanged + + + true + + From d39c47613141efb5ab367a1c012afe9fc2d1d7d8 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 5 Jun 2020 18:07:33 +0200 Subject: [PATCH 032/154] fixed entering editing event. --- .../gxschannels/GxsChannelPostFilesModel.cpp | 26 ++++++++++++++++--- .../gxschannels/GxsChannelPostFilesModel.h | 17 +++++------- .../GxsChannelPostsWidgetWithModel.cpp | 18 +++++-------- .../GxsChannelPostsWidgetWithModel.ui | 9 +------ 4 files changed, 36 insertions(+), 34 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp index 9098af57b..17554a632 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp @@ -65,7 +65,7 @@ void RsGxsChannelPostFilesModel::postMods() { endResetModel(); - emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mFiles.size(),COLUMN_THREAD_NB_COLUMNS-1,(void*)NULL)); + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mFiles.size(),COLUMN_FILES_NB_COLUMNS-1,(void*)NULL)); } #ifdef TODO @@ -107,7 +107,7 @@ int RsGxsChannelPostFilesModel::rowCount(const QModelIndex& parent) const int RsGxsChannelPostFilesModel::columnCount(const QModelIndex &/*parent*/) const { - return COLUMN_THREAD_NB_COLUMNS ; + return COLUMN_FILES_NB_COLUMNS ; } // std::vector > RsGxsChannelPostsModel::getPostVersions(const RsGxsMessageId& mid) const @@ -175,7 +175,7 @@ bool RsGxsChannelPostFilesModel::convertRefPointerToTabEntry(quintptr ref, uint3 QModelIndex RsGxsChannelPostFilesModel::index(int row, int column, const QModelIndex & parent) const { - if(row < 0 || column < 0 || column >= COLUMN_THREAD_NB_COLUMNS) + if(row < 0 || column < 0 || column >= COLUMN_FILES_NB_COLUMNS) return QModelIndex(); quintptr ref = getChildRef(parent.internalId(),row); @@ -199,7 +199,10 @@ Qt::ItemFlags RsGxsChannelPostFilesModel::flags(const QModelIndex& index) const if (!index.isValid()) return 0; - return QAbstractItemModel::flags(index); + if(index.column() == COLUMN_FILES_FILE) + return QAbstractItemModel::flags(index) | Qt::ItemIsEditable; + else + return QAbstractItemModel::flags(index); } quintptr RsGxsChannelPostFilesModel::getChildRef(quintptr ref,int index) const @@ -258,6 +261,21 @@ int RsGxsChannelPostFilesModel::getChildrenCount(quintptr ref) const return 0; } +QVariant RsGxsChannelPostFilesModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + switch(section) + { + case COLUMN_FILES_FILE: return QString("Status"); + case COLUMN_FILES_SIZE: return QString("Size"); + case COLUMN_FILES_NAME: return QString("File"); + default: + return QString("[No data]"); + } +} + QVariant RsGxsChannelPostFilesModel::data(const QModelIndex &index, int role) const { #ifdef DEBUG_CHANNEL_MODEL diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h index f42007bdb..111906e64 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h @@ -44,20 +44,14 @@ public: explicit RsGxsChannelPostFilesModel(QObject *parent = NULL); ~RsGxsChannelPostFilesModel(){} - static const int COLUMN_THREAD_NB_COLUMNS = 0x03; // columns for name, size, percentage completion - -#ifdef TODO enum Columns { - COLUMN_THREAD_TITLE =0x00, - COLUMN_THREAD_READ =0x01, - COLUMN_THREAD_DATE =0x02, - COLUMN_THREAD_DISTRIBUTION =0x03, - COLUMN_THREAD_AUTHOR =0x04, - COLUMN_THREAD_CONTENT =0x05, - COLUMN_THREAD_MSGID =0x06, - COLUMN_THREAD_DATA =0x07, + COLUMN_FILES_NAME = 0x00, + COLUMN_FILES_SIZE = 0x01, + COLUMN_FILES_FILE = 0x02, + COLUMN_FILES_NB_COLUMNS = 0x03 }; +#ifdef TODO enum Roles{ SortRole = Qt::UserRole+1, ThreadPinnedRole = Qt::UserRole+2, MissingRole = Qt::UserRole+3, @@ -106,6 +100,7 @@ public: Qt::ItemFlags flags(const QModelIndex& index) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; // Custom item roles diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 2865e2649..4e5ea5077 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -62,10 +62,6 @@ static const int CHANNEL_TABS_POSTS = 1; #define VIEW_MODE_FEEDS 1 #define VIEW_MODE_FILES 2 -#define CHANNEL_FILES_COLUMN_NAME 0 -#define CHANNEL_FILES_COLUMN_SIZE 1 -#define CHANNEL_FILES_COLUMN_FILE 2 - Q_DECLARE_METATYPE(RsGxsFile) void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const @@ -150,7 +146,7 @@ QWidget *ChannelPostFilesDelegate::createEditor(QWidget *parent, const QStyleOpt { RsGxsFile file = index.data(Qt::UserRole).value() ; - if(index.column() == CHANNEL_FILES_COLUMN_FILE) + if(index.column() == RsGxsChannelPostFilesModel::COLUMN_FILES_FILE) return new GxsChannelFilesStatusWidget(file,parent); else return NULL; @@ -208,11 +204,11 @@ void ChannelPostFilesDelegate::paint(QPainter * painter, const QStyleOptionViewI switch(index.column()) { - case CHANNEL_FILES_COLUMN_NAME: painter->drawText(option.rect,Qt::AlignLeft | Qt::AlignVCenter,QString::fromUtf8(file.mName.c_str())); + case RsGxsChannelPostFilesModel::COLUMN_FILES_NAME: painter->drawText(option.rect,Qt::AlignLeft | Qt::AlignVCenter,QString::fromUtf8(file.mName.c_str())); break; - case CHANNEL_FILES_COLUMN_SIZE: painter->drawText(option.rect,Qt::AlignLeft | Qt::AlignVCenter,misc::friendlyUnit(qulonglong(file.mSize))); + case RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE: painter->drawText(option.rect,Qt::AlignRight | Qt::AlignVCenter,misc::friendlyUnit(qulonglong(file.mSize))); break; - case CHANNEL_FILES_COLUMN_FILE: { + case RsGxsChannelPostFilesModel::COLUMN_FILES_FILE: { GxsChannelFilesStatusWidget w(file); QPixmap pixmap(w.size()); @@ -241,10 +237,10 @@ QSize ChannelPostFilesDelegate::sizeHint(const QStyleOptionViewItem& option, con switch(index.column()) { - case CHANNEL_FILES_COLUMN_NAME: return QSize(fm.width(QString::fromUtf8(file.mName.c_str())),fm.height()); - case CHANNEL_FILES_COLUMN_SIZE: return QSize(fm.width(misc::friendlyUnit(qulonglong(file.mSize))),fm.height()); + case RsGxsChannelPostFilesModel::COLUMN_FILES_NAME: return QSize(fm.width(QString::fromUtf8(file.mName.c_str())),fm.height()); + case RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE: return QSize(fm.width(misc::friendlyUnit(qulonglong(file.mSize))),fm.height()); default: - case CHANNEL_FILES_COLUMN_FILE: return GxsChannelFilesStatusWidget(file).size(); + case RsGxsChannelPostFilesModel::COLUMN_FILES_FILE: return GxsChannelFilesStatusWidget(file).size(); } } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index b6dfb43d5..18e59ff2e 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -495,20 +495,13 @@ p, li { white-space: pre-wrap; } - QAbstractItemView::CurrentChanged + QAbstractItemView::CurrentChanged|QAbstractItemView::SelectedClicked true - - - - Download selected files - - - From facad382cf319d6abaa4fb512b401076eaf8ff76 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 5 Jun 2020 22:43:43 +0200 Subject: [PATCH 033/154] fixed a few UI glitches --- .../gxschannels/GxsChannelPostFilesModel.cpp | 39 ++++++----------- .../gxschannels/GxsChannelPostFilesModel.h | 7 +++ .../GxsChannelPostsWidgetWithModel.cpp | 43 ++++++++++++------- .../GxsChannelPostsWidgetWithModel.h | 3 -- .../GxsChannelPostsWidgetWithModel.ui | 19 ++++++++ 5 files changed, 67 insertions(+), 44 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp index 17554a632..ab20c2fd8 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp @@ -43,6 +43,9 @@ RsGxsChannelPostFilesModel::RsGxsChannelPostFilesModel(QObject *parent) : QAbstractItemModel(parent) { initEmptyHierarchy(mFiles); + + mTimer = new QTimer; + connect(mTimer,SIGNAL(timeout()),this,SLOT(update())); } void RsGxsChannelPostFilesModel::initEmptyHierarchy(std::vector& files) @@ -68,6 +71,11 @@ void RsGxsChannelPostFilesModel::postMods() emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mFiles.size(),COLUMN_FILES_NB_COLUMNS-1,(void*)NULL)); } +void RsGxsChannelPostFilesModel::update() +{ + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mFiles.size(),COLUMN_FILES_NB_COLUMNS-1,(void*)NULL)); +} + #ifdef TODO void RsGxsChannelPostsModel::setSortMode(SortMode mode) { @@ -694,34 +702,13 @@ void RsGxsChannelPostFilesModel::setFiles(const std::list& files) postMods(); emit channelLoaded(); + + if(!files.empty()) + mTimer->start(5000); + else + mTimer->stop(); } -//ChannelPostsModelIndex RsGxsChannelPostsModel::addEntry(std::vector& posts,const ChannelPostsModelPostEntry& entry) -//{ -// uint32_t N = posts.size(); -// posts.push_back(entry); -// -//#ifdef DEBUG_FORUMMODEL -// std::cerr << "Added new entry " << N << " children of " << parent << std::endl; -//#endif -// if(N == parent) -// std::cerr << "(EE) trying to add a post as its own parent!" << std::endl; -// -// return ChannelPostsModelIndex(N); -//} - -//void RsGxsChannelPostsModel::convertMsgToPostEntry(const RsGxsChannelGroup& mChannelGroup,const RsMsgMetaData& msg, bool /*useChildTS*/, ChannelPostsModelPostEntry& fentry) -//{ -// fentry.mTitle = msg.mMsgName; -// fentry.mMsgId = msg.mMsgId; -// fentry.mPublishTs = msg.mPublishTs; -// fentry.mPostFlags = 0; -// fentry.mMsgStatus = msg.mMsgStatus; -// -// // Early check for a message that should be hidden because its author -// // is flagged with a bad reputation -//} - QModelIndex RsGxsChannelPostFilesModel::getIndexOfFile(const RsFileHash& hash) const { // Brutal search. This is not so nice, so dont call that in a loop! If too costly, we'll use a map. diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h index 111906e64..873f179e8 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h @@ -34,6 +34,8 @@ typedef uint32_t ChannelPostFilesModelIndex; +class QTimer; + // This class is the item model used by Qt to display the information class RsGxsChannelPostFilesModel : public QAbstractItemModel @@ -130,6 +132,9 @@ public: signals: void channelLoaded(); // emitted after the posts have been set. Can be used to updated the UI. +private slots: + void update(); + private: #ifdef TODO bool mUseChildTS; @@ -153,4 +158,6 @@ private: void initEmptyHierarchy(std::vector &files); std::vector mFiles ; // store the list of files for the post + + QTimer *mTimer; }; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 4e5ea5077..d0dc70e96 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -156,11 +156,6 @@ void ChannelPostFilesDelegate::updateEditorGeometry(QWidget *editor, const QStyl editor->setGeometry(option.rect); } -void ChannelPostFilesDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const -{ - // nothing to do here. Is this override needed? -} - void ChannelPostFilesDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { RsGxsFile file = index.data(Qt::UserRole).value() ; @@ -187,6 +182,12 @@ void ChannelPostFilesDelegate::paint(QPainter * painter, const QStyleOptionViewI painter->save(); painter->setClipRect(option.rect); + painter->save(); + + painter->fillRect( option.rect, option.backgroundBrush); + //optionFocusRect.backgroundColor = option.palette.color(colorgroup, (option.state & QStyle::State_Selected) ? QPalette::Highlight : QPalette::Background); + painter->restore(); + #ifdef TODO RsGxsFile file = index.data(Qt::UserRole).value() ; QVariant value = index.data(Qt::TextColorRole); @@ -194,25 +195,30 @@ void ChannelPostFilesDelegate::paint(QPainter * painter, const QStyleOptionViewI if(value.isValid() && qvariant_cast(value).isValid()) opt.palette.setColor(QPalette::Text, qvariant_cast(value)); - QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; + QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) ? QPalette::Normal : QPalette::Disabled; if(option.state & QStyle::State_Selected) - painter->setPen(opt.palette.color(cg, QPalette::HighlightedText)); + painter->setPen(option.palette.color(cg, QPalette::HighlightedText)); else - painter->setPen(opt.palette.color(cg, QPalette::Text)); + painter->setPen(option.palette.color(cg, QPalette::Text)); #endif switch(index.column()) { - case RsGxsChannelPostFilesModel::COLUMN_FILES_NAME: painter->drawText(option.rect,Qt::AlignLeft | Qt::AlignVCenter,QString::fromUtf8(file.mName.c_str())); + case RsGxsChannelPostFilesModel::COLUMN_FILES_NAME: painter->drawText(option.rect,Qt::AlignLeft | Qt::AlignVCenter," " + QString::fromUtf8(file.mName.c_str())); break; case RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE: painter->drawText(option.rect,Qt::AlignRight | Qt::AlignVCenter,misc::friendlyUnit(qulonglong(file.mSize))); break; case RsGxsChannelPostFilesModel::COLUMN_FILES_FILE: { - GxsChannelFilesStatusWidget w(file); - QPixmap pixmap(w.size()); - w.render(&pixmap); + GxsChannelFilesStatusWidget w(file); + + w.setFixedWidth(option.rect.width()); + + QPixmap pixmap(w.size()); + pixmap.fill(option.palette.color(QPalette::Background)); // choose the background + w.render(&pixmap,QPoint(),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background + painter->drawPixmap(option.rect.topLeft(),pixmap); #ifdef TODO @@ -237,10 +243,10 @@ QSize ChannelPostFilesDelegate::sizeHint(const QStyleOptionViewItem& option, con switch(index.column()) { - case RsGxsChannelPostFilesModel::COLUMN_FILES_NAME: return QSize(fm.width(QString::fromUtf8(file.mName.c_str())),fm.height()); - case RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE: return QSize(fm.width(misc::friendlyUnit(qulonglong(file.mSize))),fm.height()); + case RsGxsChannelPostFilesModel::COLUMN_FILES_NAME: return QSize(1.1*fm.width(QString::fromUtf8(file.mName.c_str())),fm.height()); + case RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE: return QSize(1.1*fm.width(misc::friendlyUnit(qulonglong(file.mSize))),fm.height()); default: - case RsGxsChannelPostFilesModel::COLUMN_FILES_FILE: return GxsChannelFilesStatusWidget(file).size(); + case RsGxsChannelPostFilesModel::COLUMN_FILES_FILE: return QSize(option.rect.width(),GxsChannelFilesStatusWidget(file).height()); } } @@ -398,7 +404,14 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() // Using fixed width so that the post will not displace the text when we browse. ui->postLogo_LB->setPixmap(postImage); + ui->postName_LB->setText(QString::fromUtf8(post.mMeta.mMsgName.c_str())); + ui->postLogo_LB->setFixedSize(W,postImage.height()/(float)postImage.width()*W); + ui->postName_LB->setFixedWidth(W); + + ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE); + ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); + ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_NAME); } void GxsChannelPostsWidgetWithModel::updateGroupData() diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index aee073b09..1aa555caf 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -51,9 +51,6 @@ class ChannelPostFilesDelegate: public QStyledItemDelegate void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const override; QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; - void setEditorData(QWidget *editor, const QModelIndex &index) const override; - - private: }; class ChannelPostDelegate: public QAbstractItemDelegate diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index 18e59ff2e..0332379b0 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -465,6 +465,19 @@ p, li { white-space: pre-wrap; } Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + true + + + + + + + TextLabel + + + true + @@ -500,6 +513,12 @@ p, li { white-space: pre-wrap; } true + + 5 + + + false + From 89fc77ef8e3af4a520ab5ca65fc5ec575d491f35 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 5 Jun 2020 22:47:29 +0200 Subject: [PATCH 034/154] fixed bug causing crash when clicking on non channel entries --- .../src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index d0dc70e96..d3f952e96 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -1019,8 +1019,8 @@ void GxsChannelPostsWidget::clearPosts() void GxsChannelPostsWidgetWithModel::blank() { - mStateHelper->setWidgetEnabled(ui->postButton, false); - mStateHelper->setWidgetEnabled(ui->subscribeToolButton, false); + ui->postButton->setEnabled(false); + ui->subscribeToolButton->setEnabled(false); mChannelPostsModel->clear(); groupNameChanged(QString()); From 508ff090ba65fa7441ac57c9ecfff79b5a045a3a Mon Sep 17 00:00:00 2001 From: defnax Date: Sat, 6 Jun 2020 00:13:39 +0200 Subject: [PATCH 035/154] update to use FilesDefs --- retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp b/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp index 4b3ddf5e8..4f1605c46 100644 --- a/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp +++ b/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp @@ -51,6 +51,7 @@ #include "gui/gxs/GxsIdTreeWidgetItem.h" #include "gui/Identity/IdDialog.h" #include "gui/MainWindow.h" +#include "gui/common/FilesDefs.h" #define COL_PENDING_ID 0 #define COL_PENDING_DESTINATION 1 @@ -145,7 +146,7 @@ void GxsTransportStatistics::CustomPopupMenu( QPoint ) QTreeWidgetItem *item = treeWidget->currentItem(); if (item) { - contextMnu.addAction(QIcon(":/images/info16.png"), tr("Details"), this, SLOT(personDetails())); + contextMnu.addAction(FilesDefs::getIconFromQtResourcePath(":/images/info16.png"), tr("View details"), this, SLOT(personDetails())); } @@ -158,7 +159,7 @@ void GxsTransportStatistics::CustomPopupMenuGroups( QPoint ) QTreeWidgetItem *item = groupTreeWidget->currentItem(); if (item) { - contextMnu.addAction(QIcon(":/images/info16.png"), tr("View details"), this, SLOT(showAuthorInPeople())); + contextMnu.addAction(FilesDefs::getIconFromQtResourcePath(":/images/info16.png"), tr("View details"), this, SLOT(showAuthorInPeople())); } From 4148e3c8db79097363d15f8f20abb04a3729b730 Mon Sep 17 00:00:00 2001 From: defnax Date: Sat, 6 Jun 2020 00:31:04 +0200 Subject: [PATCH 036/154] update to use FilesDefs --- retroshare-gui/src/gui/Posted/PostedCardView.cpp | 2 +- retroshare-gui/src/gui/Posted/PostedItem.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/Posted/PostedCardView.cpp b/retroshare-gui/src/gui/Posted/PostedCardView.cpp index 75a01557a..0aafaeeb5 100644 --- a/retroshare-gui/src/gui/Posted/PostedCardView.cpp +++ b/retroshare-gui/src/gui/Posted/PostedCardView.cpp @@ -192,7 +192,7 @@ void PostedCardView::fill() ui->dateLabel->setText(timestamp); } else { - QPixmap sqpixmap2 = QPixmap(":/images/thumb-default.png"); + QPixmap sqpixmap2 = FilesDefs::getPixmapFromQtResourcePath(":/images/thumb-default.png"); mInFill = true; int desired_height = 1.5*(ui->voteDownButton->height() + ui->voteUpButton->height() + ui->scoreLabel->height()); diff --git a/retroshare-gui/src/gui/Posted/PostedItem.cpp b/retroshare-gui/src/gui/Posted/PostedItem.cpp index 46de8a1e6..b4cfa2d4a 100644 --- a/retroshare-gui/src/gui/Posted/PostedItem.cpp +++ b/retroshare-gui/src/gui/Posted/PostedItem.cpp @@ -501,7 +501,7 @@ void PostedItem::fill() RetroShareLink link = RetroShareLink::createGxsGroupLink(RetroShareLink::TYPE_POSTED, mGroupMeta.mGroupId, groupName()); ui->nameLabel->setText(link.toHtml()); - QPixmap sqpixmap2 = QPixmap(":/images/thumb-default.png"); + QPixmap sqpixmap2 = FilesDefs::getPixmapFromQtResourcePath(":/images/thumb-default.png"); mInFill = true; int desired_height = 1.5*(ui->voteDownButton->height() + ui->voteUpButton->height() + ui->scoreLabel->height()); From 3106157ab0a2f371166ff7617d5582ae8fc40598 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 6 Jun 2020 13:58:14 +0200 Subject: [PATCH 037/154] fixed layout for thumbnails --- .../GxsChannelPostsWidgetWithModel.cpp | 102 +++++++++++++++--- .../GxsChannelPostsWidgetWithModel.h | 1 - .../GxsChannelPostsWidgetWithModel.ui | 3 + 3 files changed, 91 insertions(+), 15 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index d3f952e96..fd9ddedff 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -61,11 +61,59 @@ static const int CHANNEL_TABS_POSTS = 1; /* View mode */ #define VIEW_MODE_FEEDS 1 #define VIEW_MODE_FILES 2 +#define COLUMN_SIZE_FONT_FACTOR_W 6 +#define COLUMN_SIZE_FONT_FACTOR_H 12 Q_DECLARE_METATYPE(RsGxsFile) +// Class to paint the thumbnails with title + +class ThumbnailView: public QWidget +{ +public: + ThumbnailView(const RsGxsChannelPost& post,QWidget *parent=NULL) + : QWidget(parent) + { + QVBoxLayout *layout = new QVBoxLayout(this); + + QLabel *lb = new QLabel(this); + lb->setScaledContents(true); + layout->addWidget(lb); + + QLabel *lt = new QLabel(this); + layout->addWidget(lt); + + setLayout(layout); + + setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding); + + // now fill the data + + QPixmap thumbnail; + GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL); + + lb->setPixmap(thumbnail); + + QFontMetricsF fm(font()); + int W = 8 * fm.height() ; + int H = 12 * fm.height() ; + + lb->setFixedSize(W,H); + + lt->setText(QString::fromUtf8(post.mMeta.mMsgName.c_str())); + lt->setMaximumWidth(W); + lt->setWordWrap(true); + + adjustSize(); + update(); + } +}; + +// Delegate used to paint into the table of thumbnails + void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { +#ifdef TODO QString byteUnits[4] = {tr("B"), tr("KB"), tr("MB"), tr("GB")}; QStyleOptionViewItem opt = option; QStyleOptionProgressBarV2 newopt; @@ -79,14 +127,16 @@ void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & qlonglong completed; qlonglong downloadtime; qint64 qi64Value; +#endif // prepare painter->save(); - painter->setClipRect(opt.rect); + painter->setClipRect(option.rect); RsGxsChannelPost post = index.data(Qt::UserRole).value() ; //const RsGxsChannelPost& post(*pinfo); +#ifdef TODO QVariant value = index.data(Qt::TextColorRole); if(value.isValid() && qvariant_cast(value).isValid()) @@ -122,12 +172,42 @@ void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & painter->drawPixmap(QRect(opt.rect.topLeft() + img_pos,opt.rect.topLeft()+img_pos+img_size),thumbnail.scaled(W,H,Qt::KeepAspectRatio,Qt::SmoothTransformation)); painter->drawText(QRect(option.rect.topLeft() + txt_pos,option.rect.bottomRight()),Qt::AlignCenter,QString::fromStdString(post.mMeta.mMsgName)); +#endif + + painter->save(); + painter->fillRect( option.rect, option.backgroundBrush); + painter->restore(); + + ThumbnailView w(post); + + //w.setFixedWidth(option.rect.width()); + + QPixmap pixmap(w.size()); + pixmap.fill(option.palette.color(QPalette::Background)); // choose the background + w.render(&pixmap,QPoint(),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background + + // debug + if(index.row()==0 && index.column()==0) + { + QFile file("yourFile.png"); + file.open(QIODevice::WriteOnly); + pixmap.save(&file, "PNG"); + std::cerr << "Saved pxmap to png" << std::endl; + } + std::cerr << "option.rect = " << option.rect.width() << "x" << option.rect.height() << ". fm.height()=" << QFontMetricsF(option.font).height() << std::endl; + painter->drawPixmap(option.rect.topLeft(), + pixmap.scaled(option.rect.width(),option.rect.width()*w.height()/(float)w.width(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation)); } QSize ChannelPostDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { - RsGxsChannelPost post = index.data(Qt::UserRole).value() ; + // This is the only place where we actually set the size of cells + QFontMetricsF fm(option.font); + + return QSize(COLUMN_SIZE_FONT_FACTOR_W*fm.height(),COLUMN_SIZE_FONT_FACTOR_H*fm.height()); + +#ifdef TODO //QPixmap thumbnail; //GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL); @@ -140,6 +220,7 @@ QSize ChannelPostDelegate::sizeHint(const QStyleOptionViewItem& option, const QM int w = fm.width("X") ; return QSize(W+IMAGE_MARGIN_FACTOR*w,H + 2*h); +#endif } QWidget *ChannelPostFilesDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex& index) const @@ -266,20 +347,13 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI connect(ui->postsTree->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),this,SLOT(showPostDetails())); + QFontMetricsF fm(font()); + + for(int i=0;icolumnCount();++i) + ui->postsTree->setColumnWidth(i,COLUMN_SIZE_FONT_FACTOR_W*fm.height()); + /* Setup UI helper */ - //mStateHelper->addWidget(mTokenTypeAllPosts, ui->progressBar, UISTATE_LOADING_VISIBLE); - //mStateHelper->addWidget(mTokenTypeAllPosts, ui->loadingLabel, UISTATE_LOADING_VISIBLE); - //mStateHelper->addWidget(mTokenTypeAllPosts, ui->filterLineEdit); - - //mStateHelper->addWidget(mTokenTypePosts, ui->loadingLabel, UISTATE_LOADING_VISIBLE); - - //mStateHelper->addLoadPlaceholder(mTokenTypeGroupData, ui->nameLabel); - - //mStateHelper->addWidget(mTokenTypeGroupData, ui->postButton); - //mStateHelper->addWidget(mTokenTypeGroupData, ui->logoLabel); - //mStateHelper->addWidget(mTokenTypeGroupData, ui->subscribeToolButton); - /* Connect signals */ connect(ui->postButton, SIGNAL(clicked()), this, SLOT(createMsg())); connect(ui->subscribeToolButton, SIGNAL(subscribe(bool)), this, SLOT(subscribeGroup(bool))); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index 1aa555caf..51bc79b6b 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -155,7 +155,6 @@ private: RsGxsChannelPostsModel *mChannelPostsModel; RsGxsChannelPostFilesModel *mChannelPostFilesModel; - UIStateHelper *mStateHelper; /* UI - from Designer */ Ui::GxsChannelPostsWidgetWithModel *ui; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index 0332379b0..66c4d4ba3 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -419,6 +419,9 @@ p, li { white-space: pre-wrap; } QAbstractItemView::SelectItems + + Qt::ElideNone + 0 From 129ffdd6c5021a1eb358dcc3e8f29e0b16e0906c Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 6 Jun 2020 19:07:03 +0200 Subject: [PATCH 038/154] fixed auto-layout of thumbnails --- retroshare-gui/src/gui/common/RSTreeView.cpp | 6 ++ retroshare-gui/src/gui/common/RSTreeView.h | 6 +- .../GxsChannelFilesStatusWidget.ui | 4 +- .../gxschannels/GxsChannelPostFilesModel.cpp | 2 +- .../gui/gxschannels/GxsChannelPostsModel.cpp | 21 +++++- .../gui/gxschannels/GxsChannelPostsModel.h | 1 + .../GxsChannelPostsWidgetWithModel.cpp | 64 ++++++++++++++----- .../GxsChannelPostsWidgetWithModel.h | 2 + .../GxsChannelPostsWidgetWithModel.ui | 9 ++- 9 files changed, 89 insertions(+), 26 deletions(-) diff --git a/retroshare-gui/src/gui/common/RSTreeView.cpp b/retroshare-gui/src/gui/common/RSTreeView.cpp index 918fbc558..da1aa5840 100644 --- a/retroshare-gui/src/gui/common/RSTreeView.cpp +++ b/retroshare-gui/src/gui/common/RSTreeView.cpp @@ -19,12 +19,18 @@ *******************************************************************************/ #include +#include #include "RSTreeView.h" RSTreeView::RSTreeView(QWidget *parent) : QTreeView(parent) { } +void RSTreeView::resizeEvent(QResizeEvent *e) +{ + emit sizeChanged(e->size()); +} + void RSTreeView::setPlaceholderText(const QString &text) { placeholderText = text; diff --git a/retroshare-gui/src/gui/common/RSTreeView.h b/retroshare-gui/src/gui/common/RSTreeView.h index 022a643db..f895571f0 100644 --- a/retroshare-gui/src/gui/common/RSTreeView.h +++ b/retroshare-gui/src/gui/common/RSTreeView.h @@ -33,8 +33,12 @@ public: void setPlaceholderText(const QString &text); +signals: + void sizeChanged(QSize); + protected: - void paintEvent(QPaintEvent *event); + virtual void resizeEvent(QResizeEvent *e) override; + virtual void paintEvent(QPaintEvent *event) override; QString placeholderText; }; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.ui index 59fa846da..39e32271d 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.ui @@ -6,8 +6,8 @@ 0 0 - 367 - 27 + 421 + 29 diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp index ab20c2fd8..06ba27a0f 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp @@ -33,7 +33,7 @@ #include "GxsChannelPostFilesModel.h" -#define DEBUG_CHANNEL_MODEL +//#define DEBUG_CHANNEL_MODEL Q_DECLARE_METATYPE(RsGxsFile) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index 5d82110d5..b7649af26 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -32,7 +32,7 @@ #include "retroshare/rsgxschannels.h" #include "retroshare/rsexpr.h" -#define DEBUG_CHANNEL_MODEL +//#define DEBUG_CHANNEL_MODEL Q_DECLARE_METATYPE(RsMsgMetaData) @@ -221,6 +221,21 @@ Qt::ItemFlags RsGxsChannelPostsModel::flags(const QModelIndex& index) const return QAbstractItemModel::flags(index); } +void RsGxsChannelPostsModel::setNumColumns(int n) +{ + preMods(); + + beginRemoveRows(QModelIndex(),0,rowCount()-1); + endRemoveRows(); + + mColumns = n; + + beginInsertRows(QModelIndex(),0,rowCount()-1); + endInsertRows(); + + postMods(); +} + quintptr RsGxsChannelPostsModel::getChildRef(quintptr ref,int index) const { if (index < 0) @@ -675,7 +690,7 @@ void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vecto { preMods(); - beginRemoveRows(QModelIndex(),0,mPosts.size()-1); + beginRemoveRows(QModelIndex(),0,rowCount()-1); endRemoveRows(); mPosts.clear(); @@ -692,7 +707,7 @@ void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vecto // debug_dump(); #endif - beginInsertRows(QModelIndex(),0,mPosts.size()-1); + beginInsertRows(QModelIndex(),0,rowCount()-1); endInsertRows(); postMods(); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.h index de4713e79..60b4065de 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.h @@ -110,6 +110,7 @@ public: const RsGxsGroupId& currentGroupId() const; void setTreeMode(TreeMode mode) ; + void setNumColumns(int n); #ifdef TODO void setSortMode(SortMode mode) ; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index fd9ddedff..8bfbb5e3d 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -61,8 +61,21 @@ static const int CHANNEL_TABS_POSTS = 1; /* View mode */ #define VIEW_MODE_FEEDS 1 #define VIEW_MODE_FILES 2 + +// Size of thumbnails as a function of the height of the font. An aspect ratio of 3/4 is good. + +#define THUMBNAIL_W 4 +#define THUMBNAIL_H 6 + +// Determine the Shape and size of cells as a factor of the font height. An aspect ratio of 3/4 is what's needed +// for the image, so it's important that the height is a bit larger so as to leave some room for the text. +// +// #define COLUMN_SIZE_FONT_FACTOR_W 6 -#define COLUMN_SIZE_FONT_FACTOR_H 12 +#define COLUMN_SIZE_FONT_FACTOR_H 10 + +// This variable determines the zoom factor on the text below thumbnails. 2.0 is mostly correct for all screen. +#define THUMBNAIL_OVERSAMPLE_FACTOR 2.0 Q_DECLARE_METATYPE(RsGxsFile) @@ -95,8 +108,8 @@ public: lb->setPixmap(thumbnail); QFontMetricsF fm(font()); - int W = 8 * fm.height() ; - int H = 12 * fm.height() ; + int W = THUMBNAIL_OVERSAMPLE_FACTOR * THUMBNAIL_W * fm.height() ; + int H = THUMBNAIL_OVERSAMPLE_FACTOR * THUMBNAIL_H * fm.height() ; lb->setFixedSize(W,H); @@ -183,18 +196,19 @@ void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & //w.setFixedWidth(option.rect.width()); QPixmap pixmap(w.size()); - pixmap.fill(option.palette.color(QPalette::Background)); // choose the background + pixmap.fill(QRgb(0x00ffffff)); // choose a fully transparent background w.render(&pixmap,QPoint(),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background // debug - if(index.row()==0 && index.column()==0) - { - QFile file("yourFile.png"); - file.open(QIODevice::WriteOnly); - pixmap.save(&file, "PNG"); - std::cerr << "Saved pxmap to png" << std::endl; - } - std::cerr << "option.rect = " << option.rect.width() << "x" << option.rect.height() << ". fm.height()=" << QFontMetricsF(option.font).height() << std::endl; + // if(index.row()==0 && index.column()==0) + // { + // QFile file("yourFile.png"); + // file.open(QIODevice::WriteOnly); + // pixmap.save(&file, "PNG"); + // std::cerr << "Saved pxmap to png" << std::endl; + // } + //std::cerr << "option.rect = " << option.rect.width() << "x" << option.rect.height() << ". fm.height()=" << QFontMetricsF(option.font).height() << std::endl; + painter->drawPixmap(option.rect.topLeft(), pixmap.scaled(option.rect.width(),option.rect.width()*w.height()/(float)w.width(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation)); } @@ -297,7 +311,7 @@ void ChannelPostFilesDelegate::paint(QPainter * painter, const QStyleOptionViewI w.setFixedWidth(option.rect.width()); QPixmap pixmap(w.size()); - pixmap.fill(option.palette.color(QPalette::Background)); // choose the background + pixmap.fill(QRgb(0x00ffffff)); // choose a fully transparent background w.render(&pixmap,QPoint(),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background painter->drawPixmap(option.rect.topLeft(),pixmap); @@ -344,6 +358,7 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->channelPostFiles_TV->setModel(mChannelPostFilesModel = new RsGxsChannelPostFilesModel()); ui->channelPostFiles_TV->setItemDelegate(new ChannelPostFilesDelegate()); + ui->channelPostFiles_TV->setPlaceholderText(tr("Post files")); connect(ui->postsTree->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),this,SLOT(showPostDetails())); @@ -386,6 +401,8 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->loadingLabel->hide(); ui->progressBar->hide(); + ui->postsTree->setPlaceholderText(tr("Thumbnails")); + ui->postsTree->setMinimumWidth(COLUMN_SIZE_FONT_FACTOR_W*QFontMetricsF(font()).height()+1); //ui->nameLabel->setMinimumWidth(20); @@ -414,10 +431,23 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI mEventHandlerId = 0; // Needs to be asynced because this function is called by another thread! - rsEvents->registerEventsHandler( - [this](std::shared_ptr event) - { RsQThreadUtils::postToObject([=](){ handleEvent_main_thread(event); }, this ); }, - mEventHandlerId, RsEventType::GXS_CHANNELS ); + rsEvents->registerEventsHandler( [this](std::shared_ptr event) + { + RsQThreadUtils::postToObject([=](){ handleEvent_main_thread(event); }, this ); + }, mEventHandlerId, RsEventType::GXS_CHANNELS ); + + connect(ui->postsTree,SIGNAL(sizeChanged(QSize)),this,SLOT(handlePostsTreeSizeChange(QSize))); +} + +void GxsChannelPostsWidgetWithModel::handlePostsTreeSizeChange(QSize s) +{ +// adjustSize(); +// + int n_columns = std::max(1,(int)floor(s.width() / (COLUMN_SIZE_FONT_FACTOR_W*QFontMetricsF(font()).height()))); + std::cerr << "nb columns: " << n_columns << std::endl; + + if(n_columns != mChannelPostsModel->columnCount()) + mChannelPostsModel->setNumColumns(n_columns); } void GxsChannelPostsWidgetWithModel::handleEvent_main_thread(std::shared_ptr event) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index 51bc79b6b..48caeaf49 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -108,6 +108,7 @@ public: protected: /* GxsMessageFramePostWidget */ virtual void groupNameChanged(const QString &name); + #ifdef TODO virtual bool insertGroupData(const RsGxsGenericGroupData *data) override; #endif @@ -134,6 +135,7 @@ private slots: void filterChanged(int filter); void setViewMode(int viewMode); void settingsChanged(); + void handlePostsTreeSizeChange(QSize s); private: void processSettings(bool load); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index 66c4d4ba3..0f3405cda 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -412,7 +412,7 @@ p, li { white-space: pre-wrap; } Qt::Vertical - + QAbstractScrollArea::AdjustToContents @@ -509,7 +509,7 @@ p, li { white-space: pre-wrap; } - + QAbstractItemView::CurrentChanged|QAbstractItemView::SelectedClicked @@ -566,6 +566,11 @@ p, li { white-space: pre-wrap; } QLineEdit
gui/common/LineEditClear.h
+ + RSTreeView + QTreeView +
gui/common/RSTreeView.h
+
From fecd4369ec7e436bceffd44219dd202823ac455e Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 6 Jun 2020 21:32:06 +0200 Subject: [PATCH 039/154] fixed a few bugs in posts model --- .../gui/gxschannels/GxsChannelPostsModel.cpp | 67 ++++++++----------- .../GxsChannelPostsWidgetWithModel.cpp | 3 + 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index b7649af26..e0af09eee 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -115,13 +115,10 @@ int RsGxsChannelPostsModel::rowCount(const QModelIndex& parent) const return 0; if(!parent.isValid()) - return (getChildrenCount(0) + mColumns-1)/mColumns; + return (mPosts.size()-1 + mColumns-1)/mColumns; // mPosts always has an item at 0, so size()>=1, and mColumn>=1 RsErr() << __PRETTY_FUNCTION__ << " rowCount cannot figure out the porper number of rows." << std::endl; return 0; - - //else - // return getChildrenCount(parent.internalId()); } int RsGxsChannelPostsModel::columnCount(const QModelIndex &/*parent*/) const @@ -173,7 +170,7 @@ bool RsGxsChannelPostsModel::convertTabEntryToRefPointer(uint32_t entry,quintptr // This means that the whole software has the following build-in limitation: // * 4 B simultaenous posts. Should be enough ! - ref = (intptr_t)entry; + ref = (intptr_t)(entry+1); return true; } @@ -187,7 +184,13 @@ bool RsGxsChannelPostsModel::convertRefPointerToTabEntry(quintptr ref, uint32_t& RsErr() << "(EE) trying to make a ChannelPostsModelIndex out of a number that is larger than 2^32-1 !" << std::endl; return false ; } - entry = quintptr(val); + if(val==0) + { + RsErr() << "(EE) trying to make a ChannelPostsModelIndex out of index 0." << std::endl; + return false; + } + + entry = val - 1; return true; } @@ -197,7 +200,7 @@ QModelIndex RsGxsChannelPostsModel::index(int row, int column, const QModelIndex if(row < 0 || column < 0 || column >= mColumns) return QModelIndex(); - quintptr ref = getChildRef(parent.internalId(),row + column*mColumns); + quintptr ref = getChildRef(parent.internalId(),column + row*mColumns); #ifdef DEBUG_CHANNEL_MODEL std::cerr << "index-3(" << row << "," << column << " parent=" << parent << ") : " << createIndex(row,column,ref) << std::endl; @@ -223,7 +226,12 @@ Qt::ItemFlags RsGxsChannelPostsModel::flags(const QModelIndex& index) const void RsGxsChannelPostsModel::setNumColumns(int n) { - preMods(); + if(n < 1) + { + RsErr() << __PRETTY_FUNCTION__ << " Attempt to set a number of column of 0. This is wrong." << std::endl; + return; + } + preMods(); beginRemoveRows(QModelIndex(),0,rowCount()-1); endRemoveRows(); @@ -241,15 +249,10 @@ quintptr RsGxsChannelPostsModel::getChildRef(quintptr ref,int index) const if (index < 0) return 0; - ChannelPostsModelIndex entry ; - - if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) - return 0 ; - - if(entry == 0) + if(ref == quintptr(0)) { quintptr new_ref; - convertTabEntryToRefPointer(index+1,new_ref); + convertTabEntryToRefPointer(index,new_ref); return new_ref; } else @@ -278,18 +281,10 @@ int RsGxsChannelPostsModel::getChildrenCount(quintptr ref) const { uint32_t entry = 0 ; - if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) - return 0 ; + if(ref == quintptr(0)) + return rowCount()-1; - if(entry == 0) - { -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << "Children count (flat mode): " << mPosts.size()-1 << std::endl; -#endif - return ((int)mPosts.size())-1; - } - else - return 0; + return 0; } QVariant RsGxsChannelPostsModel::data(const QModelIndex &index, int role) const @@ -803,7 +798,7 @@ void RsGxsChannelPostsModel::createPostsArray(std::vector& pos { // collect new versions of posts if any -#ifdef DEBUG_CHANNEL_MODEL +#ifndef DEBUG_CHANNEL_MODEL std::cerr << "Inserting channel posts" << std::endl; #endif @@ -813,8 +808,8 @@ void RsGxsChannelPostsModel::createPostsArray(std::vector& pos if(posts[i].mMeta.mOrigMsgId == posts[i].mMeta.mMsgId) posts[i].mMeta.mOrigMsgId.clear(); -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << " " << i << ": msg_id=" << posts[i].mMeta.mMsgId << ": orig msg id = " << posts[i].mMeta.mOrigMsgId << std::endl; +#ifndef DEBUG_CHANNEL_MODEL + std::cerr << " " << i << ": name=\"" << posts[i].mMeta.mMsgName << "\" msg_id=" << posts[i].mMeta.mMsgId << ": orig msg id = " << posts[i].mMeta.mOrigMsgId << std::endl; #endif if(!posts[i].mMeta.mOrigMsgId.isNull()) @@ -903,20 +898,16 @@ void RsGxsChannelPostsModel::createPostsArray(std::vector& pos for (std::vector::const_reverse_iterator it = posts.rbegin(); it != posts.rend(); ++it) { -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << " adding post: " << (*it).mMeta.mMsgId ; -#endif - if(!(*it).mMeta.mMsgId.isNull()) { -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << " added" << std::endl; +#ifndef DEBUG_CHANNEL_MODEL + std::cerr << " adding post \"" << (*it).mMeta.mMsgName << "\"" << std::endl; #endif mPosts.push_back(*it); } #ifdef DEBUG_CHANNEL_MODEL else - std::cerr << " skipped" << std::endl; + std::cerr << " skipped older version post \"" << (*it).mMeta.mMsgName << "\"" << std::endl; #endif } } @@ -1025,7 +1016,7 @@ QModelIndex RsGxsChannelPostsModel::getIndexOfMessage(const RsGxsMessageId& mid) quintptr ref ; convertTabEntryToRefPointer(i,ref); // we dont use i+1 here because i is not a row, but an index in the mPosts tab - return createIndex(i-1,0,ref); + return createIndex((i-1)%mColumns, (i-1)/mColumns,ref); } if(mPosts[i].mMeta.mMsgId == postId) @@ -1033,7 +1024,7 @@ QModelIndex RsGxsChannelPostsModel::getIndexOfMessage(const RsGxsMessageId& mid) quintptr ref ; convertTabEntryToRefPointer(i,ref); // we dont use i+1 here because i is not a row, but an index in the mPosts tab - return createIndex(i-1,0,ref); + return createIndex((i-1)%mColumns, (i-1)/mColumns,ref); } } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 8bfbb5e3d..0b4463f80 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -488,6 +488,9 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() mChannelPostFilesModel->clear(); return; } + if(index.row()==0 && index.column()==0) + std::cerr << "here" << std::endl; + RsGxsChannelPost post = index.data(Qt::UserRole).value() ; mChannelPostFilesModel->setFiles(post.mFiles); From baf7b06e4ce71ff7b3e31e4e49ce2b9b14e7756e Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 6 Jun 2020 21:51:40 +0200 Subject: [PATCH 040/154] fixed double click problem on files --- retroshare-gui/src/gui/common/RSTreeView.cpp | 19 + retroshare-gui/src/gui/common/RSTreeView.h | 6 + .../gui/gxschannels/GxsChannelPostsModel.cpp | 502 +----------------- .../GxsChannelPostsWidgetWithModel.cpp | 1 + 4 files changed, 29 insertions(+), 499 deletions(-) diff --git a/retroshare-gui/src/gui/common/RSTreeView.cpp b/retroshare-gui/src/gui/common/RSTreeView.cpp index da1aa5840..36034166f 100644 --- a/retroshare-gui/src/gui/common/RSTreeView.cpp +++ b/retroshare-gui/src/gui/common/RSTreeView.cpp @@ -24,6 +24,25 @@ RSTreeView::RSTreeView(QWidget *parent) : QTreeView(parent) { + setMouseTracking(false); // normally the default, but who knows if it's not goign to change in the future. +} + +void RSTreeView::mouseMoveEvent(QMouseEvent *e) +{ + QModelIndex idx = indexAt(e->pos()); + + if(idx != selectionModel()->currentIndex()) + selectionModel()->setCurrentIndex(idx,QItemSelectionModel::ClearAndSelect); + + QTreeView::mouseMoveEvent(e); +} + +void RSTreeView::setAutoSelect(bool b) +{ + if(b) + setMouseTracking(true); + else + setMouseTracking(false); } void RSTreeView::resizeEvent(QResizeEvent *e) diff --git a/retroshare-gui/src/gui/common/RSTreeView.h b/retroshare-gui/src/gui/common/RSTreeView.h index f895571f0..f7942ef64 100644 --- a/retroshare-gui/src/gui/common/RSTreeView.h +++ b/retroshare-gui/src/gui/common/RSTreeView.h @@ -33,10 +33,16 @@ public: void setPlaceholderText(const QString &text); + // Use this to make selection automatic based on mouse position. This is useful to trigger selection and therefore editing mode + // in trees that show editing widgets using a QStyledItemDelegate + + void setAutoSelect(bool b); + signals: void sizeChanged(QSize); protected: + virtual void mouseMoveEvent(QMouseEvent *e) override; // overriding so as to manage auto-selection virtual void resizeEvent(QResizeEvent *e) override; virtual void paintEvent(QPaintEvent *event) override; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index e0af09eee..6fc4325a5 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -84,28 +84,6 @@ void RsGxsChannelPostsModel::setTreeMode(TreeMode mode) postMods(); } -#ifdef TODO -void RsGxsChannelPostsModel::setSortMode(SortMode mode) -{ - preMods(); - - mSortMode = mode; - - postMods(); -} - -void RsGxsForumModel::initEmptyHierarchy(std::vector& posts) -{ - preMods(); - - posts.resize(1); // adds a sentinel item - posts[0].mTitle = "Root sentinel post" ; - posts[0].mParent = 0; - - postMods(); -} -#endif - int RsGxsChannelPostsModel::rowCount(const QModelIndex& parent) const { if(parent.column() > 0) @@ -126,16 +104,6 @@ int RsGxsChannelPostsModel::columnCount(const QModelIndex &/*parent*/) const return mColumns ; } -// std::vector > RsGxsChannelPostsModel::getPostVersions(const RsGxsMessageId& mid) const -// { -// auto it = mPostVersions.find(mid); -// -// if(it != mPostVersions.end()) -// return it->second; -// else -// return std::vector >(); -// } - bool RsGxsChannelPostsModel::getPostData(const QModelIndex& i,RsGxsChannelPost& fmpe) const { if(!i.isValid()) @@ -328,303 +296,28 @@ QVariant RsGxsChannelPostsModel::data(const QModelIndex &index, int role) const const RsGxsChannelPost& fmpe(mPosts[entry]); -#ifdef TODO - if(role == Qt::FontRole) - { - QFont font ; - font.setBold( (fmpe.mPostFlags & (ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN | ForumModelPostEntry::FLAG_POST_IS_PINNED)) || IS_MSG_UNREAD(fmpe.mMsgStatus)); - return QVariant(font); - } - - if(role == UnreadChildrenRole) - return bool(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN); - -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << " [ok]" << std::endl; -#endif -#endif - switch(role) { case Qt::DisplayRole: return displayRole (fmpe,index.column()) ; case Qt::UserRole: return userRole (fmpe,index.column()) ; -#ifdef TODO - case Qt::DecorationRole: return decorationRole(fmpe,index.column()) ; - case Qt::ToolTipRole: return toolTipRole (fmpe,index.column()) ; - case Qt::TextColorRole: return textColorRole (fmpe,index.column()) ; - case Qt::BackgroundRole: return backgroundRole(fmpe,index.column()) ; - - case FilterRole: return filterRole (fmpe,index.column()) ; - case ThreadPinnedRole: return pinnedRole (fmpe,index.column()) ; - case MissingRole: return missingRole (fmpe,index.column()) ; - case StatusRole: return statusRole (fmpe,index.column()) ; - case SortRole: return sortRole (fmpe,index.column()) ; -#endif default: return QVariant(); } } -#ifdef TODO -QVariant RsGxsForumModel::textColorRole(const ForumModelPostEntry& fmpe,int /*column*/) const -{ - if( (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING)) - return QVariant(mTextColorMissing); - - if(IS_MSG_UNREAD(fmpe.mMsgStatus) || (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED)) - return QVariant(mTextColorUnread); - else - return QVariant(mTextColorRead); - - return QVariant(); -} - -QVariant RsGxsForumModel::statusRole(const ForumModelPostEntry& fmpe,int column) const -{ - if(column != COLUMN_THREAD_DATA) - return QVariant(); - - return QVariant(fmpe.mMsgStatus); -} - -QVariant RsGxsForumModel::filterRole(const ForumModelPostEntry& fmpe,int /*column*/) const -{ - if(!mFilteringEnabled || (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER)) - return QVariant(FilterString); - - return QVariant(QString()); -} - -uint32_t RsGxsForumModel::recursUpdateFilterStatus(ForumModelIndex i,int column,const QStringList& strings) -{ - QString s ; - uint32_t count = 0; - - switch(column) - { - default: - case COLUMN_THREAD_DATE: - case COLUMN_THREAD_TITLE: s = displayRole(mPosts[i],column).toString(); - break; - case COLUMN_THREAD_AUTHOR: - { - QString comment ; - QList icons; - - GxsIdDetails::MakeIdDesc(mPosts[i].mAuthorId, false,s, icons, comment,GxsIdDetails::ICON_TYPE_NONE); - } - break; - } - - if(!strings.empty()) - { - mPosts[i].mPostFlags &= ~(ForumModelPostEntry::FLAG_POST_PASSES_FILTER | ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER); - - for(auto iter(strings.begin()); iter != strings.end(); ++iter) - if(s.contains(*iter,Qt::CaseInsensitive)) - { - mPosts[i].mPostFlags |= ForumModelPostEntry::FLAG_POST_PASSES_FILTER | ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER; - - count++; - break; - } - } - else - { - mPosts[i].mPostFlags |= ForumModelPostEntry::FLAG_POST_PASSES_FILTER |ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER; - count++; - } - - for(uint32_t j=0;j 0) - mPosts[i].mPostFlags |= ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER; - } - - return count; -} - - -void RsGxsForumModel::setFilter(int column,const QStringList& strings,uint32_t& count) -{ - preMods(); - - if(!strings.empty()) - { - count = recursUpdateFilterStatus(ForumModelIndex(0),column,strings); - mFilteringEnabled = true; - } - else - { - count=0; - mFilteringEnabled = false; - } - - postMods(); -} - -QVariant RsGxsForumModel::missingRole(const ForumModelPostEntry& fmpe,int /*column*/) const -{ - if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING) - return QVariant(true); - else - return QVariant(false); -} - -QVariant RsGxsForumModel::toolTipRole(const ForumModelPostEntry& fmpe,int column) const -{ - if(column == COLUMN_THREAD_DISTRIBUTION) - switch(fmpe.mReputationWarningLevel) - { - case 3: return QVariant(tr("Information for this identity is currently missing.")) ; - case 2: return QVariant(tr("You have banned this ID. The message will not be\ndisplayed nor forwarded to your friends.")) ; - case 1: return QVariant(tr("You have not set an opinion for this person,\n and your friends do not vote positively: Spam regulation \nprevents the message to be forwarded to your friends.")) ; - case 0: return QVariant(tr("Message will be forwarded to your friends.")) ; - default: - return QVariant("[ERROR: missing reputation level information - contact the developers]"); - } - - if(column == COLUMN_THREAD_AUTHOR) - { - QString str,comment ; - QList icons; - - if(!GxsIdDetails::MakeIdDesc(fmpe.mAuthorId, true, str, icons, comment,GxsIdDetails::ICON_TYPE_AVATAR)) - return QVariant(); - - int S = QFontMetricsF(QApplication::font()).height(); - QImage pix( (*icons.begin()).pixmap(QSize(4*S,4*S)).toImage()); - - QString embeddedImage; - if(RsHtml::makeEmbeddedImage(pix.scaled(QSize(4*S,4*S), Qt::KeepAspectRatio, Qt::SmoothTransformation), embeddedImage, 8*S * 8*S)) - comment = "
" + embeddedImage + "" + comment + "
"; - - return comment; - } - - return QVariant(); -} - -QVariant RsGxsForumModel::pinnedRole(const ForumModelPostEntry& fmpe,int /*column*/) const -{ - if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) - return QVariant(true); - else - return QVariant(false); -} - -QVariant RsGxsForumModel::backgroundRole(const ForumModelPostEntry& fmpe,int /*column*/) const -{ - if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) - return QVariant(QBrush(QColor(255,200,180))); - - if(mFilteringEnabled && (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_PASSES_FILTER)) - return QVariant(QBrush(QColor(255,240,210))); - - return QVariant(); -} -#endif - QVariant RsGxsChannelPostsModel::sizeHintRole(int col) const { float factor = QFontMetricsF(QApplication::font()).height()/14.0f ; return QVariant( QSize(factor * 170, factor*14 )); -#ifdef TODO - switch(col) - { - default: - case COLUMN_THREAD_TITLE: return QVariant( QSize(factor * 170, factor*14 )); - case COLUMN_THREAD_DATE: return QVariant( QSize(factor * 75 , factor*14 )); - case COLUMN_THREAD_AUTHOR: return QVariant( QSize(factor * 75 , factor*14 )); - case COLUMN_THREAD_DISTRIBUTION: return QVariant( QSize(factor * 15 , factor*14 )); - } -#endif } -#ifdef TODO -QVariant RsGxsForumModel::authorRole(const ForumModelPostEntry& fmpe,int column) const -{ - if(column == COLUMN_THREAD_DATA) - return QVariant(QString::fromStdString(fmpe.mAuthorId.toStdString())); - - return QVariant(); -} - -QVariant RsGxsForumModel::sortRole(const ForumModelPostEntry& fmpe,int column) const -{ - switch(column) - { - case COLUMN_THREAD_DATE: if(mSortMode == SORT_MODE_PUBLISH_TS) - return QVariant(QString::number(fmpe.mPublishTs)); // we should probably have leading zeroes here - else - return QVariant(QString::number(fmpe.mMostRecentTsInThread)); // we should probably have leading zeroes here - - case COLUMN_THREAD_READ: return QVariant((bool)IS_MSG_UNREAD(fmpe.mMsgStatus)); - case COLUMN_THREAD_DISTRIBUTION: return decorationRole(fmpe,column); - case COLUMN_THREAD_AUTHOR: - { - QString str,comment ; - QList icons; - GxsIdDetails::MakeIdDesc(fmpe.mAuthorId, false, str, icons, comment,GxsIdDetails::ICON_TYPE_NONE); - - return QVariant(str); - } - default: - return displayRole(fmpe,column); - } -} -#endif - QVariant RsGxsChannelPostsModel::displayRole(const RsGxsChannelPost& fmpe,int col) const { switch(col) { default: return QString::fromUtf8(fmpe.mMeta.mMsgName.c_str()); -#ifdef TODO - case COLUMN_THREAD_TITLE: if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_REDACTED) - return QVariant(tr("[ ... Redacted message ... ]")); - else if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) - return QVariant(tr("[PINNED] ") + QString::fromUtf8(fmpe.mTitle.c_str())); - else - return QVariant(QString::fromUtf8(fmpe.mTitle.c_str())); - - case COLUMN_THREAD_READ:return QVariant(); - case COLUMN_THREAD_DATE:{ - if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING) - return QVariant(QString()); - - QDateTime qtime; - qtime.setTime_t(fmpe.mPublishTs); - - return QVariant(DateTime::formatDateTime(qtime)); - } - - case COLUMN_THREAD_DISTRIBUTION: - 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(); -#endif -#ifdef TODO - if (filterColumn == COLUMN_THREAD_CONTENT) { - // need content for filter - QTextDocument doc; - doc.setHtml(QString::fromUtf8(msg.mMsg.c_str())); - item->setText(COLUMN_THREAD_CONTENT, doc.toPlainText().replace(QString("\n"), QString(" "))); - } -#endif } @@ -640,23 +333,6 @@ QVariant RsGxsChannelPostsModel::userRole(const RsGxsChannelPost& fmpe,int col) } } -#ifdef TODO -QVariant RsGxsForumModel::decorationRole(const ForumModelPostEntry& fmpe,int col) const -{ - bool exist=false; - switch(col) - { - case COLUMN_THREAD_DISTRIBUTION: - return QVariant(fmpe.mReputationWarningLevel); - 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(); -} -#endif - const RsGxsGroupId& RsGxsChannelPostsModel::currentGroupId() const { return mChannelGroup.mMeta.mGroupId; @@ -766,39 +442,13 @@ void RsGxsChannelPostsModel::update_posts(const RsGxsGroupId& group_id) }); } -//ChannelPostsModelIndex RsGxsChannelPostsModel::addEntry(std::vector& posts,const ChannelPostsModelPostEntry& entry) -//{ -// uint32_t N = posts.size(); -// posts.push_back(entry); -// -//#ifdef DEBUG_FORUMMODEL -// std::cerr << "Added new entry " << N << " children of " << parent << std::endl; -//#endif -// if(N == parent) -// std::cerr << "(EE) trying to add a post as its own parent!" << std::endl; -// -// return ChannelPostsModelIndex(N); -//} - -//void RsGxsChannelPostsModel::convertMsgToPostEntry(const RsGxsChannelGroup& mChannelGroup,const RsMsgMetaData& msg, bool /*useChildTS*/, ChannelPostsModelPostEntry& fentry) -//{ -// fentry.mTitle = msg.mMsgName; -// fentry.mMsgId = msg.mMsgId; -// fentry.mPublishTs = msg.mPublishTs; -// fentry.mPostFlags = 0; -// fentry.mMsgStatus = msg.mMsgStatus; -// -// // Early check for a message that should be hidden because its author -// // is flagged with a bad reputation -//} - static bool decreasing_time_comp(const std::pair& e1,const std::pair& e2) { return e2.first < e1.first ; } void RsGxsChannelPostsModel::createPostsArray(std::vector& posts) { // collect new versions of posts if any -#ifndef DEBUG_CHANNEL_MODEL +#ifdef DEBUG_CHANNEL_MODEL std::cerr << "Inserting channel posts" << std::endl; #endif @@ -808,7 +458,7 @@ void RsGxsChannelPostsModel::createPostsArray(std::vector& pos if(posts[i].mMeta.mOrigMsgId == posts[i].mMeta.mMsgId) posts[i].mMeta.mOrigMsgId.clear(); -#ifndef DEBUG_CHANNEL_MODEL +#ifdef DEBUG_CHANNEL_MODEL std::cerr << " " << i << ": name=\"" << posts[i].mMeta.mMsgName << "\" msg_id=" << posts[i].mMeta.mMsgId << ": orig msg id = " << posts[i].mMeta.mOrigMsgId << std::endl; #endif @@ -900,7 +550,7 @@ void RsGxsChannelPostsModel::createPostsArray(std::vector& pos { if(!(*it).mMeta.mMsgId.isNull()) { -#ifndef DEBUG_CHANNEL_MODEL +#ifdef DEBUG_CHANNEL_MODEL std::cerr << " adding post \"" << (*it).mMeta.mMsgName << "\"" << std::endl; #endif mPosts.push_back(*it); @@ -929,77 +579,8 @@ void RsGxsChannelPostsModel::setMsgReadStatus(const QModelIndex& i,bool read_sta // bool has_unread_below, has_read_below; // recursSetMsgReadStatus(entry,read_status,with_children) ; // recursUpdateReadStatusAndTimes(0,has_unread_below,has_read_below); - } -#ifdef TODO -void RsGxsForumModel::recursSetMsgReadStatus(ForumModelIndex i,bool read_status,bool with_children) -{ - int newStatus = (read_status ? mPosts[i].mMsgStatus & ~static_cast(GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD) - : mPosts[i].mMsgStatus | static_cast(GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD)); - bool bChanged = (mPosts[i].mMsgStatus != newStatus); - mPosts[i].mMsgStatus = newStatus; - //Remove Unprocessed and New flags - mPosts[i].mMsgStatus &= ~(GXS_SERV::GXS_MSG_STATUS_UNPROCESSED | GXS_SERV::GXS_MSG_STATUS_GUI_NEW); - - if (bChanged) - { - //Don't recurs post versions as this should be done before, if no change. - uint32_t token; - auto s = getPostVersions(mPosts[i].mMsgId) ; - - if(!s.empty()) - for(auto it(s.begin());it!=s.end();++it) - { - rsGxsForums->setMessageReadStatus(token,std::make_pair( mForumGroup.mMeta.mGroupId, it->second ), read_status); - std::cerr << "Setting version " << it->second << " of post " << mPosts[i].mMsgId << " as read." << std::endl; - } - else - rsGxsForums->setMessageReadStatus(token,std::make_pair( mForumGroup.mMeta.mGroupId, mPosts[i].mMsgId ), read_status); - - QModelIndex itemIndex = createIndex(i - 1, 0, &mPosts[i]); - emit dataChanged(itemIndex, itemIndex); - } - - if(!with_children) - return; - - for(uint32_t j=0;j& entries,ForumModelIndex index,int depth) -{ - const ForumModelPostEntry& e(entries[index]); - - QDateTime qtime; - qtime.setTime_t(e.mPublishTs); - - std::cerr << std::string(depth*2,' ') << index << " : " << e.mAuthorId.toStdString() << " " - << QString("%1").arg((uint32_t)e.mPostFlags,8,16,QChar('0')).toStdString() << " " - << QString("%1").arg((uint32_t)e.mMsgStatus,8,16,QChar('0')).toStdString() << " " - << qtime.toString().toStdString() << " \"" << e.mTitle << "\"" << std::endl; - - for(uint32_t i=0;i= mPosts.size()) - return ; - - std::cerr << "Setting own opinion for author " << mPosts[entry].mAuthorId - << " to " << static_cast(op) << std::endl; - RsGxsId author_id = mPosts[entry].mAuthorId; - - rsReputations->setOwnOpinion(author_id,op) ; - - // update opinions and distribution flags. No need to re-load all posts. - - for(uint32_t i=0;ichannelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE); ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_NAME); + ui->channelPostFiles_TV->setAutoSelect(true); } void GxsChannelPostsWidgetWithModel::updateGroupData() From 878111d22449d31569b222fd8c13ee3a98e5202b Mon Sep 17 00:00:00 2001 From: sehraf Date: Fri, 5 Jun 2020 22:05:38 +0200 Subject: [PATCH 041/154] remove password from json tokens --- libretroshare/src/jsonapi/jsonapi.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libretroshare/src/jsonapi/jsonapi.cpp b/libretroshare/src/jsonapi/jsonapi.cpp index 338782a01..82d082520 100644 --- a/libretroshare/src/jsonapi/jsonapi.cpp +++ b/libretroshare/src/jsonapi/jsonapi.cpp @@ -180,6 +180,7 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"), std::string errorMessage; bool makeHidden = false; bool makeAutoTor = false; + std::string createToken; // deserialize input parameters from JSON { @@ -189,6 +190,7 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"), RS_SERIAL_PROCESS(password); RS_SERIAL_PROCESS(makeHidden); RS_SERIAL_PROCESS(makeAutoTor); + RS_SERIAL_PROCESS(createToken); } // call retroshare C++ API @@ -196,8 +198,9 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"), location, password, errorMessage, makeHidden, makeAutoTor ); - if(retval) - authorizeUser(location.mLocationId.toStdString(),password); + std::string tokenUser, tokenPw; + if(retval && parseToken(createToken, tokenUser, tokenPw)) + authorizeUser(tokenUser,tokenPw); // serialize out parameters and return value to JSON { @@ -238,9 +241,6 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"), RsInit::LoadCertificateStatus retval = rsLoginHelper->attemptLogin(account, password); - if( retval == RsInit::OK ) - authorizeUser(account.toStdString(), password); - // serialize out parameters and return value to JSON { RsGenericSerializer::SerializeContext& ctx(cAns); From 591ffc2fa7ef8004d3d882baed2b6e589d9efbb5 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 6 Jun 2020 22:37:44 +0200 Subject: [PATCH 042/154] added display of selected item and empty widget for channel files --- .../GxsChannelPostsWidgetWithModel.cpp | 318 +----------------- .../GxsChannelPostsWidgetWithModel.ui | 10 + 2 files changed, 19 insertions(+), 309 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 165537823..4a64024a1 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -126,66 +126,11 @@ public: void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { -#ifdef TODO - QString byteUnits[4] = {tr("B"), tr("KB"), tr("MB"), tr("GB")}; - QStyleOptionViewItem opt = option; - QStyleOptionProgressBarV2 newopt; - QRect pixmapRect; - QPixmap pixmap; - qlonglong fileSize; - double dlspeed, multi; - int seconds,minutes, hours, days; - qlonglong remaining; - QString temp ; - qlonglong completed; - qlonglong downloadtime; - qint64 qi64Value; -#endif - // prepare painter->save(); painter->setClipRect(option.rect); RsGxsChannelPost post = index.data(Qt::UserRole).value() ; - //const RsGxsChannelPost& post(*pinfo); - -#ifdef TODO - QVariant value = index.data(Qt::TextColorRole); - - if(value.isValid() && qvariant_cast(value).isValid()) - opt.palette.setColor(QPalette::Text, qvariant_cast(value)); - - QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; - - if(option.state & QStyle::State_Selected) - painter->setPen(opt.palette.color(cg, QPalette::HighlightedText)); - else - painter->setPen(opt.palette.color(cg, QPalette::Text)); - - //painter->drawText(option.rect, Qt::AlignRight, QString("TODO")); - - QPixmap thumbnail; - GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL); - - QFontMetricsF fm(opt.font); - - int W = IMAGE_SIZE_FACTOR_W * fm.height() * IMAGE_ZOOM_FACTOR; - int H = IMAGE_SIZE_FACTOR_H * fm.height() * IMAGE_ZOOM_FACTOR; - - int w = fm.width("X") ; - int h = fm.height() ; - - float img_coord_x = IMAGE_MARGIN_FACTOR*0.5*w; - float img_coord_y = IMAGE_MARGIN_FACTOR*0.5*h; - - QPoint img_pos(img_coord_x,img_coord_y); - QPoint img_size(W,H); - - QPoint txt_pos(0,img_coord_y + H + h); - - painter->drawPixmap(QRect(opt.rect.topLeft() + img_pos,opt.rect.topLeft()+img_pos+img_size),thumbnail.scaled(W,H,Qt::KeepAspectRatio,Qt::SmoothTransformation)); - painter->drawText(QRect(option.rect.topLeft() + txt_pos,option.rect.bottomRight()),Qt::AlignCenter,QString::fromStdString(post.mMeta.mMsgName)); -#endif painter->save(); painter->fillRect( option.rect, option.backgroundBrush); @@ -193,10 +138,13 @@ void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & ThumbnailView w(post); - //w.setFixedWidth(option.rect.width()); - QPixmap pixmap(w.size()); - pixmap.fill(QRgb(0x00ffffff)); // choose a fully transparent background + + if(option.state & QStyle::State_Selected) + pixmap.fill(QRgb(0xff308dc7)); // I dont know how to grab the backgroud color for selected objects automatically. + else + pixmap.fill(QRgb(0x00ffffff)); // choose a fully transparent background + w.render(&pixmap,QPoint(),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background // debug @@ -220,21 +168,6 @@ QSize ChannelPostDelegate::sizeHint(const QStyleOptionViewItem& option, const QM QFontMetricsF fm(option.font); return QSize(COLUMN_SIZE_FONT_FACTOR_W*fm.height(),COLUMN_SIZE_FONT_FACTOR_H*fm.height()); - -#ifdef TODO - //QPixmap thumbnail; - //GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL); - - QFontMetricsF fm(option.font); - - int W = IMAGE_SIZE_FACTOR_W * fm.height() * IMAGE_ZOOM_FACTOR; - int H = IMAGE_SIZE_FACTOR_H * fm.height() * IMAGE_ZOOM_FACTOR; - - int h = fm.height() ; - int w = fm.width("X") ; - - return QSize(W+IMAGE_MARGIN_FACTOR*w,H + 2*h); -#endif } QWidget *ChannelPostFilesDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex& index) const @@ -255,24 +188,6 @@ void ChannelPostFilesDelegate::paint(QPainter * painter, const QStyleOptionViewI { RsGxsFile file = index.data(Qt::UserRole).value() ; -#ifdef TODO - - QString byteUnits[4] = {tr("B"), tr("KB"), tr("MB"), tr("GB")}; - - QStyleOptionViewItem opt = option; - QStyleOptionProgressBarV2 newopt; - QRect pixmapRect; - QPixmap pixmap; - qlonglong fileSize; - double dlspeed, multi; - int seconds,minutes, hours, days; - qlonglong remaining; - QString temp ; - qlonglong completed; - qlonglong downloadtime; - qint64 qi64Value; -#endif - // prepare painter->save(); painter->setClipRect(option.rect); @@ -283,21 +198,6 @@ void ChannelPostFilesDelegate::paint(QPainter * painter, const QStyleOptionViewI //optionFocusRect.backgroundColor = option.palette.color(colorgroup, (option.state & QStyle::State_Selected) ? QPalette::Highlight : QPalette::Background); painter->restore(); -#ifdef TODO - RsGxsFile file = index.data(Qt::UserRole).value() ; - QVariant value = index.data(Qt::TextColorRole); - - if(value.isValid() && qvariant_cast(value).isValid()) - opt.palette.setColor(QPalette::Text, qvariant_cast(value)); - - QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) ? QPalette::Normal : QPalette::Disabled; - - if(option.state & QStyle::State_Selected) - painter->setPen(option.palette.color(cg, QPalette::HighlightedText)); - else - painter->setPen(option.palette.color(cg, QPalette::Text)); -#endif - switch(index.column()) { case RsGxsChannelPostFilesModel::COLUMN_FILES_NAME: painter->drawText(option.rect,Qt::AlignLeft | Qt::AlignVCenter," " + QString::fromUtf8(file.mName.c_str())); @@ -315,12 +215,6 @@ void ChannelPostFilesDelegate::paint(QPainter * painter, const QStyleOptionViewI w.render(&pixmap,QPoint(),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background painter->drawPixmap(option.rect.topLeft(),pixmap); - -#ifdef TODO - FileInfo finfo; - if(rsFiles->FileDetails(file.mHash,RS_FILE_HINTS_DOWNLOAD,finfo)) - painter->drawText(option.rect,Qt::AlignLeft,QString::number(finfo.transfered)); -#endif } break; @@ -360,6 +254,8 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->channelPostFiles_TV->setItemDelegate(new ChannelPostFilesDelegate()); ui->channelPostFiles_TV->setPlaceholderText(tr("Post files")); + ui->channelFiles_TV->setPlaceholderText(tr("All files in the channel")); + connect(ui->postsTree->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),this,SLOT(showPostDetails())); QFontMetricsF fm(font()); @@ -547,6 +443,7 @@ void GxsChannelPostsWidgetWithModel::updateGroupData() { mGroup = groups[0]; mChannelPostsModel->updateChannel(groupId()); + insertChannelDetails(mGroup); } ); }); @@ -974,155 +871,6 @@ void GxsChannelPostsWidget::fillThreadCreatePost(const QVariant &post, bool rela createPostItem(post.value(), related); } - -void GxsChannelPostsWidget::insertChannelPosts(std::vector& posts, GxsMessageFramePostThread *thread, bool related) -{ - if (related && thread) { - std::cerr << "GxsChannelPostsWidget::insertChannelPosts fill only related posts as thread is not possible" << std::endl; - return; - } - - int count = posts.size(); - int pos = 0; - - if (!thread) { - ui->feedWidget->setSortingEnabled(false); - } - - // collect new versions of posts if any - -#ifdef DEBUG_CHANNEL - std::cerr << "Inserting channel posts" << std::endl; -#endif - - std::vector new_versions ; - for (uint32_t i=0;i search_map ; - for (uint32_t i=0;i versions ; - std::map::const_iterator vit ; - - while(search_map.end() != (vit=search_map.find(posts[current_index].mMeta.mOrigMsgId))) - { -#ifdef DEBUG_CHANNEL - std::cerr << " post at index " << current_index << " replaces a post at position " << vit->second ; -#endif - - // Now replace the post only if the new versionis more recent. It may happen indeed that the same post has been corrected multiple - // times. In this case, we only need to replace the post with the newest version - - //uint32_t prev_index = current_index ; - current_index = vit->second ; - - if(posts[current_index].mMeta.mMsgId.isNull()) // This handles the branching situation where this post has been already erased. No need to go down further. - { -#ifdef DEBUG_CHANNEL - std::cerr << " already erased. Stopping." << std::endl; -#endif - break ; - } - - if(posts[current_index].mMeta.mPublishTs < posts[source_index].mMeta.mPublishTs) - { -#ifdef DEBUG_CHANNEL - std::cerr << " and is more recent => following" << std::endl; -#endif - for(std::set::const_iterator itt(posts[current_index].mOlderVersions.begin());itt!=posts[current_index].mOlderVersions.end();++itt) - posts[source_index].mOlderVersions.insert(*itt); - - posts[source_index].mOlderVersions.insert(posts[current_index].mMeta.mMsgId); - posts[current_index].mMeta.mMsgId.clear(); // clear the msg Id so the post will be ignored - } -#ifdef DEBUG_CHANNEL - else - std::cerr << " but is older -> Stopping" << std::endl; -#endif - } - } - } - -#ifdef DEBUG_CHANNEL - std::cerr << "Now adding posts..." << std::endl; -#endif - - for (std::vector::const_reverse_iterator it = posts.rbegin(); it != posts.rend(); ++it) - { -#ifdef DEBUG_CHANNEL - std::cerr << " adding post: " << (*it).mMeta.mMsgId ; -#endif - - if(!(*it).mMeta.mMsgId.isNull()) - { -#ifdef DEBUG_CHANNEL - std::cerr << " added" << std::endl; -#endif - - if (thread && thread->stopped()) - break; - - if (thread) - thread->emitAddPost(QVariant::fromValue(*it), related, ++pos, count); - else - createPostItem(*it, related); - } -#ifdef DEBUG_CHANNEL - else - std::cerr << " skipped" << std::endl; -#endif - } - - if (!thread) { - ui->feedWidget->setSortingEnabled(true); - } -} - -void GxsChannelPostsWidget::clearPosts() -{ - ui->feedWidget->clear(); - ui->fileWidget->clear(); -} #endif void GxsChannelPostsWidgetWithModel::blank() @@ -1183,57 +931,9 @@ void GxsChannelPostsWidgetWithModel::toggleAutoDownload() << "for channel: " << grpId.toStdString() << std::endl; return; } - -// RsQThreadUtils::postToObject( [=]() -// { -// /* Here it goes any code you want to be executed on the Qt Gui -// * thread, for example to update the data model with new information -// * after a blocking call to RetroShare API complete, note that -// * Qt::QueuedConnection is important! -// */ -// -// std::cerr << __PRETTY_FUNCTION__ << " Has been executed on GUI " -// << "thread but was scheduled by async thread" << std::endl; -// }, this ); }); } -#ifdef TODO -bool GxsChannelPostsWidgetWithModel::insertGroupData(const RsGxsGenericGroupData *data) -{ - const RsGxsChannelGroup *d = dynamic_cast(data); - - if(!d) - { - RsErr() << __PRETTY_FUNCTION__ << " Cannot dynamic cast input data (" << (void*)data << " to RsGxsGenericGroupData. Something bad happenned." << std::endl; - return false; - } - - insertChannelDetails(*d); - return true; -} - -void GxsChannelPostsWidget::insertAllPosts(const std::vector& posts, GxsMessageFramePostThread *thread) -{ - std::vector cposts; - - for(auto post: posts) // This is not so nice but we have somehow to convert to RsGxsChannelPost at some time, and the cposts list is being modified in the insert method. - cposts.push_back(*static_cast(post)); - - insertChannelPosts(cposts, thread, false); -} - -void GxsChannelPostsWidget::insertPosts(const std::vector& posts) -{ - std::vector cposts; - - for(auto post: posts) // This is not so nice but we have somehow to convert to RsGxsChannelPost at some timer, and the cposts list is being modified in the insert method. - cposts.push_back(*static_cast(post)); - - insertChannelPosts(cposts); -} -#endif - class GxsChannelPostsReadData { public: diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index 0f3405cda..e6795a63b 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -536,6 +536,16 @@ p, li { white-space: pre-wrap; }
+ + + Files + + + + + + +
From 944c5b3592bcb0f976bae77d79f8330f97ebe540 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 7 Jun 2020 14:50:31 +0200 Subject: [PATCH 043/154] added list of files for the whole channel --- .../gxschannels/GxsChannelPostFilesModel.cpp | 35 ++++++------------- .../gxschannels/GxsChannelPostFilesModel.h | 10 ++---- .../gui/gxschannels/GxsChannelPostsModel.cpp | 16 +++++++++ .../gui/gxschannels/GxsChannelPostsModel.h | 5 +++ .../GxsChannelPostsWidgetWithModel.cpp | 17 +++++++++ .../GxsChannelPostsWidgetWithModel.h | 2 ++ .../GxsChannelPostsWidgetWithModel.ui | 16 +++++++-- 7 files changed, 67 insertions(+), 34 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp index 06ba27a0f..b1b7eddbd 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp @@ -345,6 +345,7 @@ QVariant RsGxsChannelPostFilesModel::data(const QModelIndex &index, int role) co { case Qt::DisplayRole: return displayRole (fmpe,index.column()) ; case Qt::UserRole: return userRole (fmpe,index.column()) ; + case SortRole: return sortRole (fmpe,index.column()) ; #ifdef TODO case Qt::DecorationRole: return decorationRole(fmpe,index.column()) ; case Qt::ToolTipRole: return toolTipRole (fmpe,index.column()) ; @@ -355,7 +356,6 @@ QVariant RsGxsChannelPostFilesModel::data(const QModelIndex &index, int role) co case ThreadPinnedRole: return pinnedRole (fmpe,index.column()) ; case MissingRole: return missingRole (fmpe,index.column()) ; case StatusRole: return statusRole (fmpe,index.column()) ; - case SortRole: return sortRole (fmpe,index.column()) ; #endif default: return QVariant(); @@ -542,39 +542,26 @@ QVariant RsGxsChannelPostFilesModel::sizeHintRole(int col) const #endif } -#ifdef TODO -QVariant RsGxsForumModel::authorRole(const ForumModelPostEntry& fmpe,int column) const -{ - if(column == COLUMN_THREAD_DATA) - return QVariant(QString::fromStdString(fmpe.mAuthorId.toStdString())); - - return QVariant(); -} - -QVariant RsGxsForumModel::sortRole(const ForumModelPostEntry& fmpe,int column) const +QVariant RsGxsChannelPostFilesModel::sortRole(const RsGxsFile& fmpe,int column) const { switch(column) { - case COLUMN_THREAD_DATE: if(mSortMode == SORT_MODE_PUBLISH_TS) - return QVariant(QString::number(fmpe.mPublishTs)); // we should probably have leading zeroes here - else - return QVariant(QString::number(fmpe.mMostRecentTsInThread)); // we should probably have leading zeroes here - - case COLUMN_THREAD_READ: return QVariant((bool)IS_MSG_UNREAD(fmpe.mMsgStatus)); - case COLUMN_THREAD_DISTRIBUTION: return decorationRole(fmpe,column); - case COLUMN_THREAD_AUTHOR: + case COLUMN_FILES_NAME: return QVariant(QString::fromUtf8(fmpe.mName.c_str())); + case COLUMN_FILES_SIZE: return QVariant(qulonglong(fmpe.mSize)); + case COLUMN_FILES_FILE: { - QString str,comment ; - QList icons; - GxsIdDetails::MakeIdDesc(fmpe.mAuthorId, false, str, icons, comment,GxsIdDetails::ICON_TYPE_NONE); + FileInfo finfo; + if(rsFiles->FileDetails(fmpe.mHash,RS_FILE_HINTS_DOWNLOAD,finfo)) + return qulonglong(finfo.transfered); - return QVariant(str); + return QVariant(qulonglong(fmpe.mSize)); } + break; + default: return displayRole(fmpe,column); } } -#endif QVariant RsGxsChannelPostFilesModel::displayRole(const RsGxsFile& fmpe,int col) const { diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h index 873f179e8..eb214516a 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h @@ -53,15 +53,9 @@ public: COLUMN_FILES_NB_COLUMNS = 0x03 }; -#ifdef TODO enum Roles{ SortRole = Qt::UserRole+1, - ThreadPinnedRole = Qt::UserRole+2, - MissingRole = Qt::UserRole+3, - StatusRole = Qt::UserRole+4, - UnreadChildrenRole = Qt::UserRole+5, - FilterRole = Qt::UserRole+6, + FilterRole = Qt::UserRole+2, }; -#endif #ifdef TODO enum SortMode{ SORT_MODE_PUBLISH_TS = 0x00, @@ -110,13 +104,13 @@ public: QVariant displayRole (const RsGxsFile& fmpe, int col) const; QVariant toolTipRole (const RsGxsFile& fmpe, int col) const; QVariant userRole (const RsGxsFile& fmpe, int col) const; + QVariant sortRole (const RsGxsFile& fmpe, int col) const; #ifdef TODO QVariant decorationRole(const ForumModelPostEntry& fmpe, int col) const; QVariant pinnedRole (const ForumModelPostEntry& fmpe, int col) const; QVariant missingRole (const ForumModelPostEntry& fmpe, int col) const; QVariant statusRole (const ForumModelPostEntry& fmpe, int col) const; QVariant authorRole (const ForumModelPostEntry& fmpe, int col) const; - QVariant sortRole (const ForumModelPostEntry& fmpe, int col) const; QVariant fontRole (const ForumModelPostEntry& fmpe, int col) const; QVariant filterRole (const ForumModelPostEntry& fmpe, int col) const; QVariant textColorRole (const ForumModelPostEntry& fmpe, int col) const; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index 6fc4325a5..87cd08ca8 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -71,6 +71,22 @@ void RsGxsChannelPostsModel::postMods() emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mPosts.size(),mColumns-1,(void*)NULL)); } +void RsGxsChannelPostsModel::getFilesList(std::list& files) +{ + // We use an intermediate map so as to remove duplicates + + std::map files_map; + + for(uint32_t i=1;i& files); + #ifdef TODO void setSortMode(SortMode mode) ; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 4a64024a1..550e97d39 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -255,8 +255,11 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->channelPostFiles_TV->setPlaceholderText(tr("Post files")); ui->channelFiles_TV->setPlaceholderText(tr("All files in the channel")); + ui->channelFiles_TV->setModel(mChannelFilesModel = new RsGxsChannelPostFilesModel()); + ui->channelFiles_TV->setItemDelegate(new ChannelPostFilesDelegate()); connect(ui->postsTree->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),this,SLOT(showPostDetails())); + connect(mChannelPostsModel,SIGNAL(channelLoaded()),this,SLOT(updateChannelFiles())); QFontMetricsF fm(font()); @@ -416,6 +419,20 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_NAME); ui->channelPostFiles_TV->setAutoSelect(true); + +} + +void GxsChannelPostsWidgetWithModel::updateChannelFiles() +{ + std::list files; + + mChannelPostsModel->getFilesList(files); + mChannelFilesModel->setFiles(files); + + ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE); + ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); + ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_NAME); + ui->channelFiles_TV->setAutoSelect(true); } void GxsChannelPostsWidgetWithModel::updateGroupData() diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index 48caeaf49..c679a732d 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -136,6 +136,7 @@ private slots: void setViewMode(int viewMode); void settingsChanged(); void handlePostsTreeSizeChange(QSize s); + void updateChannelFiles(); private: void processSettings(bool load); @@ -157,6 +158,7 @@ private: RsGxsChannelPostsModel *mChannelPostsModel; RsGxsChannelPostFilesModel *mChannelPostFilesModel; + RsGxsChannelPostFilesModel *mChannelFilesModel; /* UI - from Designer */ Ui::GxsChannelPostsWidgetWithModel *ui; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index e6795a63b..5cc94fbbc 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -224,7 +224,7 @@ - 1 + 2 @@ -530,6 +530,11 @@ p, li { white-space: pre-wrap; } Comments + + + + + @@ -542,7 +547,14 @@ p, li { white-space: pre-wrap; } - + + + QAbstractItemView::CurrentChanged|QAbstractItemView::SelectedClicked + + + true + + From 1cb6369cb6e0febeb49d4f2141be0077164528cd Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 7 Jun 2020 22:50:17 +0200 Subject: [PATCH 044/154] added comments --- .../src/gui/gxs/GxsCommentDialog.cpp | 22 ++++++++++++++++--- retroshare-gui/src/gui/gxs/GxsCommentDialog.h | 4 ++++ .../GxsChannelPostsWidgetWithModel.cpp | 9 ++++++-- .../GxsChannelPostsWidgetWithModel.ui | 12 +++++++--- 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/retroshare-gui/src/gui/gxs/GxsCommentDialog.cpp b/retroshare-gui/src/gui/gxs/GxsCommentDialog.cpp index f9b8b1dbc..6512c0c54 100644 --- a/retroshare-gui/src/gui/gxs/GxsCommentDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsCommentDialog.cpp @@ -36,10 +36,12 @@ GxsCommentDialog::GxsCommentDialog(QWidget *parent, RsTokenService *token_servic /* Invoke the Qt Designer generated QObject setup routine */ ui->setupUi(this); - //ui->postFrame->setVisible(false); - - ui->treeWidget->setup(token_service, comment_service); + setTokenService(token_service,comment_service); + init(); +} +void GxsCommentDialog::init() +{ /* Set header resize modes and initial section sizes */ QHeaderView * ttheader = ui->treeWidget->header () ; ttheader->resizeSection (0, 440); @@ -62,6 +64,20 @@ GxsCommentDialog::GxsCommentDialog(QWidget *parent, RsTokenService *token_servic ui->sortBox->setIconSize(QSize(S*1.5,S*1.5)); } +void GxsCommentDialog::setTokenService(RsTokenService *token_service, RsGxsCommentService *comment_service) +{ + ui->treeWidget->setup(token_service, comment_service); +} + +GxsCommentDialog::GxsCommentDialog(QWidget *parent) + : QWidget(parent), ui(new Ui::GxsCommentDialog) +{ + /* Invoke the Qt Designer generated QObject setup routine */ + ui->setupUi(this); + + init(); +} + GxsCommentDialog::~GxsCommentDialog() { delete(ui); diff --git a/retroshare-gui/src/gui/gxs/GxsCommentDialog.h b/retroshare-gui/src/gui/gxs/GxsCommentDialog.h index 82d2fdbd1..4c506dd21 100644 --- a/retroshare-gui/src/gui/gxs/GxsCommentDialog.h +++ b/retroshare-gui/src/gui/gxs/GxsCommentDialog.h @@ -32,9 +32,11 @@ class GxsCommentDialog: public QWidget Q_OBJECT public: + GxsCommentDialog(QWidget *parent); GxsCommentDialog(QWidget *parent, RsTokenService *token_service, RsGxsCommentService *comment_service); virtual ~GxsCommentDialog(); + void setTokenService(RsTokenService *token_service, RsGxsCommentService *comment_service); void setCommentHeader(QWidget *header); void commentLoad(const RsGxsGroupId &grpId, const std::set &msg_versions, const RsGxsMessageId &most_recent_msgId); @@ -48,6 +50,8 @@ private slots: void sortComments(int); private: + void init(); + RsGxsGroupId mGrpId; RsGxsMessageId mMostRecentMsgId; std::set mMsgVersions; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 550e97d39..82bc63234 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -322,6 +322,8 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->subscribeToolButton->addSubscribedAction(mAutoDownloadAction); + ui->commentsDialog->setTokenService(rsGxsChannels->getTokenService(),rsGxsChannels); + /* Initialize GUI */ setAutoDownload(false); settingsChanged(); @@ -394,6 +396,11 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() mChannelPostFilesModel->setFiles(post.mFiles); + auto all_msgs_versions(post.mOlderVersions); + all_msgs_versions.insert(post.mMeta.mMsgId); + + ui->commentsDialog->commentLoad(post.mMeta.mGroupId, all_msgs_versions, post.mMeta.mMsgId); + std::cerr << "Showing details about selected index : "<< index.row() << "," << index.column() << std::endl; ui->postDetails_TE->setText(RsHtml().formatText(NULL, QString::fromUtf8(post.mMsg.c_str()), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); @@ -417,7 +424,6 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE); ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); - ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_NAME); ui->channelPostFiles_TV->setAutoSelect(true); } @@ -431,7 +437,6 @@ void GxsChannelPostsWidgetWithModel::updateChannelFiles() ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE); ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); - ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_NAME); ui->channelFiles_TV->setAutoSelect(true); } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index 5cc94fbbc..7bee202b7 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -224,7 +224,7 @@ - 2 + 1 @@ -448,7 +448,7 @@ p, li { white-space: pre-wrap; }
- 1 + 2 @@ -532,7 +532,7 @@ p, li { white-space: pre-wrap; } - + @@ -593,6 +593,12 @@ p, li { white-space: pre-wrap; } QTreeView
gui/common/RSTreeView.h
+ + GxsCommentDialog + QWidget +
gui/gxs/GxsCommentDialog.h
+ 1 +
From 730a3be2e4c86ccf9fa744b2cf7941bfcf704cbe Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 8 Jun 2020 20:56:59 +0200 Subject: [PATCH 045/154] added filtering for posts --- .../gui/gxschannels/GxsChannelPostsModel.cpp | 80 +++++++++++++------ .../gui/gxschannels/GxsChannelPostsModel.h | 10 ++- .../GxsChannelPostsWidgetWithModel.cpp | 13 +-- .../GxsChannelPostsWidgetWithModel.h | 2 +- 4 files changed, 70 insertions(+), 35 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index 87cd08ca8..8800513eb 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -45,15 +45,17 @@ const QString RsGxsChannelPostsModel::FilterString("filtered"); RsGxsChannelPostsModel::RsGxsChannelPostsModel(QObject *parent) : QAbstractItemModel(parent), mTreeMode(TREE_MODE_PLAIN), mColumns(6) { - initEmptyHierarchy(mPosts); + initEmptyHierarchy(); } -void RsGxsChannelPostsModel::initEmptyHierarchy(std::vector& posts) +void RsGxsChannelPostsModel::initEmptyHierarchy() { preMods(); - posts.resize(1); // adds a sentinel item - posts[0].mMeta.mMsgName = "Root sentinel post" ; + mPosts.resize(1); // adds a sentinel item + mPosts[0].mMeta.mMsgName = "Root sentinel post" ; + mFilteredPosts.resize(1); + mFilteredPosts[0] = 1; postMods(); } @@ -68,7 +70,7 @@ void RsGxsChannelPostsModel::postMods() { endResetModel(); - emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mPosts.size(),mColumns-1,(void*)NULL)); + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mFilteredPosts.size(),mColumns-1,(void*)NULL)); } void RsGxsChannelPostsModel::getFilesList(std::list& files) @@ -87,17 +89,43 @@ void RsGxsChannelPostsModel::getFilesList(std::list& files) files.push_back(it.second); } -void RsGxsChannelPostsModel::setTreeMode(TreeMode mode) +void RsGxsChannelPostsModel::setFilter(const QStringList& strings, uint32_t& count) { - if(mode == mTreeMode) - return; - preMods(); - // We're not removing/adding rows here. We're simply asking for re-draw. + beginRemoveRows(QModelIndex(),0,rowCount()-1); + endRemoveRows(); - mTreeMode = mode; - postMods(); + if(strings.empty()) + { + mFilteredPosts.clear(); + for(int i=0;i 0) return 0; - if(mPosts.empty()) // security. Should never happen. + if(mFilteredPosts.empty()) // security. Should never happen. return 0; if(!parent.isValid()) - return (mPosts.size()-1 + mColumns-1)/mColumns; // mPosts always has an item at 0, so size()>=1, and mColumn>=1 + return (mFilteredPosts.size()-1 + mColumns-1)/mColumns; // mFilteredPosts always has an item at 0, so size()>=1, and mColumn>=1 RsErr() << __PRETTY_FUNCTION__ << " rowCount cannot figure out the porper number of rows." << std::endl; return 0; @@ -128,10 +156,10 @@ bool RsGxsChannelPostsModel::getPostData(const QModelIndex& i,RsGxsChannelPost& quintptr ref = i.internalId(); uint32_t entry = 0; - if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mFilteredPosts.size()) return false ; - fmpe = mPosts[entry]; + fmpe = mPosts[mFilteredPosts[entry]]; return true; @@ -247,7 +275,7 @@ quintptr RsGxsChannelPostsModel::getParentRow(quintptr ref,int& row) const { ChannelPostsModelIndex ref_entry; - if(!convertRefPointerToTabEntry(ref,ref_entry) || ref_entry >= mPosts.size()) + if(!convertRefPointerToTabEntry(ref,ref_entry) || ref_entry >= mFilteredPosts.size()) return 0 ; if(ref_entry == 0) @@ -302,7 +330,7 @@ QVariant RsGxsChannelPostsModel::data(const QModelIndex &index, int role) const return QVariant() ; } - if(!convertRefPointerToTabEntry(ref,entry) || entry >= mPosts.size()) + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mFilteredPosts.size()) { #ifdef DEBUG_CHANNEL_MODEL std::cerr << "Bad pointer: " << (void*)ref << std::endl; @@ -310,7 +338,7 @@ QVariant RsGxsChannelPostsModel::data(const QModelIndex &index, int role) const return QVariant() ; } - const RsGxsChannelPost& fmpe(mPosts[entry]); + const RsGxsChannelPost& fmpe(mPosts[mFilteredPosts[entry]]); switch(role) { @@ -367,7 +395,7 @@ void RsGxsChannelPostsModel::clear() preMods(); mPosts.clear(); - initEmptyHierarchy(mPosts); + initEmptyHierarchy(); postMods(); emit channelLoaded(); @@ -385,6 +413,10 @@ void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vecto createPostsArray(posts); + mFilteredPosts.clear(); + for(int i=0;i= mPosts.size()) + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mFilteredPosts.size()) return ; #warning TODO @@ -603,11 +635,11 @@ QModelIndex RsGxsChannelPostsModel::getIndexOfMessage(const RsGxsMessageId& mid) RsGxsMessageId postId = mid; - for(uint32_t i=1;i &msgs_array, std::vector &posts, std::map > > &mPostVersions); void createPostsArray(std::vector &posts); void setPosts(const RsGxsChannelGroup& group, std::vector &posts); - void initEmptyHierarchy(std::vector& posts); + void initEmptyHierarchy(); + + std::vector mFilteredPosts; // stores the list of displayes indices due to filtering. + std::vector mPosts ; // store the list of posts updated from rsForums. - std::vector mPosts ; // store the list of posts updated from rsForums. //std::map > > mPostVersions; // stores versions of posts QColor mTextColorRead ; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 82bc63234..bfae93391 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -209,6 +209,7 @@ void ChannelPostFilesDelegate::paint(QPainter * painter, const QStyleOptionViewI GxsChannelFilesStatusWidget w(file); w.setFixedWidth(option.rect.width()); + w.setFixedHeight(option.rect.height()); QPixmap pixmap(w.size()); pixmap.fill(QRgb(0x00ffffff)); // choose a fully transparent background @@ -283,7 +284,8 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), ui->feedWidget, SLOT(setFilterText(QString))); connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), ui->fileWidget, SLOT(setFilterText(QString))); #endif - connect(ui->filterLineEdit, SIGNAL(filterChanged(int)), this, SLOT(filterChanged(int))); + connect(ui->filterLineEdit, SIGNAL(filterChanged(int)), this, SLOT(filterChanged())); + connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged())); /* Initialize view button */ //setViewMode(VIEW_MODE_FEEDS); see processSettings @@ -743,12 +745,11 @@ void GxsChannelPostsWidgetWithModel::setViewMode(int viewMode) #endif } -void GxsChannelPostsWidgetWithModel::filterChanged(int filter) +void GxsChannelPostsWidgetWithModel::filterChanged() { -#ifdef TODO - ui->feedWidget->setFilterType(filter); - ui->fileWidget->setFilterType(filter); -#endif + QStringList ql = ui->filterLineEdit->text().split(' ',QString::SkipEmptyParts); + uint32_t count; + mChannelPostsModel->setFilter(ql,count); } #ifdef TODO diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index c679a732d..a4e70d75e 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -132,7 +132,7 @@ private slots: void createMsg(); void toggleAutoDownload(); void subscribeGroup(bool subscribe); - void filterChanged(int filter); + void filterChanged(); void setViewMode(int viewMode); void settingsChanged(); void handlePostsTreeSizeChange(QSize s); From 405fd2b5cae7bbf2cf0b1b16dccfe3faaf7b1113 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 8 Jun 2020 21:09:23 +0200 Subject: [PATCH 046/154] removed some unused buttons --- .../GxsChannelPostsWidgetWithModel.cpp | 55 +++++++------- .../GxsChannelPostsWidgetWithModel.h | 2 +- .../GxsChannelPostsWidgetWithModel.ui | 71 +------------------ 3 files changed, 29 insertions(+), 99 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index bfae93391..3aa9084d6 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -277,31 +277,24 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->postButton->setText(tr("Add new post")); /* add filter actions */ - ui->filterLineEdit->addFilter(QIcon(), tr("Title"), FILTER_TITLE, tr("Search Title")); - ui->filterLineEdit->addFilter(QIcon(), tr("Message"), FILTER_MSG, tr("Search Message")); - ui->filterLineEdit->addFilter(QIcon(), tr("Filename"), FILTER_FILE_NAME, tr("Search Filename")); -#ifdef TODO - connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), ui->feedWidget, SLOT(setFilterText(QString))); - connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), ui->fileWidget, SLOT(setFilterText(QString))); -#endif - connect(ui->filterLineEdit, SIGNAL(filterChanged(int)), this, SLOT(filterChanged())); - connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged())); + connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); /* Initialize view button */ //setViewMode(VIEW_MODE_FEEDS); see processSettings //ui->infoWidget->hide(); - QSignalMapper *signalMapper = new QSignalMapper(this); - connect(ui->feedToolButton, SIGNAL(clicked()), signalMapper, SLOT(map())); - connect(ui->fileToolButton, SIGNAL(clicked()), signalMapper, SLOT(map())); - signalMapper->setMapping(ui->feedToolButton, VIEW_MODE_FEEDS); - signalMapper->setMapping(ui->fileToolButton, VIEW_MODE_FILES); - connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(setViewMode(int))); + //QSignalMapper *signalMapper = new QSignalMapper(this); + //connect(ui->feedToolButton, SIGNAL(clicked()), signalMapper, SLOT(map())); + //connect(ui->fileToolButton, SIGNAL(clicked()), signalMapper, SLOT(map())); + //signalMapper->setMapping(ui->feedToolButton, VIEW_MODE_FEEDS); + //signalMapper->setMapping(ui->fileToolButton, VIEW_MODE_FILES); + //connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(setViewMode(int))); /*************** Setup Left Hand Side (List of Channels) ****************/ - ui->loadingLabel->hide(); - ui->progressBar->hide(); + //ui->loadingLabel->hide(); + //ui->progressBar->hide(); + ui->postsTree->setPlaceholderText(tr("Thumbnails")); ui->postsTree->setMinimumWidth(COLUMN_SIZE_FONT_FACTOR_W*QFontMetricsF(font()).height()+1); @@ -521,21 +514,25 @@ void GxsChannelPostsWidgetWithModel::processSettings(bool load) Settings->beginGroup(QString("ChannelPostsWidget")); if (load) { +#ifdef TO_REMOVE // load settings /* Filter */ - ui->filterLineEdit->setCurrentFilter(Settings->value("filter", FILTER_TITLE).toInt()); + //ui->filterLineEdit->setCurrentFilter(Settings->value("filter", FILTER_TITLE).toInt()); /* View mode */ - setViewMode(Settings->value("viewMode", VIEW_MODE_FEEDS).toInt()); + //setViewMode(Settings->value("viewMode", VIEW_MODE_FEEDS).toInt()); +#endif } else { +#ifdef TO_REMOVE // save settings /* Filter */ - Settings->setValue("filter", ui->filterLineEdit->currentFilter()); + //Settings->setValue("filter", ui->filterLineEdit->currentFilter()); /* View mode */ - Settings->setValue("viewMode", viewMode()); + //Settings->setValue("viewMode", viewMode()); +#endif } Settings->endGroup(); @@ -629,8 +626,8 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou if (IS_GROUP_SUBSCRIBED(group.mMeta.mSubscribeFlags)) { ui->subscribeToolButton->setText(tr("Subscribed") + " " + QString::number(group.mMeta.mPop) ); - ui->feedToolButton->setEnabled(true); - ui->fileToolButton->setEnabled(true); + //ui->feedToolButton->setEnabled(true); + //ui->fileToolButton->setEnabled(true); ui->channel_TW->setTabEnabled(CHANNEL_TABS_POSTS,true); ui->details_TW->setEnabled(true); } @@ -698,14 +695,15 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou ui->infoWidget->show(); ui->feedWidget->hide(); ui->fileWidget->hide(); -#endif - ui->feedToolButton->setEnabled(false); - ui->fileToolButton->setEnabled(false); + //ui->feedToolButton->setEnabled(false); + //ui->fileToolButton->setEnabled(false); +#endif ui->subscribeToolButton->setText(tr("Subscribe ") + " " + QString::number(group.mMeta.mPop) ); } +#ifdef TODO int GxsChannelPostsWidgetWithModel::viewMode() { if (ui->feedToolButton->isChecked()) { @@ -717,6 +715,7 @@ int GxsChannelPostsWidgetWithModel::viewMode() /* Default */ return VIEW_MODE_FEEDS; } +#endif void GxsChannelPostsWidgetWithModel::setViewMode(int viewMode) { @@ -745,9 +744,9 @@ void GxsChannelPostsWidgetWithModel::setViewMode(int viewMode) #endif } -void GxsChannelPostsWidgetWithModel::filterChanged() +void GxsChannelPostsWidgetWithModel::filterChanged(QString s) { - QStringList ql = ui->filterLineEdit->text().split(' ',QString::SkipEmptyParts); + QStringList ql = s.split(' ',QString::SkipEmptyParts); uint32_t count; mChannelPostsModel->setFilter(ql,count); } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index a4e70d75e..8dd9a66bd 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -132,7 +132,7 @@ private slots: void createMsg(); void toggleAutoDownload(); void subscribeGroup(bool subscribe); - void filterChanged(); + void filterChanged(QString); void setViewMode(int viewMode); void settingsChanged(); void handlePostsTreeSizeChange(QSize s); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index 7bee202b7..84a73fb9c 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -120,78 +120,15 @@ - - - - Loading - - - - - - - - 0 - 0 - - - - - 16777215 - 10 - - - - 1000 - - - 0 - - - 0 - - - - Show feeds - - - - :/images/view-feeds.png:/images/view-feeds.png - - - true - - - true - - - - - - - Show files - - - - :/images/view-files.png:/images/view-files.png - - - true - - - true - - - - + 0 @@ -583,11 +520,6 @@ p, li { white-space: pre-wrap; } QToolButton
gui/common/SubscribeToolButton.h
- - LineEditClear - QLineEdit -
gui/common/LineEditClear.h
-
RSTreeView QTreeView @@ -601,7 +533,6 @@ p, li { white-space: pre-wrap; } - From 32050af8da471d6b773c9ade456a468abac0a87c Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 8 Jun 2020 21:26:48 +0200 Subject: [PATCH 047/154] fixed bug causing impossibility to display thumbnails with one post only --- .../src/gui/gxschannels/GxsChannelPostsModel.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index 8800513eb..b2363b99c 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -52,10 +52,12 @@ void RsGxsChannelPostsModel::initEmptyHierarchy() { preMods(); - mPosts.resize(1); // adds a sentinel item - mPosts[0].mMeta.mMsgName = "Root sentinel post" ; - mFilteredPosts.resize(1); - mFilteredPosts[0] = 1; + mPosts.clear(); + mFilteredPosts.clear(); +// mPosts.resize(1); // adds a sentinel item +// mPosts[0].mMeta.mMsgName = "Root sentinel post" ; +// mFilteredPosts.resize(1); +// mFilteredPosts[0] = 1; postMods(); } @@ -105,9 +107,9 @@ void RsGxsChannelPostsModel::setFilter(const QStringList& strings, uint32_t& cou else { mFilteredPosts.clear(); - mFilteredPosts.push_back(0); + //mFilteredPosts.push_back(0); - for(int i=1;i=1, and mColumn>=1 + return (mFilteredPosts.size() + mColumns-1)/mColumns; // mFilteredPosts always has an item at 0, so size()>=1, and mColumn>=1 RsErr() << __PRETTY_FUNCTION__ << " rowCount cannot figure out the porper number of rows." << std::endl; return 0; From fe591c2bd7d1f08931b54d02e12318d37ecbcd8f Mon Sep 17 00:00:00 2001 From: defnax Date: Tue, 9 Jun 2020 00:23:46 +0200 Subject: [PATCH 048/154] fixing stylesheet for the subscribe button --- .../src/gui/qss/stylesheet/Standard.qss | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/retroshare-gui/src/gui/qss/stylesheet/Standard.qss b/retroshare-gui/src/gui/qss/stylesheet/Standard.qss index 53ac80a44..9024c6a83 100644 --- a/retroshare-gui/src/gui/qss/stylesheet/Standard.qss +++ b/retroshare-gui/src/gui/qss/stylesheet/Standard.qss @@ -745,12 +745,7 @@ GxsForumMsgItem QFrame#frame{ background-color: white; } -GxsChannelPostsWidget QFrame#infoFrame -{ - -} - -GxsChannelPostsWidget QToolButton#subscribeToolButton { +GxsChannelPostsWidgetWithModel QToolButton#subscribeToolButton { font: bold; font-size: 14px; color: white; @@ -759,18 +754,18 @@ GxsChannelPostsWidget QToolButton#subscribeToolButton { max-height: 27px; } -GxsChannelPostsWidget QToolButton#subscribeToolButton:hover { +GxsChannelPostsWidgetWithModel QToolButton#subscribeToolButton:hover { background: #03b1f3; border-radius: 4px; } -GxsChannelPostsWidget QToolButton#subscribeToolButton:pressed { +GxsChannelPostsWidgetWithModel QToolButton#subscribeToolButton:pressed { background: #03b1f3; border-radius: 4px; border: 1px solid gray; } -GxsChannelPostsWidget QToolButton#subscribeToolButton:disabled { +GxsChannelPostsWidgetWithModel QToolButton#subscribeToolButton:disabled { background: gray; border-radius: 4px; border: 1px solid gray; @@ -778,15 +773,15 @@ GxsChannelPostsWidget QToolButton#subscribeToolButton:disabled { } /* only for MenuButtonPopup */ -GxsChannelPostsWidget QToolButton#subscribeToolButton[popupMode="1"] { +GxsChannelPostsWidgetWithModel QToolButton#subscribeToolButton[popupMode="1"] { padding-right: 0px; } -GxsChannelPostsWidget QToolButton#subscribeToolButton::menu-arrow { +GxsChannelPostsWidgetWithModel QToolButton#subscribeToolButton::menu-arrow { image: none; } -GxsChannelPostsWidget QToolButton#subscribeToolButton::menu-button { +GxsChannelPostsWidgetWithModel QToolButton#subscribeToolButton::menu-button { image: none; } From f99a8a0fc63d8eb404100246b31b1f6ad2e2ba44 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Tue, 9 Jun 2020 16:10:07 +0200 Subject: [PATCH 049/154] Improve homogeneity of rsdebug Offer variadic style macros also for RsInfo...RsFatal --- libretroshare/src/util/rsdebug.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/libretroshare/src/util/rsdebug.h b/libretroshare/src/util/rsdebug.h index 4a88d8c90..71645e6dc 100644 --- a/libretroshare/src/util/rsdebug.h +++ b/libretroshare/src/util/rsdebug.h @@ -148,7 +148,8 @@ RS_DBG4("Hello 4 ", "my debug ", my_variable) << " message " << variable2; * even if are not printed, due to how C++ is made it is not possible to avoid * this, so we suggest to use variadic style for debug messages. */ -using RsDbg = t_RsLogger; +using RsDbg = t_RsLogger; +#define RS_DBG(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__) /** * Comfortable log information reporting helper, supports chaining like @@ -158,17 +159,21 @@ using RsDbg = t_RsLogger; RsInfo() << __PRETTY_FUNCTION__ << "My information message" << std::cerr; @endcode */ -using RsInfo = t_RsLogger; +using RsInfo = t_RsLogger; +#define RS_INFO(...) RsInfo(__PRETTY_FUNCTION__, " ", __VA_ARGS__) /// Similar to @see RsInfo but for warning messages -using RsWarn = t_RsLogger; +using RsWarn = t_RsLogger; +#define RS_WARN(...) RsWarn(__PRETTY_FUNCTION__, " ", __VA_ARGS__) /// Similar to @see RsInfo but for error messages -using RsErr = t_RsLogger; +using RsErr = t_RsLogger; +#define RS_ERR(...) RsErr(__PRETTY_FUNCTION__, " ", __VA_ARGS__) /** Similar to @see RsInfo but for fatal errors (the ones which cause RetroShare * to terminate) messages */ -using RsFatal = t_RsLogger; +using RsFatal = t_RsLogger; +#define RS_FATAL(...) RsFatal(__PRETTY_FUNCTION__, " ", __VA_ARGS__) /** From 4f0e18cbfd48ba13f5b1cb164d0c9f16931abc31 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Tue, 9 Jun 2020 20:02:40 +0200 Subject: [PATCH 050/154] Fix Android armv7 compilation due to narrowing --- libretroshare/src/util/rsdebug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretroshare/src/util/rsdebug.h b/libretroshare/src/util/rsdebug.h index 71645e6dc..49aadcd5a 100644 --- a/libretroshare/src/util/rsdebug.h +++ b/libretroshare/src/util/rsdebug.h @@ -80,7 +80,7 @@ struct t_RsLogger : std::ostringstream /* Combine initializer list and comma operator so the compiler unpack * template arguments and feed our own stream without recursion * see https://stackoverflow.com/a/27375675 */ - using expander = char[]; + using expander = int[]; (void) expander {0, (void((*this) << std::forward(args)), 0)...}; } From 275bdba1329e007e781232422fc222c0974f8d3f Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Tue, 9 Jun 2020 20:08:23 +0200 Subject: [PATCH 051/154] Unify common error category message into a function --- libretroshare/src/retroshare/rsevents.h | 4 ++-- libretroshare/src/retroshare/rsfiles.h | 4 ++-- libretroshare/src/util/rsdebug.cc | 6 ++++++ libretroshare/src/util/rsdebug.h | 5 ++++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/libretroshare/src/retroshare/rsevents.h b/libretroshare/src/retroshare/rsevents.h index 47a499497..65e0e8557 100644 --- a/libretroshare/src/retroshare/rsevents.h +++ b/libretroshare/src/retroshare/rsevents.h @@ -33,6 +33,7 @@ #include "serialiser/rsserializable.h" #include "serialiser/rstypeserializer.h" #include "util/rstime.h" +#include "util/rsdebug.h" class RsEvents; @@ -126,8 +127,7 @@ struct RsEventsErrorCategory: std::error_category case RsEventsErrorNum::INVALID_HANDLER_ID: return "Invalid handler id"; default: - return "Error message for error: " + std::to_string(ev) + - " not available in category: " + name(); + return rsErrorNotInCategory(ev, name()); } } diff --git a/libretroshare/src/retroshare/rsfiles.h b/libretroshare/src/retroshare/rsfiles.h index 92c017cef..fa6b37e29 100644 --- a/libretroshare/src/retroshare/rsfiles.h +++ b/libretroshare/src/retroshare/rsfiles.h @@ -37,6 +37,7 @@ #include "util/rstime.h" #include "retroshare/rsevents.h" #include "util/rsmemory.h" +#include "util/rsdebug.h" class RsFiles; @@ -63,8 +64,7 @@ struct RsFilesErrorCategory: std::error_category case RsFilesErrorNum::FILES_HANDLE_NOT_FOUND: return "Files handle not found"; default: - return "Error message for error: " + std::to_string(ev) + - " not available in category: " + name(); + return rsErrorNotInCategory(ev, name()); } } diff --git a/libretroshare/src/util/rsdebug.cc b/libretroshare/src/util/rsdebug.cc index 93049e1b9..0a4777ab0 100644 --- a/libretroshare/src/util/rsdebug.cc +++ b/libretroshare/src/util/rsdebug.cc @@ -30,6 +30,12 @@ std::ostream &operator<<(std::ostream& out, const std::error_condition& err) << " category: " << err.category().name(); } +std::string rsErrorNotInCategory(int errNum, const std::string& categoryName) +{ + return "Error message for error: " + std::to_string(errNum) + + " not available in category: " + categoryName; +} + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// diff --git a/libretroshare/src/util/rsdebug.h b/libretroshare/src/util/rsdebug.h index 49aadcd5a..6409e9492 100644 --- a/libretroshare/src/util/rsdebug.h +++ b/libretroshare/src/util/rsdebug.h @@ -61,6 +61,10 @@ enum class RsLoggerCategories /** Stream helper for std::error_condition */ std::ostream &operator<<(std::ostream& out, const std::error_condition& err); +/** Provide unkown error message for all error categories to avoid duplicating + * the message around */ +std::string rsErrorNotInCategory(int errNum, const std::string& categoryName); + template struct t_RsLogger : std::ostringstream @@ -201,7 +205,6 @@ struct RsNoDbg - //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// From 4a34cfaf11975d2fdb97c83c964629ba601e03bc Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Tue, 9 Jun 2020 20:13:22 +0200 Subject: [PATCH 052/154] Improve API to create locations Improve on top of sehraf work, add documentation for API token params Deprecate old version and disable it once RS 0.6.6 is released New method take relevant paramethers explicitely instead of having them incapsualted inside a RsLoginHelper::Location struct New method return a proper error_condition instead of boolean + string RsLoginHelper::attemptLogin doesn't need manual wrapper anymore --- libretroshare/src/jsonapi/jsonapi.cpp | 40 +++++-- libretroshare/src/retroshare/rsinit.h | 128 ++++++++++++++++++++--- libretroshare/src/retroshare/rsjsonapi.h | 4 +- libretroshare/src/rsserver/rsinit.cc | 44 ++++++++ 4 files changed, 194 insertions(+), 22 deletions(-) diff --git a/libretroshare/src/jsonapi/jsonapi.cpp b/libretroshare/src/jsonapi/jsonapi.cpp index c219896d4..3dcde2a27 100644 --- a/libretroshare/src/jsonapi/jsonapi.cpp +++ b/libretroshare/src/jsonapi/jsonapi.cpp @@ -165,6 +165,7 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"), RsThread::setStopTimeout(10); #endif +#if !RS_VERSION_AT_LEAST(0,6,6) registerHandler("/rsLoginHelper/createLocation", [this](const std::shared_ptr session) { @@ -215,8 +216,9 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"), DEFAULT_API_CALL_JSON_RETURN(rb::OK); } ); }, false); +#endif // !RS_VERSION_AT_LEAST(0,6,6) - registerHandler("/rsLoginHelper/attemptLogin", + registerHandler("/rsLoginHelper/createLocationV2", [this](const std::shared_ptr session) { auto reqSize = session->get_request()->get_header("Content-Length", 0); @@ -226,25 +228,51 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"), { INITIALIZE_API_CALL_JSON_CONTEXT; - RsPeerId account; + RsPeerId locationId; + RsPgpId pgpId; + std::string locationName; + std::string pgpName; std::string password; + // JSON API only + std::string apiUser; + std::string apiPass; + // deserialize input parameters from JSON { RsGenericSerializer::SerializeContext& ctx(cReq); RsGenericSerializer::SerializeJob j(RsGenericSerializer::FROM_JSON); - RS_SERIAL_PROCESS(account); + RS_SERIAL_PROCESS(locationId); + RS_SERIAL_PROCESS(pgpId); + RS_SERIAL_PROCESS(locationName); + RS_SERIAL_PROCESS(pgpName); RS_SERIAL_PROCESS(password); + + // JSON API only + RS_SERIAL_PROCESS(apiUser); + RS_SERIAL_PROCESS(apiPass); } - // call retroshare C++ API - RsInit::LoadCertificateStatus retval = - rsLoginHelper->attemptLogin(account, password); + std::error_condition retval; + + if(apiUser.empty()) + retval = RsJsonApiErrorNum::TOKEN_FORMAT_INVALID; + + if(!retval) + retval = badApiCredientalsFormat(apiUser, apiPass); + + if(!retval) // call retroshare C++ API + retval = rsLoginHelper->createLocationV2( + locationId, pgpId, locationName, pgpName, password ); + + if(!retval) retval = authorizeUser(apiUser, apiPass); // serialize out parameters and return value to JSON { RsGenericSerializer::SerializeContext& ctx(cAns); RsGenericSerializer::SerializeJob j(RsGenericSerializer::TO_JSON); + RS_SERIAL_PROCESS(locationId); + RS_SERIAL_PROCESS(pgpId); RS_SERIAL_PROCESS(retval); } diff --git a/libretroshare/src/retroshare/rsinit.h b/libretroshare/src/retroshare/rsinit.h index 165649f16..19c0349bb 100644 --- a/libretroshare/src/retroshare/rsinit.h +++ b/libretroshare/src/retroshare/rsinit.h @@ -20,8 +20,7 @@ *******************************************************************************/ #pragma once -/// RetroShare initialization and login API - +/// @file RetroShare initialization and login API // Initialize ok, result >= 0 #define RS_INIT_OK 0 // Initialize ok @@ -32,11 +31,15 @@ #define RS_INIT_NO_KEYRING -3 // Keyring is empty. Need to import it. #define RS_INIT_NO_EXECUTABLE -4 // executable path hasn't been set in config options -#include #include #include #include -#include +#include +#include + +#include "retroshare/rstypes.h" +#include "retroshare/rsversion.h" + class RsLoginHelper; @@ -46,6 +49,71 @@ class RsLoginHelper; */ extern RsLoginHelper* rsLoginHelper; + +enum class RsInitErrorNum : int32_t +{ + ALREADY_LOGGED_IN = 6000, + CANT_ACQUIRE_LOCK = 6001, + INVALID_LOCATION_NAME = 6002, + PGP_NAME_OR_ID_NEEDED = 6003, + PGP_KEY_CREATION_FAILED = 6004, + SSL_KEY_CREATION_FAILED = 6005, + INVALID_SSL_ID = 6006, + LOGIN_FAILED = 6007 +}; + +struct RsInitErrorCategory: std::error_category +{ + const char* name() const noexcept override + { return "RetroShare init"; } + + std::string message(int ev) const override + { + switch (static_cast(ev)) + { + case RsInitErrorNum::ALREADY_LOGGED_IN: + return "Already logged in"; + case RsInitErrorNum::CANT_ACQUIRE_LOCK: + return "Cannot aquire lock on location data. Another instance is " + "already running with this profile?"; + case RsInitErrorNum::INVALID_LOCATION_NAME: + return "Invalid location name"; + case RsInitErrorNum::PGP_NAME_OR_ID_NEEDED: + return "Either PGP name or PGP id is needed"; + case RsInitErrorNum::PGP_KEY_CREATION_FAILED: + return "Failure creating PGP key"; + case RsInitErrorNum::SSL_KEY_CREATION_FAILED: + return "Failure creating SSL key"; + case RsInitErrorNum::INVALID_SSL_ID: + return "Invalid SSL id"; + case RsInitErrorNum::LOGIN_FAILED: + return "Generic login failure"; + default: + return rsErrorNotInCategory(ev, name()); + } + } + + const static RsInitErrorCategory instance; +}; + + +namespace std +{ +/** Register RsJsonApiErrorNum as an error condition enum, must be in std + * namespace */ +template<> struct is_error_condition_enum : true_type {}; +} + +/** Provide RsInitErrorNum conversion to std::error_condition, must be in + * same namespace of RsInitErrorNum */ +inline std::error_condition make_error_condition(RsInitErrorNum e) noexcept +{ + return std::error_condition( + static_cast(e), RsInitErrorCategory::instance ); +}; + + + /** * @brief The RsInitConfig struct * This class contains common configuration options, that executables using libretroshare may want to @@ -85,7 +153,7 @@ struct RsConfigOptions class RsInit { public: - enum LoadCertificateStatus : uint8_t + enum RS_DEPRECATED_FOR(RsInitErrorNum) LoadCertificateStatus : uint8_t { OK, /// Everything go as expected, no error occurred ERR_ALREADY_RUNNING, /// Another istance is running already @@ -317,7 +385,7 @@ public: /** * @brief Normal way to attempt login - * @jsonapi{development,manualwrapper} + * @jsonapi{development,unauthenticated} * @param[in] account Id of the account to which attempt login * @param[in] password Password for the given account * @return RsInit::OK if login attempt success, error code otherwhise @@ -353,6 +421,44 @@ public: void getLocations(std::vector& locations); /** + * @brief Creates a new RetroShare location, and log in once is created + * @jsonapi{development,manualwrapper} + * @param[out] locationId storage for generated location SSL id + * @param[inout] pgpId specify PGP id to use to sign the location, if a null + * id is passed the PGP key is created too and this param is used as + * storage for its id. + * @param[in] password to protect and unlock the associated PGP key + * param[in] apiUser (JSON API only) string containing username for JSON API + * so it can be later used to authenticate JSON API calls. It is passed + * down to @see RsJsonApi::authorizeUser under the hood. + * param[in] apiPass (JSON API only) string containing password for JSON API + * so it can be later used to authenticate JSON API calls. It is passed + * down to @see RsJsonApi::authorizeUser under the hood. + * To improve security we strongly advise to not use the same as the + * password used for the PGP key. + * @return Success or error information + */ + std::error_condition createLocationV2( + RsPeerId& locationId, + RsPgpId& pgpId, + const std::string& locationName, + const std::string& pgpName, + const std::string& password + /* JSON API only + * const std::string& apiUser + * const std::string& apiPass */ ); + + /** + * @brief Check if RetroShare is already logged in, this usually return true + * after a successfull attemptLogin() and before closeSession() + * @jsonapi{development,unauthenticated} + * @return true if already logged in, false otherwise + */ + bool isLoggedIn(); + +#if !RS_VERSION_AT_LEAST(0,6,6) + /** + * @deprecated Use @see createLocationV2 instead * @brief Creates a new RetroShare location, and log in once is created * @jsonapi{development,manualwrapper} * @param[inout] location provide input information to generate the location @@ -365,15 +471,9 @@ public: * Tor hidden location. UNTESTED! * @return true if success, false otherwise */ + RS_DEPRECATED_FOR(createLocationV2) bool createLocation( RsLoginHelper::Location& location, const std::string& password, std::string& errorMessage, bool makeHidden = false, bool makeAutoTor = false ); - - /** - * @brief Check if RetroShare is already logged in, this usually return true - * after a successfull attemptLogin() and before closeSession() - * @jsonapi{development,unauthenticated} - * @return true if already logged in, false otherwise - */ - bool isLoggedIn(); +#endif // !RS_VERSION_AT_LEAST(0,6,6) }; diff --git a/libretroshare/src/retroshare/rsjsonapi.h b/libretroshare/src/retroshare/rsjsonapi.h index 147011787..38e33490e 100644 --- a/libretroshare/src/retroshare/rsjsonapi.h +++ b/libretroshare/src/retroshare/rsjsonapi.h @@ -29,6 +29,7 @@ #include #include +#include "util/rsdebug.h" #include "util/rsmemory.h" class RsJsonApi; @@ -74,8 +75,7 @@ struct RsJsonApiErrorCategory: std::error_category case RsJsonApiErrorNum::NOT_A_MACHINE_GUN: return "Method must not be called in burst"; default: - return "Error message for error: " + std::to_string(ev) + - " not available in category: " + name(); + return rsErrorNotInCategory(ev, name()); } } diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 25391fcbe..5dcccfe0c 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -114,6 +114,8 @@ RsLoginHelper* rsLoginHelper = nullptr; RsAccounts* rsAccounts = nullptr; +const RsInitErrorCategory RsInitErrorCategory::instance; + RsConfigOptions::RsConfigOptions() : autoLogin(false), @@ -1950,6 +1952,47 @@ void RsLoginHelper::getLocations(std::vector& store) } } +std::error_condition RsLoginHelper::createLocationV2( + RsPeerId& locationId, RsPgpId& pgpId, + const std::string& locationName, const std::string& pgpName, + const std::string& password ) +{ + if(isLoggedIn()) return RsInitErrorNum::ALREADY_LOGGED_IN; + if(locationName.empty()) return RsInitErrorNum::INVALID_LOCATION_NAME; + if(pgpId.isNull() && pgpName.empty()) + return RsInitErrorNum::PGP_NAME_OR_ID_NEEDED; + + std::string errorMessage; + if(pgpId.isNull() && !RsAccounts::GeneratePGPCertificate( + pgpName, "", password, pgpId, 4096, errorMessage ) ) + { + RS_ERR("Failure creating PGP key: ", errorMessage); + return RsInitErrorNum::PGP_KEY_CREATION_FAILED; + } + + std::string sslPassword = + RsRandom::random_alphaNumericString(RsInit::getSslPwdLen()); + + rsNotify->cachePgpPassphrase(password); + rsNotify->setDisableAskPassword(true); + + bool ret = RsAccounts::createNewAccount( + pgpId, "", locationName, "", false, false, sslPassword, + locationId, errorMessage ); + if(!ret) + { + RS_ERR("Failure creating SSL key: ", errorMessage); + return RsInitErrorNum::SSL_KEY_CREATION_FAILED; + } + + RsInit::LoadPassword(sslPassword); + ret = (RsInit::OK == attemptLogin(locationId, password)); + rsNotify->setDisableAskPassword(false); + + return (ret ? std::error_condition() : RsInitErrorNum::LOGIN_FAILED); +} + +#if !RS_VERSION_AT_LEAST(0,6,6) bool RsLoginHelper::createLocation( RsLoginHelper::Location& l, const std::string& password, std::string& errorMessage, bool makeHidden, bool makeAutoTor ) @@ -1991,6 +2034,7 @@ bool RsLoginHelper::createLocation( rsNotify->setDisableAskPassword(false); return ret; } +#endif // !RS_VERSION_AT_LEAST(0,6,6) bool RsLoginHelper::isLoggedIn() { From dc61167733df4bcfc8fd7ed3c0a32ffca2baa47a Mon Sep 17 00:00:00 2001 From: defnax Date: Tue, 9 Jun 2020 21:03:55 +0200 Subject: [PATCH 053/154] store splitter position --- .../src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 3aa9084d6..ab299d343 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -523,6 +523,8 @@ void GxsChannelPostsWidgetWithModel::processSettings(bool load) /* View mode */ //setViewMode(Settings->value("viewMode", VIEW_MODE_FEEDS).toInt()); #endif + // state of splitter + ui->splitter->restoreState(Settings->value("SplitterChannelPosts").toByteArray()); } else { #ifdef TO_REMOVE // save settings @@ -533,6 +535,8 @@ void GxsChannelPostsWidgetWithModel::processSettings(bool load) /* View mode */ //Settings->setValue("viewMode", viewMode()); #endif + // state of splitter + Settings->setValue("SplitterChannelPosts", ui->splitter->saveState()); } Settings->endGroup(); From c9019a7e99ab0d4f07df11840f7e7f749c16c1c6 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 9 Jun 2020 21:08:21 +0200 Subject: [PATCH 054/154] added sorting and filtering for files using a QPSortFilterProxyModel but it doesnt work yet --- .../gxschannels/GxsChannelPostFilesModel.cpp | 10 ---- .../gxschannels/GxsChannelPostFilesModel.h | 2 +- .../gui/gxschannels/GxsChannelPostsModel.cpp | 2 - .../gui/gxschannels/GxsChannelPostsModel.h | 2 - .../GxsChannelPostsWidgetWithModel.cpp | 57 ++++++++++++++++++- .../GxsChannelPostsWidgetWithModel.h | 4 ++ .../GxsChannelPostsWidgetWithModel.ui | 2 +- 7 files changed, 62 insertions(+), 17 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp index b1b7eddbd..b585d242b 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp @@ -384,14 +384,6 @@ QVariant RsGxsForumModel::statusRole(const ForumModelPostEntry& fmpe,int column) return QVariant(fmpe.mMsgStatus); } -QVariant RsGxsForumModel::filterRole(const ForumModelPostEntry& fmpe,int /*column*/) const -{ - if(!mFilteringEnabled || (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER)) - return QVariant(FilterString); - - return QVariant(QString()); -} - uint32_t RsGxsForumModel::recursUpdateFilterStatus(ForumModelIndex i,int column,const QStringList& strings) { QString s ; @@ -609,8 +601,6 @@ QVariant RsGxsChannelPostFilesModel::displayRole(const RsGxsFile& fmpe,int col) return QVariant(tr("[Unknown]")); } case COLUMN_THREAD_MSGID: return QVariant(); -#endif -#ifdef TODO if (filterColumn == COLUMN_THREAD_CONTENT) { // need content for filter QTextDocument doc; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h index eb214516a..e7dd47802 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h @@ -105,6 +105,7 @@ public: QVariant toolTipRole (const RsGxsFile& fmpe, int col) const; QVariant userRole (const RsGxsFile& fmpe, int col) const; QVariant sortRole (const RsGxsFile& fmpe, int col) const; + QVariant filterRole (const RsGxsFile& fmpe, int col) const; #ifdef TODO QVariant decorationRole(const ForumModelPostEntry& fmpe, int col) const; QVariant pinnedRole (const ForumModelPostEntry& fmpe, int col) const; @@ -112,7 +113,6 @@ public: QVariant statusRole (const ForumModelPostEntry& fmpe, int col) const; QVariant authorRole (const ForumModelPostEntry& fmpe, int col) const; QVariant fontRole (const ForumModelPostEntry& fmpe, int col) const; - QVariant filterRole (const ForumModelPostEntry& fmpe, int col) const; QVariant textColorRole (const ForumModelPostEntry& fmpe, int col) const; QVariant backgroundRole(const ForumModelPostEntry& fmpe, int col) const; #endif diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index b2363b99c..94d6f6406 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -40,8 +40,6 @@ Q_DECLARE_METATYPE(RsGxsChannelPost) std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsewhere -const QString RsGxsChannelPostsModel::FilterString("filtered"); - RsGxsChannelPostsModel::RsGxsChannelPostsModel(QObject *parent) : QAbstractItemModel(parent), mTreeMode(TREE_MODE_PLAIN), mColumns(6) { diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.h index 51d794b4b..b82f91783 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.h @@ -101,8 +101,6 @@ public: QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;} QModelIndex getIndexOfMessage(const RsGxsMessageId& mid) const; - static const QString FilterString ; - std::vector > getPostVersions(const RsGxsMessageId& mid) const; // This method will asynchroneously update the data diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 3aa9084d6..1d3a47d71 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -240,6 +240,40 @@ QSize ChannelPostFilesDelegate::sizeHint(const QStyleOptionViewItem& option, con } } +class RsGxsChannelPostFilesProxyModel: public QSortFilterProxyModel +{ +public: + RsGxsChannelPostFilesProxyModel(QObject *parent = NULL): QSortFilterProxyModel(parent) {} + + bool lessThan(const QModelIndex& left, const QModelIndex& right) const override + { + return left.data(RsGxsChannelPostFilesModel::SortRole) < right.data(RsGxsChannelPostFilesModel::SortRole) ; + } + + bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override + { + if(filter_list.empty()) + return true; + + QString name = sourceModel()->data(sourceModel()->index(source_row,RsGxsChannelPostFilesModel::COLUMN_FILES_NAME,source_parent)).toString(); + + for(auto& s:filter_list) + if(!name.contains(s,Qt::CaseInsensitive)) + return false; + + return true; + } + + void setFilterList(const QStringList& str) + { + filter_list = str; + invalidateFilter(); + } + +private: + QStringList filter_list; +}; + /** Constructor */ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupId &channelId, QWidget *parent) : GxsMessageFrameWidget(rsGxsChannels, parent), @@ -251,14 +285,24 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->postsTree->setModel(mChannelPostsModel = new RsGxsChannelPostsModel()); ui->postsTree->setItemDelegate(new ChannelPostDelegate()); - ui->channelPostFiles_TV->setModel(mChannelPostFilesModel = new RsGxsChannelPostFilesModel()); + mChannelPostFilesModel = new RsGxsChannelPostFilesModel(this); + + mChannelPostFilesProxyModel = new RsGxsChannelPostFilesProxyModel(this); + mChannelPostFilesProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + mChannelPostFilesProxyModel->setSourceModel(mChannelPostFilesModel); + mChannelPostFilesProxyModel->setDynamicSortFilter(true); + + ui->channelPostFiles_TV->setModel(mChannelPostFilesProxyModel); ui->channelPostFiles_TV->setItemDelegate(new ChannelPostFilesDelegate()); ui->channelPostFiles_TV->setPlaceholderText(tr("Post files")); + ui->channelPostFiles_TV->setSortingEnabled(true); + ui->channelPostFiles_TV->sortByColumn(0, Qt::AscendingOrder); ui->channelFiles_TV->setPlaceholderText(tr("All files in the channel")); ui->channelFiles_TV->setModel(mChannelFilesModel = new RsGxsChannelPostFilesModel()); ui->channelFiles_TV->setItemDelegate(new ChannelPostFilesDelegate()); + connect(ui->channelPostFiles_TV->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortColumn(int,Qt::SortOrder))); connect(ui->postsTree->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),this,SLOT(showPostDetails())); connect(mChannelPostsModel,SIGNAL(channelLoaded()),this,SLOT(updateChannelFiles())); @@ -277,6 +321,7 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->postButton->setText(tr("Add new post")); /* add filter actions */ + ui->filterLineEdit->setPlaceholderText(tr("Search...")); connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); /* Initialize view button */ @@ -335,6 +380,12 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI connect(ui->postsTree,SIGNAL(sizeChanged(QSize)),this,SLOT(handlePostsTreeSizeChange(QSize))); } +void GxsChannelPostsWidgetWithModel::sortColumn(int col,Qt::SortOrder so) +{ + std::cerr << "Sorting!!"<< std::endl; + mChannelPostFilesProxyModel->sort(col,so); +} + void GxsChannelPostsWidgetWithModel::handlePostsTreeSizeChange(QSize s) { // adjustSize(); @@ -749,6 +800,10 @@ void GxsChannelPostsWidgetWithModel::filterChanged(QString s) QStringList ql = s.split(' ',QString::SkipEmptyParts); uint32_t count; mChannelPostsModel->setFilter(ql,count); + + mChannelPostFilesProxyModel->setFilterKeyColumn(RsGxsChannelPostFilesModel::COLUMN_FILES_NAME); + mChannelPostFilesProxyModel->setFilterList(ql); + mChannelPostFilesProxyModel->setFilterRegExp(QRegExp()) ;// triggers a re-display. } #ifdef TODO diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index 8dd9a66bd..375290f61 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -34,9 +34,11 @@ class GxsChannelPostsWidgetWithModel; class GxsChannelPostItem; class QTreeWidgetItem; +class QSortFilterProxyModel; class FeedItem; class RsGxsChannelPostsModel; class RsGxsChannelPostFilesModel; +class RsGxsChannelPostFilesProxyModel; class ChannelPostFilesDelegate: public QStyledItemDelegate { @@ -137,6 +139,7 @@ private slots: void settingsChanged(); void handlePostsTreeSizeChange(QSize s); void updateChannelFiles(); + void sortColumn(int col,Qt::SortOrder so); private: void processSettings(bool load); @@ -159,6 +162,7 @@ private: RsGxsChannelPostsModel *mChannelPostsModel; RsGxsChannelPostFilesModel *mChannelPostFilesModel; RsGxsChannelPostFilesModel *mChannelFilesModel; + RsGxsChannelPostFilesProxyModel *mChannelPostFilesProxyModel ; /* UI - from Designer */ Ui::GxsChannelPostsWidgetWithModel *ui; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index 84a73fb9c..751c2bc69 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -161,7 +161,7 @@ - 1 + 2 From 2baa5513483a383c50443f9cd2d40c37ebb86f19 Mon Sep 17 00:00:00 2001 From: defnax Date: Tue, 9 Jun 2020 23:32:18 +0200 Subject: [PATCH 055/154] added stretch factor for the splitter --- .../src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index ab299d343..d09367cf0 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -262,6 +262,10 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI connect(ui->postsTree->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),this,SLOT(showPostDetails())); connect(mChannelPostsModel,SIGNAL(channelLoaded()),this,SLOT(updateChannelFiles())); + // Set initial size of the splitter + ui->splitter->setStretchFactor(0, 1); + ui->splitter->setStretchFactor(1, 0); + QFontMetricsF fm(font()); for(int i=0;icolumnCount();++i) From ba6269311d6f91ca54de2a566d4b2abdf98df891 Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 10 Jun 2020 18:24:02 +0200 Subject: [PATCH 056/154] minor changes to files view --- .../GxsChannelPostsWidgetWithModel.cpp | 24 ++++--------------- .../GxsChannelPostsWidgetWithModel.ui | 6 +++++ 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 1d3a47d71..d20d8e5f1 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -298,7 +298,7 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->channelPostFiles_TV->setSortingEnabled(true); ui->channelPostFiles_TV->sortByColumn(0, Qt::AscendingOrder); - ui->channelFiles_TV->setPlaceholderText(tr("All files in the channel")); + ui->channelFiles_TV->setPlaceholderText(tr("No files in the channel, or no channel selected")); ui->channelFiles_TV->setModel(mChannelFilesModel = new RsGxsChannelPostFilesModel()); ui->channelFiles_TV->setItemDelegate(new ChannelPostFilesDelegate()); @@ -324,25 +324,11 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->filterLineEdit->setPlaceholderText(tr("Search...")); connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); - /* Initialize view button */ - //setViewMode(VIEW_MODE_FEEDS); see processSettings - //ui->infoWidget->hide(); - - //QSignalMapper *signalMapper = new QSignalMapper(this); - //connect(ui->feedToolButton, SIGNAL(clicked()), signalMapper, SLOT(map())); - //connect(ui->fileToolButton, SIGNAL(clicked()), signalMapper, SLOT(map())); - //signalMapper->setMapping(ui->feedToolButton, VIEW_MODE_FEEDS); - //signalMapper->setMapping(ui->fileToolButton, VIEW_MODE_FILES); - //connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(setViewMode(int))); - - /*************** Setup Left Hand Side (List of Channels) ****************/ - - //ui->loadingLabel->hide(); - //ui->progressBar->hide(); - ui->postsTree->setPlaceholderText(tr("Thumbnails")); ui->postsTree->setMinimumWidth(COLUMN_SIZE_FONT_FACTOR_W*QFontMetricsF(font()).height()+1); + connect(ui->postsTree,SIGNAL(sizeChanged(QSize)),this,SLOT(handlePostsTreeSizeChange(QSize))); + //ui->nameLabel->setMinimumWidth(20); /* Initialize feed widget */ @@ -376,8 +362,6 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI { RsQThreadUtils::postToObject([=](){ handleEvent_main_thread(event); }, this ); }, mEventHandlerId, RsEventType::GXS_CHANNELS ); - - connect(ui->postsTree,SIGNAL(sizeChanged(QSize)),this,SLOT(handlePostsTreeSizeChange(QSize))); } void GxsChannelPostsWidgetWithModel::sortColumn(int col,Qt::SortOrder so) @@ -803,7 +787,7 @@ void GxsChannelPostsWidgetWithModel::filterChanged(QString s) mChannelPostFilesProxyModel->setFilterKeyColumn(RsGxsChannelPostFilesModel::COLUMN_FILES_NAME); mChannelPostFilesProxyModel->setFilterList(ql); - mChannelPostFilesProxyModel->setFilterRegExp(QRegExp()) ;// triggers a re-display. + mChannelPostFilesProxyModel->setFilterRegExp(s)) ;// triggers a re-display. s is actually not used. } #ifdef TODO diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index 751c2bc69..cfa36e40d 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -488,9 +488,15 @@ p, li { white-space: pre-wrap; } QAbstractItemView::CurrentChanged|QAbstractItemView::SelectedClicked + + false + true + + false + From 3412bb2a8f9853df5d68bc72f8441d236d57275c Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 10 Jun 2020 18:30:43 +0200 Subject: [PATCH 057/154] fixed compilation --- .../src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index d20d8e5f1..846f0bcdd 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -787,7 +787,7 @@ void GxsChannelPostsWidgetWithModel::filterChanged(QString s) mChannelPostFilesProxyModel->setFilterKeyColumn(RsGxsChannelPostFilesModel::COLUMN_FILES_NAME); mChannelPostFilesProxyModel->setFilterList(ql); - mChannelPostFilesProxyModel->setFilterRegExp(s)) ;// triggers a re-display. s is actually not used. + mChannelPostFilesProxyModel->setFilterRegExp(s) ;// triggers a re-display. s is actually not used. } #ifdef TODO From cbf4ce66705c8cf6884b32f8415fa4987be32a7c Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 10 Jun 2020 19:05:41 +0200 Subject: [PATCH 058/154] fixed some errors in model --- .../gxschannels/GxsChannelPostFilesModel.cpp | 61 +++++-------------- .../GxsChannelPostsWidgetWithModel.cpp | 2 + 2 files changed, 17 insertions(+), 46 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp index b585d242b..8942b65b0 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp @@ -52,8 +52,7 @@ void RsGxsChannelPostFilesModel::initEmptyHierarchy(std::vector& file { preMods(); - files.resize(1); // adds a sentinel item - files[0].mName = "Root sentinel post" ; + mFiles.clear(); postMods(); } @@ -76,28 +75,6 @@ void RsGxsChannelPostFilesModel::update() emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mFiles.size(),COLUMN_FILES_NB_COLUMNS-1,(void*)NULL)); } -#ifdef TODO -void RsGxsChannelPostsModel::setSortMode(SortMode mode) -{ - preMods(); - - mSortMode = mode; - - postMods(); -} - -void RsGxsForumModel::initEmptyHierarchy(std::vector& posts) -{ - preMods(); - - posts.resize(1); // adds a sentinel item - posts[0].mTitle = "Root sentinel post" ; - posts[0].mParent = 0; - - postMods(); -} -#endif - int RsGxsChannelPostFilesModel::rowCount(const QModelIndex& parent) const { if(parent.column() > 0) @@ -107,7 +84,7 @@ int RsGxsChannelPostFilesModel::rowCount(const QModelIndex& parent) const return 0; if(!parent.isValid()) - return getChildrenCount(0); + return (mFiles.size() + COLUMN_FILES_NB_COLUMNS-1)/COLUMN_FILES_NB_COLUMNS; // mFilteredPosts always has an item at 0, so size()>=1, and mColumn>=1 RsErr() << __PRETTY_FUNCTION__ << " rowCount cannot figure out the porper number of rows." << std::endl; return 0; @@ -162,7 +139,7 @@ bool RsGxsChannelPostFilesModel::convertTabEntryToRefPointer(uint32_t entry,quin // This means that the whole software has the following build-in limitation: // * 4 B simultaenous posts. Should be enough ! - ref = (intptr_t)entry; + ref = (intptr_t)(entry+1); return true; } @@ -176,7 +153,12 @@ bool RsGxsChannelPostFilesModel::convertRefPointerToTabEntry(quintptr ref, uint3 RsErr() << "(EE) trying to make a ChannelPostsModelIndex out of a number that is larger than 2^32-1 !" << std::endl; return false ; } - entry = quintptr(val); + if(val==0) + { + RsErr() << "(EE) trying to make a ChannelPostsFileModelIndex out of index 0." << std::endl; + return false; + } + entry = val-1; return true; } @@ -218,15 +200,10 @@ quintptr RsGxsChannelPostFilesModel::getChildRef(quintptr ref,int index) const if (index < 0) return 0; - ChannelPostFilesModelIndex entry ; - - if(!convertRefPointerToTabEntry(ref,entry) || entry >= mFiles.size()) - return 0 ; - - if(entry == 0) + if(ref == quintptr(0)) { quintptr new_ref; - convertTabEntryToRefPointer(index+1,new_ref); + convertTabEntryToRefPointer(index,new_ref); return new_ref; } else @@ -253,20 +230,12 @@ quintptr RsGxsChannelPostFilesModel::getParentRow(quintptr ref,int& row) const int RsGxsChannelPostFilesModel::getChildrenCount(quintptr ref) const { - uint32_t entry = 0 ; + uint32_t entry = 0 ; - if(!convertRefPointerToTabEntry(ref,entry) || entry >= mFiles.size()) - return 0 ; + if(ref == quintptr(0)) + return rowCount()-1; - if(entry == 0) - { -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << "Children count (flat mode): " << mFiles.size()-1 << std::endl; -#endif - return ((int)mFiles.size())-1; - } - else - return 0; + return 0; } QVariant RsGxsChannelPostFilesModel::headerData(int section, Qt::Orientation orientation, int role) const diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 846f0bcdd..d6a317151 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -468,6 +468,8 @@ void GxsChannelPostsWidgetWithModel::updateChannelFiles() ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE); ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); ui->channelFiles_TV->setAutoSelect(true); + + mChannelPostFilesProxyModel->sort(0, Qt::AscendingOrder); } void GxsChannelPostsWidgetWithModel::updateGroupData() From 462f52585b0c59fb509cd285f3b96e8ac6a4bea3 Mon Sep 17 00:00:00 2001 From: sehraf Date: Fri, 8 May 2020 16:10:17 +0200 Subject: [PATCH 059/154] add helper for i2p related functions --- libretroshare/src/libretroshare.pro | 4 +- libretroshare/src/util/i2pcommon.cpp | 172 +++++++++++++++++++++ libretroshare/src/util/i2pcommon.h | 222 +++++++++++++++++++++++++++ 3 files changed, 397 insertions(+), 1 deletion(-) create mode 100644 libretroshare/src/util/i2pcommon.cpp create mode 100644 libretroshare/src/util/i2pcommon.h diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 76a39b662..837c1f715 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -154,6 +154,7 @@ rs_webui { HEADERS += plugins/pluginmanager.h \ plugins/dlfcn_win32.h \ rsitems/rspluginitems.h \ + util/i2pcommon.h \ util/rsinitedptr.h HEADERS += $$PUBLIC_HEADERS @@ -517,7 +518,8 @@ SOURCES += ft/ftchunkmap.cc \ ft/ftfilesearch.cc \ ft/ftserver.cc \ ft/fttransfermodule.cc \ - ft/ftturtlefiletransferitem.cc + ft/ftturtlefiletransferitem.cc \ + util/i2pcommon.cpp SOURCES += crypto/chacha20.cpp \ crypto/hashstream.cc\ diff --git a/libretroshare/src/util/i2pcommon.cpp b/libretroshare/src/util/i2pcommon.cpp new file mode 100644 index 000000000..e50fc9d83 --- /dev/null +++ b/libretroshare/src/util/i2pcommon.cpp @@ -0,0 +1,172 @@ +#include "i2pcommon.h" + +#include "util/rsbase64.h" +#include "util/rsdebug.h" + +namespace i2p { + +const std::string generateNameSuffix(const size_t len) { + std::vector tmp(len); + RsRandom::random_bytes(tmp.data(), len); + const std::string location = Radix32::encode(tmp.data(), len); + + return location; +} + +std::string keyToBase32Addr(const std::string &key) +{ + std::string copy(key); + + // replace I2P specific chars + std::replace(copy.begin(), copy.end(), '~', '/'); + std::replace(copy.begin(), copy.end(), '-', '+'); + + // decode + std::vector bin; + RsBase64::decode(copy, bin); + + // hash + std::vector sha256 = RsUtil::BinToSha256(bin); + // encode + std::string out = Radix32::encode(sha256); + + // i2p uses lowercase + std::transform(out.begin(), out.end(), out.begin(), ::tolower); + out.append(".b32.i2p"); + + return out; +} + +const std::string makeOption(const std::string &lhs, const int8_t &rhs) { + // convert number to int + std::ostringstream oss; + oss << (int)rhs; + return lhs + "=" + oss.str(); +} + +uint16_t readTwoBytesBE(std::vector::const_iterator &p) +{ + uint16_t val = 0; + val += *p++; + val <<= 8; + val += *p++; + return val; +} + +std::string publicKeyFromPrivate(std::string const &priv) +{ + /* + * https://geti2p.net/spec/common-structures#destination + * https://geti2p.net/spec/common-structures#keysandcert + * https://geti2p.net/spec/common-structures#certificate + */ + if (priv.length() < 884) // base64 ( = 663 bytes = KeyCert + priv Keys) + return std::string(); + + // creat a copy to work on, need to convert it to standard base64 + auto priv_copy(priv); + std::replace(priv_copy.begin(), priv_copy.end(), '~', '/'); + std::replace(priv_copy.begin(), priv_copy.end(), '-', '+'); + + // get raw data + std::vector dataPriv; + RsBase64::decode(priv_copy, dataPriv); + + auto p = dataPriv.cbegin(); + RsDbg() << __PRETTY_FUNCTION__ << " dataPriv.size " << dataPriv.size() << std::endl; + + size_t publicKeyLen = 256 + 128; // default length (bytes) + uint8_t certType = 0; + uint16_t len = 0; + uint16_t signingKeyType = 0; + uint16_t cryptKey = 0; + + // only used for easy break + do { + try { + // jump to certificate + p += publicKeyLen; + // try to read type and length + certType = *p++; + len = readTwoBytesBE(p); + + // only 0 and 5 are used / valid at this point + // check for == 0 + if (certType == static_cast::type>(CertType::Null)) { + /* + * CertType.Null + * type null is followed by 0x00 0x00 + * so has to be 0! + */ + RsDbg() << __PRETTY_FUNCTION__ << " cert is CertType.Null" << std::endl; + publicKeyLen += 3; // add 0x00 0x00 0x00 + + if (len != 0) + // weird + RsDbg() << __PRETTY_FUNCTION__ << " cert is CertType.Null but len != 0" << std::endl; + + break; + } + + // check for != 5 + if (certType != static_cast::type>(CertType::Key)) { + // unsupported + RsDbg() << __PRETTY_FUNCTION__ << " cert type " << certType << " is unsupported" << std::endl; + return std::string(); + } + + RsDbg() << __PRETTY_FUNCTION__ << " cert is CertType.Key" << std::endl; + publicKeyLen += 7; // = 1 + 2 + 2 + 2 = 7 bytes + + /* + * "Key certificates were introduced in release 0.9.12. Prior to that release, all PublicKeys were 256-byte ElGamal keys, and all SigningPublicKeys were 128-byte DSA-SHA1 keys." + * --> there is space for 256+128 bytes, longer keys are splitted and appended to the certificate + * We don't need to bother with the splitting here as only the lenght is important! + */ + + // Signing Public Key + // likely 7 + signingKeyType = readTwoBytesBE(p); + + RsDbg() << __PRETTY_FUNCTION__ << " signing pubkey type " << certType << std::endl; + if (signingKeyType >= 3 && signingKeyType <= 6) { + RsDbg() << __PRETTY_FUNCTION__ << " signing pubkey type " << certType << " has oversize" << std::endl; + // calculate oversize + + auto it = signingKeyLengths.find(static_cast(signingKeyType)); + if (it == signingKeyLengths.end()) { + // just in case + RsDbg() << __PRETTY_FUNCTION__ << " signing pubkey type " << certType << " cannot be found in size map!" << std::endl; + return std::string(); + } + + if (it->second.first <= 128) { + // just in case, it's supposed to be larger! + RsDbg() << __PRETTY_FUNCTION__ << " signing pubkey type " << certType << " is oversize but size calculation would underflow!" << std::endl; + return std::string(); + } + + publicKeyLen += it->second.first - 128; // 128 = default DSA key length = the space than can be used before the key must be splitted + } + + // Crypto Public Key + // likely 0 + cryptKey = readTwoBytesBE(p); + RsDbg() << __PRETTY_FUNCTION__ << " crypto pubkey type " << cryptKey << std::endl; + // info: these are all smaller than the default 256 bytes, so no oversize calculation is needed + + break; + } catch (const std::out_of_range &e) { + RsDbg() << __PRETTY_FUNCTION__ << " hit exception!" << e.what() << std::endl; + return std::string(); + } + } while(false); + + std::string pub; + auto data2 = std::vector(dataPriv.cbegin(), dataPriv.cbegin() + publicKeyLen); + RsBase64::encode(data2.data(), data2.size(), pub, false, false); + + return pub; +} + +} // namespace i2p diff --git a/libretroshare/src/util/i2pcommon.h b/libretroshare/src/util/i2pcommon.h new file mode 100644 index 000000000..98815496b --- /dev/null +++ b/libretroshare/src/util/i2pcommon.h @@ -0,0 +1,222 @@ +#ifndef I2PCOMMON_H +#define I2PCOMMON_H + +#include +#include + +#include "util/rsrandom.h" +#include "util/radix32.h" +#include "util/rsbase64.h" +#include "util/rsprint.h" +#include "util/rsdebug.h" + +/* + * This header provides common code for i2p related code, namely BOB and SAM3 support. + */ + +namespace i2p { + +static constexpr int8_t kDefaultLength = 3; // i2p default +static constexpr int8_t kDefaultQuantity = 3; // i2p default + 1 +static constexpr int8_t kDefaultVariance = 0; +static constexpr int8_t kDefaultBackupQuantity = 0; + +/** + * @brief The address struct + * This structure is a container for any i2p address/key. The public key is used for addressing and can be (optionally) hashed to generate the .b32.i2p address. + */ +struct address { + std::string base32; + std::string publicKey; + std::string privateKey; + + void clear() { + base32.clear(); + publicKey.clear(); + privateKey.clear(); + } +}; + +/** + * @brief The settings struct + * Common structure with all settings that are shared between any i2p backends + */ +struct settings { + bool enable; + struct address address; + + // connection parameter + int8_t inLength; + int8_t inQuantity; + int8_t inVariance; + int8_t inBackupQuantity; + + int8_t outLength; + int8_t outQuantity; + int8_t outVariance; + int8_t outBackupQuantity; + + void initDefault() { + enable = false; + address.clear(); + + inLength = kDefaultLength; + inQuantity = kDefaultQuantity; + inVariance = kDefaultVariance; + inBackupQuantity = kDefaultBackupQuantity; + + outLength = kDefaultLength; + outQuantity = kDefaultQuantity; + outVariance = kDefaultVariance; + outBackupQuantity = kDefaultBackupQuantity; + } +}; + +/* + Type Type Code Payload Length Total Length Notes + Null 0 0 3 + HashCash 1 varies varies Experimental, unused. Payload contains an ASCII colon-separated hashcash string. + Hidden 2 0 3 Experimental, unused. Hidden routers generally do not announce that they are hidden. + Signed 3 40 or 72 43 or 75 Experimental, unused. Payload contains a 40-byte DSA signature, optionally followed by the 32-byte Hash of the signing Destination. + Multiple 4 varies varies Experimental, unused. Payload contains multiple certificates. + Key 5 4+ 7+ Since 0.9.12. See below for details. +*/ +enum class CertType : uint8_t { + Null = 0, + HashCash = 1, + Hidden = 2, + Signed = 3, + Multiple = 4, + Key = 5 +}; + +/* + * public + Type Type Code Total Public Key Length Since Usage + DSA_SHA1 0 128 0.9.12 Legacy Router Identities and Destinations, never explicitly set + ECDSA_SHA256_P256 1 64 0.9.12 Older Destinations + ECDSA_SHA384_P384 2 96 0.9.12 Rarely if ever used for Destinations + ECDSA_SHA512_P521 3 132 0.9.12 Rarely if ever used for Destinations + RSA_SHA256_2048 4 256 0.9.12 Offline only; never used in Key Certificates for Router Identities or Destinations + RSA_SHA384_3072 5 384 0.9.12 Offline only; never used in Key Certificates for Router Identities or Destinations + RSA_SHA512_4096 6 512 0.9.12 Offline only; never used in Key Certificates for Router Identities or Destinations + EdDSA_SHA512_Ed25519 7 32 0.9.15 Recent Router Identities and Destinations + EdDSA_SHA512_Ed25519ph 8 32 0.9.25 Offline only; never used in Key Certificates for Router Identities or Destinations + reserved (GOST) 9 64 Reserved, see proposal 134 + reserved (GOST) 10 128 Reserved, see proposal 134 + RedDSA_SHA512_Ed25519 11 32 0.9.39 For Destinations and encrypted leasesets only; never used for Router Identities + reserved 65280-65534 Reserved for experimental use + reserved 65535 Reserved for future expansion + + * private + Type Length (bytes) Since Usage + DSA_SHA1 20 Legacy Router Identities and Destinations + ECDSA_SHA256_P256 32 0.9.12 Recent Destinations + ECDSA_SHA384_P384 48 0.9.12 Rarely used for Destinations + ECDSA_SHA512_P521 66 0.9.12 Rarely used for Destinations + RSA_SHA256_2048 512 0.9.12 Offline signing, never used for Router Identities or Destinations + RSA_SHA384_3072 768 0.9.12 Offline signing, never used for Router Identities or Destinations + RSA_SHA512_4096 1024 0.9.12 Offline signing, never used for Router Identities or Destinations + EdDSA_SHA512_Ed25519 32 0.9.15 Recent Router Identities and Destinations + EdDSA_SHA512_Ed25519ph 32 0.9.25 Offline signing, never used for Router Identities or Destinations + RedDSA_SHA512_Ed25519 32 0.9.39 For Destinations and encrypted leasesets only, never used for Router Identities + */ +enum class SigningKeyType : uint16_t { + DSA_SHA1 = 0, + ECDSA_SHA256_P256 = 1, + ECDSA_SHA384_P384 = 2, + ECDSA_SHA512_P521 = 3, + RSA_SHA256_2048 = 4, + RSA_SHA384_3072 = 5, + RSA_SHA512_4096 = 6, + EdDSA_SHA512_Ed25519 = 7, + EdDSA_SHA512_Ed25519ph = 8, + RedDSA_SHA512_Ed25519 = 11 +}; + +/* + * public + Type Type Code Total Public Key Length Usage + ElGamal 0 256 All Router Identities and Destinations + P256 1 64 Reserved, see proposal 145 + P384 2 96 Reserved, see proposal 145 + P521 3 132 Reserved, see proposal 145 + X25519 4 32 Not for use in key certs. See proposal 144 + reserved 65280-65534 Reserved for experimental use + reserved 65535 Reserved for future expansion + + * private + Type Length (bytes) Since Usage + ElGamal 256 All Router Identities and Destinations + P256 32 TBD Reserved, see proposal 145 + P384 48 TBD Reserved, see proposal 145 + P521 66 TBD Reserved, see proposal 145 + X25519 32 0.9.38 Little-endian. See proposal 144 +*/ +enum class CryptoKeyType : uint16_t { + ElGamal = 0, + P256 = 1, + P384 = 2, + P521 = 3, + X25519 = 4 +}; + +static const std::map> cryptoKeyLengths { + {CryptoKeyType::ElGamal, {256, 256}}, + {CryptoKeyType::P256, { 64, 32}}, + {CryptoKeyType::P384, { 96, 48}}, + {CryptoKeyType::P521, {132, 66}}, + {CryptoKeyType::X25519, { 32, 32}}, +}; + +static const std::map> signingKeyLengths { + {SigningKeyType::DSA_SHA1, {128, 128}}, + {SigningKeyType::ECDSA_SHA256_P256, { 64, 32}}, + {SigningKeyType::ECDSA_SHA384_P384, { 96, 48}}, + {SigningKeyType::ECDSA_SHA512_P521, {132, 66}}, + {SigningKeyType::RSA_SHA256_2048, {256, 512}}, + {SigningKeyType::RSA_SHA384_3072, {384, 768}}, + {SigningKeyType::RSA_SHA512_4096, {512,1024}}, + {SigningKeyType::EdDSA_SHA512_Ed25519, { 32, 32}}, + {SigningKeyType::EdDSA_SHA512_Ed25519ph,{ 32, 32}}, + {SigningKeyType::RedDSA_SHA512_Ed25519, { 32, 32}}, +}; + + +/** + * @brief generateNameSuffix Generates a base32 name suffix for tunnel identification + * @param len lenght of random bytes, will be expanded by base32 encoding + * @return base32 string + * + * RSRandom::random_alphaNumericString can return very weird looking strings like: ,,@z+M + * -> so use base32 instead + * + * 5 characters = 8 base32 symbols + */ +const std::string generateNameSuffix(const size_t len = 5); + +/** + * @brief makeOption Creates the string "lhs=rhs" used by BOB and SAM. Converts rhs + * @param lhs option to set + * @param rhs value to set + * @return concatenated string + */ +const std::string makeOption(const std::string &lhs, const int8_t &rhs); + +/** + * @brief keyToBase32Addr generated a base32 address (.b32.i2p) from a given public key + * @param key public key + * @return generated base32 address + */ +std::string keyToBase32Addr(const std::string &key); + +/** + * @brief publicKeyFromPrivate parses the private key and calculates the lenght of the public key + * @param priv private key (which includes the public key) to read + * @return public key used for addressing + */ +std::string publicKeyFromPrivate(const std::string &priv); + +} // namespace i2p + +#endif // I2PCOMMON_H From 4b6e12ca454d8673c3f0bdac3f7ff2f890305849 Mon Sep 17 00:00:00 2001 From: sehraf Date: Fri, 8 May 2020 16:13:27 +0200 Subject: [PATCH 060/154] i2p: bob: use common i2p::keyToBase32Addr() --- .../src/services/autoproxy/p3i2pbob.cc | 24 +------------------ .../src/services/autoproxy/p3i2pbob.h | 9 ++++--- 2 files changed, 5 insertions(+), 28 deletions(-) diff --git a/libretroshare/src/services/autoproxy/p3i2pbob.cc b/libretroshare/src/services/autoproxy/p3i2pbob.cc index 693570ac2..256a1cf4d 100644 --- a/libretroshare/src/services/autoproxy/p3i2pbob.cc +++ b/libretroshare/src/services/autoproxy/p3i2pbob.cc @@ -250,28 +250,6 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) } } -std::string p3I2pBob::keyToBase32Addr(const std::string &key) -{ - std::string copy(key); - - // replace I2P specific chars - std::replace(copy.begin(), copy.end(), '~', '/'); - std::replace(copy.begin(), copy.end(), '-', '+'); - - // decode - std::vector bin = Radix64::decode(copy); - // hash - std::vector sha256 = RsUtil::BinToSha256(bin); - // encode - std::string out = Radix32::encode(sha256); - - // i2p uses lowercase - std::transform(out.begin(), out.end(), out.begin(), ::tolower); - out.append(".b32.i2p"); - - return out; -} - bool inline isAnswerOk(const std::string &answer) { return (answer.compare(0, 2, "OK") == 0); } @@ -346,7 +324,7 @@ int p3I2pBob::stateMachineBOB() switch (mBOBState) { case bsNewkeysN: key = answer.substr(3, answer.length()-3); - mSetting.addr = keyToBase32Addr(key); + mSetting.addr = i2p::keyToBase32Addr(key); IndicateConfigChanged(); break; case bsGetkeys: diff --git a/libretroshare/src/services/autoproxy/p3i2pbob.h b/libretroshare/src/services/autoproxy/p3i2pbob.h index e6ef60bae..428501a4d 100644 --- a/libretroshare/src/services/autoproxy/p3i2pbob.h +++ b/libretroshare/src/services/autoproxy/p3i2pbob.h @@ -30,9 +30,10 @@ #include #endif +#include "pqi/p3cfgmgr.h" #include "services/autoproxy/rsautoproxymonitor.h" #include "util/rsthreads.h" -#include "pqi/p3cfgmgr.h" +#include "util/i2pcommon.h" /* * This class implements I2P BOB (BASIC OPEN BRIDGE) communication to allow RS @@ -49,7 +50,7 @@ * * Note 3: * BOB needs a unique name as an ID for each tunnel. - * We use 'RetroShare-' + 8 base32 characters. + * We use 'RetroShare-' + 8 random base32 characters. * * Design: * The service uses three state machines to manage its task: @@ -72,7 +73,7 @@ * mCommands[bobState::quit] = {quit, bobState::cleared}; * * stateMachineController: - * This state machone manages the high level tasks. + * This state machine manages the high level tasks. * It is controlled by mState and mTask. * * mTast: @@ -203,8 +204,6 @@ public: void processTaskAsync(taskTicket *ticket); void processTaskSync(taskTicket *ticket); - static std::string keyToBase32Addr(const std::string &key); - void threadTick() override; /// @see RsTickingThread private: From 6136416b5627a6858eace83d78b406c636059e9f Mon Sep 17 00:00:00 2001 From: sehraf Date: Fri, 8 May 2020 16:33:47 +0200 Subject: [PATCH 061/154] i2p: bob: convert bobSettings to i2p::settings --- libretroshare/src/rsserver/rsinit.cc | 2 +- .../src/services/autoproxy/p3i2pbob.cc | 40 ++++++++----------- .../src/services/autoproxy/p3i2pbob.h | 14 +------ .../src/gui/settings/ServerPage.cpp | 32 ++++++++------- 4 files changed, 35 insertions(+), 53 deletions(-) diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 5dcccfe0c..1c4e2a062 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -1724,7 +1724,7 @@ int RsServer::StartupRetroShare() // now enable bob bobSettings bs; autoProxy->taskSync(autoProxyType::I2PBOB, autoProxyTask::getSettings, &bs); - bs.enableBob = true; + bs.enable = true; autoProxy->taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &bs); } else { std::cerr << "RsServer::StartupRetroShare failed to receive keys" << std::endl; diff --git a/libretroshare/src/services/autoproxy/p3i2pbob.cc b/libretroshare/src/services/autoproxy/p3i2pbob.cc index 256a1cf4d..6a52120dc 100644 --- a/libretroshare/src/services/autoproxy/p3i2pbob.cc +++ b/libretroshare/src/services/autoproxy/p3i2pbob.cc @@ -74,15 +74,7 @@ p3I2pBob::p3I2pBob(p3PeerMgr *peerMgr) mProcessing(NULL), mLock("I2P-BOB") { // set defaults - mSetting.enableBob = kDefaultBOBEnable; - mSetting.keys = ""; - mSetting.addr = ""; - mSetting.inLength = kDefaultLength; - mSetting.inQuantity = kDefaultQuantity; - mSetting.inVariance = kDefaultVariance; - mSetting.outLength = kDefaultLength; - mSetting.outQuantity = kDefaultQuantity; - mSetting.outVariance = kDefaultVariance; + mSetting.initDefault(); mCommands.clear(); } @@ -90,7 +82,7 @@ p3I2pBob::p3I2pBob(p3PeerMgr *peerMgr) bool p3I2pBob::isEnabled() { RS_STACK_MUTEX(mLock); - return mSetting.enableBob; + return mSetting.enable; } bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/) @@ -151,7 +143,7 @@ bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/) { RS_STACK_MUTEX(mLock); - addr = mSetting.addr; + addr = mSetting.address.base32; } std::cout << "p3I2pBob::initialSetup addr '" << addr << "'" << std::endl; @@ -324,12 +316,12 @@ int p3I2pBob::stateMachineBOB() switch (mBOBState) { case bsNewkeysN: key = answer.substr(3, answer.length()-3); - mSetting.addr = i2p::keyToBase32Addr(key); + mSetting.address.base32 = i2p::keyToBase32Addr(key); IndicateConfigChanged(); break; case bsGetkeys: key = answer.substr(3, answer.length()-3); - mSetting.keys = key; + mSetting.address.privateKey = key; IndicateConfigChanged(); break; default: @@ -465,7 +457,7 @@ int p3I2pBob::stateMachineController_locked_idle() mProcessing = mPending.front(); mPending.pop(); - if (!mSetting.enableBob && ( + if (!mSetting.enable && ( mProcessing->task == autoProxyTask::start || mProcessing->task == autoProxyTask::stop || mProcessing->task == autoProxyTask::proxyStatusCheck)) { @@ -539,7 +531,7 @@ int p3I2pBob::stateMachineController_locked_connected() switch (mTask) { case ctRunSetUp: // when we have a key use it for server tunnel! - if(mSetting.keys.empty()) { + if(mSetting.address.privateKey.empty()) { rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = setnickC"); mBOBState = bsSetnickC; } else { @@ -750,9 +742,9 @@ bool p3I2pBob::saveList(bool &cleanup, std::list &lst) RsTlvKeyValue kv; RS_STACK_MUTEX(mLock); - addKVS(vitem, kv, kConfigKeyBOBEnable, mSetting.enableBob ? "TRUE" : "FALSE") - addKVS(vitem, kv, kConfigKeyBOBKey, mSetting.keys) - addKVS(vitem, kv, kConfigKeyBOBAddr, mSetting.addr) + addKVS(vitem, kv, kConfigKeyBOBEnable, mSetting.enable ? "TRUE" : "FALSE") + addKVS(vitem, kv, kConfigKeyBOBKey, mSetting.address.privateKey) + addKVS(vitem, kv, kConfigKeyBOBAddr, mSetting.address.base32) addKVSInt(vitem, kv, kConfigKeyInLength, mSetting.inLength) addKVSInt(vitem, kv, kConfigKeyInQuantity, mSetting.inQuantity) addKVSInt(vitem, kv, kConfigKeyInVariance, mSetting.inVariance) @@ -786,11 +778,11 @@ bool p3I2pBob::loadList(std::list &load) RS_STACK_MUTEX(mLock); for(std::list::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit) { if (kit->key == kConfigKeyBOBEnable) - mSetting.enableBob = kit->value == "TRUE"; + mSetting.enable = kit->value == "TRUE"; else if (kit->key == kConfigKeyBOBKey) - mSetting.keys = kit->value; + mSetting.address.privateKey = kit->value; else if (kit->key == kConfigKeyBOBAddr) - mSetting.addr = kit->value; + mSetting.address.base32 = kit->value; getKVSUInt(kit, kConfigKeyInLength, mSetting.inLength) getKVSUInt(kit, kConfigKeyInQuantity, mSetting.inQuantity) getKVSUInt(kit, kConfigKeyInVariance, mSetting.inVariance) @@ -958,7 +950,7 @@ void p3I2pBob::finalizeSettings_locked() sockaddr_storage_setport(mI2PProxyAddr, 2827); rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using " + sockaddr_storage_tostring(mI2PProxyAddr)); - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using " + mSetting.addr); + rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using " + mSetting.address.base32); peerState ps; mPeerMgr->getOwnNetStatus(ps); @@ -980,7 +972,7 @@ void p3I2pBob::finalizeSettings_locked() const std::string getnick = "getnick RetroShare-" + location; const std::string newkeys = "newkeys"; const std::string getkeys = "getkeys"; - const std::string setkeys = "setkeys " + mSetting.keys; + const std::string setkeys = "setkeys " + mSetting.address.privateKey; const std::string inhost = "inhost " + sockaddr_storage_iptostring(proxy); const std::string inport = toString("inport ", sockaddr_storage_port(proxy)); const std::string outhost = "outhost " + sockaddr_storage_iptostring(ps.localaddr); @@ -1049,7 +1041,7 @@ void p3I2pBob::updateSettings_locked() peerState ps; mPeerMgr->getOwnNetStatus(ps); - const std::string setkeys = "setkeys " + mSetting.keys; + const std::string setkeys = "setkeys " + mSetting.address.privateKey; const std::string inhost = "inhost " + sockaddr_storage_iptostring(proxy); const std::string inport = toString("inport ", sockaddr_storage_port(proxy)); const std::string outhost = "outhost " + sockaddr_storage_iptostring(ps.localaddr); diff --git a/libretroshare/src/services/autoproxy/p3i2pbob.h b/libretroshare/src/services/autoproxy/p3i2pbob.h index 428501a4d..29bcbcb61 100644 --- a/libretroshare/src/services/autoproxy/p3i2pbob.h +++ b/libretroshare/src/services/autoproxy/p3i2pbob.h @@ -163,19 +163,7 @@ struct bobStateInfo { bobState nextState; }; -struct bobSettings { - bool enableBob; ///< This field is used by the pqi subsystem to determinine whether SOCKS proxy or BOB is used for I2P connections - std::string keys; ///< (optional) server keys - std::string addr; ///< (optional) hidden service addr. in base32 form - - int8_t inLength; - int8_t inQuantity; - int8_t inVariance; - - int8_t outLength; - int8_t outQuantity; - int8_t outVariance; -}; +struct bobSettings : i2p::settings {}; /// /// \brief The bobStates struct diff --git a/retroshare-gui/src/gui/settings/ServerPage.cpp b/retroshare-gui/src/gui/settings/ServerPage.cpp index 2881acd60..f0f8566e0 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.cpp +++ b/retroshare-gui/src/gui/settings/ServerPage.cpp @@ -23,6 +23,7 @@ #include #include "rshare.h" #include "rsharesettings.h" +#include "util/i2pcommon.h" #include "util/RsNetUtil.h" #include "util/misc.h" @@ -1352,7 +1353,7 @@ void ServerPage::updateInProxyIndicator() ui.iconlabel_service_incoming->setMovie(movie); movie->start(); - if (mHiddenType == RS_HIDDEN_TYPE_I2P && mBobSettings.enableBob) { + if (mHiddenType == RS_HIDDEN_TYPE_I2P && mBobSettings.enable) { QTcpSocket tcpSocket; @@ -1439,15 +1440,16 @@ void ServerPage::getNewKey() void ServerPage::loadKey() { - mBobSettings.keys = ui.pteBobServerKey->toPlainText().toStdString(); - mBobSettings.addr = p3I2pBob::keyToBase32Addr(mBobSettings.keys); + mBobSettings.address.privateKey = ui.pteBobServerKey->toPlainText().toStdString(); + mBobSettings.address.publicKey = i2p::publicKeyFromPrivate(mBobSettings.address.privateKey); + mBobSettings.address.base32 = i2p::keyToBase32Addr(mBobSettings.address.publicKey); rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &mBobSettings); } void ServerPage::enableBob(bool checked) { - mBobSettings.enableBob = checked; + mBobSettings.enable = checked; rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &mBobSettings); @@ -1487,7 +1489,7 @@ void ServerPage::toggleBobAdvancedSettings(bool checked) { ui.swBobAdvanced->setCurrentIndex(checked ? 1 : 0); - if (!mBobSettings.keys.empty()) { + if (!mBobSettings.address.privateKey.empty()) { if (checked) { ui.pbBobGenAddr->show(); } else { @@ -1578,9 +1580,9 @@ void ServerPage::loadCommon() whileBlocking(ui.hiddenpage_proxyPort_i2p_2)->setValue(proxyport); // this one is for bob tab // don't use whileBlocking here - ui.cb_enableBob->setChecked(mBobSettings.enableBob); + ui.cb_enableBob->setChecked(mBobSettings.enable); - if (!mBobSettings.keys.empty()) { + if (!mBobSettings.address.privateKey.empty()) { ui.lBobB32Addr->show(); ui.leBobB32Addr->show(); } @@ -1623,13 +1625,13 @@ void ServerPage::saveBob() void ServerPage::updateStatusBob() { - QString addr = QString::fromStdString(mBobSettings.addr); + QString addr = QString::fromStdString(mBobSettings.address.base32); if (ui.leBobB32Addr->text() != addr) { ui.leBobB32Addr->setText(addr); ui.hiddenpage_serviceAddress->setText(addr); - ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.keys)); + ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.address.privateKey)); - if (!mBobSettings.keys.empty()) { + if (!mBobSettings.address.privateKey.empty()) { // we have an addr -> show fields ui.lBobB32Addr->show(); ui.leBobB32Addr->show(); @@ -1655,7 +1657,7 @@ void ServerPage::updateStatusBob() QString bobSimpleText = QString(); bobSimpleText.append(tr("RetroShare uses BOB to set up a %1 tunnel at %2:%3 (named %4)\n\n" "When changing options (e.g. port) use the buttons at the bottom to restart BOB.\n\n"). - arg(mBobSettings.keys.empty() ? tr("client") : tr("server"), + arg(mBobSettings.address.privateKey.empty() ? tr("client") : tr("server"), ui.hiddenpage_proxyAddress_i2p_2->text(), ui.hiddenpage_proxyPort_i2p_2->text(), bs.tunnelName.empty() ? tr("unknown") : @@ -1777,15 +1779,15 @@ void ServerPage::updateStatusBob() void ServerPage::setUpBobElements() { - ui.gbBob->setEnabled(mBobSettings.enableBob); - if (mBobSettings.enableBob) { + ui.gbBob->setEnabled(mBobSettings.enable); + if (mBobSettings.enable) { ui.hiddenpage_proxyAddress_i2p->setEnabled(false); ui.hiddenpage_proxyAddress_i2p->setToolTip("Use I2P/BOB settings to change this value"); ui.hiddenpage_proxyPort_i2p->setEnabled(false); ui.hiddenpage_proxyPort_i2p->setToolTip("Use I2P/BOB settings to change this value"); - ui.leBobB32Addr->setText(QString::fromStdString(mBobSettings.addr)); - ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.keys)); + ui.leBobB32Addr->setText(QString::fromStdString(mBobSettings.address.base32)); + ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.address.privateKey)); // cast to int to avoid problems int li, lo, qi, qo, vi, vo; From c20d92f04cfcb64d508ea25b60bf1e181da61a93 Mon Sep 17 00:00:00 2001 From: sehraf Date: Fri, 8 May 2020 16:50:30 +0200 Subject: [PATCH 062/154] i2p: bob: convert to RsDbg --- .../src/services/autoproxy/p3i2pbob.cc | 113 +++++++++--------- 1 file changed, 57 insertions(+), 56 deletions(-) diff --git a/libretroshare/src/services/autoproxy/p3i2pbob.cc b/libretroshare/src/services/autoproxy/p3i2pbob.cc index 6a52120dc..a68d85396 100644 --- a/libretroshare/src/services/autoproxy/p3i2pbob.cc +++ b/libretroshare/src/services/autoproxy/p3i2pbob.cc @@ -26,6 +26,7 @@ #include "pqi/p3peermgr.h" #include "rsitems/rsconfigitems.h" +#include "util/rsdebug.h" #include "util/radix32.h" #include "util/radix64.h" #include "util/rsdebug.h" @@ -56,7 +57,7 @@ static const int sleepFactorDefault = 10; // 0.5s static const int sleepFactorFast = 1; // 0.05s static const int sleepFactorSlow = 20; // 1s -static struct RsLog::logInfo i2pBobLogInfo = {RsLog::Default, "p3I2pBob"}; +RS_SET_CONTEXT_DEBUG_LEVEL(0) static const rstime_t selfCheckPeroid = 30; @@ -164,7 +165,7 @@ void p3I2pBob::processTaskAsync(taskTicket *ticket) } break; default: - rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::processTaskAsync unknown task"); + RsDbg() << __PRETTY_FUNCTION__ << " p3I2pBob::processTaskAsync unknown task" << std::endl; rsAutoProxyMonitor::taskError(ticket); break; } @@ -179,7 +180,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) case autoProxyTask::status: // check if everything needed is set if (!data) { - rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::status autoProxyTask::status data is missing"); + RsDbg() << __PRETTY_FUNCTION__ << " p3I2pBob::status autoProxyTask::status data is missing" << std::endl; rsAutoProxyMonitor::taskError(ticket); break; } @@ -193,7 +194,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) case autoProxyTask::getSettings: // check if everything needed is set if (!data) { - rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::data_tick autoProxyTask::getSettings data is missing"); + RsDbg() << __PRETTY_FUNCTION__ << " p3I2pBob::data_tick autoProxyTask::getSettings data is missing" << std::endl; rsAutoProxyMonitor::taskError(ticket); break; } @@ -207,7 +208,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) case autoProxyTask::setSettings: // check if everything needed is set if (!data) { - rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::data_tick autoProxyTask::setSettings data is missing"); + RsDbg() << __PRETTY_FUNCTION__ << " p3I2pBob::data_tick autoProxyTask::setSettings data is missing" << std::endl; rsAutoProxyMonitor::taskError(ticket); break; } @@ -227,7 +228,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) break; case autoProxyTask::getErrorInfo: if (!data) { - rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::data_tick autoProxyTask::getErrorInfo data is missing"); + RsDbg() << __PRETTY_FUNCTION__ << " p3I2pBob::data_tick autoProxyTask::getErrorInfo data is missing" << std::endl; rsAutoProxyMonitor::taskError(ticket); } else { RS_STACK_MUTEX(mLock); @@ -236,7 +237,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) } break; default: - rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::processTaskSync unknown task"); + RsDbg() << __PRETTY_FUNCTION__ << " p3I2pBob::processTaskSync unknown task" << std::endl; rsAutoProxyMonitor::taskError(ticket); break; } @@ -257,7 +258,7 @@ void p3I2pBob::threadTick() RS_STACK_MUTEX(mLock); std::stringstream ss; ss << "data_tick mState: " << mState << " mTask: " << mTask << " mBOBState: " << mBOBState << " mPending: " << mPending.size(); - rslog(RsLog::Debug_All, &i2pBobLogInfo, ss.str()); + Dbg4() << __PRETTY_FUNCTION__ << " " + ss.str() << std::endl; } sleepTime += stateMachineController(); @@ -298,13 +299,13 @@ int p3I2pBob::stateMachineBOB() while (answer.find("OK Listing done") == std::string::npos) { std::stringstream ss; ss << "stateMachineBOB status check: read loop, counter: " << counter; - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, ss.str()); + Dbg3() << __PRETTY_FUNCTION__ << " " + ss.str() << std::endl; answer += recv(); counter++; } if (answer.find(mTunnelName) == std::string::npos) { - rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineBOB status check: tunnel down!"); + RsDbg() << __PRETTY_FUNCTION__ << " stateMachineBOB status check: tunnel down!" << std::endl; // signal error *((bool *)mProcessing->data) = true; } @@ -344,8 +345,8 @@ int p3I2pBob::stateMachineBOB_locked_failure(const std::string &answer, const bo return sleepFactorDefault; } - rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineBOB FAILED to run command '" + currentState.command + "'"); - rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineBOB '" + answer + "'"); + RsDbg() << __PRETTY_FUNCTION__ << " stateMachineBOB FAILED to run command '" + currentState.command + "'" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " stateMachineBOB '" + answer + "'" << std::endl; mErrorMsg.append("FAILED to run command '" + currentState.command + "'" + '\n'); mErrorMsg.append("reason '" + answer + "'" + '\n'); @@ -392,14 +393,14 @@ int p3I2pBob::stateMachineController() return stateMachineController_locked_idle(); case csDoConnect: if (!connectI2P()) { - rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController doConnect: unable to connect"); + RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController doConnect: unable to connect" << std::endl; mStateOld = mState; mState = csError; mErrorMsg = "unable to connect to BOB port"; return sleepFactorSlow; } - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController doConnect: connected"); + Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController doConnect: connected" << std::endl; mState = csConnected; break; case csConnected: @@ -407,7 +408,7 @@ int p3I2pBob::stateMachineController() case csWaitForBob: // check connection problems if (mSocket == 0) { - rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController waitForBob: conection lost"); + RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController waitForBob: conection lost" << std::endl; mStateOld = mState; mState = csError; mErrorMsg = "connection lost to BOB"; @@ -417,21 +418,21 @@ int p3I2pBob::stateMachineController() // check for finished BOB protocol if (mBOBState == bsCleared) { // done - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController waitForBob: mBOBState == bsCleared"); + Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController waitForBob: mBOBState == bsCleared" << std::endl; mState = csDoDisconnect; } break; case csDoDisconnect: if (!disconnectI2P() || mSocket != 0) { // just in case - rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController doDisconnect: can't disconnect"); + RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController doDisconnect: can't disconnect" << std::endl; mStateOld = mState; mState = csError; mErrorMsg = "unable to disconnect from BOB"; return sleepFactorDefault; } - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController doDisconnect: disconnected"); + Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController doDisconnect: disconnected" << std::endl; mState = csDisconnected; break; case csDisconnected: @@ -462,7 +463,7 @@ int p3I2pBob::stateMachineController_locked_idle() mProcessing->task == autoProxyTask::stop || mProcessing->task == autoProxyTask::proxyStatusCheck)) { // skip since we are not enabled - rslog(RsLog::Debug_Alert, &i2pBobLogInfo, "stateMachineController_locked_idle: disabled -> skipping ticket"); + Dbg1() << __PRETTY_FUNCTION__ << " stateMachineController_locked_idle: disabled -> skipping ticket" << std::endl; rsAutoProxyMonitor::taskDone(mProcessing, autoProxyStatus::disabled); mProcessing = NULL; } else { @@ -484,7 +485,7 @@ int p3I2pBob::stateMachineController_locked_idle() mTask = ctRunCheck; break; default: - rslog(RsLog::Debug_Alert, &i2pBobLogInfo, "stateMachineController_locked_idle unknown async task"); + Dbg1() << __PRETTY_FUNCTION__ << " stateMachineController_locked_idle unknown async task" << std::endl; rsAutoProxyMonitor::taskError(mProcessing); mProcessing = NULL; break; @@ -532,28 +533,28 @@ int p3I2pBob::stateMachineController_locked_connected() case ctRunSetUp: // when we have a key use it for server tunnel! if(mSetting.address.privateKey.empty()) { - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = setnickC"); + Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController_locked_connected: setting mBOBState = setnickC" << std::endl; mBOBState = bsSetnickC; } else { - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = setnickS"); + Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController_locked_connected: setting mBOBState = setnickS" << std::endl; mBOBState = bsSetnickS; } break; case ctRunShutDown: // shut down existing tunnel - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = getnick"); + Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController_locked_connected: setting mBOBState = getnick" << std::endl; mBOBState = bsGetnick; break; case ctRunCheck: - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = list"); + Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController_locked_connected: setting mBOBState = list" << std::endl; mBOBState = bsList; break; case ctRunGetKeys: - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = setnickN"); + Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController_locked_connected: setting mBOBState = setnickN" << std::endl; mBOBState = bsSetnickN; break; case ctIdle: - rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_connected: task is idle. This should not happen!"); + RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_connected: task is idle. This should not happen!" << std::endl; break; } @@ -569,7 +570,7 @@ int p3I2pBob::stateMachineController_locked_disconnected() if(errorHappened) { // reset old state mStateOld = csIdel; - rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_disconnected: error during process!"); + RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_disconnected: error during process!" << std::endl; } // answer ticket @@ -598,12 +599,12 @@ int p3I2pBob::stateMachineController_locked_disconnected() mTask = mTaskOld; if (!errorHappened) { - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_disconnected: run check result: ok"); + Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController_locked_disconnected: run check result: ok" << std::endl; break; } // switch to error newState = csError; - rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_disconnected: run check result: error"); + RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_disconnected: run check result: error" << std::endl; mErrorMsg = "Connection check failed. Will try to restart tunnel."; break; @@ -626,7 +627,7 @@ int p3I2pBob::stateMachineController_locked_disconnected() mTask = mTaskOld; break; case ctIdle: - rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_disconnected: task is idle. This should not happen!"); + RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_disconnected: task is idle. This should not happen!" << std::endl; rsAutoProxyMonitor::taskError(mProcessing); } mProcessing = NULL; @@ -642,14 +643,14 @@ int p3I2pBob::stateMachineController_locked_error() { // wait for bob protocoll if (mBOBState != bsCleared) { - rslog(RsLog::Debug_All, &i2pBobLogInfo, "stateMachineController_locked_error: waiting for BOB"); + Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController_locked_error: waiting for BOB" << std::endl; return sleepFactorFast; } #if 0 std::stringstream ss; ss << "stateMachineController_locked_error: mProcessing: " << (mProcessing ? "not null" : "null"); - rslog(RsLog::Debug_All, &i2pBobLogInfo, ss.str()); + Dbg4() << __PRETTY_FUNCTION__ << " " + ss.str() << std::endl; #endif // try to finish ticket @@ -657,7 +658,7 @@ int p3I2pBob::stateMachineController_locked_error() switch (mTask) { case ctRunCheck: // connection check failed at some point - rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: failed to check proxy status (it's likely dead)!"); + RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_error: failed to check proxy status (it's likely dead)!" << std::endl; *((bool *)mProcessing->data) = true; mState = csDoDisconnect; mStateOld = csIdel; @@ -665,7 +666,7 @@ int p3I2pBob::stateMachineController_locked_error() break; case ctRunShutDown: // not a big deal though - rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: failed to shut down tunnel (it's likely dead though)!"); + RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_error: failed to shut down tunnel (it's likely dead though)!" << std::endl; mState = csDoDisconnect; mStateOld = csIdel; mErrorMsg.clear(); @@ -673,14 +674,14 @@ int p3I2pBob::stateMachineController_locked_error() case ctIdle: // should not happen but we need to deal with it // this will produce some error messages in the log and finish the task (marked as failed) - rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: task is idle. This should not happen!"); + RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_error: task is idle. This should not happen!" << std::endl; mState = csDoDisconnect; mStateOld = csIdel; mErrorMsg.clear(); break; case ctRunGetKeys: case ctRunSetUp: - rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: failed to receive key / start up"); + RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_error: failed to receive key / start up" << std::endl; mStateOld = csError; mState = csDoDisconnect; // keep the error message @@ -691,7 +692,7 @@ int p3I2pBob::stateMachineController_locked_error() // periodically retry if (mLastProxyCheck < time(NULL) - (selfCheckPeroid >> 1) && mTask == ctRunSetUp) { - rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: retrying"); + RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_error: retrying" << std::endl; mLastProxyCheck = time(NULL); mErrorMsg.clear(); @@ -704,7 +705,7 @@ int p3I2pBob::stateMachineController_locked_error() // check for new tickets if (!mPending.empty()) { - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_error: processing new ticket"); + Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController_locked_error: processing new ticket" << std::endl; // reset and try new task mTask = ctIdle; @@ -735,7 +736,7 @@ RsSerialiser *p3I2pBob::setupSerialiser() bool p3I2pBob::saveList(bool &cleanup, std::list &lst) { - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "saveList"); + Dbg4() << __PRETTY_FUNCTION__ << " saveList" << std::endl; cleanup = true; RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet; @@ -770,7 +771,7 @@ bool p3I2pBob::saveList(bool &cleanup, std::list &lst) bool p3I2pBob::loadList(std::list &load) { - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "loadList"); + Dbg4() << __PRETTY_FUNCTION__ << " loadList" << std::endl; for(std::list::const_iterator it = load.begin(); it!=load.end(); ++it) { RsConfigKeyValueSet *vitem = dynamic_cast(*it); @@ -790,7 +791,7 @@ bool p3I2pBob::loadList(std::list &load) getKVSUInt(kit, kConfigKeyOutQuantity, mSetting.outQuantity) getKVSUInt(kit, kConfigKeyOutVariance, mSetting.outVariance) else - rslog(RsLog::Warning, &i2pBobLogInfo, "loadList unknown key: " + kit->key); + RsDbg() << __PRETTY_FUNCTION__ << " loadList unknown key: " + kit->key << std::endl; } } delete vitem; @@ -854,7 +855,7 @@ void p3I2pBob::getStates(bobStates *bs) std::string p3I2pBob::executeCommand(const std::string &command) { - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "executeCommand_locked running '" + command + "'"); + Dbg4() << __PRETTY_FUNCTION__ << " executeCommand_locked running '" + command + "'" << std::endl; std::string copy = command; copy.push_back('\n'); @@ -866,7 +867,7 @@ std::string p3I2pBob::executeCommand(const std::string &command) // receive answer (trailing new line is already removed!) std::string ans = recv(); - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "executeCommand_locked answer '" + ans + "'"); + Dbg4() << __PRETTY_FUNCTION__ << " executeCommand_locked answer '" + ans + "'" << std::endl; return ans; } @@ -876,7 +877,7 @@ bool p3I2pBob::connectI2P() // there is only one thread that touches mSocket - no need for a lock if (mSocket != 0) { - rslog(RsLog::Warning, &i2pBobLogInfo, "connectI2P_locked mSocket != 0"); + RsDbg() << __PRETTY_FUNCTION__ << " connectI2P_locked mSocket != 0" << std::endl; return false; } @@ -884,21 +885,21 @@ bool p3I2pBob::connectI2P() mSocket = unix_socket(PF_INET, SOCK_STREAM, 0); if (mSocket < 0) { - rslog(RsLog::Warning, &i2pBobLogInfo, "connectI2P_locked Failed to open socket! Socket Error: " + socket_errorType(errno)); + RsDbg() << __PRETTY_FUNCTION__ << " connectI2P_locked Failed to open socket! Socket Error: " + socket_errorType(errno) << std::endl; return false; } // connect int err = unix_connect(mSocket, mI2PProxyAddr); if (err != 0) { - rslog(RsLog::Warning, &i2pBobLogInfo, "connectI2P_locked Failed to connect to BOB! Socket Error: " + socket_errorType(errno)); + RsDbg() << __PRETTY_FUNCTION__ << " connectI2P_locked Failed to connect to BOB! Socket Error: " + socket_errorType(errno) << std::endl; return false; } // receive hello msg recv(); - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "connectI2P_locked done"); + Dbg4() << __PRETTY_FUNCTION__ << " connectI2P_locked done" << std::endl; return true; } @@ -907,17 +908,17 @@ bool p3I2pBob::disconnectI2P() // there is only one thread that touches mSocket - no need for a lock if (mSocket == 0) { - rslog(RsLog::Warning, &i2pBobLogInfo, "disconnectI2P_locked mSocket == 0"); + RsDbg() << __PRETTY_FUNCTION__ << " disconnectI2P_locked mSocket == 0" << std::endl; return true; } int err = unix_close(mSocket); if (err != 0) { - rslog(RsLog::Warning, &i2pBobLogInfo, "disconnectI2P_locked Failed to close socket! Socket Error: " + socket_errorType(errno)); + RsDbg() << __PRETTY_FUNCTION__ << " disconnectI2P_locked Failed to close socket! Socket Error: " + socket_errorType(errno) << std::endl; return false; } - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "disconnectI2P_locked done"); + Dbg4() << __PRETTY_FUNCTION__ << " disconnectI2P_locked done" << std::endl; mSocket = 0; return true; } @@ -938,7 +939,7 @@ std::string toString(const std::string &a, const int8_t b) { void p3I2pBob::finalizeSettings_locked() { - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked"); + Dbg4() << __PRETTY_FUNCTION__ << " finalizeSettings_locked" << std::endl; sockaddr_storage_clear(mI2PProxyAddr); // get i2p proxy addr @@ -949,8 +950,8 @@ void p3I2pBob::finalizeSettings_locked() sockaddr_storage_setipv4(mI2PProxyAddr, (sockaddr_in*)&proxy); sockaddr_storage_setport(mI2PProxyAddr, 2827); - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using " + sockaddr_storage_tostring(mI2PProxyAddr)); - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using " + mSetting.address.base32); + Dbg4() << __PRETTY_FUNCTION__ << " finalizeSettings_locked using " + sockaddr_storage_tostring(mI2PProxyAddr) << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " finalizeSettings_locked using " + mSetting.address.base32 << std::endl; peerState ps; mPeerMgr->getOwnNetStatus(ps); @@ -965,7 +966,7 @@ void p3I2pBob::finalizeSettings_locked() std::vector tmp(len); RSRandom::random_bytes(tmp.data(), len); const std::string location = Radix32::encode(tmp.data(), len); - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using suffix " + location); + Dbg4() << __PRETTY_FUNCTION__ << " finalizeSettings_locked using suffix " + location << std::endl; mTunnelName = "RetroShare-" + location; const std::string setnick = "setnick RetroShare-" + location; @@ -1033,7 +1034,7 @@ void p3I2pBob::finalizeSettings_locked() void p3I2pBob::updateSettings_locked() { - rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "updateSettings_locked"); + Dbg4() << __PRETTY_FUNCTION__ << " updateSettings_locked" << std::endl; sockaddr_storage proxy; mPeerMgr->getProxyServerAddress(RS_HIDDEN_TYPE_I2P, proxy); @@ -1095,7 +1096,7 @@ std::string p3I2pBob::recv() #if 0 std::stringstream ss; ss << "recv length: " << length << " (bufferSize: " << bufferSize << ") ans: " << ans.length(); - rslog(RsLog::Debug_All, &i2pBobLogInfo, ss.str()); + Dbg4() << __PRETTY_FUNCTION__ << " " + ss.str() << std::endl; #endif // clear and resize buffer again From a41e10b178e3903173e535893a0bbaf6f5dbdd26 Mon Sep 17 00:00:00 2001 From: sehraf Date: Fri, 8 May 2020 16:50:59 +0200 Subject: [PATCH 063/154] i2p: bob: remove unused variables --- libretroshare/src/services/autoproxy/p3i2pbob.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libretroshare/src/services/autoproxy/p3i2pbob.cc b/libretroshare/src/services/autoproxy/p3i2pbob.cc index a68d85396..f63a10b7f 100644 --- a/libretroshare/src/services/autoproxy/p3i2pbob.cc +++ b/libretroshare/src/services/autoproxy/p3i2pbob.cc @@ -44,11 +44,6 @@ static const std::string kConfigKeyOutLength = "OUT_LENGTH"; static const std::string kConfigKeyOutQuantity = "OUT_QUANTITY"; static const std::string kConfigKeyOutVariance = "OUT_VARIANCE"; -static const bool kDefaultBOBEnable = false; -static const int8_t kDefaultLength = 3; -static const int8_t kDefaultQuantity = 4; -static const int8_t kDefaultVariance = 0; - /// Sleep duration for receiving loop static const useconds_t sleepTimeRecv = 10; // times 1000 = 10ms /// Sleep duration for everything else From 1da3d262d94ef68d0289fdfcae243570d842fd85 Mon Sep 17 00:00:00 2001 From: sehraf Date: Fri, 8 May 2020 16:54:51 +0200 Subject: [PATCH 064/154] i2p: bob: removed function name within debug output (replaced by __PRETTY_FUNCTION__) --- .../src/services/autoproxy/p3i2pbob.cc | 102 +++++++++--------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/libretroshare/src/services/autoproxy/p3i2pbob.cc b/libretroshare/src/services/autoproxy/p3i2pbob.cc index f63a10b7f..e8ebb5979 100644 --- a/libretroshare/src/services/autoproxy/p3i2pbob.cc +++ b/libretroshare/src/services/autoproxy/p3i2pbob.cc @@ -160,7 +160,7 @@ void p3I2pBob::processTaskAsync(taskTicket *ticket) } break; default: - RsDbg() << __PRETTY_FUNCTION__ << " p3I2pBob::processTaskAsync unknown task" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " unknown task" << std::endl; rsAutoProxyMonitor::taskError(ticket); break; } @@ -175,7 +175,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) case autoProxyTask::status: // check if everything needed is set if (!data) { - RsDbg() << __PRETTY_FUNCTION__ << " p3I2pBob::status autoProxyTask::status data is missing" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " autoProxyTask::status data is missing" << std::endl; rsAutoProxyMonitor::taskError(ticket); break; } @@ -189,7 +189,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) case autoProxyTask::getSettings: // check if everything needed is set if (!data) { - RsDbg() << __PRETTY_FUNCTION__ << " p3I2pBob::data_tick autoProxyTask::getSettings data is missing" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " autoProxyTask::getSettings data is missing" << std::endl; rsAutoProxyMonitor::taskError(ticket); break; } @@ -203,7 +203,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) case autoProxyTask::setSettings: // check if everything needed is set if (!data) { - RsDbg() << __PRETTY_FUNCTION__ << " p3I2pBob::data_tick autoProxyTask::setSettings data is missing" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " autoProxyTask::setSettings data is missing" << std::endl; rsAutoProxyMonitor::taskError(ticket); break; } @@ -223,7 +223,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) break; case autoProxyTask::getErrorInfo: if (!data) { - RsDbg() << __PRETTY_FUNCTION__ << " p3I2pBob::data_tick autoProxyTask::getErrorInfo data is missing" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " autoProxyTask::getErrorInfo data is missing" << std::endl; rsAutoProxyMonitor::taskError(ticket); } else { RS_STACK_MUTEX(mLock); @@ -232,7 +232,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) } break; default: - RsDbg() << __PRETTY_FUNCTION__ << " p3I2pBob::processTaskSync unknown task" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " unknown task" << std::endl; rsAutoProxyMonitor::taskError(ticket); break; } @@ -300,7 +300,7 @@ int p3I2pBob::stateMachineBOB() } if (answer.find(mTunnelName) == std::string::npos) { - RsDbg() << __PRETTY_FUNCTION__ << " stateMachineBOB status check: tunnel down!" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " status check: tunnel down!" << std::endl; // signal error *((bool *)mProcessing->data) = true; } @@ -340,8 +340,8 @@ int p3I2pBob::stateMachineBOB_locked_failure(const std::string &answer, const bo return sleepFactorDefault; } - RsDbg() << __PRETTY_FUNCTION__ << " stateMachineBOB FAILED to run command '" + currentState.command + "'" << std::endl; - RsDbg() << __PRETTY_FUNCTION__ << " stateMachineBOB '" + answer + "'" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " FAILED to run command '" + currentState.command + "'" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " '" + answer + "'" << std::endl; mErrorMsg.append("FAILED to run command '" + currentState.command + "'" + '\n'); mErrorMsg.append("reason '" + answer + "'" + '\n'); @@ -388,14 +388,14 @@ int p3I2pBob::stateMachineController() return stateMachineController_locked_idle(); case csDoConnect: if (!connectI2P()) { - RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController doConnect: unable to connect" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " doConnect: unable to connect" << std::endl; mStateOld = mState; mState = csError; mErrorMsg = "unable to connect to BOB port"; return sleepFactorSlow; } - Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController doConnect: connected" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " doConnect: connected" << std::endl; mState = csConnected; break; case csConnected: @@ -403,7 +403,7 @@ int p3I2pBob::stateMachineController() case csWaitForBob: // check connection problems if (mSocket == 0) { - RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController waitForBob: conection lost" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " waitForBob: conection lost" << std::endl; mStateOld = mState; mState = csError; mErrorMsg = "connection lost to BOB"; @@ -413,21 +413,21 @@ int p3I2pBob::stateMachineController() // check for finished BOB protocol if (mBOBState == bsCleared) { // done - Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController waitForBob: mBOBState == bsCleared" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " waitForBob: mBOBState == bsCleared" << std::endl; mState = csDoDisconnect; } break; case csDoDisconnect: if (!disconnectI2P() || mSocket != 0) { // just in case - RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController doDisconnect: can't disconnect" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " doDisconnect: can't disconnect" << std::endl; mStateOld = mState; mState = csError; mErrorMsg = "unable to disconnect from BOB"; return sleepFactorDefault; } - Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController doDisconnect: disconnected" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " doDisconnect: disconnected" << std::endl; mState = csDisconnected; break; case csDisconnected: @@ -458,7 +458,7 @@ int p3I2pBob::stateMachineController_locked_idle() mProcessing->task == autoProxyTask::stop || mProcessing->task == autoProxyTask::proxyStatusCheck)) { // skip since we are not enabled - Dbg1() << __PRETTY_FUNCTION__ << " stateMachineController_locked_idle: disabled -> skipping ticket" << std::endl; + Dbg1() << __PRETTY_FUNCTION__ << " disabled -> skipping ticket" << std::endl; rsAutoProxyMonitor::taskDone(mProcessing, autoProxyStatus::disabled); mProcessing = NULL; } else { @@ -480,7 +480,7 @@ int p3I2pBob::stateMachineController_locked_idle() mTask = ctRunCheck; break; default: - Dbg1() << __PRETTY_FUNCTION__ << " stateMachineController_locked_idle unknown async task" << std::endl; + Dbg1() << __PRETTY_FUNCTION__ << " unknown async task" << std::endl; rsAutoProxyMonitor::taskError(mProcessing); mProcessing = NULL; break; @@ -528,28 +528,28 @@ int p3I2pBob::stateMachineController_locked_connected() case ctRunSetUp: // when we have a key use it for server tunnel! if(mSetting.address.privateKey.empty()) { - Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController_locked_connected: setting mBOBState = setnickC" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " setting mBOBState = setnickC" << std::endl; mBOBState = bsSetnickC; } else { - Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController_locked_connected: setting mBOBState = setnickS" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " setting mBOBState = setnickS" << std::endl; mBOBState = bsSetnickS; } break; case ctRunShutDown: // shut down existing tunnel - Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController_locked_connected: setting mBOBState = getnick" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " setting mBOBState = getnick" << std::endl; mBOBState = bsGetnick; break; case ctRunCheck: - Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController_locked_connected: setting mBOBState = list" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " setting mBOBState = list" << std::endl; mBOBState = bsList; break; case ctRunGetKeys: - Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController_locked_connected: setting mBOBState = setnickN" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " setting mBOBState = setnickN" << std::endl; mBOBState = bsSetnickN; break; case ctIdle: - RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_connected: task is idle. This should not happen!" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " task is idle. This should not happen!" << std::endl; break; } @@ -565,7 +565,7 @@ int p3I2pBob::stateMachineController_locked_disconnected() if(errorHappened) { // reset old state mStateOld = csIdel; - RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_disconnected: error during process!" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " error during process!" << std::endl; } // answer ticket @@ -594,12 +594,12 @@ int p3I2pBob::stateMachineController_locked_disconnected() mTask = mTaskOld; if (!errorHappened) { - Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController_locked_disconnected: run check result: ok" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " run check result: ok" << std::endl; break; } // switch to error newState = csError; - RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_disconnected: run check result: error" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " run check result: error" << std::endl; mErrorMsg = "Connection check failed. Will try to restart tunnel."; break; @@ -622,7 +622,7 @@ int p3I2pBob::stateMachineController_locked_disconnected() mTask = mTaskOld; break; case ctIdle: - RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_disconnected: task is idle. This should not happen!" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " task is idle. This should not happen!" << std::endl; rsAutoProxyMonitor::taskError(mProcessing); } mProcessing = NULL; @@ -638,7 +638,7 @@ int p3I2pBob::stateMachineController_locked_error() { // wait for bob protocoll if (mBOBState != bsCleared) { - Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController_locked_error: waiting for BOB" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " waiting for BOB" << std::endl; return sleepFactorFast; } @@ -653,7 +653,7 @@ int p3I2pBob::stateMachineController_locked_error() switch (mTask) { case ctRunCheck: // connection check failed at some point - RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_error: failed to check proxy status (it's likely dead)!" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " failed to check proxy status (it's likely dead)!" << std::endl; *((bool *)mProcessing->data) = true; mState = csDoDisconnect; mStateOld = csIdel; @@ -661,7 +661,7 @@ int p3I2pBob::stateMachineController_locked_error() break; case ctRunShutDown: // not a big deal though - RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_error: failed to shut down tunnel (it's likely dead though)!" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " failed to shut down tunnel (it's likely dead though)!" << std::endl; mState = csDoDisconnect; mStateOld = csIdel; mErrorMsg.clear(); @@ -669,14 +669,14 @@ int p3I2pBob::stateMachineController_locked_error() case ctIdle: // should not happen but we need to deal with it // this will produce some error messages in the log and finish the task (marked as failed) - RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_error: task is idle. This should not happen!" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " task is idle. This should not happen!" << std::endl; mState = csDoDisconnect; mStateOld = csIdel; mErrorMsg.clear(); break; case ctRunGetKeys: case ctRunSetUp: - RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_error: failed to receive key / start up" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " failed to receive key / start up" << std::endl; mStateOld = csError; mState = csDoDisconnect; // keep the error message @@ -687,7 +687,7 @@ int p3I2pBob::stateMachineController_locked_error() // periodically retry if (mLastProxyCheck < time(NULL) - (selfCheckPeroid >> 1) && mTask == ctRunSetUp) { - RsDbg() << __PRETTY_FUNCTION__ << " stateMachineController_locked_error: retrying" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " retrying" << std::endl; mLastProxyCheck = time(NULL); mErrorMsg.clear(); @@ -700,7 +700,7 @@ int p3I2pBob::stateMachineController_locked_error() // check for new tickets if (!mPending.empty()) { - Dbg4() << __PRETTY_FUNCTION__ << " stateMachineController_locked_error: processing new ticket" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " processing new ticket" << std::endl; // reset and try new task mTask = ctIdle; @@ -731,7 +731,7 @@ RsSerialiser *p3I2pBob::setupSerialiser() bool p3I2pBob::saveList(bool &cleanup, std::list &lst) { - Dbg4() << __PRETTY_FUNCTION__ << " saveList" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << std::endl; cleanup = true; RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet; @@ -766,7 +766,7 @@ bool p3I2pBob::saveList(bool &cleanup, std::list &lst) bool p3I2pBob::loadList(std::list &load) { - Dbg4() << __PRETTY_FUNCTION__ << " loadList" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << std::endl; for(std::list::const_iterator it = load.begin(); it!=load.end(); ++it) { RsConfigKeyValueSet *vitem = dynamic_cast(*it); @@ -786,7 +786,7 @@ bool p3I2pBob::loadList(std::list &load) getKVSUInt(kit, kConfigKeyOutQuantity, mSetting.outQuantity) getKVSUInt(kit, kConfigKeyOutVariance, mSetting.outVariance) else - RsDbg() << __PRETTY_FUNCTION__ << " loadList unknown key: " + kit->key << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " unknown key: " + kit->key << std::endl; } } delete vitem; @@ -850,7 +850,7 @@ void p3I2pBob::getStates(bobStates *bs) std::string p3I2pBob::executeCommand(const std::string &command) { - Dbg4() << __PRETTY_FUNCTION__ << " executeCommand_locked running '" + command + "'" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " running '" + command + "'" << std::endl; std::string copy = command; copy.push_back('\n'); @@ -862,7 +862,7 @@ std::string p3I2pBob::executeCommand(const std::string &command) // receive answer (trailing new line is already removed!) std::string ans = recv(); - Dbg4() << __PRETTY_FUNCTION__ << " executeCommand_locked answer '" + ans + "'" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " answer '" + ans + "'" << std::endl; return ans; } @@ -872,7 +872,7 @@ bool p3I2pBob::connectI2P() // there is only one thread that touches mSocket - no need for a lock if (mSocket != 0) { - RsDbg() << __PRETTY_FUNCTION__ << " connectI2P_locked mSocket != 0" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " mSocket != 0" << std::endl; return false; } @@ -880,21 +880,21 @@ bool p3I2pBob::connectI2P() mSocket = unix_socket(PF_INET, SOCK_STREAM, 0); if (mSocket < 0) { - RsDbg() << __PRETTY_FUNCTION__ << " connectI2P_locked Failed to open socket! Socket Error: " + socket_errorType(errno) << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " Failed to open socket! Socket Error: " + socket_errorType(errno) << std::endl; return false; } // connect int err = unix_connect(mSocket, mI2PProxyAddr); if (err != 0) { - RsDbg() << __PRETTY_FUNCTION__ << " connectI2P_locked Failed to connect to BOB! Socket Error: " + socket_errorType(errno) << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " Failed to connect to BOB! Socket Error: " + socket_errorType(errno) << std::endl; return false; } // receive hello msg recv(); - Dbg4() << __PRETTY_FUNCTION__ << " connectI2P_locked done" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " done" << std::endl; return true; } @@ -903,17 +903,17 @@ bool p3I2pBob::disconnectI2P() // there is only one thread that touches mSocket - no need for a lock if (mSocket == 0) { - RsDbg() << __PRETTY_FUNCTION__ << " disconnectI2P_locked mSocket == 0" << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " mSocket == 0" << std::endl; return true; } int err = unix_close(mSocket); if (err != 0) { - RsDbg() << __PRETTY_FUNCTION__ << " disconnectI2P_locked Failed to close socket! Socket Error: " + socket_errorType(errno) << std::endl; + RsDbg() << __PRETTY_FUNCTION__ << " Failed to close socket! Socket Error: " + socket_errorType(errno) << std::endl; return false; } - Dbg4() << __PRETTY_FUNCTION__ << " disconnectI2P_locked done" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " done" << std::endl; mSocket = 0; return true; } @@ -934,7 +934,7 @@ std::string toString(const std::string &a, const int8_t b) { void p3I2pBob::finalizeSettings_locked() { - Dbg4() << __PRETTY_FUNCTION__ << " finalizeSettings_locked" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << std::endl; sockaddr_storage_clear(mI2PProxyAddr); // get i2p proxy addr @@ -945,8 +945,8 @@ void p3I2pBob::finalizeSettings_locked() sockaddr_storage_setipv4(mI2PProxyAddr, (sockaddr_in*)&proxy); sockaddr_storage_setport(mI2PProxyAddr, 2827); - Dbg4() << __PRETTY_FUNCTION__ << " finalizeSettings_locked using " + sockaddr_storage_tostring(mI2PProxyAddr) << std::endl; - Dbg4() << __PRETTY_FUNCTION__ << " finalizeSettings_locked using " + mSetting.address.base32 << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " using " + sockaddr_storage_tostring(mI2PProxyAddr) << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " using " + mSetting.address.base32 << std::endl; peerState ps; mPeerMgr->getOwnNetStatus(ps); @@ -961,7 +961,7 @@ void p3I2pBob::finalizeSettings_locked() std::vector tmp(len); RSRandom::random_bytes(tmp.data(), len); const std::string location = Radix32::encode(tmp.data(), len); - Dbg4() << __PRETTY_FUNCTION__ << " finalizeSettings_locked using suffix " + location << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << " using suffix " + location << std::endl; mTunnelName = "RetroShare-" + location; const std::string setnick = "setnick RetroShare-" + location; @@ -1029,7 +1029,7 @@ void p3I2pBob::finalizeSettings_locked() void p3I2pBob::updateSettings_locked() { - Dbg4() << __PRETTY_FUNCTION__ << " updateSettings_locked" << std::endl; + Dbg4() << __PRETTY_FUNCTION__ << std::endl; sockaddr_storage proxy; mPeerMgr->getProxyServerAddress(RS_HIDDEN_TYPE_I2P, proxy); From f4f08f037922ac292d509c62812789cc06803bb1 Mon Sep 17 00:00:00 2001 From: sehraf Date: Sun, 10 May 2020 13:37:53 +0200 Subject: [PATCH 065/154] i2p: bob: rework recv() to check for new line character as EOL indicator --- .../src/services/autoproxy/p3i2pbob.cc | 72 ++++++++++++------- 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/libretroshare/src/services/autoproxy/p3i2pbob.cc b/libretroshare/src/services/autoproxy/p3i2pbob.cc index e8ebb5979..ef8e1ad48 100644 --- a/libretroshare/src/services/autoproxy/p3i2pbob.cc +++ b/libretroshare/src/services/autoproxy/p3i2pbob.cc @@ -44,8 +44,8 @@ static const std::string kConfigKeyOutLength = "OUT_LENGTH"; static const std::string kConfigKeyOutQuantity = "OUT_QUANTITY"; static const std::string kConfigKeyOutVariance = "OUT_VARIANCE"; -/// Sleep duration for receiving loop -static const useconds_t sleepTimeRecv = 10; // times 1000 = 10ms +/// Sleep duration for receiving loop in error/no-data case +static const useconds_t sleepTimeRecv = 250; // times 1000 = 250ms /// Sleep duration for everything else static const useconds_t sleepTimeWait = 50; // times 1000 = 50ms or 0.05s static const int sleepFactorDefault = 10; // 0.5s @@ -1069,38 +1069,62 @@ void p3I2pBob::updateSettings_locked() std::string p3I2pBob::recv() { + // BOB works line based + // -> \n indicates and of the line + + constexpr uint16_t bufferSize = 128; + char buffer[bufferSize]; + std::string ans; - ssize_t length; - const uint16_t bufferSize = 128; - std::vector buffer(bufferSize); + uint16_t retry = 10; do { - doSleep(sleepTimeRecv); + memset(buffer, 0, bufferSize); - // there is only one thread that touches mSocket - no need for a lock - length = ::recv(mSocket, buffer.data(), buffer.size(), 0); - if (length < 0) + // peek at data + auto length = ::recv(mSocket, buffer, bufferSize, MSG_PEEK); + if (length <= 0) { + if (length < 0) { + // error + perror(__PRETTY_FUNCTION__); + } + retry--; + doSleep(sleepTimeRecv); continue; + } - ans.append(buffer.begin(), buffer.end()); + // at least one byte was read - // clean received string - ans.erase(std::remove(ans.begin(), ans.end(), '\0'), ans.end()); - ans.erase(std::remove(ans.begin(), ans.end(), '\n'), ans.end()); + // search for new line + auto bufferStr = std::string(buffer); + size_t pos = bufferStr.find('\n'); -#if 0 - std::stringstream ss; - ss << "recv length: " << length << " (bufferSize: " << bufferSize << ") ans: " << ans.length(); - Dbg4() << __PRETTY_FUNCTION__ << " " + ss.str() << std::endl; -#endif + if (pos == std::string::npos) { + // no new line found -> more to read - // clear and resize buffer again - buffer.clear(); - buffer.resize(bufferSize); + // sanity check + if (length != bufferSize) { + // expectation: a full buffer was peeked) + Dbg1() << __PRETTY_FUNCTION__ << " peeked less than bufferSize but also didn't found a new line character" << std::endl; + } + // this should never happen + assert(length <= bufferSize); + } else { + // new line found -> end of message - if (this->shouldStop()) - break; - } while(length == bufferSize || ans.size() < 4); + // calculate how much there is to read, read the \n, too! + length = pos + 1; + + // end loop + retry = 0; + } + + // now read for real + memset(buffer, 0, bufferSize); + length = ::recv(mSocket, buffer, length, 0); + bufferStr = std::string(buffer); + ans.append(bufferStr); + } while(retry > 0); return ans; } From b6a550b8f5509ce9e97da65614e2cfbd87cab32b Mon Sep 17 00:00:00 2001 From: sehraf Date: Thu, 21 May 2020 10:12:59 +0200 Subject: [PATCH 066/154] autoproxy: make use of rsdebug.h --- .../services/autoproxy/rsautoproxymonitor.cc | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc b/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc index d198bd207..263663a4e 100644 --- a/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc +++ b/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc @@ -22,6 +22,7 @@ #include "rsautoproxymonitor.h" #include /* for usleep() */ +#include "util/rsdebug.h" #include "util/rstime.h" rsAutoProxyMonitor *rsAutoProxyMonitor::mInstance = NULL; @@ -42,8 +43,10 @@ rsAutoProxyMonitor *rsAutoProxyMonitor::instance() void rsAutoProxyMonitor::addProxy(autoProxyType::autoProxyType_enum type, autoProxyService *service) { RS_STACK_MUTEX(mLock); - if (mProxies.find(type) != mProxies.end()) - std::cerr << "sAutoProxyMonitor::addProxy type " << type << " already added - OVERWRITING" << std::endl; + if (mProxies.find(type) != mProxies.end()) { + RsErr() << __PRETTY_FUNCTION__<< " type " << type << " already added - OVERWRITING" << std::endl; + print_stacktrace(); + } mProxies[type] = service; } @@ -117,7 +120,7 @@ void rsAutoProxyMonitor::stopAllRSShutdown() do { rstime::rs_usleep(1000 * 1000); RS_STACK_MUTEX(mLock); - std::cout << "(II) waiting for auto proxy service(s) to shut down " << t << "/" << timeout << " (remaining: " << mProxies.size() << ")" << std::endl; + RsDbg() << __PRETTY_FUNCTION__<< " waiting for auto proxy service(s) to shut down " << t << "/" << timeout << " (remaining: " << mProxies.size() << ")" << std::endl; if (mProxies.empty()) break; t++; @@ -146,13 +149,16 @@ void rsAutoProxyMonitor::task(taskTicket *ticket) { // sanity checks if (!ticket->async && ticket->types.size() > 1) { - std::cerr << "(WW) rsAutoProxyMonitor::task synchronous call to multiple services. This can cause problems!" << std::endl; + RsErr() << __PRETTY_FUNCTION__<< " synchronous call to multiple services. This can cause problems!" << std::endl; + print_stacktrace(); } if (ticket->async && !ticket->cb && ticket->data) { - std::cerr << "(WW) rsAutoProxyMonitor::task asynchronous call with data but no callback. This will likely causes memory leak!" << std::endl; + RsErr() << __PRETTY_FUNCTION__<< " asynchronous call with data but no callback. This will likely causes memory leak!" << std::endl; + print_stacktrace(); } if (ticket->types.size() > 1 && ticket->data) { - std::cerr << "(WW) rsAutoProxyMonitor::task call with data to multiple services. This will likely causes memory leak!" << std::endl; + RsErr() << __PRETTY_FUNCTION__<< " call with data to multiple services. This will likely causes memory leak!" << std::endl; + print_stacktrace(); } std::vector::const_iterator it; @@ -187,7 +193,8 @@ void rsAutoProxyMonitor::taskAsync(std::vector if (isAsyncTask(task)) { // Usually the services will reject this ticket. // Just print a warning - maybe there is some special case where this is a good idea. - std::cerr << "(WW) rsAutoProxyMonitor::taskSync called with an asynchronous task!" << std::endl; + RsErr() << __PRETTY_FUNCTION__<< " called with an asynchronous task!" << std::endl; + print_stacktrace(); } taskTicket *tt = getTicket(); @@ -244,7 +252,8 @@ void rsAutoProxyMonitor::taskDone(taskTicket *t, autoProxyStatus::autoProxyStatu t->cb->taskFinished(t); if (t != NULL) { // callack did not clean up properly - std::cerr << "(WW) rsAutoProxyMonitor::taskFinish callback did not clean up!" << std::endl; + RsErr() << __PRETTY_FUNCTION__<< " callback did not clean up!" << std::endl; + print_stacktrace(); cleanUp = true; } } else if (t->async){ @@ -252,12 +261,13 @@ void rsAutoProxyMonitor::taskDone(taskTicket *t, autoProxyStatus::autoProxyStatu // we must take care of deleting cleanUp = true; if(t->data) - std::cerr << "(WW) rsAutoProxyMonitor::taskFinish async call with data attached but no callback set!" << std::endl; + RsErr() << __PRETTY_FUNCTION__<< " async call with data attached but no callback set!" << std::endl; } if (cleanUp) { if (t->data) { - std::cerr << "(WW) rsAutoProxyMonitor::taskFinish will try to delete void pointer!" << std::endl; + RsErr() << __PRETTY_FUNCTION__<< " will try to delete void pointer!" << std::endl; + print_stacktrace(); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdelete-incomplete" delete t->data; @@ -290,7 +300,8 @@ void rsAutoProxyMonitor::taskFinished(taskTicket *&ticket) // clean up if (ticket->data) { - std::cerr << "rsAutoProxyMonitor::taskFinished data set. Will try to delete void pointer" << std::endl; + RsErr() << __PRETTY_FUNCTION__<< " data set. Will try to delete void pointer" << std::endl; + print_stacktrace(); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdelete-incomplete" delete ticket->data; @@ -308,7 +319,7 @@ autoProxyService *rsAutoProxyMonitor::lookUpService(autoProxyType::autoProxyType if ((itService = mProxies.find(t)) != mProxies.end()) { return itService->second; } - std::cerr << "sAutoProxyMonitor::lookUpService no service for type " << t << " found!" << std::endl; + RsDbg() << __PRETTY_FUNCTION__<< " no service for type " << t << " found!" << std::endl; return NULL; } From 9a5504bb4733384763a648222f39c636c73dd541 Mon Sep 17 00:00:00 2001 From: sehraf Date: Thu, 21 May 2020 10:17:13 +0200 Subject: [PATCH 067/154] autoproxy: make async really async --- libretroshare/src/services/autoproxy/rsautoproxymonitor.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc b/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc index 263663a4e..62b47dfea 100644 --- a/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc +++ b/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc @@ -174,7 +174,11 @@ void rsAutoProxyMonitor::task(taskTicket *ticket) *tt = *ticket; tt->types.clear(); tt->types.push_back(*it); - s->processTaskAsync(tt); + + // it's async! + RsThread::async([s, tt] { + s->processTaskAsync(tt); + }); } else { s->processTaskSync(ticket); } From a5a2b49d992df09249cff439a7474351643ae7f3 Mon Sep 17 00:00:00 2001 From: sehraf Date: Mon, 25 May 2020 21:51:06 +0200 Subject: [PATCH 068/154] i2p: bob: add option to disable bob CONFIG+=no_rs_bob --- libretroshare/src/rsserver/p3face.h | 2 ++ libretroshare/src/rsserver/rsinit.cc | 6 ++++++ retroshare-gui/src/gui/settings/ServerPage.cpp | 4 ++++ retroshare.pri | 9 +++++++++ 4 files changed, 21 insertions(+) diff --git a/libretroshare/src/rsserver/p3face.h b/libretroshare/src/rsserver/p3face.h index a2637ceaf..661cb244f 100644 --- a/libretroshare/src/rsserver/p3face.h +++ b/libretroshare/src/rsserver/p3face.h @@ -161,7 +161,9 @@ public: p3ChatService *chatSrv; p3StatusService *mStatusSrv; p3GxsTunnelService *mGxsTunnels; +#ifdef RS_USE_I2P_BOB p3I2pBob *mI2pBob; +#endif // This list contains all threaded services. It will be used to shut them down properly. diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 1c4e2a062..fa21b82e7 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -923,8 +923,10 @@ int RsServer::StartupRetroShare() mNetMgr->setManagers(mPeerMgr, mLinkMgr); rsAutoProxyMonitor *autoProxy = rsAutoProxyMonitor::instance(); +#ifdef RS_USE_I2P_BOB mI2pBob = new p3I2pBob(mPeerMgr); autoProxy->addProxy(autoProxyType::I2PBOB, mI2pBob); +#endif //load all the SSL certs as friends // std::list sslIds; @@ -1649,7 +1651,9 @@ int RsServer::StartupRetroShare() mConfigMgr->addConfiguration("wire.cfg", wire_ns); #endif #endif //RS_ENABLE_GXS +#ifdef RS_USE_I2P_BOB mConfigMgr->addConfiguration("I2PBOB.cfg", mI2pBob); +#endif mPluginsManager->addConfigurations(mConfigMgr) ; @@ -1795,7 +1799,9 @@ int RsServer::StartupRetroShare() /**************************************************************************/ // auto proxy threads +#ifdef RS_USE_I2P_BOB startServiceThread(mI2pBob, "I2P-BOB"); +#endif #ifdef RS_ENABLE_GXS // Must Set the GXS pointers before starting threads. diff --git a/retroshare-gui/src/gui/settings/ServerPage.cpp b/retroshare-gui/src/gui/settings/ServerPage.cpp index f0f8566e0..37291be0f 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.cpp +++ b/retroshare-gui/src/gui/settings/ServerPage.cpp @@ -83,6 +83,10 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags) manager = NULL ; mOngoingConnectivityCheck = -1; +#ifndef RS_USE_I2P_BOB + ui.hiddenServiceTab->removeTab(TAB_HIDDEN_SERVICE_I2P_BOB); // warning: the order of operation here is very important. +#endif + if(RsAccounts::isHiddenNode()) { if(RsAccounts::isTorAuto()) diff --git a/retroshare.pri b/retroshare.pri index 6bccc1f5a..994ced0f2 100644 --- a/retroshare.pri +++ b/retroshare.pri @@ -140,6 +140,11 @@ rs_macos10.15:CONFIG -= rs_macos10.11 CONFIG *= no_rs_jsonapi rs_jsonapi:CONFIG -= no_rs_jsonapi +# Disable i2p BOB support for automatically setting up an i2p tunnel for RS +# "CONFIG+=no_rs_bob" +CONFIG *= rs_bob +no_rs_bob:CONFIG -= rs_bob + # To enable channel indexing append the following assignation to qmake command # line "CONFIG+=rs_deep_channel_index" CONFIG *= no_rs_deep_channel_index @@ -550,6 +555,10 @@ rs_webui { DEFINES *= RS_WEBUI } +rs_bob { + DEFINES *= RS_USE_I2P_BOB +} + rs_deep_channels_index:DEFINES *= RS_DEEP_CHANNEL_INDEX rs_deep_files_index:DEFINES *= RS_DEEP_FILES_INDEX From 950703c398f7f5bc920b04c60433f612c677020e Mon Sep 17 00:00:00 2001 From: sehraf Date: Mon, 25 May 2020 22:23:58 +0200 Subject: [PATCH 069/154] i2p: bob: handle CONFIG+=no_rs_bob when creating a new location --- retroshare-gui/src/gui/GenCertDialog.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/retroshare-gui/src/gui/GenCertDialog.cpp b/retroshare-gui/src/gui/GenCertDialog.cpp index 4fdb9f714..aae80b753 100644 --- a/retroshare-gui/src/gui/GenCertDialog.cpp +++ b/retroshare-gui/src/gui/GenCertDialog.cpp @@ -340,6 +340,10 @@ void GenCertDialog::setupState() ui.hiddenport_spinBox->setVisible(hidden_state && !tor_auto); ui.cbUseBob->setVisible(hidden_state && !tor_auto); +#ifndef RS_USE_I2P_BOB + ui.cbUseBob->setDisabled(true); + ui.cbUseBob->setToolTip(tr("BOB support is not available")); +#endif if(!mAllFieldsOk) { From 85ce2c0f33aba78fc9b1c3ba51a657eb4492b691 Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 10 Jun 2020 20:08:23 +0200 Subject: [PATCH 070/154] fixed bug in files model --- retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp | 2 +- .../src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp index 8942b65b0..7a5ae4a34 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp @@ -84,7 +84,7 @@ int RsGxsChannelPostFilesModel::rowCount(const QModelIndex& parent) const return 0; if(!parent.isValid()) - return (mFiles.size() + COLUMN_FILES_NB_COLUMNS-1)/COLUMN_FILES_NB_COLUMNS; // mFilteredPosts always has an item at 0, so size()>=1, and mColumn>=1 + return mFiles.size(); // mFilteredPosts always has an item at 0, so size()>=1, and mColumn>=1 RsErr() << __PRETTY_FUNCTION__ << " rowCount cannot figure out the porper number of rows." << std::endl; return 0; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index 375290f61..b5d8c289d 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -139,6 +139,8 @@ private slots: void settingsChanged(); void handlePostsTreeSizeChange(QSize s); void updateChannelFiles(); + +public slots: void sortColumn(int col,Qt::SortOrder so); private: From 8c3c973d02c94c993662c5802e5f7c8e01bb80d1 Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 10 Jun 2020 22:04:34 +0200 Subject: [PATCH 071/154] changed filtering model to a hand-made solution --- .../gxschannels/GxsChannelPostFilesModel.cpp | 74 +++++++++--- .../gxschannels/GxsChannelPostFilesModel.h | 7 +- .../GxsChannelPostsWidgetWithModel.cpp | 107 +++++++++--------- .../GxsChannelPostsWidgetWithModel.h | 5 +- 4 files changed, 117 insertions(+), 76 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp index 7a5ae4a34..86dc330cc 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp @@ -42,17 +42,18 @@ static std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// define RsGxsChannelPostFilesModel::RsGxsChannelPostFilesModel(QObject *parent) : QAbstractItemModel(parent) { - initEmptyHierarchy(mFiles); + initEmptyHierarchy(); mTimer = new QTimer; connect(mTimer,SIGNAL(timeout()),this,SLOT(update())); } -void RsGxsChannelPostFilesModel::initEmptyHierarchy(std::vector& files) +void RsGxsChannelPostFilesModel::initEmptyHierarchy() { preMods(); mFiles.clear(); + mFilteredFiles.clear(); postMods(); } @@ -67,12 +68,12 @@ void RsGxsChannelPostFilesModel::postMods() { endResetModel(); - emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mFiles.size(),COLUMN_FILES_NB_COLUMNS-1,(void*)NULL)); + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mFilteredFiles.size(),COLUMN_FILES_NB_COLUMNS-1,(void*)NULL)); } void RsGxsChannelPostFilesModel::update() { - emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mFiles.size(),COLUMN_FILES_NB_COLUMNS-1,(void*)NULL)); + emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mFilteredFiles.size(),COLUMN_FILES_NB_COLUMNS-1,(void*)NULL)); } int RsGxsChannelPostFilesModel::rowCount(const QModelIndex& parent) const @@ -80,11 +81,11 @@ int RsGxsChannelPostFilesModel::rowCount(const QModelIndex& parent) const if(parent.column() > 0) return 0; - if(mFiles.empty()) // security. Should never happen. + if(mFilteredFiles.empty()) // security. Should never happen. return 0; if(!parent.isValid()) - return mFiles.size(); // mFilteredPosts always has an item at 0, so size()>=1, and mColumn>=1 + return mFilteredFiles.size(); // mFilteredPosts always has an item at 0, so size()>=1, and mColumn>=1 RsErr() << __PRETTY_FUNCTION__ << " rowCount cannot figure out the porper number of rows." << std::endl; return 0; @@ -116,7 +117,7 @@ bool RsGxsChannelPostFilesModel::getFileData(const QModelIndex& i,RsGxsFile& fmp if(!convertRefPointerToTabEntry(ref,entry) || entry >= mFiles.size()) return false ; - fmpe = mFiles[entry]; + fmpe = mFiles[mFilteredFiles[entry]]; return true; @@ -214,7 +215,7 @@ quintptr RsGxsChannelPostFilesModel::getParentRow(quintptr ref,int& row) const { ChannelPostFilesModelIndex ref_entry; - if(!convertRefPointerToTabEntry(ref,ref_entry) || ref_entry >= mFiles.size()) + if(!convertRefPointerToTabEntry(ref,ref_entry) || ref_entry >= mFilteredFiles.size()) return 0 ; if(ref_entry == 0) @@ -284,7 +285,7 @@ QVariant RsGxsChannelPostFilesModel::data(const QModelIndex &index, int role) co return QVariant() ; } - if(!convertRefPointerToTabEntry(ref,entry) || entry >= mFiles.size()) + if(!convertRefPointerToTabEntry(ref,entry) || entry >= mFilteredFiles.size()) { #ifdef DEBUG_CHANNEL_MODEL std::cerr << "Bad pointer: " << (void*)ref << std::endl; @@ -292,7 +293,7 @@ QVariant RsGxsChannelPostFilesModel::data(const QModelIndex &index, int role) co return QVariant() ; } - const RsGxsFile& fmpe(mFiles[entry]); + const RsGxsFile& fmpe(mFiles[mFilteredFiles[entry]]); #ifdef TODO if(role == Qt::FontRole) @@ -331,6 +332,44 @@ QVariant RsGxsChannelPostFilesModel::data(const QModelIndex &index, int role) co } } +void RsGxsChannelPostFilesModel::setFilter(const QStringList& strings, uint32_t& count) +{ + preMods(); + + beginRemoveRows(QModelIndex(),0,rowCount()-1); + endRemoveRows(); + + if(strings.empty()) + { + mFilteredFiles.clear(); + for(int i=0;i& files) { preMods(); - beginRemoveRows(QModelIndex(),0,mFiles.size()-1); + beginRemoveRows(QModelIndex(),0,mFilteredFiles.size()-1); endRemoveRows(); - mFiles.clear(); - initEmptyHierarchy(mFiles); + initEmptyHierarchy(); for(auto& file:files) mFiles.push_back(file); + for(uint32_t i=0;i& files) // debug_dump(); #endif - beginInsertRows(QModelIndex(),0,mFiles.size()-1); + beginInsertRows(QModelIndex(),0,mFilteredFiles.size()-1); endInsertRows(); postMods(); @@ -655,6 +695,7 @@ void RsGxsChannelPostFilesModel::setFiles(const std::list& files) mTimer->stop(); } +#ifdef DEBUG_FORUMMODEL QModelIndex RsGxsChannelPostFilesModel::getIndexOfFile(const RsFileHash& hash) const { // Brutal search. This is not so nice, so dont call that in a loop! If too costly, we'll use a map. @@ -671,7 +712,6 @@ QModelIndex RsGxsChannelPostFilesModel::getIndexOfFile(const RsFileHash& hash) c return QModelIndex(); } -#ifdef DEBUG_FORUMMODEL static void recursPrintModel(const std::vector& entries,ForumModelIndex index,int depth) { const ForumModelPostEntry& e(entries[index]); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h index e7dd47802..17563fa6d 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h @@ -64,12 +64,13 @@ public: #endif QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;} - QModelIndex getIndexOfFile(const RsFileHash& hash) const; // This method will asynchroneously update the data void setFiles(const std::list& files); + void setFilter(const QStringList &strings, uint32_t &count) ; #ifdef TODO + QModelIndex getIndexOfFile(const RsFileHash& hash) const; void setSortMode(SortMode mode) ; void setTextColorRead (QColor color) { mTextColorRead = color;} @@ -77,7 +78,6 @@ public: void setTextColorUnreadChildren(QColor color) { mTextColorUnreadChildren = color;} void setTextColorNotSubscribed (QColor color) { mTextColorNotSubscribed = color;} void setTextColorMissing (QColor color) { mTextColorMissing = color;} - void setFilter(int column, const QStringList &strings, uint32_t &count) ; void setAuthorOpinion(const QModelIndex& indx,RsOpinion op); #endif @@ -149,8 +149,9 @@ private: #ifdef TODO static void generateMissingItem(const RsGxsMessageId &msgId,ChannelPostsModelPostEntry& entry); #endif - void initEmptyHierarchy(std::vector &files); + void initEmptyHierarchy(); + std::vector mFilteredFiles ; // store the list of files for the post std::vector mFiles ; // store the list of files for the post QTimer *mTimer; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index d6a317151..d7b565e0b 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -240,39 +240,39 @@ QSize ChannelPostFilesDelegate::sizeHint(const QStyleOptionViewItem& option, con } } -class RsGxsChannelPostFilesProxyModel: public QSortFilterProxyModel -{ -public: - RsGxsChannelPostFilesProxyModel(QObject *parent = NULL): QSortFilterProxyModel(parent) {} - - bool lessThan(const QModelIndex& left, const QModelIndex& right) const override - { - return left.data(RsGxsChannelPostFilesModel::SortRole) < right.data(RsGxsChannelPostFilesModel::SortRole) ; - } - - bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override - { - if(filter_list.empty()) - return true; - - QString name = sourceModel()->data(sourceModel()->index(source_row,RsGxsChannelPostFilesModel::COLUMN_FILES_NAME,source_parent)).toString(); - - for(auto& s:filter_list) - if(!name.contains(s,Qt::CaseInsensitive)) - return false; - - return true; - } - - void setFilterList(const QStringList& str) - { - filter_list = str; - invalidateFilter(); - } - -private: - QStringList filter_list; -}; +// class RsGxsChannelPostFilesProxyModel: public QSortFilterProxyModel +// { +// public: +// RsGxsChannelPostFilesProxyModel(QObject *parent = NULL): QSortFilterProxyModel(parent) {} +// +// bool lessThan(const QModelIndex& left, const QModelIndex& right) const override +// { +// return left.data(RsGxsChannelPostFilesModel::SortRole) < right.data(RsGxsChannelPostFilesModel::SortRole) ; +// } +// +// bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override +// { +// if(filter_list.empty()) +// return true; +// +// QString name = sourceModel()->data(sourceModel()->index(source_row,RsGxsChannelPostFilesModel::COLUMN_FILES_NAME,source_parent)).toString(); +// +// for(auto& s:filter_list) +// if(!name.contains(s,Qt::CaseInsensitive)) +// return false; +// +// return true; +// } +// +// void setFilterList(const QStringList& str) +// { +// filter_list = str; +// invalidateFilter(); +// } +// +// private: +// QStringList filter_list; +// }; /** Constructor */ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupId &channelId, QWidget *parent) : @@ -285,24 +285,25 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->postsTree->setModel(mChannelPostsModel = new RsGxsChannelPostsModel()); ui->postsTree->setItemDelegate(new ChannelPostDelegate()); - mChannelPostFilesModel = new RsGxsChannelPostFilesModel(this); - - mChannelPostFilesProxyModel = new RsGxsChannelPostFilesProxyModel(this); - mChannelPostFilesProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - mChannelPostFilesProxyModel->setSourceModel(mChannelPostFilesModel); - mChannelPostFilesProxyModel->setDynamicSortFilter(true); - - ui->channelPostFiles_TV->setModel(mChannelPostFilesProxyModel); + ui->channelPostFiles_TV->setModel(mChannelPostFilesModel = new RsGxsChannelPostFilesModel(this)); ui->channelPostFiles_TV->setItemDelegate(new ChannelPostFilesDelegate()); - ui->channelPostFiles_TV->setPlaceholderText(tr("Post files")); + ui->channelPostFiles_TV->setPlaceholderText(tr("No files in this post, or no post selected")); ui->channelPostFiles_TV->setSortingEnabled(true); ui->channelPostFiles_TV->sortByColumn(0, Qt::AscendingOrder); - ui->channelFiles_TV->setPlaceholderText(tr("No files in the channel, or no channel selected")); +// mChannelPostFilesProxyModel = new RsGxsChannelPostFilesProxyModel(this); +// mChannelPostFilesProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); +// mChannelPostFilesProxyModel->setSourceModel(mChannelPostFilesModel); +// mChannelPostFilesProxyModel->setDynamicSortFilter(true); + ui->channelFiles_TV->setModel(mChannelFilesModel = new RsGxsChannelPostFilesModel()); ui->channelFiles_TV->setItemDelegate(new ChannelPostFilesDelegate()); + ui->channelFiles_TV->setPlaceholderText(tr("No files in the channel, or no channel selected")); + ui->channelFiles_TV->setSortingEnabled(true); + ui->channelFiles_TV->sortByColumn(0, Qt::AscendingOrder); + + //connect(ui->channelPostFiles_TV->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortColumn(int,Qt::SortOrder))); - connect(ui->channelPostFiles_TV->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortColumn(int,Qt::SortOrder))); connect(ui->postsTree->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),this,SLOT(showPostDetails())); connect(mChannelPostsModel,SIGNAL(channelLoaded()),this,SLOT(updateChannelFiles())); @@ -364,11 +365,11 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI }, mEventHandlerId, RsEventType::GXS_CHANNELS ); } -void GxsChannelPostsWidgetWithModel::sortColumn(int col,Qt::SortOrder so) -{ - std::cerr << "Sorting!!"<< std::endl; - mChannelPostFilesProxyModel->sort(col,so); -} +//void GxsChannelPostsWidgetWithModel::sortColumn(int col,Qt::SortOrder so) +//{ +// std::cerr << "Sorting!!"<< std::endl; +// mChannelPostFilesProxyModel->sort(col,so); +//} void GxsChannelPostsWidgetWithModel::handlePostsTreeSizeChange(QSize s) { @@ -469,7 +470,7 @@ void GxsChannelPostsWidgetWithModel::updateChannelFiles() ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); ui->channelFiles_TV->setAutoSelect(true); - mChannelPostFilesProxyModel->sort(0, Qt::AscendingOrder); + //mChannelPostFilesProxyModel->sort(0, Qt::AscendingOrder); } void GxsChannelPostsWidgetWithModel::updateGroupData() @@ -786,10 +787,10 @@ void GxsChannelPostsWidgetWithModel::filterChanged(QString s) QStringList ql = s.split(' ',QString::SkipEmptyParts); uint32_t count; mChannelPostsModel->setFilter(ql,count); + mChannelFilesModel->setFilter(ql,count); - mChannelPostFilesProxyModel->setFilterKeyColumn(RsGxsChannelPostFilesModel::COLUMN_FILES_NAME); - mChannelPostFilesProxyModel->setFilterList(ql); - mChannelPostFilesProxyModel->setFilterRegExp(s) ;// triggers a re-display. s is actually not used. + //mChannelPostFilesProxyModel->setFilterKeyColumn(RsGxsChannelPostFilesModel::COLUMN_FILES_NAME); + //mChannelPostFilesProxyModel->setFilterRegExp(s) ;// triggers a re-display. s is actually not used. } #ifdef TODO diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index b5d8c289d..cf7ead667 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -140,8 +140,8 @@ private slots: void handlePostsTreeSizeChange(QSize s); void updateChannelFiles(); -public slots: - void sortColumn(int col,Qt::SortOrder so); +// public slots: +// void sortColumn(int col,Qt::SortOrder so); private: void processSettings(bool load); @@ -164,7 +164,6 @@ private: RsGxsChannelPostsModel *mChannelPostsModel; RsGxsChannelPostFilesModel *mChannelPostFilesModel; RsGxsChannelPostFilesModel *mChannelFilesModel; - RsGxsChannelPostFilesProxyModel *mChannelPostFilesProxyModel ; /* UI - from Designer */ Ui::GxsChannelPostsWidgetWithModel *ui; From d0c5dc4e2496204cf88e0b0c73091485d87be441 Mon Sep 17 00:00:00 2001 From: sehraf Date: Wed, 10 Jun 2020 21:22:45 +0200 Subject: [PATCH 072/154] i2p: bob: convert to RS_DBG --- .../src/services/autoproxy/p3i2pbob.cc | 129 +++++++++--------- 1 file changed, 63 insertions(+), 66 deletions(-) diff --git a/libretroshare/src/services/autoproxy/p3i2pbob.cc b/libretroshare/src/services/autoproxy/p3i2pbob.cc index ef8e1ad48..c1b32fa76 100644 --- a/libretroshare/src/services/autoproxy/p3i2pbob.cc +++ b/libretroshare/src/services/autoproxy/p3i2pbob.cc @@ -26,7 +26,6 @@ #include "pqi/p3peermgr.h" #include "rsitems/rsconfigitems.h" -#include "util/rsdebug.h" #include "util/radix32.h" #include "util/radix64.h" #include "util/rsdebug.h" @@ -52,8 +51,6 @@ static const int sleepFactorDefault = 10; // 0.5s static const int sleepFactorFast = 1; // 0.05s static const int sleepFactorSlow = 20; // 1s -RS_SET_CONTEXT_DEBUG_LEVEL(0) - static const rstime_t selfCheckPeroid = 30; void doSleep(useconds_t timeToSleepMS) { @@ -83,7 +80,7 @@ bool p3I2pBob::isEnabled() bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/) { - std::cout << "p3I2pBob::initialSetup" << std::endl; + RS_DBG("") << std::endl; // update config { @@ -96,7 +93,7 @@ bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/) } } - std::cout << "p3I2pBob::initialSetup config updated" << std::endl; + RS_DBG("config updated") << std::endl; // request keys // p3I2pBob::stateMachineBOB expects mProcessing to be set therefore @@ -106,12 +103,12 @@ bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/) fakeTicket->task = autoProxyTask::receiveKey; processTaskAsync(fakeTicket); - std::cout << "p3I2pBob::initialSetup fakeTicket requested" << std::endl; + RS_DBG("fakeTicket requested") << std::endl; // now start thread start("I2P-BOB gen key"); - std::cout << "p3I2pBob::initialSetup thread started" << std::endl; + RS_DBG("thread started") << std::endl; int counter = 0; // wait for keys @@ -125,24 +122,24 @@ bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/) break; if (++counter > 30) { - std::cout << "p3I2pBob::initialSetup timeout!" << std::endl; + RS_DBG4("timeout!") << std::endl; return false; } } - std::cout << "p3I2pBob::initialSetup got keys" << std::endl; + RS_DBG("got keys") << std::endl; // stop thread fullstop(); - std::cout << "p3I2pBob::initialSetup thread stopped" << std::endl; + RS_DBG("thread stopped") << std::endl; { RS_STACK_MUTEX(mLock); addr = mSetting.address.base32; } - std::cout << "p3I2pBob::initialSetup addr '" << addr << "'" << std::endl; + RS_DBG4("addr '" + addr + "'") << std::endl; return true; } @@ -160,7 +157,7 @@ void p3I2pBob::processTaskAsync(taskTicket *ticket) } break; default: - RsDbg() << __PRETTY_FUNCTION__ << " unknown task" << std::endl; + RS_DBG("unknown task") << std::endl; rsAutoProxyMonitor::taskError(ticket); break; } @@ -175,7 +172,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) case autoProxyTask::status: // check if everything needed is set if (!data) { - RsDbg() << __PRETTY_FUNCTION__ << " autoProxyTask::status data is missing" << std::endl; + RS_DBG("autoProxyTask::status data is missing") << std::endl; rsAutoProxyMonitor::taskError(ticket); break; } @@ -189,7 +186,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) case autoProxyTask::getSettings: // check if everything needed is set if (!data) { - RsDbg() << __PRETTY_FUNCTION__ << " autoProxyTask::getSettings data is missing" << std::endl; + RS_DBG("autoProxyTask::getSettings data is missing") << std::endl; rsAutoProxyMonitor::taskError(ticket); break; } @@ -203,7 +200,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) case autoProxyTask::setSettings: // check if everything needed is set if (!data) { - RsDbg() << __PRETTY_FUNCTION__ << " autoProxyTask::setSettings data is missing" << std::endl; + RS_DBG("autoProxyTask::setSettings data is missing") << std::endl; rsAutoProxyMonitor::taskError(ticket); break; } @@ -223,7 +220,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) break; case autoProxyTask::getErrorInfo: if (!data) { - RsDbg() << __PRETTY_FUNCTION__ << " autoProxyTask::getErrorInfo data is missing" << std::endl; + RS_DBG("autoProxyTask::getErrorInfo data is missing") << std::endl; rsAutoProxyMonitor::taskError(ticket); } else { RS_STACK_MUTEX(mLock); @@ -232,7 +229,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) } break; default: - RsDbg() << __PRETTY_FUNCTION__ << " unknown task" << std::endl; + RS_DBG("unknown task") << std::endl; rsAutoProxyMonitor::taskError(ticket); break; } @@ -253,7 +250,7 @@ void p3I2pBob::threadTick() RS_STACK_MUTEX(mLock); std::stringstream ss; ss << "data_tick mState: " << mState << " mTask: " << mTask << " mBOBState: " << mBOBState << " mPending: " << mPending.size(); - Dbg4() << __PRETTY_FUNCTION__ << " " + ss.str() << std::endl; + RS_DBG4("" + ss.str()) << std::endl; } sleepTime += stateMachineController(); @@ -294,13 +291,13 @@ int p3I2pBob::stateMachineBOB() while (answer.find("OK Listing done") == std::string::npos) { std::stringstream ss; ss << "stateMachineBOB status check: read loop, counter: " << counter; - Dbg3() << __PRETTY_FUNCTION__ << " " + ss.str() << std::endl; + RS_DBG3("" + ss.str()) << std::endl; answer += recv(); counter++; } if (answer.find(mTunnelName) == std::string::npos) { - RsDbg() << __PRETTY_FUNCTION__ << " status check: tunnel down!" << std::endl; + RS_DBG("status check: tunnel down!") << std::endl; // signal error *((bool *)mProcessing->data) = true; } @@ -340,8 +337,8 @@ int p3I2pBob::stateMachineBOB_locked_failure(const std::string &answer, const bo return sleepFactorDefault; } - RsDbg() << __PRETTY_FUNCTION__ << " FAILED to run command '" + currentState.command + "'" << std::endl; - RsDbg() << __PRETTY_FUNCTION__ << " '" + answer + "'" << std::endl; + RS_DBG("FAILED to run command '" + currentState.command + "'") << std::endl; + RS_DBG("'" + answer + "'") << std::endl; mErrorMsg.append("FAILED to run command '" + currentState.command + "'" + '\n'); mErrorMsg.append("reason '" + answer + "'" + '\n'); @@ -388,14 +385,14 @@ int p3I2pBob::stateMachineController() return stateMachineController_locked_idle(); case csDoConnect: if (!connectI2P()) { - RsDbg() << __PRETTY_FUNCTION__ << " doConnect: unable to connect" << std::endl; + RS_DBG("doConnect: unable to connect") << std::endl; mStateOld = mState; mState = csError; mErrorMsg = "unable to connect to BOB port"; return sleepFactorSlow; } - Dbg4() << __PRETTY_FUNCTION__ << " doConnect: connected" << std::endl; + RS_DBG4("doConnect: connected") << std::endl; mState = csConnected; break; case csConnected: @@ -403,7 +400,7 @@ int p3I2pBob::stateMachineController() case csWaitForBob: // check connection problems if (mSocket == 0) { - RsDbg() << __PRETTY_FUNCTION__ << " waitForBob: conection lost" << std::endl; + RS_DBG("waitForBob: conection lost") << std::endl; mStateOld = mState; mState = csError; mErrorMsg = "connection lost to BOB"; @@ -413,21 +410,21 @@ int p3I2pBob::stateMachineController() // check for finished BOB protocol if (mBOBState == bsCleared) { // done - Dbg4() << __PRETTY_FUNCTION__ << " waitForBob: mBOBState == bsCleared" << std::endl; + RS_DBG4("waitForBob: mBOBState == bsCleared") << std::endl; mState = csDoDisconnect; } break; case csDoDisconnect: if (!disconnectI2P() || mSocket != 0) { // just in case - RsDbg() << __PRETTY_FUNCTION__ << " doDisconnect: can't disconnect" << std::endl; + RS_DBG("doDisconnect: can't disconnect") << std::endl; mStateOld = mState; mState = csError; mErrorMsg = "unable to disconnect from BOB"; return sleepFactorDefault; } - Dbg4() << __PRETTY_FUNCTION__ << " doDisconnect: disconnected" << std::endl; + RS_DBG4("doDisconnect: disconnected") << std::endl; mState = csDisconnected; break; case csDisconnected: @@ -458,7 +455,7 @@ int p3I2pBob::stateMachineController_locked_idle() mProcessing->task == autoProxyTask::stop || mProcessing->task == autoProxyTask::proxyStatusCheck)) { // skip since we are not enabled - Dbg1() << __PRETTY_FUNCTION__ << " disabled -> skipping ticket" << std::endl; + RS_DBG1("disabled -> skipping ticket") << std::endl; rsAutoProxyMonitor::taskDone(mProcessing, autoProxyStatus::disabled); mProcessing = NULL; } else { @@ -480,7 +477,7 @@ int p3I2pBob::stateMachineController_locked_idle() mTask = ctRunCheck; break; default: - Dbg1() << __PRETTY_FUNCTION__ << " unknown async task" << std::endl; + RS_DBG1("unknown async task") << std::endl; rsAutoProxyMonitor::taskError(mProcessing); mProcessing = NULL; break; @@ -528,28 +525,28 @@ int p3I2pBob::stateMachineController_locked_connected() case ctRunSetUp: // when we have a key use it for server tunnel! if(mSetting.address.privateKey.empty()) { - Dbg4() << __PRETTY_FUNCTION__ << " setting mBOBState = setnickC" << std::endl; + RS_DBG4("setting mBOBState = setnickC") << std::endl; mBOBState = bsSetnickC; } else { - Dbg4() << __PRETTY_FUNCTION__ << " setting mBOBState = setnickS" << std::endl; + RS_DBG4("setting mBOBState = setnickS") << std::endl; mBOBState = bsSetnickS; } break; case ctRunShutDown: // shut down existing tunnel - Dbg4() << __PRETTY_FUNCTION__ << " setting mBOBState = getnick" << std::endl; + RS_DBG4("setting mBOBState = getnick") << std::endl; mBOBState = bsGetnick; break; case ctRunCheck: - Dbg4() << __PRETTY_FUNCTION__ << " setting mBOBState = list" << std::endl; + RS_DBG4("setting mBOBState = list") << std::endl; mBOBState = bsList; break; case ctRunGetKeys: - Dbg4() << __PRETTY_FUNCTION__ << " setting mBOBState = setnickN" << std::endl; + RS_DBG4("setting mBOBState = setnickN") << std::endl; mBOBState = bsSetnickN; break; case ctIdle: - RsDbg() << __PRETTY_FUNCTION__ << " task is idle. This should not happen!" << std::endl; + RS_DBG("task is idle. This should not happen!") << std::endl; break; } @@ -565,7 +562,7 @@ int p3I2pBob::stateMachineController_locked_disconnected() if(errorHappened) { // reset old state mStateOld = csIdel; - RsDbg() << __PRETTY_FUNCTION__ << " error during process!" << std::endl; + RS_DBG("error during process!") << std::endl; } // answer ticket @@ -594,12 +591,12 @@ int p3I2pBob::stateMachineController_locked_disconnected() mTask = mTaskOld; if (!errorHappened) { - Dbg4() << __PRETTY_FUNCTION__ << " run check result: ok" << std::endl; + RS_DBG4("run check result: ok") << std::endl; break; } // switch to error newState = csError; - RsDbg() << __PRETTY_FUNCTION__ << " run check result: error" << std::endl; + RS_DBG("run check result: error") << std::endl; mErrorMsg = "Connection check failed. Will try to restart tunnel."; break; @@ -622,7 +619,7 @@ int p3I2pBob::stateMachineController_locked_disconnected() mTask = mTaskOld; break; case ctIdle: - RsDbg() << __PRETTY_FUNCTION__ << " task is idle. This should not happen!" << std::endl; + RS_DBG("task is idle. This should not happen!") << std::endl; rsAutoProxyMonitor::taskError(mProcessing); } mProcessing = NULL; @@ -638,14 +635,14 @@ int p3I2pBob::stateMachineController_locked_error() { // wait for bob protocoll if (mBOBState != bsCleared) { - Dbg4() << __PRETTY_FUNCTION__ << " waiting for BOB" << std::endl; + RS_DBG4("waiting for BOB") << std::endl; return sleepFactorFast; } #if 0 std::stringstream ss; ss << "stateMachineController_locked_error: mProcessing: " << (mProcessing ? "not null" : "null"); - Dbg4() << __PRETTY_FUNCTION__ << " " + ss.str() << std::endl; + RS_DBG4("" + ss.str()) << std::endl; #endif // try to finish ticket @@ -653,7 +650,7 @@ int p3I2pBob::stateMachineController_locked_error() switch (mTask) { case ctRunCheck: // connection check failed at some point - RsDbg() << __PRETTY_FUNCTION__ << " failed to check proxy status (it's likely dead)!" << std::endl; + RS_DBG("failed to check proxy status (it's likely dead)!") << std::endl; *((bool *)mProcessing->data) = true; mState = csDoDisconnect; mStateOld = csIdel; @@ -661,7 +658,7 @@ int p3I2pBob::stateMachineController_locked_error() break; case ctRunShutDown: // not a big deal though - RsDbg() << __PRETTY_FUNCTION__ << " failed to shut down tunnel (it's likely dead though)!" << std::endl; + RS_DBG("failed to shut down tunnel (it's likely dead though)!") << std::endl; mState = csDoDisconnect; mStateOld = csIdel; mErrorMsg.clear(); @@ -669,14 +666,14 @@ int p3I2pBob::stateMachineController_locked_error() case ctIdle: // should not happen but we need to deal with it // this will produce some error messages in the log and finish the task (marked as failed) - RsDbg() << __PRETTY_FUNCTION__ << " task is idle. This should not happen!" << std::endl; + RS_DBG("task is idle. This should not happen!") << std::endl; mState = csDoDisconnect; mStateOld = csIdel; mErrorMsg.clear(); break; case ctRunGetKeys: case ctRunSetUp: - RsDbg() << __PRETTY_FUNCTION__ << " failed to receive key / start up" << std::endl; + RS_DBG("failed to receive key / start up") << std::endl; mStateOld = csError; mState = csDoDisconnect; // keep the error message @@ -687,7 +684,7 @@ int p3I2pBob::stateMachineController_locked_error() // periodically retry if (mLastProxyCheck < time(NULL) - (selfCheckPeroid >> 1) && mTask == ctRunSetUp) { - RsDbg() << __PRETTY_FUNCTION__ << " retrying" << std::endl; + RS_DBG("retrying") << std::endl; mLastProxyCheck = time(NULL); mErrorMsg.clear(); @@ -700,7 +697,7 @@ int p3I2pBob::stateMachineController_locked_error() // check for new tickets if (!mPending.empty()) { - Dbg4() << __PRETTY_FUNCTION__ << " processing new ticket" << std::endl; + RS_DBG4("processing new ticket") << std::endl; // reset and try new task mTask = ctIdle; @@ -731,7 +728,7 @@ RsSerialiser *p3I2pBob::setupSerialiser() bool p3I2pBob::saveList(bool &cleanup, std::list &lst) { - Dbg4() << __PRETTY_FUNCTION__ << std::endl; + RS_DBG4("") << std::endl; cleanup = true; RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet; @@ -766,7 +763,7 @@ bool p3I2pBob::saveList(bool &cleanup, std::list &lst) bool p3I2pBob::loadList(std::list &load) { - Dbg4() << __PRETTY_FUNCTION__ << std::endl; + RS_DBG4("") << std::endl; for(std::list::const_iterator it = load.begin(); it!=load.end(); ++it) { RsConfigKeyValueSet *vitem = dynamic_cast(*it); @@ -786,7 +783,7 @@ bool p3I2pBob::loadList(std::list &load) getKVSUInt(kit, kConfigKeyOutQuantity, mSetting.outQuantity) getKVSUInt(kit, kConfigKeyOutVariance, mSetting.outVariance) else - RsDbg() << __PRETTY_FUNCTION__ << " unknown key: " + kit->key << std::endl; + RS_DBG("unknown key: " + kit->key) << std::endl; } } delete vitem; @@ -850,7 +847,7 @@ void p3I2pBob::getStates(bobStates *bs) std::string p3I2pBob::executeCommand(const std::string &command) { - Dbg4() << __PRETTY_FUNCTION__ << " running '" + command + "'" << std::endl; + RS_DBG4("running '" + command + "'") << std::endl; std::string copy = command; copy.push_back('\n'); @@ -862,7 +859,7 @@ std::string p3I2pBob::executeCommand(const std::string &command) // receive answer (trailing new line is already removed!) std::string ans = recv(); - Dbg4() << __PRETTY_FUNCTION__ << " answer '" + ans + "'" << std::endl; + RS_DBG4("answer '" + ans + "'") << std::endl; return ans; } @@ -872,7 +869,7 @@ bool p3I2pBob::connectI2P() // there is only one thread that touches mSocket - no need for a lock if (mSocket != 0) { - RsDbg() << __PRETTY_FUNCTION__ << " mSocket != 0" << std::endl; + RS_DBG("mSocket != 0") << std::endl; return false; } @@ -880,21 +877,21 @@ bool p3I2pBob::connectI2P() mSocket = unix_socket(PF_INET, SOCK_STREAM, 0); if (mSocket < 0) { - RsDbg() << __PRETTY_FUNCTION__ << " Failed to open socket! Socket Error: " + socket_errorType(errno) << std::endl; + RS_DBG("Failed to open socket! Socket Error: " + socket_errorType(errno)) << std::endl; return false; } // connect int err = unix_connect(mSocket, mI2PProxyAddr); if (err != 0) { - RsDbg() << __PRETTY_FUNCTION__ << " Failed to connect to BOB! Socket Error: " + socket_errorType(errno) << std::endl; + RS_DBG("Failed to connect to BOB! Socket Error: " + socket_errorType(errno)) << std::endl; return false; } // receive hello msg recv(); - Dbg4() << __PRETTY_FUNCTION__ << " done" << std::endl; + RS_DBG4("done") << std::endl; return true; } @@ -903,17 +900,17 @@ bool p3I2pBob::disconnectI2P() // there is only one thread that touches mSocket - no need for a lock if (mSocket == 0) { - RsDbg() << __PRETTY_FUNCTION__ << " mSocket == 0" << std::endl; + RS_DBG("mSocket == 0") << std::endl; return true; } int err = unix_close(mSocket); if (err != 0) { - RsDbg() << __PRETTY_FUNCTION__ << " Failed to close socket! Socket Error: " + socket_errorType(errno) << std::endl; + RS_DBG("Failed to close socket! Socket Error: " + socket_errorType(errno)) << std::endl; return false; } - Dbg4() << __PRETTY_FUNCTION__ << " done" << std::endl; + RS_DBG4("done") << std::endl; mSocket = 0; return true; } @@ -934,7 +931,7 @@ std::string toString(const std::string &a, const int8_t b) { void p3I2pBob::finalizeSettings_locked() { - Dbg4() << __PRETTY_FUNCTION__ << std::endl; + RS_DBG4("") << std::endl; sockaddr_storage_clear(mI2PProxyAddr); // get i2p proxy addr @@ -945,8 +942,8 @@ void p3I2pBob::finalizeSettings_locked() sockaddr_storage_setipv4(mI2PProxyAddr, (sockaddr_in*)&proxy); sockaddr_storage_setport(mI2PProxyAddr, 2827); - Dbg4() << __PRETTY_FUNCTION__ << " using " + sockaddr_storage_tostring(mI2PProxyAddr) << std::endl; - Dbg4() << __PRETTY_FUNCTION__ << " using " + mSetting.address.base32 << std::endl; + RS_DBG4("using " + sockaddr_storage_tostring(mI2PProxyAddr)) << std::endl; + RS_DBG4("using " + mSetting.address.base32) << std::endl; peerState ps; mPeerMgr->getOwnNetStatus(ps); @@ -961,7 +958,7 @@ void p3I2pBob::finalizeSettings_locked() std::vector tmp(len); RSRandom::random_bytes(tmp.data(), len); const std::string location = Radix32::encode(tmp.data(), len); - Dbg4() << __PRETTY_FUNCTION__ << " using suffix " + location << std::endl; + RS_DBG4("using suffix " + location) << std::endl; mTunnelName = "RetroShare-" + location; const std::string setnick = "setnick RetroShare-" + location; @@ -1029,7 +1026,7 @@ void p3I2pBob::finalizeSettings_locked() void p3I2pBob::updateSettings_locked() { - Dbg4() << __PRETTY_FUNCTION__ << std::endl; + RS_DBG4("") << std::endl; sockaddr_storage proxy; mPeerMgr->getProxyServerAddress(RS_HIDDEN_TYPE_I2P, proxy); @@ -1105,7 +1102,7 @@ std::string p3I2pBob::recv() // sanity check if (length != bufferSize) { // expectation: a full buffer was peeked) - Dbg1() << __PRETTY_FUNCTION__ << " peeked less than bufferSize but also didn't found a new line character" << std::endl; + RS_DBG1("peeked less than bufferSize but also didn't found a new line character") << std::endl; } // this should never happen assert(length <= bufferSize); From 008a4b87b30a04586fc8d5c4e2c12c9e9d10df4d Mon Sep 17 00:00:00 2001 From: sehraf Date: Wed, 10 Jun 2020 21:46:59 +0200 Subject: [PATCH 073/154] replace std::map with std::array --- libretroshare/src/util/i2pcommon.cpp | 8 +++---- libretroshare/src/util/i2pcommon.h | 36 +++++++++++++++------------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/libretroshare/src/util/i2pcommon.cpp b/libretroshare/src/util/i2pcommon.cpp index e50fc9d83..46064ee83 100644 --- a/libretroshare/src/util/i2pcommon.cpp +++ b/libretroshare/src/util/i2pcommon.cpp @@ -133,20 +133,20 @@ std::string publicKeyFromPrivate(std::string const &priv) RsDbg() << __PRETTY_FUNCTION__ << " signing pubkey type " << certType << " has oversize" << std::endl; // calculate oversize - auto it = signingKeyLengths.find(static_cast(signingKeyType)); - if (it == signingKeyLengths.end()) { + if (signingKeyType >= signingKeyLengths.size()) { // just in case RsDbg() << __PRETTY_FUNCTION__ << " signing pubkey type " << certType << " cannot be found in size map!" << std::endl; return std::string(); } - if (it->second.first <= 128) { + auto values = signingKeyLengths[signingKeyType]; + if (values.first <= 128) { // just in case, it's supposed to be larger! RsDbg() << __PRETTY_FUNCTION__ << " signing pubkey type " << certType << " is oversize but size calculation would underflow!" << std::endl; return std::string(); } - publicKeyLen += it->second.first - 128; // 128 = default DSA key length = the space than can be used before the key must be splitted + publicKeyLen += values.first - 128; // 128 = default DSA key length = the space than can be used before the key must be splitted } // Crypto Public Key diff --git a/libretroshare/src/util/i2pcommon.h b/libretroshare/src/util/i2pcommon.h index 98815496b..63f1ba5af 100644 --- a/libretroshare/src/util/i2pcommon.h +++ b/libretroshare/src/util/i2pcommon.h @@ -161,25 +161,27 @@ enum class CryptoKeyType : uint16_t { X25519 = 4 }; -static const std::map> cryptoKeyLengths { - {CryptoKeyType::ElGamal, {256, 256}}, - {CryptoKeyType::P256, { 64, 32}}, - {CryptoKeyType::P384, { 96, 48}}, - {CryptoKeyType::P521, {132, 66}}, - {CryptoKeyType::X25519, { 32, 32}}, +static const std::array, 5> cryptoKeyLengths { + /*CryptoKeyType::ElGamal*/ std::make_pair(256, 256), + /*CryptoKeyType::P256, */ std::make_pair( 64, 32), + /*CryptoKeyType::P384, */ std::make_pair( 96, 48), + /*CryptoKeyType::P521, */ std::make_pair(132, 66), + /*CryptoKeyType::X25519,*/ std::make_pair( 32, 32), }; -static const std::map> signingKeyLengths { - {SigningKeyType::DSA_SHA1, {128, 128}}, - {SigningKeyType::ECDSA_SHA256_P256, { 64, 32}}, - {SigningKeyType::ECDSA_SHA384_P384, { 96, 48}}, - {SigningKeyType::ECDSA_SHA512_P521, {132, 66}}, - {SigningKeyType::RSA_SHA256_2048, {256, 512}}, - {SigningKeyType::RSA_SHA384_3072, {384, 768}}, - {SigningKeyType::RSA_SHA512_4096, {512,1024}}, - {SigningKeyType::EdDSA_SHA512_Ed25519, { 32, 32}}, - {SigningKeyType::EdDSA_SHA512_Ed25519ph,{ 32, 32}}, - {SigningKeyType::RedDSA_SHA512_Ed25519, { 32, 32}}, +static const std::array, 12> signingKeyLengths { + /*SigningKeyType::DSA_SHA1, */ std::make_pair(128, 128), + /*SigningKeyType::ECDSA_SHA256_P256, */ std::make_pair( 64, 32), + /*SigningKeyType::ECDSA_SHA384_P384, */ std::make_pair( 96, 48), + /*SigningKeyType::ECDSA_SHA512_P521, */ std::make_pair(132, 66), + /*SigningKeyType::RSA_SHA256_2048, */ std::make_pair(256, 512), + /*SigningKeyType::RSA_SHA384_3072, */ std::make_pair(384, 768), + /*SigningKeyType::RSA_SHA512_4096, */ std::make_pair(512,1024), + /*SigningKeyType::EdDSA_SHA512_Ed25519 */ std::make_pair( 32, 32), + /*SigningKeyType::EdDSA_SHA512_Ed25519ph */ std::make_pair( 32, 32), + /*reserved (GOST) */ std::make_pair( 64, 0), + /*reserved (GOST) */ std::make_pair(128, 0), + /*SigningKeyType::RedDSA_SHA512_Ed25519 */ std::make_pair( 32, 32), }; From 7207e6a2c15837ca22dc8e4ae8f34f72053f74f5 Mon Sep 17 00:00:00 2001 From: sehraf Date: Wed, 10 Jun 2020 21:59:45 +0200 Subject: [PATCH 074/154] use RS_DBG --- libretroshare/src/util/i2pcommon.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libretroshare/src/util/i2pcommon.cpp b/libretroshare/src/util/i2pcommon.cpp index 46064ee83..86c83c367 100644 --- a/libretroshare/src/util/i2pcommon.cpp +++ b/libretroshare/src/util/i2pcommon.cpp @@ -73,7 +73,7 @@ std::string publicKeyFromPrivate(std::string const &priv) RsBase64::decode(priv_copy, dataPriv); auto p = dataPriv.cbegin(); - RsDbg() << __PRETTY_FUNCTION__ << " dataPriv.size " << dataPriv.size() << std::endl; + RS_DBG("dataPriv.size ") << dataPriv.size() << std::endl; size_t publicKeyLen = 256 + 128; // default length (bytes) uint8_t certType = 0; @@ -98,12 +98,12 @@ std::string publicKeyFromPrivate(std::string const &priv) * type null is followed by 0x00 0x00 * so has to be 0! */ - RsDbg() << __PRETTY_FUNCTION__ << " cert is CertType.Null" << std::endl; + RS_DBG("cert is CertType.Null"); publicKeyLen += 3; // add 0x00 0x00 0x00 if (len != 0) // weird - RsDbg() << __PRETTY_FUNCTION__ << " cert is CertType.Null but len != 0" << std::endl; + RS_DBG("cert is CertType.Null but len != 0"); break; } @@ -111,11 +111,11 @@ std::string publicKeyFromPrivate(std::string const &priv) // check for != 5 if (certType != static_cast::type>(CertType::Key)) { // unsupported - RsDbg() << __PRETTY_FUNCTION__ << " cert type " << certType << " is unsupported" << std::endl; + RS_DBG("cert type ") << certType << " is unsupported" << std::endl; return std::string(); } - RsDbg() << __PRETTY_FUNCTION__ << " cert is CertType.Key" << std::endl; + RS_DBG("cert is CertType.Key"); publicKeyLen += 7; // = 1 + 2 + 2 + 2 = 7 bytes /* @@ -128,21 +128,21 @@ std::string publicKeyFromPrivate(std::string const &priv) // likely 7 signingKeyType = readTwoBytesBE(p); - RsDbg() << __PRETTY_FUNCTION__ << " signing pubkey type " << certType << std::endl; + RS_DBG("signing pubkey type ") << certType << std::endl; if (signingKeyType >= 3 && signingKeyType <= 6) { - RsDbg() << __PRETTY_FUNCTION__ << " signing pubkey type " << certType << " has oversize" << std::endl; + RS_DBG("signing pubkey type ") << certType << " has oversize" << std::endl; // calculate oversize if (signingKeyType >= signingKeyLengths.size()) { // just in case - RsDbg() << __PRETTY_FUNCTION__ << " signing pubkey type " << certType << " cannot be found in size map!" << std::endl; + RS_DBG("signing pubkey type ") << certType << " cannot be found in size map!" << std::endl; return std::string(); } auto values = signingKeyLengths[signingKeyType]; if (values.first <= 128) { // just in case, it's supposed to be larger! - RsDbg() << __PRETTY_FUNCTION__ << " signing pubkey type " << certType << " is oversize but size calculation would underflow!" << std::endl; + RS_DBG("signing pubkey type ") << certType << " is oversize but size calculation would underflow!" << std::endl; return std::string(); } @@ -152,12 +152,12 @@ std::string publicKeyFromPrivate(std::string const &priv) // Crypto Public Key // likely 0 cryptKey = readTwoBytesBE(p); - RsDbg() << __PRETTY_FUNCTION__ << " crypto pubkey type " << cryptKey << std::endl; + RS_DBG("crypto pubkey type ") << cryptKey << std::endl; // info: these are all smaller than the default 256 bytes, so no oversize calculation is needed break; } catch (const std::out_of_range &e) { - RsDbg() << __PRETTY_FUNCTION__ << " hit exception!" << e.what() << std::endl; + RS_DBG("hit exception! ") << e.what() << std::endl; return std::string(); } } while(false); From ebbdc082c0b4a5dc75276e580bdda73699b32c8f Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 10 Jun 2020 23:16:32 +0200 Subject: [PATCH 075/154] implemented sorting manually in channel files lists --- .../gxschannels/GxsChannelPostFilesModel.cpp | 37 +++++++++++++++++++ .../gxschannels/GxsChannelPostFilesModel.h | 1 + .../GxsChannelPostsWidgetWithModel.cpp | 18 ++++++--- .../GxsChannelPostsWidgetWithModel.h | 5 ++- 4 files changed, 53 insertions(+), 8 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp index 86dc330cc..6b4a4b14d 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp @@ -370,6 +370,43 @@ void RsGxsChannelPostFilesModel::setFilter(const QStringList& strings, uint32_t& postMods(); } + +class compareOperator +{ +public: + compareOperator(int column,Qt::SortOrder order): col(column),ord(order) {} + + bool operator()(const RsGxsFile& f1,const RsGxsFile& f2) const + { + switch(col) + { + default: + case RsGxsChannelPostFilesModel::COLUMN_FILES_NAME: return (ord==Qt::AscendingOrder)?(f1.mNamef2.mName); + case RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE: return (ord==Qt::AscendingOrder)?(f1.mSizef2.mSize); + case RsGxsChannelPostFilesModel::COLUMN_FILES_FILE: + { + FileInfo fi1,fi2; + rsFiles->FileDetails(f1.mHash,RS_FILE_HINTS_DOWNLOAD,fi1); + rsFiles->FileDetails(f2.mHash,RS_FILE_HINTS_DOWNLOAD,fi2); + + return (ord==Qt::AscendingOrder)?(fi1.transferedfi2.transfered); + } + } + + } + +private: + int col; + Qt::SortOrder ord; +}; + +void RsGxsChannelPostFilesModel::sort(int column, Qt::SortOrder order) +{ + std::sort(mFiles.begin(),mFiles.end(),compareOperator(column,order)); + + update(); +} + #ifdef TODO QVariant RsGxsForumModel::textColorRole(const ForumModelPostEntry& fmpe,int /*column*/) const { diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h index 17563fa6d..4f0e432ff 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h @@ -90,6 +90,7 @@ public: int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; + void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex& child) const override; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index d7b565e0b..c9d0a882a 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -302,7 +302,8 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->channelFiles_TV->setSortingEnabled(true); ui->channelFiles_TV->sortByColumn(0, Qt::AscendingOrder); - //connect(ui->channelPostFiles_TV->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortColumn(int,Qt::SortOrder))); + connect(ui->channelPostFiles_TV->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortColumnPostFiles(int,Qt::SortOrder))); + connect(ui->channelFiles_TV->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortColumnFiles(int,Qt::SortOrder))); connect(ui->postsTree->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),this,SLOT(showPostDetails())); connect(mChannelPostsModel,SIGNAL(channelLoaded()),this,SLOT(updateChannelFiles())); @@ -365,11 +366,16 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI }, mEventHandlerId, RsEventType::GXS_CHANNELS ); } -//void GxsChannelPostsWidgetWithModel::sortColumn(int col,Qt::SortOrder so) -//{ -// std::cerr << "Sorting!!"<< std::endl; -// mChannelPostFilesProxyModel->sort(col,so); -//} +void GxsChannelPostsWidgetWithModel::sortColumnPostFiles(int col,Qt::SortOrder so) +{ + std::cerr << "Sorting post files according to col " << col << std::endl; + mChannelPostFilesModel->sort(col,so); +} +void GxsChannelPostsWidgetWithModel::sortColumnFiles(int col,Qt::SortOrder so) +{ + std::cerr << "Sorting channel files according to col " << col << std::endl; + mChannelFilesModel->sort(col,so); +} void GxsChannelPostsWidgetWithModel::handlePostsTreeSizeChange(QSize s) { diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index cf7ead667..90c1f76ad 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -140,8 +140,9 @@ private slots: void handlePostsTreeSizeChange(QSize s); void updateChannelFiles(); -// public slots: -// void sortColumn(int col,Qt::SortOrder so); +public slots: + void sortColumnFiles(int col,Qt::SortOrder so); + void sortColumnPostFiles(int col,Qt::SortOrder so); private: void processSettings(bool load); From 86c30a01dd5fb20e1474ec6a859ee72d8306cc40 Mon Sep 17 00:00:00 2001 From: sehraf Date: Thu, 11 Jun 2020 10:45:33 +0200 Subject: [PATCH 076/154] next attampt to use RS_DBG correctly --- .../src/services/autoproxy/p3i2pbob.cc | 136 +++++++++--------- libretroshare/src/util/i2pcommon.cpp | 16 +-- 2 files changed, 74 insertions(+), 78 deletions(-) diff --git a/libretroshare/src/services/autoproxy/p3i2pbob.cc b/libretroshare/src/services/autoproxy/p3i2pbob.cc index c1b32fa76..02b951397 100644 --- a/libretroshare/src/services/autoproxy/p3i2pbob.cc +++ b/libretroshare/src/services/autoproxy/p3i2pbob.cc @@ -33,6 +33,8 @@ #include "util/rsprint.h" #include "util/rsrandom.h" +#include "util/rsdebuglevel4.h" + static const std::string kConfigKeyBOBEnable = "BOB_ENABLE"; static const std::string kConfigKeyBOBKey = "BOB_KEY"; static const std::string kConfigKeyBOBAddr = "BOB_ADDR"; @@ -80,7 +82,7 @@ bool p3I2pBob::isEnabled() bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/) { - RS_DBG("") << std::endl; + RS_DBG(""); // update config { @@ -93,7 +95,7 @@ bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/) } } - RS_DBG("config updated") << std::endl; + RS_DBG("config updated"); // request keys // p3I2pBob::stateMachineBOB expects mProcessing to be set therefore @@ -103,12 +105,12 @@ bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/) fakeTicket->task = autoProxyTask::receiveKey; processTaskAsync(fakeTicket); - RS_DBG("fakeTicket requested") << std::endl; + RS_DBG("fakeTicket requested"); // now start thread start("I2P-BOB gen key"); - RS_DBG("thread started") << std::endl; + RS_DBG("thread started"); int counter = 0; // wait for keys @@ -122,24 +124,24 @@ bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/) break; if (++counter > 30) { - RS_DBG4("timeout!") << std::endl; + RS_DBG4("timeout!"); return false; } } - RS_DBG("got keys") << std::endl; + RS_DBG("got keys"); // stop thread fullstop(); - RS_DBG("thread stopped") << std::endl; + RS_DBG("thread stopped"); { RS_STACK_MUTEX(mLock); addr = mSetting.address.base32; } - RS_DBG4("addr '" + addr + "'") << std::endl; + RS_DBG4("addr ", addr); return true; } @@ -157,7 +159,7 @@ void p3I2pBob::processTaskAsync(taskTicket *ticket) } break; default: - RS_DBG("unknown task") << std::endl; + RS_DBG("unknown task"); rsAutoProxyMonitor::taskError(ticket); break; } @@ -172,7 +174,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) case autoProxyTask::status: // check if everything needed is set if (!data) { - RS_DBG("autoProxyTask::status data is missing") << std::endl; + RS_DBG("autoProxyTask::status data is missing"); rsAutoProxyMonitor::taskError(ticket); break; } @@ -186,7 +188,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) case autoProxyTask::getSettings: // check if everything needed is set if (!data) { - RS_DBG("autoProxyTask::getSettings data is missing") << std::endl; + RS_DBG("autoProxyTask::getSettings data is missing"); rsAutoProxyMonitor::taskError(ticket); break; } @@ -200,7 +202,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) case autoProxyTask::setSettings: // check if everything needed is set if (!data) { - RS_DBG("autoProxyTask::setSettings data is missing") << std::endl; + RS_DBG("autoProxyTask::setSettings data is missing"); rsAutoProxyMonitor::taskError(ticket); break; } @@ -220,7 +222,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) break; case autoProxyTask::getErrorInfo: if (!data) { - RS_DBG("autoProxyTask::getErrorInfo data is missing") << std::endl; + RS_DBG("autoProxyTask::getErrorInfo data is missing"); rsAutoProxyMonitor::taskError(ticket); } else { RS_STACK_MUTEX(mLock); @@ -229,7 +231,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket) } break; default: - RS_DBG("unknown task") << std::endl; + RS_DBG("unknown task"); rsAutoProxyMonitor::taskError(ticket); break; } @@ -247,10 +249,8 @@ void p3I2pBob::threadTick() { int sleepTime = 0; { - RS_STACK_MUTEX(mLock); - std::stringstream ss; - ss << "data_tick mState: " << mState << " mTask: " << mTask << " mBOBState: " << mBOBState << " mPending: " << mPending.size(); - RS_DBG4("" + ss.str()) << std::endl; + RS_STACK_MUTEX(mLock); + RS_DBG4("data_tick mState: ", mState, " mTask: ", mTask, " mBOBState: ", mBOBState, " mPending: ", mPending.size()); } sleepTime += stateMachineController(); @@ -289,15 +289,13 @@ int p3I2pBob::stateMachineBOB() if (mBOBState == bsList) { int counter = 0; while (answer.find("OK Listing done") == std::string::npos) { - std::stringstream ss; - ss << "stateMachineBOB status check: read loop, counter: " << counter; - RS_DBG3("" + ss.str()) << std::endl; + RS_DBG3("stateMachineBOB status check: read loop, counter: ", counter); answer += recv(); counter++; } if (answer.find(mTunnelName) == std::string::npos) { - RS_DBG("status check: tunnel down!") << std::endl; + RS_DBG("status check: tunnel down!"); // signal error *((bool *)mProcessing->data) = true; } @@ -337,8 +335,8 @@ int p3I2pBob::stateMachineBOB_locked_failure(const std::string &answer, const bo return sleepFactorDefault; } - RS_DBG("FAILED to run command '" + currentState.command + "'") << std::endl; - RS_DBG("'" + answer + "'") << std::endl; + RS_DBG("FAILED to run command: ", currentState.command); + RS_DBG("answer: ", answer); mErrorMsg.append("FAILED to run command '" + currentState.command + "'" + '\n'); mErrorMsg.append("reason '" + answer + "'" + '\n'); @@ -385,14 +383,14 @@ int p3I2pBob::stateMachineController() return stateMachineController_locked_idle(); case csDoConnect: if (!connectI2P()) { - RS_DBG("doConnect: unable to connect") << std::endl; + RS_DBG("doConnect: unable to connect"); mStateOld = mState; mState = csError; mErrorMsg = "unable to connect to BOB port"; return sleepFactorSlow; } - RS_DBG4("doConnect: connected") << std::endl; + RS_DBG4("doConnect: connected"); mState = csConnected; break; case csConnected: @@ -400,7 +398,7 @@ int p3I2pBob::stateMachineController() case csWaitForBob: // check connection problems if (mSocket == 0) { - RS_DBG("waitForBob: conection lost") << std::endl; + RS_DBG("waitForBob: conection lost"); mStateOld = mState; mState = csError; mErrorMsg = "connection lost to BOB"; @@ -410,21 +408,21 @@ int p3I2pBob::stateMachineController() // check for finished BOB protocol if (mBOBState == bsCleared) { // done - RS_DBG4("waitForBob: mBOBState == bsCleared") << std::endl; + RS_DBG4("waitForBob: mBOBState == bsCleared"); mState = csDoDisconnect; } break; case csDoDisconnect: if (!disconnectI2P() || mSocket != 0) { // just in case - RS_DBG("doDisconnect: can't disconnect") << std::endl; + RS_DBG("doDisconnect: can't disconnect"); mStateOld = mState; mState = csError; mErrorMsg = "unable to disconnect from BOB"; return sleepFactorDefault; } - RS_DBG4("doDisconnect: disconnected") << std::endl; + RS_DBG4("doDisconnect: disconnected"); mState = csDisconnected; break; case csDisconnected: @@ -455,7 +453,7 @@ int p3I2pBob::stateMachineController_locked_idle() mProcessing->task == autoProxyTask::stop || mProcessing->task == autoProxyTask::proxyStatusCheck)) { // skip since we are not enabled - RS_DBG1("disabled -> skipping ticket") << std::endl; + RS_DBG1("disabled -> skipping ticket"); rsAutoProxyMonitor::taskDone(mProcessing, autoProxyStatus::disabled); mProcessing = NULL; } else { @@ -477,7 +475,7 @@ int p3I2pBob::stateMachineController_locked_idle() mTask = ctRunCheck; break; default: - RS_DBG1("unknown async task") << std::endl; + RS_DBG1("unknown async task"); rsAutoProxyMonitor::taskError(mProcessing); mProcessing = NULL; break; @@ -525,28 +523,28 @@ int p3I2pBob::stateMachineController_locked_connected() case ctRunSetUp: // when we have a key use it for server tunnel! if(mSetting.address.privateKey.empty()) { - RS_DBG4("setting mBOBState = setnickC") << std::endl; + RS_DBG4("setting mBOBState = setnickC"); mBOBState = bsSetnickC; } else { - RS_DBG4("setting mBOBState = setnickS") << std::endl; + RS_DBG4("setting mBOBState = setnickS"); mBOBState = bsSetnickS; } break; case ctRunShutDown: // shut down existing tunnel - RS_DBG4("setting mBOBState = getnick") << std::endl; + RS_DBG4("setting mBOBState = getnick"); mBOBState = bsGetnick; break; case ctRunCheck: - RS_DBG4("setting mBOBState = list") << std::endl; + RS_DBG4("setting mBOBState = list"); mBOBState = bsList; break; case ctRunGetKeys: - RS_DBG4("setting mBOBState = setnickN") << std::endl; + RS_DBG4("setting mBOBState = setnickN"); mBOBState = bsSetnickN; break; case ctIdle: - RS_DBG("task is idle. This should not happen!") << std::endl; + RS_DBG("task is idle. This should not happen!"); break; } @@ -562,7 +560,7 @@ int p3I2pBob::stateMachineController_locked_disconnected() if(errorHappened) { // reset old state mStateOld = csIdel; - RS_DBG("error during process!") << std::endl; + RS_DBG("error during process!"); } // answer ticket @@ -591,12 +589,12 @@ int p3I2pBob::stateMachineController_locked_disconnected() mTask = mTaskOld; if (!errorHappened) { - RS_DBG4("run check result: ok") << std::endl; + RS_DBG4("run check result: ok"); break; } // switch to error newState = csError; - RS_DBG("run check result: error") << std::endl; + RS_DBG("run check result: error"); mErrorMsg = "Connection check failed. Will try to restart tunnel."; break; @@ -619,7 +617,7 @@ int p3I2pBob::stateMachineController_locked_disconnected() mTask = mTaskOld; break; case ctIdle: - RS_DBG("task is idle. This should not happen!") << std::endl; + RS_DBG("task is idle. This should not happen!"); rsAutoProxyMonitor::taskError(mProcessing); } mProcessing = NULL; @@ -635,14 +633,12 @@ int p3I2pBob::stateMachineController_locked_error() { // wait for bob protocoll if (mBOBState != bsCleared) { - RS_DBG4("waiting for BOB") << std::endl; + RS_DBG4("waiting for BOB"); return sleepFactorFast; } #if 0 - std::stringstream ss; - ss << "stateMachineController_locked_error: mProcessing: " << (mProcessing ? "not null" : "null"); - RS_DBG4("" + ss.str()) << std::endl; + RS_DBG4("stateMachineController_locked_error: mProcessing: ", (mProcessing ? "not null" : "null")); #endif // try to finish ticket @@ -650,7 +646,7 @@ int p3I2pBob::stateMachineController_locked_error() switch (mTask) { case ctRunCheck: // connection check failed at some point - RS_DBG("failed to check proxy status (it's likely dead)!") << std::endl; + RS_DBG("failed to check proxy status (it's likely dead)!"); *((bool *)mProcessing->data) = true; mState = csDoDisconnect; mStateOld = csIdel; @@ -658,7 +654,7 @@ int p3I2pBob::stateMachineController_locked_error() break; case ctRunShutDown: // not a big deal though - RS_DBG("failed to shut down tunnel (it's likely dead though)!") << std::endl; + RS_DBG("failed to shut down tunnel (it's likely dead though)!"); mState = csDoDisconnect; mStateOld = csIdel; mErrorMsg.clear(); @@ -666,14 +662,14 @@ int p3I2pBob::stateMachineController_locked_error() case ctIdle: // should not happen but we need to deal with it // this will produce some error messages in the log and finish the task (marked as failed) - RS_DBG("task is idle. This should not happen!") << std::endl; + RS_DBG("task is idle. This should not happen!"); mState = csDoDisconnect; mStateOld = csIdel; mErrorMsg.clear(); break; case ctRunGetKeys: case ctRunSetUp: - RS_DBG("failed to receive key / start up") << std::endl; + RS_DBG("failed to receive key / start up"); mStateOld = csError; mState = csDoDisconnect; // keep the error message @@ -684,7 +680,7 @@ int p3I2pBob::stateMachineController_locked_error() // periodically retry if (mLastProxyCheck < time(NULL) - (selfCheckPeroid >> 1) && mTask == ctRunSetUp) { - RS_DBG("retrying") << std::endl; + RS_DBG("retrying"); mLastProxyCheck = time(NULL); mErrorMsg.clear(); @@ -697,7 +693,7 @@ int p3I2pBob::stateMachineController_locked_error() // check for new tickets if (!mPending.empty()) { - RS_DBG4("processing new ticket") << std::endl; + RS_DBG4("processing new ticket"); // reset and try new task mTask = ctIdle; @@ -728,7 +724,7 @@ RsSerialiser *p3I2pBob::setupSerialiser() bool p3I2pBob::saveList(bool &cleanup, std::list &lst) { - RS_DBG4("") << std::endl; + RS_DBG4(""); cleanup = true; RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet; @@ -763,7 +759,7 @@ bool p3I2pBob::saveList(bool &cleanup, std::list &lst) bool p3I2pBob::loadList(std::list &load) { - RS_DBG4("") << std::endl; + RS_DBG4(""); for(std::list::const_iterator it = load.begin(); it!=load.end(); ++it) { RsConfigKeyValueSet *vitem = dynamic_cast(*it); @@ -783,7 +779,7 @@ bool p3I2pBob::loadList(std::list &load) getKVSUInt(kit, kConfigKeyOutQuantity, mSetting.outQuantity) getKVSUInt(kit, kConfigKeyOutVariance, mSetting.outVariance) else - RS_DBG("unknown key: " + kit->key) << std::endl; + RS_DBG("unknown key: ", kit->key); } } delete vitem; @@ -847,7 +843,7 @@ void p3I2pBob::getStates(bobStates *bs) std::string p3I2pBob::executeCommand(const std::string &command) { - RS_DBG4("running '" + command + "'") << std::endl; + RS_DBG4("running: ", command); std::string copy = command; copy.push_back('\n'); @@ -859,7 +855,7 @@ std::string p3I2pBob::executeCommand(const std::string &command) // receive answer (trailing new line is already removed!) std::string ans = recv(); - RS_DBG4("answer '" + ans + "'") << std::endl; + RS_DBG4("answer: ", ans); return ans; } @@ -869,7 +865,7 @@ bool p3I2pBob::connectI2P() // there is only one thread that touches mSocket - no need for a lock if (mSocket != 0) { - RS_DBG("mSocket != 0") << std::endl; + RS_DBG("mSocket != 0"); return false; } @@ -877,21 +873,21 @@ bool p3I2pBob::connectI2P() mSocket = unix_socket(PF_INET, SOCK_STREAM, 0); if (mSocket < 0) { - RS_DBG("Failed to open socket! Socket Error: " + socket_errorType(errno)) << std::endl; + RS_DBG("Failed to open socket! Socket Error: ", socket_errorType(errno)); return false; } // connect int err = unix_connect(mSocket, mI2PProxyAddr); if (err != 0) { - RS_DBG("Failed to connect to BOB! Socket Error: " + socket_errorType(errno)) << std::endl; + RS_DBG("Failed to connect to BOB! Socket Error: ", socket_errorType(errno)); return false; } // receive hello msg recv(); - RS_DBG4("done") << std::endl; + RS_DBG4("done"); return true; } @@ -900,17 +896,17 @@ bool p3I2pBob::disconnectI2P() // there is only one thread that touches mSocket - no need for a lock if (mSocket == 0) { - RS_DBG("mSocket == 0") << std::endl; + RS_DBG("mSocket == 0"); return true; } int err = unix_close(mSocket); if (err != 0) { - RS_DBG("Failed to close socket! Socket Error: " + socket_errorType(errno)) << std::endl; + RS_DBG("Failed to close socket! Socket Error: ", socket_errorType(errno)); return false; } - RS_DBG4("done") << std::endl; + RS_DBG4("done"); mSocket = 0; return true; } @@ -931,7 +927,7 @@ std::string toString(const std::string &a, const int8_t b) { void p3I2pBob::finalizeSettings_locked() { - RS_DBG4("") << std::endl; + RS_DBG4(""); sockaddr_storage_clear(mI2PProxyAddr); // get i2p proxy addr @@ -942,8 +938,8 @@ void p3I2pBob::finalizeSettings_locked() sockaddr_storage_setipv4(mI2PProxyAddr, (sockaddr_in*)&proxy); sockaddr_storage_setport(mI2PProxyAddr, 2827); - RS_DBG4("using " + sockaddr_storage_tostring(mI2PProxyAddr)) << std::endl; - RS_DBG4("using " + mSetting.address.base32) << std::endl; + RS_DBG4("using ", sockaddr_storage_tostring(mI2PProxyAddr)); + RS_DBG4("using ", mSetting.address.base32); peerState ps; mPeerMgr->getOwnNetStatus(ps); @@ -958,7 +954,7 @@ void p3I2pBob::finalizeSettings_locked() std::vector tmp(len); RSRandom::random_bytes(tmp.data(), len); const std::string location = Radix32::encode(tmp.data(), len); - RS_DBG4("using suffix " + location) << std::endl; + RS_DBG4("using suffix ", location); mTunnelName = "RetroShare-" + location; const std::string setnick = "setnick RetroShare-" + location; @@ -1026,7 +1022,7 @@ void p3I2pBob::finalizeSettings_locked() void p3I2pBob::updateSettings_locked() { - RS_DBG4("") << std::endl; + RS_DBG4(""); sockaddr_storage proxy; mPeerMgr->getProxyServerAddress(RS_HIDDEN_TYPE_I2P, proxy); @@ -1102,7 +1098,7 @@ std::string p3I2pBob::recv() // sanity check if (length != bufferSize) { // expectation: a full buffer was peeked) - RS_DBG1("peeked less than bufferSize but also didn't found a new line character") << std::endl; + RS_DBG1("peeked less than bufferSize but also didn't found a new line character"); } // this should never happen assert(length <= bufferSize); diff --git a/libretroshare/src/util/i2pcommon.cpp b/libretroshare/src/util/i2pcommon.cpp index 86c83c367..eedb9596d 100644 --- a/libretroshare/src/util/i2pcommon.cpp +++ b/libretroshare/src/util/i2pcommon.cpp @@ -73,7 +73,7 @@ std::string publicKeyFromPrivate(std::string const &priv) RsBase64::decode(priv_copy, dataPriv); auto p = dataPriv.cbegin(); - RS_DBG("dataPriv.size ") << dataPriv.size() << std::endl; + RS_DBG("dataPriv.size ", dataPriv.size()); size_t publicKeyLen = 256 + 128; // default length (bytes) uint8_t certType = 0; @@ -111,7 +111,7 @@ std::string publicKeyFromPrivate(std::string const &priv) // check for != 5 if (certType != static_cast::type>(CertType::Key)) { // unsupported - RS_DBG("cert type ") << certType << " is unsupported" << std::endl; + RS_DBG("cert type ", certType, " is unsupported"); return std::string(); } @@ -128,21 +128,21 @@ std::string publicKeyFromPrivate(std::string const &priv) // likely 7 signingKeyType = readTwoBytesBE(p); - RS_DBG("signing pubkey type ") << certType << std::endl; + RS_DBG("signing pubkey type ", certType); if (signingKeyType >= 3 && signingKeyType <= 6) { - RS_DBG("signing pubkey type ") << certType << " has oversize" << std::endl; + RS_DBG("signing pubkey type ", certType, " has oversize"); // calculate oversize if (signingKeyType >= signingKeyLengths.size()) { // just in case - RS_DBG("signing pubkey type ") << certType << " cannot be found in size map!" << std::endl; + RS_DBG("signing pubkey type ", certType, " cannot be found in size data!"); return std::string(); } auto values = signingKeyLengths[signingKeyType]; if (values.first <= 128) { // just in case, it's supposed to be larger! - RS_DBG("signing pubkey type ") << certType << " is oversize but size calculation would underflow!" << std::endl; + RS_DBG("signing pubkey type ", certType, " is oversize but size calculation would underflow!"); return std::string(); } @@ -152,12 +152,12 @@ std::string publicKeyFromPrivate(std::string const &priv) // Crypto Public Key // likely 0 cryptKey = readTwoBytesBE(p); - RS_DBG("crypto pubkey type ") << cryptKey << std::endl; + RS_DBG("crypto pubkey type ", cryptKey); // info: these are all smaller than the default 256 bytes, so no oversize calculation is needed break; } catch (const std::out_of_range &e) { - RS_DBG("hit exception! ") << e.what() << std::endl; + RS_DBG("hit exception! ", e.what()); return std::string(); } } while(false); From 3d784e88714d5282f8f0fe01ee890ae0e0f3c152 Mon Sep 17 00:00:00 2001 From: sehraf Date: Thu, 11 Jun 2020 11:03:08 +0200 Subject: [PATCH 077/154] remove unnecessary std::replace --- libretroshare/src/services/autoproxy/p3i2pbob.cc | 2 -- libretroshare/src/util/i2pcommon.cpp | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libretroshare/src/services/autoproxy/p3i2pbob.cc b/libretroshare/src/services/autoproxy/p3i2pbob.cc index 02b951397..7fd7594b9 100644 --- a/libretroshare/src/services/autoproxy/p3i2pbob.cc +++ b/libretroshare/src/services/autoproxy/p3i2pbob.cc @@ -33,8 +33,6 @@ #include "util/rsprint.h" #include "util/rsrandom.h" -#include "util/rsdebuglevel4.h" - static const std::string kConfigKeyBOBEnable = "BOB_ENABLE"; static const std::string kConfigKeyBOBKey = "BOB_KEY"; static const std::string kConfigKeyBOBAddr = "BOB_ADDR"; diff --git a/libretroshare/src/util/i2pcommon.cpp b/libretroshare/src/util/i2pcommon.cpp index eedb9596d..8c6f2238b 100644 --- a/libretroshare/src/util/i2pcommon.cpp +++ b/libretroshare/src/util/i2pcommon.cpp @@ -19,7 +19,8 @@ std::string keyToBase32Addr(const std::string &key) // replace I2P specific chars std::replace(copy.begin(), copy.end(), '~', '/'); - std::replace(copy.begin(), copy.end(), '-', '+'); + // replacing the - with a + is not necessary, as RsBase64 can handle base64url encoding, too + // std::replace(copy.begin(), copy.end(), '-', '+'); // decode std::vector bin; From 591d2ad8646758465df380bdc9e0c01de97b094f Mon Sep 17 00:00:00 2001 From: sehraf Date: Thu, 11 Jun 2020 11:15:09 +0200 Subject: [PATCH 078/154] autoproxy: use new RS_DBG --- .../services/autoproxy/rsautoproxymonitor.cc | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc b/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc index 62b47dfea..3c52cfdc5 100644 --- a/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc +++ b/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc @@ -44,7 +44,7 @@ void rsAutoProxyMonitor::addProxy(autoProxyType::autoProxyType_enum type, autoPr { RS_STACK_MUTEX(mLock); if (mProxies.find(type) != mProxies.end()) { - RsErr() << __PRETTY_FUNCTION__<< " type " << type << " already added - OVERWRITING" << std::endl; + RS_ERR("type ", type, " already added - OVERWRITING"); print_stacktrace(); } @@ -120,7 +120,7 @@ void rsAutoProxyMonitor::stopAllRSShutdown() do { rstime::rs_usleep(1000 * 1000); RS_STACK_MUTEX(mLock); - RsDbg() << __PRETTY_FUNCTION__<< " waiting for auto proxy service(s) to shut down " << t << "/" << timeout << " (remaining: " << mProxies.size() << ")" << std::endl; + RS_DBG("waiting for auto proxy service(s) to shut down ", t, "/", timeout, " (remaining: ", mProxies.size(), ")"); if (mProxies.empty()) break; t++; @@ -149,15 +149,15 @@ void rsAutoProxyMonitor::task(taskTicket *ticket) { // sanity checks if (!ticket->async && ticket->types.size() > 1) { - RsErr() << __PRETTY_FUNCTION__<< " synchronous call to multiple services. This can cause problems!" << std::endl; + RS_ERR("synchronous call to multiple services. This can cause problems!"); print_stacktrace(); } if (ticket->async && !ticket->cb && ticket->data) { - RsErr() << __PRETTY_FUNCTION__<< " asynchronous call with data but no callback. This will likely causes memory leak!" << std::endl; + RS_ERR("asynchronous call with data but no callback. This will likely causes memory leak!"); print_stacktrace(); } if (ticket->types.size() > 1 && ticket->data) { - RsErr() << __PRETTY_FUNCTION__<< " call with data to multiple services. This will likely causes memory leak!" << std::endl; + RS_ERR("call with data to multiple services. This will likely causes memory leak!"); print_stacktrace(); } @@ -197,7 +197,7 @@ void rsAutoProxyMonitor::taskAsync(std::vector if (isAsyncTask(task)) { // Usually the services will reject this ticket. // Just print a warning - maybe there is some special case where this is a good idea. - RsErr() << __PRETTY_FUNCTION__<< " called with an asynchronous task!" << std::endl; + RS_ERR("called with an asynchronous task!"); print_stacktrace(); } @@ -256,7 +256,7 @@ void rsAutoProxyMonitor::taskDone(taskTicket *t, autoProxyStatus::autoProxyStatu t->cb->taskFinished(t); if (t != NULL) { // callack did not clean up properly - RsErr() << __PRETTY_FUNCTION__<< " callback did not clean up!" << std::endl; + RS_ERR("callback did not clean up!"); print_stacktrace(); cleanUp = true; } @@ -265,12 +265,12 @@ void rsAutoProxyMonitor::taskDone(taskTicket *t, autoProxyStatus::autoProxyStatu // we must take care of deleting cleanUp = true; if(t->data) - RsErr() << __PRETTY_FUNCTION__<< " async call with data attached but no callback set!" << std::endl; + RS_ERR("sync call with data attached but no callback set!"); } if (cleanUp) { if (t->data) { - RsErr() << __PRETTY_FUNCTION__<< " will try to delete void pointer!" << std::endl; + RS_ERR("will try to delete void pointer!"); print_stacktrace(); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdelete-incomplete" @@ -304,7 +304,7 @@ void rsAutoProxyMonitor::taskFinished(taskTicket *&ticket) // clean up if (ticket->data) { - RsErr() << __PRETTY_FUNCTION__<< " data set. Will try to delete void pointer" << std::endl; + RS_ERR(" data set. Will try to delete void pointer"); print_stacktrace(); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdelete-incomplete" @@ -323,7 +323,7 @@ autoProxyService *rsAutoProxyMonitor::lookUpService(autoProxyType::autoProxyType if ((itService = mProxies.find(t)) != mProxies.end()) { return itService->second; } - RsDbg() << __PRETTY_FUNCTION__<< " no service for type " << t << " found!" << std::endl; + RS_DBG("no service for type ", t, " found!"); return NULL; } From ebc5a116b22c28f59cf1f584c5a0afe020986550 Mon Sep 17 00:00:00 2001 From: sehraf Date: Thu, 11 Jun 2020 11:18:52 +0200 Subject: [PATCH 079/154] remove unnecessary std::replace --- libretroshare/src/util/i2pcommon.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libretroshare/src/util/i2pcommon.cpp b/libretroshare/src/util/i2pcommon.cpp index 8c6f2238b..575b0fec0 100644 --- a/libretroshare/src/util/i2pcommon.cpp +++ b/libretroshare/src/util/i2pcommon.cpp @@ -67,7 +67,8 @@ std::string publicKeyFromPrivate(std::string const &priv) // creat a copy to work on, need to convert it to standard base64 auto priv_copy(priv); std::replace(priv_copy.begin(), priv_copy.end(), '~', '/'); - std::replace(priv_copy.begin(), priv_copy.end(), '-', '+'); + // replacing the - with a + is not necessary, as RsBase64 can handle base64url encoding, too + // std::replace(copy.begin(), copy.end(), '-', '+'); // get raw data std::vector dataPriv; From 92379b35344a439a133c192b1775458ca42fd94e Mon Sep 17 00:00:00 2001 From: defnax Date: Thu, 11 Jun 2020 16:32:55 +0200 Subject: [PATCH 080/154] Added open file feature for file status widget * Added open file feature for file status widget --- .../GxsChannelFilesStatusWidget.cpp | 70 +++++++++++++++--- .../gxschannels/GxsChannelFilesStatusWidget.h | 1 + .../GxsChannelFilesStatusWidget.ui | 22 +++++- retroshare-gui/src/gui/icons.qrc | 1 + retroshare-gui/src/gui/icons/png/arrow.png | Bin 0 -> 935 bytes 5 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 retroshare-gui/src/gui/icons/png/arrow.png diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.cpp index c28601fed..bc019e426 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.cpp @@ -18,6 +18,7 @@ * * *******************************************************************************/ +#include #include #include #include @@ -27,6 +28,8 @@ #include "GxsChannelFilesStatusWidget.h" #include "ui_GxsChannelFilesStatusWidget.h" #include "gui/common/RsUrlHandler.h" +#include "gui/common/FilesDefs.h" +#include "util/misc.h" #include "retroshare/rsfiles.h" @@ -40,11 +43,21 @@ GxsChannelFilesStatusWidget::GxsChannelFilesStatusWidget(const RsGxsFile &file, setSize(mFile.mSize); /* Connect signals */ - connect(ui->downloadToolButton, SIGNAL(clicked()), this, SLOT(download())); + connect(ui->downloadPushButton, SIGNAL(clicked()), this, SLOT(download())); connect(ui->resumeToolButton, SIGNAL(clicked()), this, SLOT(resume())); connect(ui->pauseToolButton, SIGNAL(clicked()), this, SLOT(pause())); connect(ui->cancelToolButton, SIGNAL(clicked()), this, SLOT(cancel())); - connect(ui->openFolderToolButton, SIGNAL(clicked()), this, SLOT(openFolder())); + connect(ui->openFilePushButton, SIGNAL(clicked()), this, SLOT(openFile())); + + ui->downloadPushButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/download.png")); + ui->openFolderToolButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/arrow.png")); + + QAction *openfolder = new QAction(tr("Open folder"), this); + connect(openfolder, SIGNAL(triggered()), this, SLOT(openFolder())); + + QMenu *menu = new QMenu(); + menu->addAction(openfolder); + ui->openFolderToolButton->setMenu(menu); check(); } @@ -80,6 +93,17 @@ void GxsChannelFilesStatusWidget::check() if (rsFiles->alreadyHaveFile(mFile.mHash, fileInfo)) { mState = STATE_LOCAL; setSize(fileInfo.size); + + /* check if the file is a media file */ + if (!misc::isPreviewable(QFileInfo(QString::fromUtf8(fileInfo.path.c_str())).suffix())) + { + /* check if the file is not a media file and change text */ + ui->openFilePushButton->setText(tr("Open file")); + } else { + ui->openFilePushButton->setText(tr("Play")); + ui->openFilePushButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/play.png")); + } + } else { FileInfo fileInfo; bool detailsOk = rsFiles->FileDetails(mFile.mHash, RS_FILE_HINTS_DOWNLOAD | RS_FILE_HINTS_SPEC_ONLY, fileInfo); @@ -126,11 +150,12 @@ void GxsChannelFilesStatusWidget::check() case STATE_ERROR: repeat = 0; - ui->downloadToolButton->hide(); + ui->downloadPushButton->hide(); ui->resumeToolButton->hide(); ui->pauseToolButton->hide(); ui->cancelToolButton->hide(); ui->progressBar->hide(); + ui->openFilePushButton->hide(); ui->openFolderToolButton->hide(); statusText = tr("Error"); @@ -140,11 +165,12 @@ void GxsChannelFilesStatusWidget::check() case STATE_REMOTE: repeat = 30000; - ui->downloadToolButton->show(); + ui->downloadPushButton->show(); ui->resumeToolButton->hide(); ui->pauseToolButton->hide(); ui->cancelToolButton->hide(); ui->progressBar->hide(); + ui->openFilePushButton->hide(); ui->openFolderToolButton->hide(); break; @@ -152,11 +178,12 @@ void GxsChannelFilesStatusWidget::check() case STATE_DOWNLOAD: repeat = 1000; - ui->downloadToolButton->hide(); + ui->downloadPushButton->hide(); ui->resumeToolButton->hide(); ui->pauseToolButton->show(); ui->cancelToolButton->show(); ui->progressBar->show(); + ui->openFilePushButton->hide(); ui->openFolderToolButton->hide(); break; @@ -164,11 +191,12 @@ void GxsChannelFilesStatusWidget::check() case STATE_PAUSED: repeat = 1000; - ui->downloadToolButton->hide(); + ui->downloadPushButton->hide(); ui->resumeToolButton->show(); ui->pauseToolButton->hide(); ui->cancelToolButton->show(); ui->progressBar->hide(); + ui->openFilePushButton->hide(); ui->openFolderToolButton->hide(); statusText = tr("Paused"); @@ -178,11 +206,12 @@ void GxsChannelFilesStatusWidget::check() case STATE_WAITING: repeat = 1000; - ui->downloadToolButton->hide(); + ui->downloadPushButton->hide(); ui->resumeToolButton->hide(); ui->pauseToolButton->show(); ui->cancelToolButton->show(); ui->progressBar->hide(); + ui->openFilePushButton->hide(); ui->openFolderToolButton->hide(); statusText = tr("Waiting"); @@ -192,11 +221,12 @@ void GxsChannelFilesStatusWidget::check() case STATE_CHECKING: repeat = 1000; - ui->downloadToolButton->hide(); + ui->downloadPushButton->hide(); ui->resumeToolButton->hide(); ui->pauseToolButton->hide(); ui->cancelToolButton->show(); ui->progressBar->hide(); + ui->openFilePushButton->hide(); ui->openFolderToolButton->hide(); statusText = tr("Checking"); @@ -206,11 +236,12 @@ void GxsChannelFilesStatusWidget::check() case STATE_LOCAL: repeat = 60000; - ui->downloadToolButton->hide(); + ui->downloadPushButton->hide(); ui->resumeToolButton->hide(); ui->pauseToolButton->hide(); ui->cancelToolButton->hide(); ui->progressBar->hide(); + ui->openFilePushButton->show(); ui->openFolderToolButton->show(); break; @@ -296,3 +327,24 @@ void GxsChannelFilesStatusWidget::openFolder() } } } + +void GxsChannelFilesStatusWidget::openFile() +{ + FileInfo fileInfo; + if (!rsFiles->alreadyHaveFile(mFile.mHash, fileInfo)) { + return; + } + + /* open file with a suitable application */ + QFileInfo qinfo; + qinfo.setFile(QString::fromUtf8(fileInfo.path.c_str())); + if (qinfo.exists()) { + if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(qinfo.absoluteFilePath()))) { + std::cerr << "GxsChannelFilesStatusWidget(): can't open file " << fileInfo.path << std::endl; + } + }else{ + QMessageBox::information(this, tr("Play File"), + tr("File %1 does not exist at location.").arg(fileInfo.path.c_str())); + return; + } +} diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.h b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.h index 3d58cc4d7..1effe0549 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.h @@ -44,6 +44,7 @@ private slots: void pause(); void resume(); void openFolder(); + void openFile(); private: void setSize(uint64_t size); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.ui index 39e32271d..c1b02ab83 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.ui @@ -48,7 +48,7 @@ 2
- + 0 @@ -126,18 +126,31 @@ - + 0 0 + + Play + + + + + + + + 0 + 0 + + Qt::NoFocus - - Open folder + + QToolButton::InstantPopup @@ -148,6 +161,7 @@
+ diff --git a/retroshare-gui/src/gui/icons.qrc b/retroshare-gui/src/gui/icons.qrc index 6e4bd7569..656cdc7fd 100644 --- a/retroshare-gui/src/gui/icons.qrc +++ b/retroshare-gui/src/gui/icons.qrc @@ -60,6 +60,7 @@ icons/png/anonymous.png icons/png/attach-image.png icons/png/attach.png + icons/png/arrow.png icons/png/cert.png icons/png/channels-notify.png icons/png/channels.png diff --git a/retroshare-gui/src/gui/icons/png/arrow.png b/retroshare-gui/src/gui/icons/png/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..e238538026d1e88b3f373287ead27e503f5c161d GIT binary patch literal 935 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD`S&v7|ftIx;Y9?C1WI$O_~uBzpw; zGB8xB0oAoIF#H0kf5E^|YQVtoDuIE)Y6b&?c)^@qfi^&iMFBn`u0Wb$)qm#M*O+Ht zWtx2zNHR41XP9}3Y4$aySyx$Sg2Y+pTxFPc3CIA+&OgsG`zjDYxwEb_%(%uf=L*ZL z%WN~Rv(387F!Kyls_!v~G3N@y?8{J*xi^^SfHX4AxxzH(D$sneI9PVpHHMjYftE7Q zx&}0y3CLY?8z>8O-HvEab0B3>666=mz#P8n@?9p4ix-UE8wx&tB+%9V{DqpTwUw?m z*S9a6E0=5j{GpzdSXf!~FX&Yuf5Fb{`FuN0{n!N5&zR)x?!wT)D(eB{a29w(7BevL z9RXp+soH$fKtc8rPhVH|Cv02-W^(6FzMKZs)8Xmj7*cWT?bYxgCP$IhhhhRDXDrnX z8dfYQ|DXN2QSwm>pLs~+^PC62<*h8*6D8W9=thZjZ(4S6?%K4)d*76A^QgQ%*R_86 z>bJtB<uG!l<>snA z+9VXecEOc!trZ_axwL9qo226REVw4F_u+#p_nw-AO#bm}4%`;k;`rdo)l}2i7) z!i{vjjt`OCi)xNFdCXs{a4TKQ<3l9Zq?)!S7yF$GH~n=IK1}9{_|w9qX1}Z9Y`;#z zm&IHWe><4c>~}QW<<}AT(9GrXr-4cF{%(ge-*p7O?B#N)?Pp5dzs=#!dd+|j+T0<3 zx|me=Z*e%QuNm-#n>*xh6H{vaT8F#wng$={O7j%gS#0<)_qT-a-;2w8-`~0Zy~0TH z|DULz@UWElX8(=-M$jeR3Y{f~fzhN|;u=wsl30>zm0Xkxq!^40j0|)Q%ybP6LJZBU zOiiqe4YUmmtPBk9+E2cOq9HdwB{QuOw}v%I+Ic_?k{}y`^V3So6N^$A%FE03GV`*F clM@S4_413-XTP(N0xDwgboFyt=akR{0M4y>Jpcdz literal 0 HcmV?d00001 From e92c89bdfbee8ace9435f2515f16df4c048cac3d Mon Sep 17 00:00:00 2001 From: defnax Date: Thu, 11 Jun 2020 20:09:24 +0200 Subject: [PATCH 081/154] forget this to commit --- retroshare-gui/src/gui/qss/stylesheet/Standard.qss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/retroshare-gui/src/gui/qss/stylesheet/Standard.qss b/retroshare-gui/src/gui/qss/stylesheet/Standard.qss index 53ac80a44..505fc83c9 100644 --- a/retroshare-gui/src/gui/qss/stylesheet/Standard.qss +++ b/retroshare-gui/src/gui/qss/stylesheet/Standard.qss @@ -791,6 +791,14 @@ GxsChannelPostsWidget QToolButton#subscribeToolButton::menu-button { } +GxsChannelFilesStatusWidget QToolButton#openFolderToolButton::menu-indicator { + image: none; +} + +GxsChannelFilesStatusWidget QToolButton#openFolderToolButton[popupMode="0"] { + padding-right: 0px; +} + GxsGroupDialog QLabel#groupLogo{ border: 2px solid #CCCCCC; border-radius: 3px; From 2faaccbb7a4963f6d8288282b50c7e99914c02f9 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 11 Jun 2020 21:55:52 +0200 Subject: [PATCH 082/154] fixed a few cosmetic details in channels model and UI --- .../gui/gxschannels/GxsChannelPostsModel.cpp | 8 +-- .../GxsChannelPostsWidgetWithModel.cpp | 71 +++++++++++++++---- .../GxsChannelPostsWidgetWithModel.h | 3 + .../GxsChannelPostsWidgetWithModel.ui | 16 ++++- 4 files changed, 80 insertions(+), 18 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index 94d6f6406..caca20f93 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -145,7 +145,7 @@ int RsGxsChannelPostsModel::rowCount(const QModelIndex& parent) const int RsGxsChannelPostsModel::columnCount(const QModelIndex &/*parent*/) const { - return mColumns ; + return std::min((int)mFilteredPosts.size(),(int)mColumns) ; } bool RsGxsChannelPostsModel::getPostData(const QModelIndex& i,RsGxsChannelPost& fmpe) const @@ -635,7 +635,7 @@ QModelIndex RsGxsChannelPostsModel::getIndexOfMessage(const RsGxsMessageId& mid) RsGxsMessageId postId = mid; - for(uint32_t i=1;i -#define CHAN_DEFAULT_IMAGE ":/icons/png/channels.png" +#define CHAN_DEFAULT_IMAGE ":images/thumb-default-video.png" #define ROLE_PUBLISH FEED_TREEWIDGET_SORTROLE @@ -102,10 +103,17 @@ public: // now fill the data - QPixmap thumbnail; - GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL); - - lb->setPixmap(thumbnail); + if(post.mThumbnail.mSize > 0) + { + QPixmap thumbnail; + GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL); + lb->setPixmap(thumbnail); + } + else + { + QPixmap thumbnail = FilesDefs::getPixmapFromQtResourcePath(CHAN_DEFAULT_IMAGE); + lb->setPixmap(thumbnail); + } QFontMetricsF fm(font()); int W = THUMBNAIL_OVERSAMPLE_FACTOR * THUMBNAIL_W * fm.height() ; @@ -114,6 +122,15 @@ public: lb->setFixedSize(W,H); lt->setText(QString::fromUtf8(post.mMeta.mMsgName.c_str())); + + QFont font = lt->font(); + + if(IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus)) + { + font.setBold(true); + lt->setFont(font); + } + lt->setMaximumWidth(W); lt->setWordWrap(true); @@ -401,15 +418,10 @@ void GxsChannelPostsWidgetWithModel::handleEvent_main_thread(std::shared_ptrmChannelGroupId == groupId()) updateDisplay(true); break; -// case RsChannelEventCode::READ_STATUS_CHANGED: -// if (FeedItem *feedItem = ui->feedWidget->findFeedItem(GxsChannelPostItem::computeIdentifier(e->mChannelMsgId))) -// if (GxsChannelPostItem *channelPostItem = dynamic_cast(feedItem)) -// channelPostItem->setReadStatus(false,!channelPostItem->isUnread()); -// //channelPostItem->setReadStatus(false,e->Don't get read status. Will be more easier and accurate); -// break; default: break; } @@ -419,18 +431,34 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() { QModelIndex index = ui->postsTree->selectionModel()->currentIndex(); + if(!index.isValid() && !mSelectedPost.isNull() && mGroup.mMeta.mGroupId == mSelectedGroup) + { + index = mChannelPostsModel->getIndexOfMessage(mSelectedPost); + whileBlocking(ui->postsTree)->setCurrentIndex(index); + } + if(!index.isValid()) { ui->postDetails_TE->clear(); - ui->postLogo_LB->clear(); + ui->postLogo_LB->hide(); + ui->postName_LB->hide(); mChannelPostFilesModel->clear(); + mSelectedGroup.clear(); + mSelectedPost.clear(); return; } + + ui->postLogo_LB->show(); + ui->postName_LB->show(); + if(index.row()==0 && index.column()==0) std::cerr << "here" << std::endl; RsGxsChannelPost post = index.data(Qt::UserRole).value() ; + mSelectedGroup = mGroup.mMeta.mGroupId; + mSelectedPost = post.mMeta.mMsgId; + mChannelPostFilesModel->setFiles(post.mFiles); auto all_msgs_versions(post.mOlderVersions); @@ -447,7 +475,7 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() if (post.mThumbnail.mData != NULL) GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, postImage,GxsIdDetails::ORIGINAL); else - postImage = QPixmap(CHAN_DEFAULT_IMAGE); + postImage = FilesDefs::getPixmapFromQtResourcePath(CHAN_DEFAULT_IMAGE); int W = QFontMetricsF(font()).height() * 8; @@ -463,6 +491,16 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); ui->channelPostFiles_TV->setAutoSelect(true); + // Now also set the post as read + + if(IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus)) + { + RsGxsGrpMsgIdPair postId; + postId.second = post.mMeta.mMsgId; + postId.first = post.mMeta.mGroupId; + + RsThread::async([postId]() { rsGxsChannels->markRead(postId, true) ; } ); + } } void GxsChannelPostsWidgetWithModel::updateChannelFiles() @@ -645,6 +683,8 @@ void GxsChannelPostsWidgetWithModel::createMsg() void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGroup &group) { + // save selection if needed + /* IMAGE */ QPixmap chanImage; if (group.mImage.mData != NULL) { @@ -652,6 +692,11 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou } else { chanImage = QPixmap(CHAN_DEFAULT_IMAGE); } + if(group.mMeta.mGroupName.empty()) + ui->channelName_LB->setText(tr("[No name]")); + else + ui->channelName_LB->setText(QString::fromUtf8(group.mMeta.mGroupName.c_str())); + ui->logoLabel->setPixmap(chanImage); ui->logoLabel->setFixedSize(QSize(ui->logoLabel->height()*chanImage.width()/(float)chanImage.height(),ui->logoLabel->height())); // make the logo have the same aspect ratio than the original image diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index 90c1f76ad..49e5dc21e 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -166,6 +166,9 @@ private: RsGxsChannelPostFilesModel *mChannelPostFilesModel; RsGxsChannelPostFilesModel *mChannelFilesModel; + RsGxsMessageId mSelectedPost; + RsGxsGroupId mSelectedGroup; + /* UI - from Designer */ Ui::GxsChannelPostsWidgetWithModel *ui; }; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index cfa36e40d..f44372c3a 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -161,13 +161,27 @@ - 2 + 0 Channel details + + + + + 75 + true + false + + + + Channel title + + + From 67e8b87750210ddca6428ae18b9057bdff7870de Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 11 Jun 2020 22:17:33 +0200 Subject: [PATCH 083/154] attempt to fix UI bug that automatically deselected after setting msg as read --- .../gui/gxschannels/GxsChannelPostsModel.cpp | 4 +- .../gui/gxschannels/GxsChannelPostsModel.h | 2 +- .../GxsChannelPostsWidgetWithModel.cpp | 48 ++++++++++--------- .../GxsChannelPostsWidgetWithModel.h | 2 +- 4 files changed, 29 insertions(+), 27 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index caca20f93..f22e7ca58 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -398,7 +398,7 @@ void RsGxsChannelPostsModel::clear() initEmptyHierarchy(); postMods(); - emit channelLoaded(); + emit channelPostsLoaded(); } void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vector& posts) @@ -431,7 +431,7 @@ void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vecto postMods(); - emit channelLoaded(); + emit channelPostsLoaded(); } void RsGxsChannelPostsModel::update_posts(const RsGxsGroupId& group_id) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.h index b82f91783..59d937b6c 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.h @@ -173,7 +173,7 @@ public: void debug_dump(); signals: - void channelLoaded(); // emitted after the posts have been set. Can be used to updated the UI. + void channelPostsLoaded(); // emitted after the posts have been loaded. private: RsGxsChannelGroup mChannelGroup; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 17a9d5d85..31bd27b3f 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -323,7 +323,7 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI connect(ui->channelFiles_TV->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortColumnFiles(int,Qt::SortOrder))); connect(ui->postsTree->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),this,SLOT(showPostDetails())); - connect(mChannelPostsModel,SIGNAL(channelLoaded()),this,SLOT(updateChannelFiles())); + connect(mChannelPostsModel,SIGNAL(channelPostsLoaded()),this,SLOT(postChannelLoad())); QFontMetricsF fm(font()); @@ -431,12 +431,6 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() { QModelIndex index = ui->postsTree->selectionModel()->currentIndex(); - if(!index.isValid() && !mSelectedPost.isNull() && mGroup.mMeta.mGroupId == mSelectedGroup) - { - index = mChannelPostsModel->getIndexOfMessage(mSelectedPost); - whileBlocking(ui->postsTree)->setCurrentIndex(index); - } - if(!index.isValid()) { ui->postDetails_TE->clear(); @@ -503,20 +497,6 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() } } -void GxsChannelPostsWidgetWithModel::updateChannelFiles() -{ - std::list files; - - mChannelPostsModel->getFilesList(files); - mChannelFilesModel->setFiles(files); - - ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE); - ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); - ui->channelFiles_TV->setAutoSelect(true); - - //mChannelPostFilesProxyModel->sort(0, Qt::AscendingOrder); -} - void GxsChannelPostsWidgetWithModel::updateGroupData() { if(groupId().isNull()) @@ -548,6 +528,29 @@ void GxsChannelPostsWidgetWithModel::updateGroupData() }); } +void GxsChannelPostsWidgetWithModel::postChannelLoad() +{ + std::cerr << "Post channel load..." << std::endl; + + if(!mSelectedPost.isNull() && mGroup.mMeta.mGroupId == mSelectedGroup) + { + QModelIndex index = mChannelPostsModel->getIndexOfMessage(mSelectedPost); + std::cerr << "Setting current index to " << index.row() << ","<< index.column() << " for current post " << mSelectedPost << std::endl; + whileBlocking(ui->postsTree)->setCurrentIndex(index); + } + + std::list files; + + mChannelPostsModel->getFilesList(files); + mChannelFilesModel->setFiles(files); + + ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE); + ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); + ui->channelFiles_TV->setAutoSelect(true); + + +} + void GxsChannelPostsWidgetWithModel::updateDisplay(bool complete) { #ifdef DEBUG_CHANNEL @@ -779,7 +782,6 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou } ui->infoDistribution->setText(distrib_string); - #ifdef TODO ui->infoWidget->show(); ui->feedWidget->hide(); @@ -788,8 +790,8 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou //ui->feedToolButton->setEnabled(false); //ui->fileToolButton->setEnabled(false); #endif - ui->subscribeToolButton->setText(tr("Subscribe ") + " " + QString::number(group.mMeta.mPop) ); + } #ifdef TODO diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index 49e5dc21e..7d2b9038c 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -138,7 +138,7 @@ private slots: void setViewMode(int viewMode); void settingsChanged(); void handlePostsTreeSizeChange(QSize s); - void updateChannelFiles(); + void postChannelLoad(); public slots: void sortColumnFiles(int col,Qt::SortOrder so); From 2b8d65b31ffca4494643c66dce7440810e8096b6 Mon Sep 17 00:00:00 2001 From: defnax Date: Thu, 11 Jun 2020 22:48:21 +0200 Subject: [PATCH 084/154] Fixing default stylesheet for Channel label --- .../gui/gxschannels/GxsChannelPostsWidgetWithModel.ui | 9 +++++++-- retroshare-gui/src/gui/qss/stylesheet/qss.default | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index f44372c3a..761f65e22 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -169,7 +169,7 @@ - + 75 @@ -337,7 +337,7 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Description</span></p></body></html> @@ -540,6 +540,11 @@ p, li { white-space: pre-wrap; } QToolButton
gui/common/SubscribeToolButton.h
+ + StyledElidedLabel + QLabel +
gui/common/StyledElidedLabel.h
+
RSTreeView QTreeView diff --git a/retroshare-gui/src/gui/qss/stylesheet/qss.default b/retroshare-gui/src/gui/qss/stylesheet/qss.default index f71a4b435..b4e20120a 100644 --- a/retroshare-gui/src/gui/qss/stylesheet/qss.default +++ b/retroshare-gui/src/gui/qss/stylesheet/qss.default @@ -84,7 +84,7 @@ ConfCertDialog QLabel#servicePermissionsLabel qproperty-fontSizeFactor: 125; } -GxsChannelPostsWidget QLabel#nameLabel +GxsChannelPostsWidgetWithModel QLabel#channelName_LB { qproperty-fontSizeFactor: 250; } From f40d7a75b36f009f8d42af2984cb78aa64c5de4e Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 12 Jun 2020 11:00:51 +0200 Subject: [PATCH 085/154] fixed a few UI bugs in channel posts --- .../gui/gxschannels/GxsChannelPostsModel.cpp | 7 +++++ .../GxsChannelPostsWidgetWithModel.cpp | 27 ++++++++++++------- .../GxsChannelPostsWidgetWithModel.h | 2 +- .../GxsChannelPostsWidgetWithModel.ui | 11 ++++++-- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index f22e7ca58..ae2c3d119 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -401,6 +401,11 @@ void RsGxsChannelPostsModel::clear() emit channelPostsLoaded(); } +bool operator<(const RsGxsChannelPost& p1,const RsGxsChannelPost& p2) +{ + return p1.mMeta.mPublishTs > p2.mMeta.mPublishTs; +} + void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vector& posts) { preMods(); @@ -413,6 +418,8 @@ void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vecto createPostsArray(posts); + std::sort(mPosts.begin(),mPosts.end()); + mFilteredPosts.clear(); for(int i=0;isetPixmap(thumbnail); } - else + else if(post.mMeta.mPublishTs > 0) // this is for testing that the post is not an empty post (happens at the end of the last row) { QPixmap thumbnail = FilesDefs::getPixmapFromQtResourcePath(CHAN_DEFAULT_IMAGE); lb->setPixmap(thumbnail); @@ -157,7 +157,7 @@ void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & QPixmap pixmap(w.size()); - if(option.state & QStyle::State_Selected) + if((option.state & QStyle::State_Selected) && post.mMeta.mPublishTs > 0) // check if post is selected and is not empty (end of last row) pixmap.fill(QRgb(0xff308dc7)); // I dont know how to grab the backgroud color for selected objects automatically. else pixmap.fill(QRgb(0x00ffffff)); // choose a fully transparent background @@ -323,7 +323,13 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI connect(ui->channelFiles_TV->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortColumnFiles(int,Qt::SortOrder))); connect(ui->postsTree->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),this,SLOT(showPostDetails())); - connect(mChannelPostsModel,SIGNAL(channelPostsLoaded()),this,SLOT(postChannelLoad())); + connect(mChannelPostsModel,SIGNAL(channelPostsLoaded()),this,SLOT(postChannelPostLoad())); + + ui->postName_LB->hide(); + ui->postTime_LB->hide(); + ui->postLogo_LB->hide(); + + ui->postDetails_TE->setPlaceholderText(tr("No post selected")); QFontMetricsF fm(font()); @@ -430,12 +436,14 @@ void GxsChannelPostsWidgetWithModel::handleEvent_main_thread(std::shared_ptrpostsTree->selectionModel()->currentIndex(); + RsGxsChannelPost post = index.data(Qt::UserRole).value() ; - if(!index.isValid()) + if(post.mMeta.mPublishTs == 0) { ui->postDetails_TE->clear(); ui->postLogo_LB->hide(); ui->postName_LB->hide(); + ui->postTime_LB->hide(); mChannelPostFilesModel->clear(); mSelectedGroup.clear(); mSelectedPost.clear(); @@ -444,12 +452,11 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() ui->postLogo_LB->show(); ui->postName_LB->show(); + ui->postTime_LB->show(); if(index.row()==0 && index.column()==0) std::cerr << "here" << std::endl; - RsGxsChannelPost post = index.data(Qt::UserRole).value() ; - mSelectedGroup = mGroup.mMeta.mGroupId; mSelectedPost = post.mMeta.mMsgId; @@ -476,10 +483,12 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() // Using fixed width so that the post will not displace the text when we browse. ui->postLogo_LB->setPixmap(postImage); - ui->postName_LB->setText(QString::fromUtf8(post.mMeta.mMsgName.c_str())); - ui->postLogo_LB->setFixedSize(W,postImage.height()/(float)postImage.width()*W); + + ui->postName_LB->setText(QString::fromUtf8(post.mMeta.mMsgName.c_str())); ui->postName_LB->setFixedWidth(W); + ui->postTime_LB->setText(QDateTime::fromMSecsSinceEpoch(post.mMeta.mPublishTs*1000).toString("MM/dd/yyyy, hh:mm")); + ui->postTime_LB->setFixedWidth(W); ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE); ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); @@ -528,7 +537,7 @@ void GxsChannelPostsWidgetWithModel::updateGroupData() }); } -void GxsChannelPostsWidgetWithModel::postChannelLoad() +void GxsChannelPostsWidgetWithModel::postChannelPostLoad() { std::cerr << "Post channel load..." << std::endl; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index 7d2b9038c..5f2f4adae 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -138,7 +138,7 @@ private slots: void setViewMode(int viewMode); void settingsChanged(); void handlePostsTreeSizeChange(QSize s); - void postChannelLoad(); + void postChannelPostLoad(); public slots: void sortColumnFiles(int col,Qt::SortOrder so); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index f44372c3a..71412862e 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -161,7 +161,7 @@ - 0 + 1 @@ -399,7 +399,7 @@ p, li { white-space: pre-wrap; }
- 2 + 0 @@ -434,6 +434,13 @@ p, li { white-space: pre-wrap; }
+ + + + TextLabel + + + From f88527dbd78fa8b37eb34d317f0f5f5d8c00e778 Mon Sep 17 00:00:00 2001 From: sehraf Date: Fri, 12 Jun 2020 17:28:08 +0200 Subject: [PATCH 086/154] i2pbob: remove sockaddr_storage_tostring --- libretroshare/src/services/autoproxy/p3i2pbob.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretroshare/src/services/autoproxy/p3i2pbob.cc b/libretroshare/src/services/autoproxy/p3i2pbob.cc index 7fd7594b9..a170d08ca 100644 --- a/libretroshare/src/services/autoproxy/p3i2pbob.cc +++ b/libretroshare/src/services/autoproxy/p3i2pbob.cc @@ -936,7 +936,7 @@ void p3I2pBob::finalizeSettings_locked() sockaddr_storage_setipv4(mI2PProxyAddr, (sockaddr_in*)&proxy); sockaddr_storage_setport(mI2PProxyAddr, 2827); - RS_DBG4("using ", sockaddr_storage_tostring(mI2PProxyAddr)); + RS_DBG4("using ", mI2PProxyAddr); RS_DBG4("using ", mSetting.address.base32); peerState ps; From 5ff5a32df70c001caf930a3cdfabea3f8bf0c24d Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Fri, 12 Jun 2020 18:41:42 +0200 Subject: [PATCH 087/154] Proper naming for RsRandom string functions --- libretroshare/src/util/rsrandom.cc | 25 +++++++++++++++++++------ libretroshare/src/util/rsrandom.h | 12 +++++++++++- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/libretroshare/src/util/rsrandom.cc b/libretroshare/src/util/rsrandom.cc index 7ea8eb968..dc7d9ac67 100644 --- a/libretroshare/src/util/rsrandom.cc +++ b/libretroshare/src/util/rsrandom.cc @@ -121,13 +121,26 @@ double RsRandom::random_f64() return random_u64() / (double)(~(uint64_t)0) ; } -std::string RsRandom::random_alphaNumericString(uint32_t len) +/*static*/ std::string RsRandom::alphaNumeric(uint32_t length) { - std::string s = "" ; + std::string s; + while(s.size() < length) + { + uint8_t rChar; random_bytes(&rChar, 1); rChar = rChar % 123; + /* if(isalnum(val)) isalnum result may vary depend on locale!! */ + if( (rChar >= 48 && rChar <= 57) /* 0-9 */ || + (rChar >= 65 && rChar <= 90) /* A-Z */ || + (rChar >= 97 && rChar <= 122) /* a-z */ ) + s += static_cast(rChar); + } - for(uint32_t i=0;i(&ret[0]), length); + for(uint32_t i=0; i Date: Sat, 13 Jun 2020 10:57:08 +0200 Subject: [PATCH 088/154] fix typo --- libretroshare/src/services/autoproxy/rsautoproxymonitor.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc b/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc index 3c52cfdc5..d58c871e3 100644 --- a/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc +++ b/libretroshare/src/services/autoproxy/rsautoproxymonitor.cc @@ -265,7 +265,7 @@ void rsAutoProxyMonitor::taskDone(taskTicket *t, autoProxyStatus::autoProxyStatu // we must take care of deleting cleanUp = true; if(t->data) - RS_ERR("sync call with data attached but no callback set!"); + RS_ERR("async call with data attached but no callback set!"); } if (cleanUp) { From 8323b94a6a13e574e95f909f3b6670568b85d945 Mon Sep 17 00:00:00 2001 From: sehraf Date: Sat, 13 Jun 2020 10:58:44 +0200 Subject: [PATCH 089/154] use modern c++ --- libretroshare/src/util/i2pcommon.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libretroshare/src/util/i2pcommon.cpp b/libretroshare/src/util/i2pcommon.cpp index 575b0fec0..eef359576 100644 --- a/libretroshare/src/util/i2pcommon.cpp +++ b/libretroshare/src/util/i2pcommon.cpp @@ -39,10 +39,7 @@ std::string keyToBase32Addr(const std::string &key) } const std::string makeOption(const std::string &lhs, const int8_t &rhs) { - // convert number to int - std::ostringstream oss; - oss << (int)rhs; - return lhs + "=" + oss.str(); + return lhs + "=" + std::to_string(rhs); } uint16_t readTwoBytesBE(std::vector::const_iterator &p) From f18d49db483b0dc9d8f8371b538dd8f7d506a419 Mon Sep 17 00:00:00 2001 From: sehraf Date: Sat, 13 Jun 2020 11:07:07 +0200 Subject: [PATCH 090/154] use RsRandom::alphaNumeric --- libretroshare/src/services/autoproxy/p3i2pbob.cc | 10 +++------- libretroshare/src/util/i2pcommon.cpp | 8 -------- libretroshare/src/util/i2pcommon.h | 13 ------------- 3 files changed, 3 insertions(+), 28 deletions(-) diff --git a/libretroshare/src/services/autoproxy/p3i2pbob.cc b/libretroshare/src/services/autoproxy/p3i2pbob.cc index a170d08ca..f9eb3d9b3 100644 --- a/libretroshare/src/services/autoproxy/p3i2pbob.cc +++ b/libretroshare/src/services/autoproxy/p3i2pbob.cc @@ -945,13 +945,9 @@ void p3I2pBob::finalizeSettings_locked() // setup commands // new lines are appended later! - // generate random suffix for name - // RSRandom::random_alphaNumericString can return very weird looking strings like: ,,@z+M - // use base32 instead - size_t len = 5; // 5 characters = 8 base32 symbols - std::vector tmp(len); - RSRandom::random_bytes(tmp.data(), len); - const std::string location = Radix32::encode(tmp.data(), len); + // generate 8 characater long random suffix for name + constexpr size_t len = 8; + const std::string location = RsRandom::alphaNumeric(len); RS_DBG4("using suffix ", location); mTunnelName = "RetroShare-" + location; diff --git a/libretroshare/src/util/i2pcommon.cpp b/libretroshare/src/util/i2pcommon.cpp index eef359576..ec2ebfd6b 100644 --- a/libretroshare/src/util/i2pcommon.cpp +++ b/libretroshare/src/util/i2pcommon.cpp @@ -5,14 +5,6 @@ namespace i2p { -const std::string generateNameSuffix(const size_t len) { - std::vector tmp(len); - RsRandom::random_bytes(tmp.data(), len); - const std::string location = Radix32::encode(tmp.data(), len); - - return location; -} - std::string keyToBase32Addr(const std::string &key) { std::string copy(key); diff --git a/libretroshare/src/util/i2pcommon.h b/libretroshare/src/util/i2pcommon.h index 63f1ba5af..01d655bf9 100644 --- a/libretroshare/src/util/i2pcommon.h +++ b/libretroshare/src/util/i2pcommon.h @@ -184,19 +184,6 @@ static const std::array, 12> signingKeyLengths { /*SigningKeyType::RedDSA_SHA512_Ed25519 */ std::make_pair( 32, 32), }; - -/** - * @brief generateNameSuffix Generates a base32 name suffix for tunnel identification - * @param len lenght of random bytes, will be expanded by base32 encoding - * @return base32 string - * - * RSRandom::random_alphaNumericString can return very weird looking strings like: ,,@z+M - * -> so use base32 instead - * - * 5 characters = 8 base32 symbols - */ -const std::string generateNameSuffix(const size_t len = 5); - /** * @brief makeOption Creates the string "lhs=rhs" used by BOB and SAM. Converts rhs * @param lhs option to set From ebaf5e63c3f4135a847a85d1aa607a4c19144f2f Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 13 Jun 2020 13:38:19 +0200 Subject: [PATCH 091/154] added star for new posts --- .../GxsChannelPostsWidgetWithModel.cpp | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 49d0ace88..5f3fb58de 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -77,6 +77,7 @@ static const int CHANNEL_TABS_POSTS = 1; // This variable determines the zoom factor on the text below thumbnails. 2.0 is mostly correct for all screen. #define THUMBNAIL_OVERSAMPLE_FACTOR 2.0 +#define STAR_OVERLAY_IMAGE ":icons/star_overlay_128.png" Q_DECLARE_METATYPE(RsGxsFile) @@ -103,23 +104,19 @@ public: // now fill the data + QPixmap thumbnail; + if(post.mThumbnail.mSize > 0) - { - QPixmap thumbnail; GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL); - lb->setPixmap(thumbnail); - } else if(post.mMeta.mPublishTs > 0) // this is for testing that the post is not an empty post (happens at the end of the last row) - { - QPixmap thumbnail = FilesDefs::getPixmapFromQtResourcePath(CHAN_DEFAULT_IMAGE); - lb->setPixmap(thumbnail); - } + thumbnail = FilesDefs::getPixmapFromQtResourcePath(CHAN_DEFAULT_IMAGE); QFontMetricsF fm(font()); int W = THUMBNAIL_OVERSAMPLE_FACTOR * THUMBNAIL_W * fm.height() ; int H = THUMBNAIL_OVERSAMPLE_FACTOR * THUMBNAIL_H * fm.height() ; lb->setFixedSize(W,H); + lb->setPixmap(thumbnail); lt->setText(QString::fromUtf8(post.mMeta.mMsgName.c_str())); @@ -164,6 +161,13 @@ void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & w.render(&pixmap,QPoint(),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background + if(IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus)) + { + QPainter p(&pixmap); + QFontMetricsF fm(option.font); + p.drawPixmap(QPoint(6.2*fm.height(),6.9*fm.height()),FilesDefs::getPixmapFromQtResourcePath(STAR_OVERLAY_IMAGE).scaled(7*fm.height(),7*fm.height(),Qt::KeepAspectRatio,Qt::SmoothTransformation)); + } + // debug // if(index.row()==0 && index.column()==0) // { From f8deebfc5a85237e4c17695856bacb81a216c7a0 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 13 Jun 2020 14:31:39 +0200 Subject: [PATCH 092/154] fixed updating of data after read status change --- .../gui/gxschannels/GxsChannelPostsModel.cpp | 71 ++++++++++++++++++- .../gui/gxschannels/GxsChannelPostsModel.h | 5 +- .../GxsChannelPostsWidgetWithModel.cpp | 5 +- 3 files changed, 77 insertions(+), 4 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index ae2c3d119..9c40f97e3 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -43,7 +43,76 @@ std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsew RsGxsChannelPostsModel::RsGxsChannelPostsModel(QObject *parent) : QAbstractItemModel(parent), mTreeMode(TREE_MODE_PLAIN), mColumns(6) { - initEmptyHierarchy(); + initEmptyHierarchy(); + + mEventHandlerId = 0; + // Needs to be asynced because this function is called by another thread! + + rsEvents->registerEventsHandler( [this](std::shared_ptr event) + { + RsQThreadUtils::postToObject([=](){ handleEvent_main_thread(event); }, this ); + }, mEventHandlerId, RsEventType::GXS_CHANNELS ); +} + +RsGxsChannelPostsModel::~RsGxsChannelPostsModel() +{ + rsEvents->unregisterEventsHandler(mEventHandlerId); +} + +void RsGxsChannelPostsModel::handleEvent_main_thread(std::shared_ptr event) +{ + const RsGxsChannelEvent *e = dynamic_cast(event.get()); + + if(!e) + return; + + switch(e->mChannelEventCode) + { + case RsChannelEventCode::UPDATED_MESSAGE: + case RsChannelEventCode::READ_STATUS_CHANGED: + { + // Normally we should just emit dataChanged() on the index of the data that has changed: + // + // We need to update the data! + + if(e->mChannelGroupId == mChannelGroup.mMeta.mGroupId) + RsThread::async([this, e]() + { + // 1 - get message data from p3GxsChannels + + std::vector posts; + std::vector comments; + std::vector votes; + + if(!rsGxsChannels->getChannelContent(mChannelGroup.mMeta.mGroupId,std::set{ e->mChannelMsgId }, posts,comments,votes)) + { + std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve channel message data for channel/msg " << e->mChannelGroupId << "/" << e->mChannelMsgId << std::endl; + return; + } + + // 2 - update the model in the UI thread. + + RsQThreadUtils::postToObject( [posts,comments,votes,this]() + { + for(uint32_t i=0;i #include @@ -62,7 +63,7 @@ class RsGxsChannelPostsModel : public QAbstractItemModel public: explicit RsGxsChannelPostsModel(QObject *parent = NULL); - ~RsGxsChannelPostsModel(){} + virtual ~RsGxsChannelPostsModel() override; static const int COLUMN_THREAD_NB_COLUMNS = 0x01; @@ -217,6 +218,7 @@ private: void createPostsArray(std::vector &posts); void setPosts(const RsGxsChannelGroup& group, std::vector &posts); void initEmptyHierarchy(); + void handleEvent_main_thread(std::shared_ptr event); std::vector mFilteredPosts; // stores the list of displayes indices due to filtering. std::vector mPosts ; // store the list of posts updated from rsForums. @@ -229,5 +231,6 @@ private: QColor mTextColorNotSubscribed ; QColor mTextColorMissing ; + RsEventsHandlerId_t mEventHandlerId ; friend class const_iterator; }; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 5f3fb58de..6faf2d122 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -428,10 +428,11 @@ void GxsChannelPostsWidgetWithModel::handleEvent_main_thread(std::shared_ptrmChannelGroupId == groupId()) updateDisplay(true); - break; + } + default: break; } From f13b429f1c09adff8bd99439e1c4a26766d305f8 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Sat, 13 Jun 2020 14:58:30 +0200 Subject: [PATCH 093/154] Document what chars are return RsRandom::alphaNumeric As requested by Cyril --- libretroshare/src/util/rsrandom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretroshare/src/util/rsrandom.h b/libretroshare/src/util/rsrandom.h index 5e7e0d92c..94d619537 100644 --- a/libretroshare/src/util/rsrandom.h +++ b/libretroshare/src/util/rsrandom.h @@ -48,7 +48,7 @@ public: static void random_bytes(uint8_t* data, uint32_t length); - /** Return a random alphanumeric string of the given lenght */ + /// Return a random alphanumeric *[0-9,A-Z,a-z] string of the given lenght static std::string alphaNumeric(uint32_t length); /** Return a random printable string of the given lenght */ From f1092b4a292c3b573c389d757061c657b98b563b Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 13 Jun 2020 15:00:30 +0200 Subject: [PATCH 094/154] added post editing --- .../GxsChannelPostsWidgetWithModel.cpp | 64 +++++++------------ .../GxsChannelPostsWidgetWithModel.h | 2 + .../GxsChannelPostsWidgetWithModel.ui | 3 + 3 files changed, 28 insertions(+), 41 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 6faf2d122..477c4f850 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -19,6 +19,7 @@ *******************************************************************************/ #include +#include #include #include @@ -261,40 +262,6 @@ QSize ChannelPostFilesDelegate::sizeHint(const QStyleOptionViewItem& option, con } } -// class RsGxsChannelPostFilesProxyModel: public QSortFilterProxyModel -// { -// public: -// RsGxsChannelPostFilesProxyModel(QObject *parent = NULL): QSortFilterProxyModel(parent) {} -// -// bool lessThan(const QModelIndex& left, const QModelIndex& right) const override -// { -// return left.data(RsGxsChannelPostFilesModel::SortRole) < right.data(RsGxsChannelPostFilesModel::SortRole) ; -// } -// -// bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override -// { -// if(filter_list.empty()) -// return true; -// -// QString name = sourceModel()->data(sourceModel()->index(source_row,RsGxsChannelPostFilesModel::COLUMN_FILES_NAME,source_parent)).toString(); -// -// for(auto& s:filter_list) -// if(!name.contains(s,Qt::CaseInsensitive)) -// return false; -// -// return true; -// } -// -// void setFilterList(const QStringList& str) -// { -// filter_list = str; -// invalidateFilter(); -// } -// -// private: -// QStringList filter_list; -// }; - /** Constructor */ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupId &channelId, QWidget *parent) : GxsMessageFrameWidget(rsGxsChannels, parent), @@ -312,11 +279,6 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->channelPostFiles_TV->setSortingEnabled(true); ui->channelPostFiles_TV->sortByColumn(0, Qt::AscendingOrder); -// mChannelPostFilesProxyModel = new RsGxsChannelPostFilesProxyModel(this); -// mChannelPostFilesProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); -// mChannelPostFilesProxyModel->setSourceModel(mChannelPostFilesModel); -// mChannelPostFilesProxyModel->setDynamicSortFilter(true); - ui->channelFiles_TV->setModel(mChannelFilesModel = new RsGxsChannelPostFilesModel()); ui->channelFiles_TV->setItemDelegate(new ChannelPostFilesDelegate()); ui->channelFiles_TV->setPlaceholderText(tr("No files in the channel, or no channel selected")); @@ -327,6 +289,8 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI connect(ui->channelFiles_TV->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortColumnFiles(int,Qt::SortOrder))); connect(ui->postsTree->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),this,SLOT(showPostDetails())); + connect(ui->postsTree,SIGNAL(customContextMenuRequested(const QPoint&)),this,SLOT(postContextMenu(const QPoint&))); + connect(mChannelPostsModel,SIGNAL(channelPostsLoaded()),this,SLOT(postChannelPostLoad())); ui->postName_LB->hide(); @@ -404,10 +368,28 @@ void GxsChannelPostsWidgetWithModel::sortColumnFiles(int col,Qt::SortOrder so) mChannelFilesModel->sort(col,so); } +void GxsChannelPostsWidgetWithModel::postContextMenu(const QPoint&) +{ + QMenu menu(this); + + if(IS_GROUP_PUBLISHER(mGroup.mMeta.mSubscribeFlags)) + { + menu.addAction(FilesDefs::getIconFromQtResourcePath(":/images/edit_16.png"), tr("Edit"), this, SLOT(editPost())); + menu.exec(QCursor::pos()); + } +} + +void GxsChannelPostsWidgetWithModel::editPost() +{ + QModelIndex index = ui->postsTree->selectionModel()->currentIndex(); + RsGxsChannelPost post = index.data(Qt::UserRole).value() ; + + CreateGxsChannelMsg *msgDialog = new CreateGxsChannelMsg(post.mMeta.mGroupId,post.mMeta.mMsgId); + msgDialog->show(); +} + void GxsChannelPostsWidgetWithModel::handlePostsTreeSizeChange(QSize s) { -// adjustSize(); -// int n_columns = std::max(1,(int)floor(s.width() / (COLUMN_SIZE_FONT_FACTOR_W*QFontMetricsF(font()).height()))); std::cerr << "nb columns: " << n_columns << std::endl; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index 5f2f4adae..f278fcf89 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -139,6 +139,8 @@ private slots: void settingsChanged(); void handlePostsTreeSizeChange(QSize s); void postChannelPostLoad(); + void editPost(); + void postContextMenu(const QPoint&); public slots: void sortColumnFiles(int col,Qt::SortOrder so); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index 71412862e..20b8e27c4 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -364,6 +364,9 @@ p, li { white-space: pre-wrap; } Qt::Vertical + + Qt::CustomContextMenu + QAbstractScrollArea::AdjustToContents From fd85965e7d6610b71d7f09d04cba941fe364d639 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 13 Jun 2020 16:14:15 +0200 Subject: [PATCH 095/154] added preview widget when creating pochannel posts --- .../gui/gxschannels/CreateGxsChannelMsg.cpp | 14 +- .../src/gui/gxschannels/CreateGxsChannelMsg.h | 1 + .../gui/gxschannels/CreateGxsChannelMsg.ui | 418 +++++++++--------- .../gui/gxschannels/GxsChannelPostThumbnail.h | 123 ++++++ .../GxsChannelPostsWidgetWithModel.cpp | 71 +-- retroshare-gui/src/retroshare-gui.pro | 1 + 6 files changed, 354 insertions(+), 274 deletions(-) create mode 100644 retroshare-gui/src/gui/gxschannels/GxsChannelPostThumbnail.h diff --git a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp index 56c910237..ef1a6271e 100644 --- a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp +++ b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.cpp @@ -72,7 +72,8 @@ CreateGxsChannelMsg::CreateGxsChannelMsg(const RsGxsGroupId &cId, RsGxsMessageId connect(addFileButton, SIGNAL(clicked() ), this , SLOT(addExtraFile())); connect(addfilepushButton, SIGNAL(clicked() ), this , SLOT(addExtraFile())); - + connect(subjectEdit,SIGNAL(textChanged(const QString&)),this,SLOT(updatePreviewText(const QString&))); + connect(addThumbnailButton, SIGNAL(clicked() ), this , SLOT(addThumbnail())); connect(thumbNailCb, SIGNAL(toggled(bool)), this, SLOT(allowAutoMediaThumbNail(bool))); connect(stackedWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenu(QPoint))); @@ -605,6 +606,11 @@ void CreateGxsChannelMsg::saveChannelInfo(const RsGroupMetaData &meta) subjectEdit->setFocus(); } +void CreateGxsChannelMsg::updatePreviewText(const QString& s) +{ + preview_W->setText(s); +} + void CreateGxsChannelMsg::sendMsg() { #ifdef DEBUG_CREATE_GXS_MSG @@ -717,7 +723,7 @@ void CreateGxsChannelMsg::sendMessage(const std::string &subject, const std::str void CreateGxsChannelMsg::addThumbnail() { - QPixmap img = misc::getOpenThumbnailedPicture(this, tr("Load thumbnail picture"), 156, 107); + QPixmap img = misc::getOpenThumbnailedPicture(this, tr("Load thumbnail picture"), 107,156); // these absolute sizes are terrible if (img.isNull()) return; @@ -725,7 +731,7 @@ void CreateGxsChannelMsg::addThumbnail() picture = img; // to show the selected - thumbnail_label->setPixmap(picture); + preview_W->setPixmap(picture); } void CreateGxsChannelMsg::loadOriginalChannelPostInfo() @@ -769,7 +775,7 @@ void CreateGxsChannelMsg::loadOriginalChannelPostInfo() if(post.mThumbnail.mData != NULL) { GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData,post.mThumbnail.mSize,picture,GxsIdDetails::ORIGINAL); - thumbnail_label->setPixmap(picture); + preview_W->setPixmap(picture); } diff --git a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.h b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.h index 7c1058695..44d867ba2 100644 --- a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.h +++ b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.h @@ -58,6 +58,7 @@ private slots: void addExtraFile(); void checkAttachmentReady(); void deleteAttachment(); + void updatePreviewText(const QString &); void cancelMsg(); void sendMsg(); diff --git a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.ui b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.ui index 703f43bb1..d8baaba24 100644 --- a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.ui +++ b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.ui @@ -52,52 +52,39 @@ QFrame::Raised - - - - Channel Post - - - - :/icons/png/comment.png:/icons/png/comment.png - - - - 24 - 24 - - - - - - - - Attachments - - - - :/icons/png/attachements.png:/icons/png/attachements.png - - - - 24 - 24 - - - - - - - - Qt::Horizontal - - - - 486 - 20 - - - + + + + + + Generate mass data + + + + + + + 1 + + + 999 + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + @@ -114,128 +101,8 @@ 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - 156 - 107 - - - - - 0 - 0 - - - - :/images/thumb-default-video.png - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt; font-weight:600;">Attachments:</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src=":/images/feedback_arrow.png" /><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;"> Use Drag and Drop / Add Files button, to Hash new files.</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src=":/images/feedback_arrow.png" /><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;"> Copy/Paste RetroShare links from your shares</span></p></body></html> - - - - - - - Add Channel Thumbnail - - - - :/icons/png/add-image.png:/icons/png/add-image.png - - - - 24 - 24 - - - - - - - - Add File to Attach - - - - :/icons/png/add-file.png:/icons/png/add-file.png - - - - 24 - 24 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 40 - 20 - - - - - - - - - - Message - - - - 0 - - - - - Title - - - - - - - - - - + + @@ -268,6 +135,119 @@ p, li { white-space: pre-wrap; } + + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt; font-weight:600;">Attachments:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src=":/images/feedback_arrow.png" /><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;"> Use Drag and Drop / Add Files button, to Hash new files.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src=":/images/feedback_arrow.png" /><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;"> Copy/Paste RetroShare links from your shares</span></p></body></html> + + + + + + + + + Add Channel Thumbnail + + + + :/icons/png/add-image.png:/icons/png/add-image.png + + + + 24 + 24 + + + + + + + + Add File to Attach + + + + :/icons/png/add-file.png:/icons/png/add-file.png + + + + 24 + 24 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Message + + + + 0 + + + + + Title + + + + + + + + + @@ -329,7 +309,7 @@ p, li { white-space: pre-wrap; } 0 0 - 632 + 635 24 @@ -403,39 +383,65 @@ p, li { white-space: pre-wrap; } - - - - - - Generate mass data - - - - - - - 1 - - - 999 - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - + + + + Qt::Horizontal + + + + 486 + 20 + + + + + + + + Attachments + + + + :/icons/png/attachements.png:/icons/png/attachements.png + + + + 24 + 24 + + + + + + + + Channel Post + + + + :/icons/png/comment.png:/icons/png/comment.png + + + + 24 + 24 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + @@ -455,10 +461,16 @@ p, li { white-space: pre-wrap; }
util/RichTextEdit.h
1 + + ChannelPostThumbnailView + QWidget +
gui/gxschannels/GxsChannelPostThumbnail.h
+ 1 +
- + diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostThumbnail.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostThumbnail.h new file mode 100644 index 000000000..fd5c82d6b --- /dev/null +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostThumbnail.h @@ -0,0 +1,123 @@ +/******************************************************************************* + * retroshare-gui/src/gui/gxschannels/GxsChannelPostThumbnail.h * + * * + * Copyright 2020 by Retroshare Team * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#pragma once + +#include + +#include +#include +#include + +#include "retroshare/rsgxschannels.h" +#include "retroshare/rsidentity.h" + +#include "gui/gxs/GxsIdDetails.h" +#include "gui/common/FilesDefs.h" + +// Class to paint the thumbnails with title + +class ChannelPostThumbnailView: public QWidget +{ +public: + // This variable determines the zoom factor on the text below thumbnails. 2.0 is mostly correct for all screen. + static constexpr float THUMBNAIL_OVERSAMPLE_FACTOR = 2.0; + + // Size of thumbnails as a function of the height of the font. An aspect ratio of 3/4 is good. + + static const int THUMBNAIL_W = 4; + static const int THUMBNAIL_H = 6; + + static constexpr char *CHAN_DEFAULT_IMAGE = ":images/thumb-default-video.png"; + + virtual ~ChannelPostThumbnailView() + { + delete lb; + delete lt; + } + + ChannelPostThumbnailView(QWidget *parent=NULL): QWidget(parent) + { + init(FilesDefs::getPixmapFromQtResourcePath(CHAN_DEFAULT_IMAGE), QString("New post"),false); + } + + ChannelPostThumbnailView(const RsGxsChannelPost& post,QWidget *parent=NULL) + : QWidget(parent) + { + // now fill the data + + QPixmap thumbnail; + + if(post.mThumbnail.mSize > 0) + GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL); + else if(post.mMeta.mPublishTs > 0) // this is for testing that the post is not an empty post (happens at the end of the last row) + thumbnail = FilesDefs::getPixmapFromQtResourcePath(CHAN_DEFAULT_IMAGE); + + init(thumbnail, QString::fromUtf8(post.mMeta.mMsgName.c_str()), IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus) ); + + } + + void init(const QPixmap& thumbnail,const QString& msg,bool is_msg_new) + { + QVBoxLayout *layout = new QVBoxLayout(this); + + lb = new QLabel(this); + lb->setScaledContents(true); + layout->addWidget(lb); + + lt = new QLabel(this); + layout->addWidget(lt); + + setLayout(layout); + + setSizePolicy(QSizePolicy::Maximum,QSizePolicy::Maximum); + + QFontMetricsF fm(font()); + int W = THUMBNAIL_OVERSAMPLE_FACTOR * THUMBNAIL_W * fm.height() ; + int H = THUMBNAIL_OVERSAMPLE_FACTOR * THUMBNAIL_H * fm.height() ; + + lb->setFixedSize(W,H); + lb->setPixmap(thumbnail); + + lt->setText(msg); + + QFont font = lt->font(); + + if(is_msg_new) + { + font.setBold(true); + lt->setFont(font); + } + + lt->setMaximumWidth(W); + lt->setWordWrap(true); + + adjustSize(); + update(); + } + + void setPixmap(const QPixmap& p) { lb->setPixmap(p); } + void setText(const QString& s) { lt->setText(s); } + +private: + QLabel *lb; + QLabel *lt; +}; + diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 477c4f850..2d64bf8c8 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -44,11 +44,10 @@ #include "GxsChannelPostsModel.h" #include "GxsChannelPostFilesModel.h" #include "GxsChannelFilesStatusWidget.h" +#include "GxsChannelPostThumbnail.h" #include -#define CHAN_DEFAULT_IMAGE ":images/thumb-default-video.png" - #define ROLE_PUBLISH FEED_TREEWIDGET_SORTROLE /**** @@ -64,11 +63,6 @@ static const int CHANNEL_TABS_POSTS = 1; #define VIEW_MODE_FEEDS 1 #define VIEW_MODE_FILES 2 -// Size of thumbnails as a function of the height of the font. An aspect ratio of 3/4 is good. - -#define THUMBNAIL_W 4 -#define THUMBNAIL_H 6 - // Determine the Shape and size of cells as a factor of the font height. An aspect ratio of 3/4 is what's needed // for the image, so it's important that the height is a bit larger so as to leave some room for the text. // @@ -76,67 +70,10 @@ static const int CHANNEL_TABS_POSTS = 1; #define COLUMN_SIZE_FONT_FACTOR_W 6 #define COLUMN_SIZE_FONT_FACTOR_H 10 -// This variable determines the zoom factor on the text below thumbnails. 2.0 is mostly correct for all screen. -#define THUMBNAIL_OVERSAMPLE_FACTOR 2.0 #define STAR_OVERLAY_IMAGE ":icons/star_overlay_128.png" Q_DECLARE_METATYPE(RsGxsFile) -// Class to paint the thumbnails with title - -class ThumbnailView: public QWidget -{ -public: - ThumbnailView(const RsGxsChannelPost& post,QWidget *parent=NULL) - : QWidget(parent) - { - QVBoxLayout *layout = new QVBoxLayout(this); - - QLabel *lb = new QLabel(this); - lb->setScaledContents(true); - layout->addWidget(lb); - - QLabel *lt = new QLabel(this); - layout->addWidget(lt); - - setLayout(layout); - - setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding); - - // now fill the data - - QPixmap thumbnail; - - if(post.mThumbnail.mSize > 0) - GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL); - else if(post.mMeta.mPublishTs > 0) // this is for testing that the post is not an empty post (happens at the end of the last row) - thumbnail = FilesDefs::getPixmapFromQtResourcePath(CHAN_DEFAULT_IMAGE); - - QFontMetricsF fm(font()); - int W = THUMBNAIL_OVERSAMPLE_FACTOR * THUMBNAIL_W * fm.height() ; - int H = THUMBNAIL_OVERSAMPLE_FACTOR * THUMBNAIL_H * fm.height() ; - - lb->setFixedSize(W,H); - lb->setPixmap(thumbnail); - - lt->setText(QString::fromUtf8(post.mMeta.mMsgName.c_str())); - - QFont font = lt->font(); - - if(IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus)) - { - font.setBold(true); - lt->setFont(font); - } - - lt->setMaximumWidth(W); - lt->setWordWrap(true); - - adjustSize(); - update(); - } -}; - // Delegate used to paint into the table of thumbnails void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const @@ -151,7 +88,7 @@ void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & painter->fillRect( option.rect, option.backgroundBrush); painter->restore(); - ThumbnailView w(post); + ChannelPostThumbnailView w(post); QPixmap pixmap(w.size()); @@ -463,7 +400,7 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() if (post.mThumbnail.mData != NULL) GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, postImage,GxsIdDetails::ORIGINAL); else - postImage = FilesDefs::getPixmapFromQtResourcePath(CHAN_DEFAULT_IMAGE); + postImage = FilesDefs::getPixmapFromQtResourcePath(ChannelPostThumbnailView::CHAN_DEFAULT_IMAGE); int W = QFontMetricsF(font()).height() * 8; @@ -689,7 +626,7 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou if (group.mImage.mData != NULL) { GxsIdDetails::loadPixmapFromData(group.mImage.mData, group.mImage.mSize, chanImage,GxsIdDetails::ORIGINAL); } else { - chanImage = QPixmap(CHAN_DEFAULT_IMAGE); + chanImage = QPixmap(ChannelPostThumbnailView::CHAN_DEFAULT_IMAGE); } if(group.mMeta.mGroupName.empty()) ui->channelName_LB->setText(tr("[No name]")); diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 69dfc6b85..ce23a4f9c 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -1337,6 +1337,7 @@ gxschannels { gui/gxschannels/GxsChannelPostsModel.h \ gui/gxschannels/GxsChannelPostFilesModel.h \ gui/gxschannels/GxsChannelFilesWidget.h \ + gui/gxschannels/GxsChannelPostThumbnail.h \ gui/gxschannels/GxsChannelFilesStatusWidget.h \ gui/feeds/GxsChannelGroupItem.h \ gui/feeds/GxsChannelPostItem.h \ From d1d977376d611cd0f2ad0ef5f9909799a8219f5f Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 14 Jun 2020 13:03:12 +0200 Subject: [PATCH 096/154] improved scrolling and explicitly disabled horizontal scroll slider --- .../src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 2d64bf8c8..b834e42e2 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -209,6 +209,9 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->postsTree->setModel(mChannelPostsModel = new RsGxsChannelPostsModel()); ui->postsTree->setItemDelegate(new ChannelPostDelegate()); + ui->postsTree->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // prevents bug on w10, since row size depends on widget width + ui->postsTree->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);// more beautiful if we scroll at pixel level + ui->postsTree->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); ui->channelPostFiles_TV->setModel(mChannelPostFilesModel = new RsGxsChannelPostFilesModel(this)); ui->channelPostFiles_TV->setItemDelegate(new ChannelPostFilesDelegate()); From 0b06515dfe3b50e58b62a873df3c0d5b2d23148a Mon Sep 17 00:00:00 2001 From: defnax Date: Thu, 11 Jun 2020 16:32:55 +0200 Subject: [PATCH 097/154] Added open file feature for file status widget * Added open file feature for file status widget --- .../GxsChannelFilesStatusWidget.cpp | 70 +++++++++++++++--- .../gxschannels/GxsChannelFilesStatusWidget.h | 1 + .../GxsChannelFilesStatusWidget.ui | 22 +++++- retroshare-gui/src/gui/icons.qrc | 1 + retroshare-gui/src/gui/icons/png/arrow.png | Bin 0 -> 935 bytes 5 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 retroshare-gui/src/gui/icons/png/arrow.png diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.cpp index c28601fed..bc019e426 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.cpp @@ -18,6 +18,7 @@ * * *******************************************************************************/ +#include #include #include #include @@ -27,6 +28,8 @@ #include "GxsChannelFilesStatusWidget.h" #include "ui_GxsChannelFilesStatusWidget.h" #include "gui/common/RsUrlHandler.h" +#include "gui/common/FilesDefs.h" +#include "util/misc.h" #include "retroshare/rsfiles.h" @@ -40,11 +43,21 @@ GxsChannelFilesStatusWidget::GxsChannelFilesStatusWidget(const RsGxsFile &file, setSize(mFile.mSize); /* Connect signals */ - connect(ui->downloadToolButton, SIGNAL(clicked()), this, SLOT(download())); + connect(ui->downloadPushButton, SIGNAL(clicked()), this, SLOT(download())); connect(ui->resumeToolButton, SIGNAL(clicked()), this, SLOT(resume())); connect(ui->pauseToolButton, SIGNAL(clicked()), this, SLOT(pause())); connect(ui->cancelToolButton, SIGNAL(clicked()), this, SLOT(cancel())); - connect(ui->openFolderToolButton, SIGNAL(clicked()), this, SLOT(openFolder())); + connect(ui->openFilePushButton, SIGNAL(clicked()), this, SLOT(openFile())); + + ui->downloadPushButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/download.png")); + ui->openFolderToolButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/arrow.png")); + + QAction *openfolder = new QAction(tr("Open folder"), this); + connect(openfolder, SIGNAL(triggered()), this, SLOT(openFolder())); + + QMenu *menu = new QMenu(); + menu->addAction(openfolder); + ui->openFolderToolButton->setMenu(menu); check(); } @@ -80,6 +93,17 @@ void GxsChannelFilesStatusWidget::check() if (rsFiles->alreadyHaveFile(mFile.mHash, fileInfo)) { mState = STATE_LOCAL; setSize(fileInfo.size); + + /* check if the file is a media file */ + if (!misc::isPreviewable(QFileInfo(QString::fromUtf8(fileInfo.path.c_str())).suffix())) + { + /* check if the file is not a media file and change text */ + ui->openFilePushButton->setText(tr("Open file")); + } else { + ui->openFilePushButton->setText(tr("Play")); + ui->openFilePushButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/play.png")); + } + } else { FileInfo fileInfo; bool detailsOk = rsFiles->FileDetails(mFile.mHash, RS_FILE_HINTS_DOWNLOAD | RS_FILE_HINTS_SPEC_ONLY, fileInfo); @@ -126,11 +150,12 @@ void GxsChannelFilesStatusWidget::check() case STATE_ERROR: repeat = 0; - ui->downloadToolButton->hide(); + ui->downloadPushButton->hide(); ui->resumeToolButton->hide(); ui->pauseToolButton->hide(); ui->cancelToolButton->hide(); ui->progressBar->hide(); + ui->openFilePushButton->hide(); ui->openFolderToolButton->hide(); statusText = tr("Error"); @@ -140,11 +165,12 @@ void GxsChannelFilesStatusWidget::check() case STATE_REMOTE: repeat = 30000; - ui->downloadToolButton->show(); + ui->downloadPushButton->show(); ui->resumeToolButton->hide(); ui->pauseToolButton->hide(); ui->cancelToolButton->hide(); ui->progressBar->hide(); + ui->openFilePushButton->hide(); ui->openFolderToolButton->hide(); break; @@ -152,11 +178,12 @@ void GxsChannelFilesStatusWidget::check() case STATE_DOWNLOAD: repeat = 1000; - ui->downloadToolButton->hide(); + ui->downloadPushButton->hide(); ui->resumeToolButton->hide(); ui->pauseToolButton->show(); ui->cancelToolButton->show(); ui->progressBar->show(); + ui->openFilePushButton->hide(); ui->openFolderToolButton->hide(); break; @@ -164,11 +191,12 @@ void GxsChannelFilesStatusWidget::check() case STATE_PAUSED: repeat = 1000; - ui->downloadToolButton->hide(); + ui->downloadPushButton->hide(); ui->resumeToolButton->show(); ui->pauseToolButton->hide(); ui->cancelToolButton->show(); ui->progressBar->hide(); + ui->openFilePushButton->hide(); ui->openFolderToolButton->hide(); statusText = tr("Paused"); @@ -178,11 +206,12 @@ void GxsChannelFilesStatusWidget::check() case STATE_WAITING: repeat = 1000; - ui->downloadToolButton->hide(); + ui->downloadPushButton->hide(); ui->resumeToolButton->hide(); ui->pauseToolButton->show(); ui->cancelToolButton->show(); ui->progressBar->hide(); + ui->openFilePushButton->hide(); ui->openFolderToolButton->hide(); statusText = tr("Waiting"); @@ -192,11 +221,12 @@ void GxsChannelFilesStatusWidget::check() case STATE_CHECKING: repeat = 1000; - ui->downloadToolButton->hide(); + ui->downloadPushButton->hide(); ui->resumeToolButton->hide(); ui->pauseToolButton->hide(); ui->cancelToolButton->show(); ui->progressBar->hide(); + ui->openFilePushButton->hide(); ui->openFolderToolButton->hide(); statusText = tr("Checking"); @@ -206,11 +236,12 @@ void GxsChannelFilesStatusWidget::check() case STATE_LOCAL: repeat = 60000; - ui->downloadToolButton->hide(); + ui->downloadPushButton->hide(); ui->resumeToolButton->hide(); ui->pauseToolButton->hide(); ui->cancelToolButton->hide(); ui->progressBar->hide(); + ui->openFilePushButton->show(); ui->openFolderToolButton->show(); break; @@ -296,3 +327,24 @@ void GxsChannelFilesStatusWidget::openFolder() } } } + +void GxsChannelFilesStatusWidget::openFile() +{ + FileInfo fileInfo; + if (!rsFiles->alreadyHaveFile(mFile.mHash, fileInfo)) { + return; + } + + /* open file with a suitable application */ + QFileInfo qinfo; + qinfo.setFile(QString::fromUtf8(fileInfo.path.c_str())); + if (qinfo.exists()) { + if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(qinfo.absoluteFilePath()))) { + std::cerr << "GxsChannelFilesStatusWidget(): can't open file " << fileInfo.path << std::endl; + } + }else{ + QMessageBox::information(this, tr("Play File"), + tr("File %1 does not exist at location.").arg(fileInfo.path.c_str())); + return; + } +} diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.h b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.h index 3d58cc4d7..1effe0549 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.h @@ -44,6 +44,7 @@ private slots: void pause(); void resume(); void openFolder(); + void openFile(); private: void setSize(uint64_t size); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.ui index 39e32271d..c1b02ab83 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelFilesStatusWidget.ui @@ -48,7 +48,7 @@ 2 - + 0 @@ -126,18 +126,31 @@ - + 0 0 + + Play + + + + + + + + 0 + 0 + + Qt::NoFocus - - Open folder + + QToolButton::InstantPopup @@ -148,6 +161,7 @@
+ diff --git a/retroshare-gui/src/gui/icons.qrc b/retroshare-gui/src/gui/icons.qrc index 6e4bd7569..656cdc7fd 100644 --- a/retroshare-gui/src/gui/icons.qrc +++ b/retroshare-gui/src/gui/icons.qrc @@ -60,6 +60,7 @@ icons/png/anonymous.png icons/png/attach-image.png icons/png/attach.png + icons/png/arrow.png icons/png/cert.png icons/png/channels-notify.png icons/png/channels.png diff --git a/retroshare-gui/src/gui/icons/png/arrow.png b/retroshare-gui/src/gui/icons/png/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..e238538026d1e88b3f373287ead27e503f5c161d GIT binary patch literal 935 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD`S&v7|ftIx;Y9?C1WI$O_~uBzpw; zGB8xB0oAoIF#H0kf5E^|YQVtoDuIE)Y6b&?c)^@qfi^&iMFBn`u0Wb$)qm#M*O+Ht zWtx2zNHR41XP9}3Y4$aySyx$Sg2Y+pTxFPc3CIA+&OgsG`zjDYxwEb_%(%uf=L*ZL z%WN~Rv(387F!Kyls_!v~G3N@y?8{J*xi^^SfHX4AxxzH(D$sneI9PVpHHMjYftE7Q zx&}0y3CLY?8z>8O-HvEab0B3>666=mz#P8n@?9p4ix-UE8wx&tB+%9V{DqpTwUw?m z*S9a6E0=5j{GpzdSXf!~FX&Yuf5Fb{`FuN0{n!N5&zR)x?!wT)D(eB{a29w(7BevL z9RXp+soH$fKtc8rPhVH|Cv02-W^(6FzMKZs)8Xmj7*cWT?bYxgCP$IhhhhRDXDrnX z8dfYQ|DXN2QSwm>pLs~+^PC62<*h8*6D8W9=thZjZ(4S6?%K4)d*76A^QgQ%*R_86 z>bJtB<uG!l<>snA z+9VXecEOc!trZ_axwL9qo226REVw4F_u+#p_nw-AO#bm}4%`;k;`rdo)l}2i7) z!i{vjjt`OCi)xNFdCXs{a4TKQ<3l9Zq?)!S7yF$GH~n=IK1}9{_|w9qX1}Z9Y`;#z zm&IHWe><4c>~}QW<<}AT(9GrXr-4cF{%(ge-*p7O?B#N)?Pp5dzs=#!dd+|j+T0<3 zx|me=Z*e%QuNm-#n>*xh6H{vaT8F#wng$={O7j%gS#0<)_qT-a-;2w8-`~0Zy~0TH z|DULz@UWElX8(=-M$jeR3Y{f~fzhN|;u=wsl30>zm0Xkxq!^40j0|)Q%ybP6LJZBU zOiiqe4YUmmtPBk9+E2cOq9HdwB{QuOw}v%I+Ic_?k{}y`^V3So6N^$A%FE03GV`*F clM@S4_413-XTP(N0xDwgboFyt=akR{0M4y>Jpcdz literal 0 HcmV?d00001 From 8a636024d6260185c97730bf2fe1fba94452d61a Mon Sep 17 00:00:00 2001 From: defnax Date: Thu, 11 Jun 2020 20:09:24 +0200 Subject: [PATCH 098/154] forget this to commit --- retroshare-gui/src/gui/qss/stylesheet/Standard.qss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/retroshare-gui/src/gui/qss/stylesheet/Standard.qss b/retroshare-gui/src/gui/qss/stylesheet/Standard.qss index 53ac80a44..505fc83c9 100644 --- a/retroshare-gui/src/gui/qss/stylesheet/Standard.qss +++ b/retroshare-gui/src/gui/qss/stylesheet/Standard.qss @@ -791,6 +791,14 @@ GxsChannelPostsWidget QToolButton#subscribeToolButton::menu-button { } +GxsChannelFilesStatusWidget QToolButton#openFolderToolButton::menu-indicator { + image: none; +} + +GxsChannelFilesStatusWidget QToolButton#openFolderToolButton[popupMode="0"] { + padding-right: 0px; +} + GxsGroupDialog QLabel#groupLogo{ border: 2px solid #CCCCCC; border-radius: 3px; From 0cb0678dc5f3f2a59860cefacdb48a6b0702fc60 Mon Sep 17 00:00:00 2001 From: defnax Date: Sun, 14 Jun 2020 15:06:04 +0200 Subject: [PATCH 099/154] Fixing margins & fix filter linedit to use LineEditClear class --- .../GxsChannelPostsWidgetWithModel.ui | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index 097f6b298..ef40e8713 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -128,7 +128,7 @@
- + 0 @@ -358,6 +358,9 @@ p, li { white-space: pre-wrap; } Posts + + 0 + @@ -409,6 +412,9 @@ p, li { white-space: pre-wrap; } Details + + 3 + @@ -492,6 +498,18 @@ p, li { white-space: pre-wrap; } Comments + + 0 + + + 0 + + + 0 + + + 0 + @@ -566,6 +584,11 @@ p, li { white-space: pre-wrap; }
gui/gxs/GxsCommentDialog.h
1 + + LineEditClear + QLineEdit +
gui/common/LineEditClear.h
+
From 61437cd0b409df19e679d068ade3900a9e862124 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 15 Jun 2020 21:11:58 +0200 Subject: [PATCH 100/154] added some debug info in rsgxsnetservice distant search result handling and fixed a bug causing so some search result to not show up --- libretroshare/src/gxs/rsgxsnetservice.cc | 35 ++++++++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index 72a078075..139cc21c8 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -5189,8 +5189,7 @@ bool RsGxsNetService::clearDistantSearchResults(const TurtleRequestId& id) return true ; } -void RsGxsNetService::receiveTurtleSearchResults( - TurtleRequestId req, const std::list& group_infos ) +void RsGxsNetService::receiveTurtleSearchResults( TurtleRequestId req, const std::list& group_infos ) { std::set groupsToNotifyResults; @@ -5198,20 +5197,44 @@ void RsGxsNetService::receiveTurtleSearchResults( RS_STACK_MUTEX(mNxsMutex); RsGxsGrpMetaTemporaryMap grpMeta; - std::map& - search_results_map(mDistantSearchResults[req]); + std::map& search_results_map(mDistantSearchResults[req]); + + std::cerr << "Received group summary through turtle search for the following groups:" << std::endl; for(const RsGxsGroupSummary& gps : group_infos) + { + std::cerr <<" " << gps.mGroupId << " \"" << gps.mGroupName << "\" " ; + if(search_results_map.find(gps.mGroupId) == search_results_map.end()) + { + std::cerr << "added to search." << std::endl; grpMeta[gps.mGroupId] = nullptr; + } + else + std::cerr << "ignored (already in search results)." << std::endl; + } + + // Do a search for only groups that we dont have yet in the search results. + mDataStore->retrieveGxsGrpMetaData(grpMeta); + std::cerr << "Retrieved data store group data for the following groups:" <mGroupName << std::endl; + for (const RsGxsGroupSummary& gps : group_infos) { #ifndef RS_DEEP_CHANNEL_INDEX /* Only keep groups that are not locally known, and groups that are - * not already in the mDistantSearchResults structure. */ - if(grpMeta[gps.mGroupId]) continue; + * not already in the mDistantSearchResults structure. + * mDataStore may in some situations allocate an empty group meta data, so it's important + * to test that the group meta is both non null and actually corresponds to the group id we seek. */ + + if(grpMeta[gps.mGroupId] != nullptr && grpMeta[gps.mGroupId]->mGroupId == gps.mGroupId) + continue; + + std::cerr << " group " << gps.mGroupId << " is not known. Adding it to search results..." << std::endl; + #else // ndef RS_DEEP_CHANNEL_INDEX /* When deep search is enabled search results may bring more info * then we already have also about post that are indexed by xapian, From 8e2c6707165954da4e5da657e325b968a74d820a Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 16 Jun 2020 00:00:22 +0200 Subject: [PATCH 101/154] fixed the logic with distant search. --- libretroshare/src/gxs/rsgxsnetservice.cc | 41 ++++++++---------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index 139cc21c8..7d9132f1b 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -5203,19 +5203,10 @@ void RsGxsNetService::receiveTurtleSearchResults( TurtleRequestId req, const std for(const RsGxsGroupSummary& gps : group_infos) { - std::cerr <<" " << gps.mGroupId << " \"" << gps.mGroupName << "\" " ; - - if(search_results_map.find(gps.mGroupId) == search_results_map.end()) - { - std::cerr << "added to search." << std::endl; - grpMeta[gps.mGroupId] = nullptr; - } - else - std::cerr << "ignored (already in search results)." << std::endl; + std::cerr <<" " << gps.mGroupId << " \"" << gps.mGroupName << "\"" << std::endl; + grpMeta[gps.mGroupId] = nullptr; } - // Do a search for only groups that we dont have yet in the search results. - mDataStore->retrieveGxsGrpMetaData(grpMeta); std::cerr << "Retrieved data store group data for the following groups:" <mGroupId == gps.mGroupId) + auto& meta(grpMeta[gps.mGroupId]); + + if(meta != nullptr && meta->mGroupId == gps.mGroupId) continue; std::cerr << " group " << gps.mGroupId << " is not known. Adding it to search results..." << std::endl; @@ -5244,21 +5237,15 @@ void RsGxsNetService::receiveTurtleSearchResults( TurtleRequestId req, const std groupsToNotifyResults.insert(grpId); auto it2 = search_results_map.find(grpId); - if(it2 != search_results_map.end()) - { - // update existing data - RsGxsGroupSummary& eGpS(it2->second); - eGpS.mPopularity++; - eGpS.mNumberOfMessages = std::max( - eGpS.mNumberOfMessages, - gps.mNumberOfMessages ); - } - else - { - search_results_map[grpId] = gps; - // number of results so far - search_results_map[grpId].mPopularity = 1; - } + + RsGxsGroupSummary& eGpS(search_results_map[grpId]); + + int popularity = eGpS.mPopularity + 1; + int number_of_msg = std::max( eGpS.mNumberOfMessages, gps.mNumberOfMessages ); + + eGpS = gps; + eGpS.mPopularity = popularity; + eGpS.mNumberOfMessages = number_of_msg; } } // end RS_STACK_MUTEX(mNxsMutex); From 33da5c06b8a4b436df642eabd797c7c9db3a2112 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 16 Jun 2020 21:13:55 +0200 Subject: [PATCH 102/154] removed multi-callback based distant search result handling, and use rsEvents instead --- libretroshare/src/gxs/rsgenexchange.cc | 8 +-- libretroshare/src/gxs/rsgxsnetservice.cc | 34 +++++++--- libretroshare/src/gxs/rsgxsnetservice.h | 6 +- libretroshare/src/gxs/rsgxsnotify.h | 10 --- libretroshare/src/gxs/rsnxs.h | 4 +- libretroshare/src/retroshare/rsgxschannels.h | 35 +++++++--- libretroshare/src/retroshare/rsgxsiface.h | 40 ++++++++++++ libretroshare/src/services/p3gxschannels.cc | 65 ++++++++++++------- libretroshare/src/services/p3gxschannels.h | 8 ++- .../src/gui/common/GroupTreeWidget.cpp | 6 ++ .../src/gui/common/GroupTreeWidget.h | 23 ++++--- .../src/gui/gxs/GxsGroupFrameDialog.cpp | 63 ++++++++---------- .../src/gui/gxs/GxsGroupFrameDialog.h | 5 +- .../src/gui/gxschannels/GxsChannelDialog.cpp | 18 ++--- .../src/gui/gxschannels/GxsChannelDialog.h | 2 +- 15 files changed, 204 insertions(+), 123 deletions(-) diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index bfc1bbd23..e3ef41eb9 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -1675,13 +1675,7 @@ void RsGenExchange::receiveNewMessages(std::vector& messages) void RsGenExchange::receiveDistantSearchResults(TurtleRequestId id,const RsGxsGroupId &grpId) { - std::cerr << __PRETTY_FUNCTION__ << " received result for request " - << std::hex << id << std::dec << std::endl; - - RS_STACK_MUTEX(mGenMtx); - - RsGxsDistantSearchResultChange* gc = new RsGxsDistantSearchResultChange(id,grpId); - mNotifications.push_back(gc); + std::cerr << __PRETTY_FUNCTION__ << " received result for request " << std::hex << id << std::dec << ": this method should be overloaded in the client service, but it is not. This is a bug!" << std::endl; } void RsGenExchange::notifyReceivePublishKey(const RsGxsGroupId &grpId) diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index 7d9132f1b..58a49f35c 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -5155,7 +5155,7 @@ static bool termSearch(const std::string& src, const std::string& substring) } #endif // ndef RS_DEEP_CHANNEL_INDEX -bool RsGxsNetService::retrieveDistantSearchResults(TurtleRequestId req,std::map& group_infos) +bool RsGxsNetService::retrieveDistantSearchResults(TurtleRequestId req,std::map& group_infos) { RS_STACK_MUTEX(mNxsMutex) ; @@ -5167,7 +5167,7 @@ bool RsGxsNetService::retrieveDistantSearchResults(TurtleRequestId req,std::map< group_infos = it->second; return true ; } -bool RsGxsNetService::retrieveDistantGroupSummary(const RsGxsGroupId& group_id,RsGxsGroupSummary& gs) +bool RsGxsNetService::retrieveDistantGroupSummary(const RsGxsGroupId& group_id,RsGxsGroupSearchResults& gs) { RS_STACK_MUTEX(mNxsMutex) ; for(auto it(mDistantSearchResults.begin());it!=mDistantSearchResults.end();++it) @@ -5197,7 +5197,7 @@ void RsGxsNetService::receiveTurtleSearchResults( TurtleRequestId req, const std RS_STACK_MUTEX(mNxsMutex); RsGxsGrpMetaTemporaryMap grpMeta; - std::map& search_results_map(mDistantSearchResults[req]); + std::map& search_results_map(mDistantSearchResults[req]); std::cerr << "Received group summary through turtle search for the following groups:" << std::endl; @@ -5236,16 +5236,30 @@ void RsGxsNetService::receiveTurtleSearchResults( TurtleRequestId req, const std const RsGxsGroupId& grpId(gps.mGroupId); groupsToNotifyResults.insert(grpId); - auto it2 = search_results_map.find(grpId); - RsGxsGroupSummary& eGpS(search_results_map[grpId]); + // Find search results place for this particular group - int popularity = eGpS.mPopularity + 1; - int number_of_msg = std::max( eGpS.mNumberOfMessages, gps.mNumberOfMessages ); + std::cerr << " Adding gps=" << gps.mGroupId << " name=\"" << gps.mGroupName << "\" gps.mSearchContext=\"" << gps.mSearchContext << "\"" << std::endl; + RsGxsGroupSearchResults& eGpS(search_results_map[grpId]); - eGpS = gps; - eGpS.mPopularity = popularity; - eGpS.mNumberOfMessages = number_of_msg; + if(eGpS.mGroupId != grpId) // not initialized yet. So we do it now. + { + eGpS.mGroupId = gps.mGroupId; + eGpS.mGroupName = gps.mGroupName; + eGpS.mAuthorId = gps.mAuthorId; + eGpS.mPublishTs = gps.mPublishTs; + eGpS.mSignFlags = gps.mSignFlags; + } + // We should check that the above values are always the same for all info that is received. In the end, we'll + // request the group meta and check the signature, but it may be misleading to receive a forged information + // that is not the real one. + + ++eGpS.mPopularity; // increase popularity. This is not a real counting, but therefore some heuristic estimate. + eGpS.mNumberOfMessages = std::max( eGpS.mNumberOfMessages, gps.mNumberOfMessages ); + eGpS.mLastMessageTs = std::max( eGpS.mLastMessageTs, gps.mLastMessageTs ); + + if(gps.mSearchContext != gps.mGroupName) // this is a bit of a hack. We should have flags to tell where the search hit happens + eGpS.mSearchContexts.insert(gps.mSearchContext); } } // end RS_STACK_MUTEX(mNxsMutex); diff --git a/libretroshare/src/gxs/rsgxsnetservice.h b/libretroshare/src/gxs/rsgxsnetservice.h index e4056bb06..e4f51f4b8 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.h +++ b/libretroshare/src/gxs/rsgxsnetservice.h @@ -140,9 +140,9 @@ public: virtual void receiveTurtleSearchResults(TurtleRequestId req,const std::list& group_infos); virtual void receiveTurtleSearchResults(TurtleRequestId req,const unsigned char *encrypted_group_data,uint32_t encrypted_group_data_len); - virtual bool retrieveDistantSearchResults(TurtleRequestId req, std::map &group_infos); + virtual bool retrieveDistantSearchResults(TurtleRequestId req, std::map &group_infos); virtual bool clearDistantSearchResults(const TurtleRequestId& id); - virtual bool retrieveDistantGroupSummary(const RsGxsGroupId&,RsGxsGroupSummary&); + virtual bool retrieveDistantGroupSummary(const RsGxsGroupId&, RsGxsGroupSearchResults &); /*! * pauses synchronisation of subscribed groups and request for group id @@ -609,7 +609,7 @@ private: std::set mNewPublishKeysToNotify ; // Distant search result map - std::map > mDistantSearchResults ; + std::map > mDistantSearchResults ; void debugDump(); diff --git a/libretroshare/src/gxs/rsgxsnotify.h b/libretroshare/src/gxs/rsgxsnotify.h index 4640f133a..a6fd4c6fb 100644 --- a/libretroshare/src/gxs/rsgxsnotify.h +++ b/libretroshare/src/gxs/rsgxsnotify.h @@ -76,16 +76,6 @@ protected: bool mMetaChange; }; -class RsGxsDistantSearchResultChange: public RsGxsNotify -{ -public: - RsGxsDistantSearchResultChange(TurtleRequestId id,const RsGxsGroupId& gid) : RsGxsNotify(gid), mRequestId(id){} - - NotifyType getType() { return TYPE_RECEIVED_DISTANT_SEARCH_RESULTS ; } - - TurtleRequestId mRequestId ; -}; - /*! * Relevant to message changes */ diff --git a/libretroshare/src/gxs/rsnxs.h b/libretroshare/src/gxs/rsnxs.h index 2752fa6bf..7276f3421 100644 --- a/libretroshare/src/gxs/rsnxs.h +++ b/libretroshare/src/gxs/rsnxs.h @@ -128,7 +128,7 @@ public: * \return * false when the request is unknown. */ - virtual bool retrieveDistantSearchResults(TurtleRequestId req, std::map &group_infos)=0; + virtual bool retrieveDistantSearchResults(TurtleRequestId req, std::map &group_infos)=0; /*! * \brief getDistantSearchResults * \param id @@ -136,7 +136,7 @@ public: * \return */ virtual bool clearDistantSearchResults(const TurtleRequestId& id)=0; - virtual bool retrieveDistantGroupSummary(const RsGxsGroupId&,RsGxsGroupSummary&)=0; + virtual bool retrieveDistantGroupSummary(const RsGxsGroupId&,RsGxsGroupSearchResults&)=0; virtual bool search(const std::string& substring,std::list& group_infos) =0; virtual bool search(const Sha1CheckSum& hashed_group_id,unsigned char *& encrypted_group_data,uint32_t& encrypted_group_data_len)=0; diff --git a/libretroshare/src/retroshare/rsgxschannels.h b/libretroshare/src/retroshare/rsgxschannels.h index 4b188ad01..c03f22970 100644 --- a/libretroshare/src/retroshare/rsgxschannels.h +++ b/libretroshare/src/retroshare/rsgxschannels.h @@ -117,9 +117,7 @@ enum class RsChannelEventCode: uint8_t struct RsGxsChannelEvent: RsEvent { - RsGxsChannelEvent(): - RsEvent(RsEventType::GXS_CHANNELS), - mChannelEventCode(RsChannelEventCode::UNKNOWN) {} + RsGxsChannelEvent(): RsEvent(RsEventType::GXS_CHANNELS), mChannelEventCode(RsChannelEventCode::UNKNOWN) {} RsChannelEventCode mChannelEventCode; RsGxsGroupId mChannelGroupId; @@ -138,6 +136,23 @@ struct RsGxsChannelEvent: RsEvent } }; +// This event is used to factor multiple search results notifications in a single event. + +struct RsGxsChannelSearchResultEvent: public RsEvent +{ + RsGxsChannelSearchResultEvent() : RsEvent(RsEventType::GXS_CHANNELS) {} + + std::map > mSearchResultsMap; + + ///* @see RsEvent @see RsSerializable + void serial_process( RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) override + { + RsEvent::serial_process(j, ctx); + + RS_SERIAL_PROCESS(mSearchResultsMap); + } +}; + class RsGxsChannels: public RsGxsIfaceHelper, public RsGxsCommentService { public: @@ -407,7 +422,7 @@ public: */ virtual bool getChannelStatistics(const RsGxsGroupId& channelId,GxsGroupStatistic& stat) =0; - +#ifdef TO_REMOVE /** * @brief Request remote channels search * @jsonapi{development} @@ -448,6 +463,7 @@ public: const std::string& matchString, const std::function& multiCallback, rstime_t maxWait = 30 ) = 0; +#endif /// default base URL used for channels links @see exportChannelLink static const std::string DEFAULT_CHANNEL_BASE_URL; @@ -695,16 +711,15 @@ public: /// Distant synchronisation methods /// ////////////////////////////////////////////////////////////////////////////// /// - RS_DEPRECATED_FOR(turtleChannelRequest) + /// + // This approach is much cleaner than the "multicallback" system. We should keep it and use rsEvents to warn when + // new results are received. virtual TurtleRequestId turtleGroupRequest(const RsGxsGroupId& group_id)=0; - RS_DEPRECATED virtual TurtleRequestId turtleSearchRequest(const std::string& match_string)=0; - RS_DEPRECATED_FOR(turtleSearchRequest) - virtual bool retrieveDistantSearchResults(TurtleRequestId req, std::map &results) =0; - RS_DEPRECATED virtual bool clearDistantSearchResults(TurtleRequestId req)=0; - RS_DEPRECATED_FOR(turtleChannelRequest) virtual bool retrieveDistantGroup(const RsGxsGroupId& group_id,RsGxsChannelGroup& distant_group)=0; + virtual bool retrieveDistantSearchResults(TurtleRequestId req, std::map &results) =0; + ////////////////////////////////////////////////////////////////////////////// ~RsGxsChannels() override; diff --git a/libretroshare/src/retroshare/rsgxsiface.h b/libretroshare/src/retroshare/rsgxsiface.h index 36bee517e..74e67008f 100644 --- a/libretroshare/src/retroshare/rsgxsiface.h +++ b/libretroshare/src/retroshare/rsgxsiface.h @@ -72,6 +72,46 @@ struct RsGxsGroupSummary : RsSerializable ~RsGxsGroupSummary(); }; +/*! + * This structure is used to locally store group search results for a given service. + * It contains the group information as well as a context + * strings to tell where the information was found. It is more compact than a + * GroupMeta object, so as to make search responses as light as possible. + */ +struct RsGxsGroupSearchResults : RsSerializable +{ + RsGxsGroupSearchResults() + : mPublishTs(0), mNumberOfMessages(0),mLastMessageTs(0), mSignFlags(0),mPopularity(0) + {} + + RsGxsGroupId mGroupId; + std::string mGroupName; + RsGxsId mAuthorId; + rstime_t mPublishTs; + uint32_t mNumberOfMessages; + rstime_t mLastMessageTs; + uint32_t mSignFlags; + uint32_t mPopularity; + + std::set mSearchContexts; + + /// @see RsSerializable::serial_process + void serial_process( RsGenericSerializer::SerializeJob j, + RsGenericSerializer::SerializeContext& ctx ) + { + RS_SERIAL_PROCESS(mGroupId); + RS_SERIAL_PROCESS(mGroupName); + RS_SERIAL_PROCESS(mAuthorId); + RS_SERIAL_PROCESS(mPublishTs); + RS_SERIAL_PROCESS(mNumberOfMessages); + RS_SERIAL_PROCESS(mLastMessageTs); + RS_SERIAL_PROCESS(mSignFlags); + RS_SERIAL_PROCESS(mPopularity); + RS_SERIAL_PROCESS(mSearchContexts); + } + + virtual ~RsGxsGroupSearchResults() = default; +}; /*! * Stores ids of changed gxs groups and messages. diff --git a/libretroshare/src/services/p3gxschannels.cc b/libretroshare/src/services/p3gxschannels.cc index 2a699e662..01ddb4357 100644 --- a/libretroshare/src/services/p3gxschannels.cc +++ b/libretroshare/src/services/p3gxschannels.cc @@ -80,12 +80,15 @@ p3GxsChannels::p3GxsChannels( RS_SERVICE_GXS_TYPE_CHANNELS, gixs, channelsAuthenPolicy() ), RsGxsChannels(static_cast(*this)), GxsTokenQueue(this), mSubscribedGroupsMutex("GXS channels subscribed groups cache"), - mKnownChannelsMutex("GXS channels known channels timestamp cache"), + mKnownChannelsMutex("GXS channels known channels timestamp cache") +#ifdef TO_REMOVE mSearchCallbacksMapMutex("GXS channels search callbacks map"), mDistantChannelsCallbacksMapMutex("GXS channels distant channels callbacks map") +#endif { // For Dummy Msgs. mGenActive = false; + mLastDistantSearchNotificationTS = 0; mCommentService = new p3GxsCommentService(this, RS_SERVICE_GXS_TYPE_CHANNELS); RsTickEvent::schedule_in(CHANNEL_PROCESS, 0); @@ -352,18 +355,6 @@ void p3GxsChannels::notifyChanges(std::vector &changes) } - RsGxsDistantSearchResultChange *dsrChange = dynamic_cast(*it); - - if(dsrChange && rsEvents) - { - auto ev = std::make_shared(); - ev->mChannelGroupId = dsrChange->mGroupId; - ev->mChannelEventCode = RsChannelEventCode::RECEIVED_DISTANT_SEARCH_RESULT; - ev->mDistantSearchRequestId = dsrChange->mRequestId; - - rsEvents->postEvent(ev); - } - /* shouldn't need to worry about groups - as they need to be subscribed to */ delete *it; } @@ -383,17 +374,32 @@ void p3GxsChannels::notifyChanges(std::vector &changes) void p3GxsChannels::service_tick() { static rstime_t last_dummy_tick = 0; + rstime_t now = time(NULL); if (time(NULL) > last_dummy_tick + 5) { dummy_tick(); - last_dummy_tick = time(NULL); + last_dummy_tick = now; } RsTickEvent::tick_events(); GxsTokenQueue::checkRequests(); mCommentService->comment_tick(); + + // Notify distant search results, not more than once per sec. Normally we should + // rather send one item for all, but that needs another class type + + if(now > mLastDistantSearchNotificationTS+2 && !mSearchResultsToNotify.empty()) + { + auto ev = std::make_shared(); + ev->mSearchResultsMap = mSearchResultsToNotify; + + mLastDistantSearchNotificationTS = now; + mSearchResultsToNotify.clear(); + + rsEvents->postEvent(ev); + } } bool p3GxsChannels::getGroupData(const uint32_t &token, std::vector &groups) @@ -2210,7 +2216,9 @@ void p3GxsChannels::dummy_tick() } +#ifdef TO_REMOVE cleanTimedOutCallbacks(); +#endif } @@ -2389,18 +2397,18 @@ bool p3GxsChannels::clearDistantSearchResults(TurtleRequestId req) { return netService()->clearDistantSearchResults(req); } -bool p3GxsChannels::retrieveDistantSearchResults(TurtleRequestId req,std::map& results) +bool p3GxsChannels::retrieveDistantSearchResults(TurtleRequestId req,std::map& results) { return netService()->retrieveDistantSearchResults(req,results); } bool p3GxsChannels::retrieveDistantGroup(const RsGxsGroupId& group_id,RsGxsChannelGroup& distant_group) { - RsGxsGroupSummary gs; + RsGxsGroupSearchResults gs; if(netService()->retrieveDistantGroupSummary(group_id,gs)) { - // This is a placeholder information by the time we receive the full group meta data. + // This is a placeholder information by the time we receive the full group meta data and check the signature. distant_group.mMeta.mGroupId = gs.mGroupId ; distant_group.mMeta.mGroupName = gs.mGroupName; distant_group.mMeta.mGroupFlags = GXS_SERV::FLAG_PRIVACY_PUBLIC ; @@ -2426,6 +2434,7 @@ bool p3GxsChannels::retrieveDistantGroup(const RsGxsGroupId& group_id,RsGxsChann return false ; } +#ifdef TO_REMOVE bool p3GxsChannels::turtleSearchRequest( const std::string& matchString, const std::function& multiCallback, @@ -2505,17 +2514,24 @@ bool p3GxsChannels::localSearchRequest( return true; } +#endif -void p3GxsChannels::receiveDistantSearchResults( - TurtleRequestId id, const RsGxsGroupId& grpId ) +void p3GxsChannels::receiveDistantSearchResults( TurtleRequestId id, const RsGxsGroupId& grpId ) { - std::cerr << __PRETTY_FUNCTION__ << "(" << id << ", " << grpId << ")" - << std::endl; + if(!rsEvents) + return; + + // We temporise here, in order to avoid notifying clients with many events + // So we put some data in there and will send an event with all of them at once every 1 sec at most. + + mSearchResultsToNotify[id].insert(grpId); + +#ifdef TO_REMOVE + std::cerr << __PRETTY_FUNCTION__ << "(" << id << ", " << grpId << ")" << std::endl; { RsGenExchange::receiveDistantSearchResults(id, grpId); - RsGxsGroupSummary gs; - gs.mGroupId = grpId; + RsGxsGroupSearchResults gs; netService()->retrieveDistantGroupSummary(grpId, gs); { @@ -2556,8 +2572,10 @@ void p3GxsChannels::receiveDistantSearchResults( return; } } // RS_STACK_MUTEX(mDistantChannelsCallbacksMapMutex); +#endif } +#ifdef TO_REMOVE void p3GxsChannels::cleanTimedOutCallbacks() { auto now = std::chrono::system_clock::now(); @@ -2586,6 +2604,7 @@ void p3GxsChannels::cleanTimedOutCallbacks() else ++cbpt; } // RS_STACK_MUTEX(mDistantChannelsCallbacksMapMutex) } +#endif bool p3GxsChannels::exportChannelLink( std::string& link, const RsGxsGroupId& chanId, bool includeGxsData, diff --git a/libretroshare/src/services/p3gxschannels.h b/libretroshare/src/services/p3gxschannels.h index e6917e252..12c18d5c4 100644 --- a/libretroshare/src/services/p3gxschannels.h +++ b/libretroshare/src/services/p3gxschannels.h @@ -68,7 +68,7 @@ protected: virtual TurtleRequestId turtleGroupRequest(const RsGxsGroupId& group_id); virtual TurtleRequestId turtleSearchRequest(const std::string& match_string); - virtual bool retrieveDistantSearchResults(TurtleRequestId req, std::map &results) ; + virtual bool retrieveDistantSearchResults(TurtleRequestId req, std::map &results) ; virtual bool clearDistantSearchResults(TurtleRequestId req); virtual bool retrieveDistantGroup(const RsGxsGroupId& group_id,RsGxsChannelGroup& distant_group); @@ -109,6 +109,7 @@ virtual bool getChannelAutoDownload(const RsGxsGroupId &groupid, bool& enabled); virtual bool setChannelDownloadDirectory(const RsGxsGroupId &groupId, const std::string& directory); virtual bool getChannelDownloadDirectory(const RsGxsGroupId &groupId, std::string& directory); +#ifdef TO_REMOVE /// @see RsGxsChannels::turtleSearchRequest virtual bool turtleSearchRequest(const std::string& matchString, const std::function& multiCallback, @@ -124,6 +125,7 @@ virtual bool getChannelDownloadDirectory(const RsGxsGroupId &groupId, std::strin virtual bool localSearchRequest(const std::string& matchString, const std::function& multiCallback, rstime_t maxWait = 30 ) override; +#endif /** * Receive results from turtle search @see RsGenExchange @see RsNxsObserver @@ -374,6 +376,9 @@ bool generateGroup(uint32_t &token, std::string groupName); std::map mKnownChannels; RsMutex mKnownChannelsMutex; + rstime_t mLastDistantSearchNotificationTS; + std::map > mSearchResultsToNotify; +#ifdef TO_REMOVE /** Store search callbacks with timeout*/ std::map< TurtleRequestId, @@ -394,4 +399,5 @@ bool generateGroup(uint32_t &token, std::string groupName); /// Cleanup mSearchCallbacksMap and mDistantChannelsCallbacksMap void cleanTimedOutCallbacks(); +#endif }; diff --git a/retroshare-gui/src/gui/common/GroupTreeWidget.cpp b/retroshare-gui/src/gui/common/GroupTreeWidget.cpp index fa12ebf54..799331e57 100644 --- a/retroshare-gui/src/gui/common/GroupTreeWidget.cpp +++ b/retroshare-gui/src/gui/common/GroupTreeWidget.cpp @@ -463,6 +463,12 @@ void GroupTreeWidget::fillGroupItems(QTreeWidgetItem *categoryItem, const QList< item->setData(COLUMN_DATA, ROLE_NAME, itemInfo.name); item->setData(COLUMN_DATA, ROLE_DESCRIPTION, itemInfo.description); + // Add children for context strings. This happens in the search. + while(nullptr != item->takeChild(0)); + + for(auto str:itemInfo.context_strings) + item->addChild(new QTreeWidgetItem(QStringList(QString::fromUtf8(str.c_str())))); + /* Set last post */ qlonglong lastPost = itemInfo.lastpost.toTime_t(); item->setData(COLUMN_DATA, ROLE_LASTPOST, -lastPost); // negative for correct sorting diff --git a/retroshare-gui/src/gui/common/GroupTreeWidget.h b/retroshare-gui/src/gui/common/GroupTreeWidget.h index 23c90a292..9f8d0ccd4 100644 --- a/retroshare-gui/src/gui/common/GroupTreeWidget.h +++ b/retroshare-gui/src/gui/common/GroupTreeWidget.h @@ -21,6 +21,8 @@ #ifndef GROUPTREEWIDGET_H #define GROUPTREEWIDGET_H +#include + #include #include @@ -47,16 +49,17 @@ public: {} public: - QString id; - QString name; - QString description; - int popularity; - QDateTime lastpost; - QIcon icon; - bool publishKey; - bool adminKey; - quint32 subscribeFlags; - quint32 max_visible_posts ; + QString id; + QString name; + QString description; + int popularity; + QDateTime lastpost; + QIcon icon; + bool publishKey; + bool adminKey; + quint32 subscribeFlags; + quint32 max_visible_posts ; + std::set context_strings; }; //cppcheck-suppress noConstructor diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp index 1245c80b2..59a8bbfd9 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp @@ -286,55 +286,48 @@ void GxsGroupFrameDialog::updateDisplay(bool complete) if(complete) // || !getGrpIds().empty() || !getGrpIdsMeta().empty()) { updateGroupSummary(); /* Update group list */ - updateSearchResults() ; +// updateSearchResults() ; } void GxsGroupFrameDialog::updateSearchResults() { - const std::set& reqs = getSearchRequests(); + for(auto& it:mSearchGroupsItems) + updateSearchResults(it.first); +} - for(auto it(reqs.begin());it!=reqs.end();++it) - { - std::cerr << "updating search ID " << std::hex << *it << std::dec << std::endl; +void GxsGroupFrameDialog::updateSearchResults(const TurtleRequestId& sid) +{ + std::cerr << "updating search ID " << std::hex << sid << std::dec << std::endl; - std::map group_infos; + std::map group_infos; - getDistantSearchResults(*it,group_infos) ; + getDistantSearchResults(sid,group_infos) ; - std::cerr << "retrieved " << std::endl; + std::cerr << "retrieved " << std::endl; - auto it2 = mSearchGroupsItems.find(*it); + auto it2 = mSearchGroupsItems.find(sid); - if(mSearchGroupsItems.end() == it2) - { - std::cerr << "GxsGroupFrameDialog::updateSearchResults(): received result notification for req " << std::hex << *it << std::dec << " but no item present!" << std::endl; - continue ; // we could create the item just as well but since this situation is not supposed to happen, I prefer to make this a failure case. - } + QList group_items ; - QList group_items ; + for(auto it3(group_infos.begin());it3!=group_infos.end();++it3) + { + std::cerr << " adding group " << it3->first << " " << it3->second.mGroupId << " \"" << it3->second.mGroupName << "\"" << std::endl; - for(auto it3(group_infos.begin());it3!=group_infos.end();++it3) - if(mCachedGroupMetas.find(it3->first) == mCachedGroupMetas.end()) - { - std::cerr << " adding new group " << it3->first << " " - << it3->second.mGroupId << " \"" - << it3->second.mGroupName << "\"" << std::endl; + GroupItemInfo i; + i.id = QString(it3->second.mGroupId.toStdString().c_str()); + i.name = QString::fromUtf8(it3->second.mGroupName.c_str()); + i.popularity = 0; // could be set to the number of hits + i.lastpost = QDateTime::fromTime_t(it3->second.mLastMessageTs); + i.subscribeFlags = 0; // irrelevant here + i.publishKey = false ; // IS_GROUP_PUBLISHER(groupInfo.mSubscribeFlags); + i.adminKey = false ; // IS_GROUP_ADMIN(groupInfo.mSubscribeFlags); + i.max_visible_posts = it3->second.mNumberOfMessages; + i.context_strings = it3->second.mSearchContexts; - GroupItemInfo i; - i.id = QString(it3->second.mGroupId.toStdString().c_str()); - i.name = QString::fromUtf8(it3->second.mGroupName.c_str()); - i.popularity = 0; // could be set to the number of hits - i.lastpost = QDateTime::fromTime_t(it3->second.mLastMessageTs); - i.subscribeFlags = 0; // irrelevant here - i.publishKey = false ; // IS_GROUP_PUBLISHER(groupInfo.mSubscribeFlags); - i.adminKey = false ; // IS_GROUP_ADMIN(groupInfo.mSubscribeFlags); - i.max_visible_posts = it3->second.mNumberOfMessages; + group_items.push_back(i); + } - group_items.push_back(i); - } - - ui->groupTreeWidget->fillGroupItems(it2->second, group_items); - } + ui->groupTreeWidget->fillGroupItems(it2->second, group_items); } void GxsGroupFrameDialog::todo() diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h index 902e49087..b335fc57b 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h @@ -161,7 +161,7 @@ private: virtual void groupTreeCustomActions(RsGxsGroupId /*grpId*/, int /*subscribeFlags*/, QList &/*actions*/) {} virtual RsGxsCommentService *getCommentService() { return NULL; } virtual QWidget *createCommentHeaderWidget(const RsGxsGroupId &/*grpId*/, const RsGxsMessageId &/*msgId*/) { return NULL; } - virtual bool getDistantSearchResults(TurtleRequestId /* id */, std::map& /* group_infos */){ return false ;} + virtual bool getDistantSearchResults(TurtleRequestId /* id */, std::map& /* group_infos */){ return false ;} void initUi(); @@ -187,7 +187,8 @@ private: GxsCommentDialog *commentWidget(const RsGxsMessageId &msgId); protected: - void updateSearchResults(); + void updateSearchResults(const TurtleRequestId &sid); + void updateSearchResults(); // update all searches bool mCountChildMsgs; // Count unread child messages? diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp index 8e25e4ea0..ce58177c0 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp @@ -61,9 +61,7 @@ void GxsChannelDialog::handleEvent_main_thread(std::shared_ptr ev { const RsGxsChannelEvent *e = dynamic_cast(event.get()); - if(!e) - return; - + if(e) switch(e->mChannelEventCode) { case RsChannelEventCode::NEW_MESSAGE: // [[fallthrough]]; @@ -72,11 +70,6 @@ void GxsChannelDialog::handleEvent_main_thread(std::shared_ptr ev updateGroupStatisticsReal(e->mChannelGroupId); // update the list immediately break; - case RsChannelEventCode::RECEIVED_DISTANT_SEARCH_RESULT: - mSearchResults.insert(e->mDistantSearchRequestId); - updateSearchResults(); - break; - case RsChannelEventCode::NEW_CHANNEL: // [[fallthrough]]; case RsChannelEventCode::SUBSCRIBE_STATUS_CHANGED: updateDisplay(true); @@ -89,6 +82,13 @@ void GxsChannelDialog::handleEvent_main_thread(std::shared_ptr ev default: break; } + + + const RsGxsChannelSearchResultEvent*f = dynamic_cast(event.get()); + + if(nullptr != f) + for(auto it:f->mSearchResultsMap) + updateSearchResults(it.first); } GxsChannelDialog::~GxsChannelDialog() @@ -401,7 +401,7 @@ TurtleRequestId GxsChannelDialog::distantSearch(const QString& search_string) return rsGxsChannels->turtleSearchRequest(search_string.toStdString()) ; } -bool GxsChannelDialog::getDistantSearchResults(TurtleRequestId id, std::map& group_infos) +bool GxsChannelDialog::getDistantSearchResults(TurtleRequestId id, std::map& group_infos) { return rsGxsChannels->retrieveDistantSearchResults(id,group_infos); } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h index b0b46205d..e8c23424d 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h @@ -43,7 +43,7 @@ public: protected: /* GxsGroupFrameDialog */ - virtual bool getDistantSearchResults(TurtleRequestId id, std::map& group_infos); + virtual bool getDistantSearchResults(TurtleRequestId id, std::map &group_infos); virtual TurtleRequestId distantSearch(const QString& search_string) ; virtual void checkRequestGroup(const RsGxsGroupId& grpId) ; From 9f5e7f20812504a49f0727ade65804d877899529 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 16 Jun 2020 21:29:13 +0200 Subject: [PATCH 103/154] removed debug info --- libretroshare/src/gxs/rsgxsnetservice.cc | 12 +++++++++++- libretroshare/src/gxs/rsgxsnettunnel.cc | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index 58a49f35c..743cd298a 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -272,6 +272,7 @@ NXS_NET_DEBUG_6 group sync statistics (e.g. number of posts at nighbour nodes, etc) NXS_NET_DEBUG_7 encryption/decryption of transactions NXS_NET_DEBUG_8 gxs distant sync + NXS_NET_DEBUG_9 gxs distant search ***/ //#define NXS_NET_DEBUG_0 1 @@ -283,6 +284,7 @@ //#define NXS_NET_DEBUG_6 1 //#define NXS_NET_DEBUG_7 1 //#define NXS_NET_DEBUG_8 1 +//#define NXS_NET_DEBUG_9 1 //#define NXS_FRAG @@ -318,7 +320,7 @@ static const uint32_t RS_NXS_ITEM_ENCRYPTION_STATUS_GXS_KEY_MISSING = 0x05 ; #if defined(NXS_NET_DEBUG_0) || defined(NXS_NET_DEBUG_1) || defined(NXS_NET_DEBUG_2) || defined(NXS_NET_DEBUG_3) \ || defined(NXS_NET_DEBUG_4) || defined(NXS_NET_DEBUG_5) || defined(NXS_NET_DEBUG_6) || defined(NXS_NET_DEBUG_7) \ - || defined(NXS_NET_DEBUG_8) + || defined(NXS_NET_DEBUG_8) || defined(NXS_NET_DEBUG_9) 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 @@ -5199,7 +5201,9 @@ void RsGxsNetService::receiveTurtleSearchResults( TurtleRequestId req, const std RsGxsGrpMetaTemporaryMap grpMeta; std::map& search_results_map(mDistantSearchResults[req]); +#ifdef NXS_NET_DEBUG_9 std::cerr << "Received group summary through turtle search for the following groups:" << std::endl; +#endif for(const RsGxsGroupSummary& gps : group_infos) { @@ -5209,9 +5213,11 @@ void RsGxsNetService::receiveTurtleSearchResults( TurtleRequestId req, const std mDataStore->retrieveGxsGrpMetaData(grpMeta); +#ifdef NXS_NET_DEBUG_9 std::cerr << "Retrieved data store group data for the following groups:" <mGroupName << std::endl; +#endif for (const RsGxsGroupSummary& gps : group_infos) { @@ -5226,7 +5232,9 @@ void RsGxsNetService::receiveTurtleSearchResults( TurtleRequestId req, const std if(meta != nullptr && meta->mGroupId == gps.mGroupId) continue; +#ifdef NXS_NET_DEBUG_9 std::cerr << " group " << gps.mGroupId << " is not known. Adding it to search results..." << std::endl; +#endif #else // ndef RS_DEEP_CHANNEL_INDEX /* When deep search is enabled search results may bring more info @@ -5239,7 +5247,9 @@ void RsGxsNetService::receiveTurtleSearchResults( TurtleRequestId req, const std // Find search results place for this particular group +#ifdef NXS_NET_DEBUG_9 std::cerr << " Adding gps=" << gps.mGroupId << " name=\"" << gps.mGroupName << "\" gps.mSearchContext=\"" << gps.mSearchContext << "\"" << std::endl; +#endif RsGxsGroupSearchResults& eGpS(search_results_map[grpId]); if(eGpS.mGroupId != grpId) // not initialized yet. So we do it now. diff --git a/libretroshare/src/gxs/rsgxsnettunnel.cc b/libretroshare/src/gxs/rsgxsnettunnel.cc index a58d20f5f..eabf21e7e 100644 --- a/libretroshare/src/gxs/rsgxsnettunnel.cc +++ b/libretroshare/src/gxs/rsgxsnettunnel.cc @@ -1090,8 +1090,10 @@ void RsGxsNetTunnelService::receiveSearchResult(TurtleSearchRequestId request_id { GXS_NET_TUNNEL_DEBUG() << " : result is of type group summary result for service " << result_gs->service << std::dec << ": " << std::endl; +#ifdef DEBUG_RSGXSNETTUNNEL for(auto it(result_gs->group_infos.begin());it!=result_gs->group_infos.end();++it) std::cerr << " group " << (*it).mGroupId << ": " << (*it).mGroupName << ", " << (*it).mNumberOfMessages << " messages, last is " << time(NULL)-(*it).mLastMessageTs << " secs ago." << std::endl; +#endif auto it = mSearchableServices.find(result_gs->service) ; From b3b87303e2ea716880d0b23c76d1b65d125497ae Mon Sep 17 00:00:00 2001 From: defnax Date: Wed, 17 Jun 2020 00:21:32 +0200 Subject: [PATCH 104/154] Added default column with for file name & store the column state & width * Added default column width for file name & store the column state & width * disabled resize column to contents --- .../GxsChannelPostsWidgetWithModel.cpp | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 1560eaf4f..90b820d4a 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -266,7 +266,12 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI connect(ui->postsTree,SIGNAL(sizeChanged(QSize)),this,SLOT(handlePostsTreeSizeChange(QSize))); - //ui->nameLabel->setMinimumWidth(20); + /* Set initial section sizes */ + QHeaderView * channelpostfilesheader = ui->channelPostFiles_TV->header () ; + QHeaderView * channelfilesheader = ui->channelFiles_TV->header () ; + + channelpostfilesheader->resizeSection (RsGxsChannelPostFilesModel::COLUMN_FILES_NAME, fm.width("RetroShare-v0.6.5-1487-g6714648e5-Windows-x64-portable-20200518-Qt-5.14.2.7z")*1.5); + channelfilesheader->resizeSection (RsGxsChannelPostFilesModel::COLUMN_FILES_NAME, fm.width("RetroShare-v0.6.5-1487-g6714648e5-Windows-x64-portable-20200518-Qt-5.14.2.7z")*1.5); /* Initialize feed widget */ //ui->feedWidget->setSortRole(ROLE_PUBLISH, Qt::DescendingOrder); @@ -421,8 +426,8 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() ui->postTime_LB->setText(QDateTime::fromMSecsSinceEpoch(post.mMeta.mPublishTs*1000).toString("MM/dd/yyyy, hh:mm")); ui->postTime_LB->setFixedWidth(W); - ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE); - ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); + //ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE); + //ui->channelPostFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); ui->channelPostFiles_TV->setAutoSelect(true); // Now also set the post as read @@ -484,8 +489,8 @@ void GxsChannelPostsWidgetWithModel::postChannelPostLoad() mChannelPostsModel->getFilesList(files); mChannelFilesModel->setFiles(files); - ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE); - ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); + //ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE); + //ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); ui->channelFiles_TV->setAutoSelect(true); @@ -536,6 +541,9 @@ GxsChannelPostsWidgetWithModel::~GxsChannelPostsWidgetWithModel() void GxsChannelPostsWidgetWithModel::processSettings(bool load) { + QHeaderView *channelpostfilesheader = ui->channelPostFiles_TV->header () ; + QHeaderView *channelfilesheader = ui->channelFiles_TV->header () ; + Settings->beginGroup(QString("ChannelPostsWidget")); if (load) { @@ -548,6 +556,10 @@ void GxsChannelPostsWidgetWithModel::processSettings(bool load) /* View mode */ //setViewMode(Settings->value("viewMode", VIEW_MODE_FEEDS).toInt()); #endif + // state of files tree + channelpostfilesheader->restoreState(Settings->value("PostFilesTree").toByteArray()); + channelfilesheader->restoreState(Settings->value("FilesTree").toByteArray()); + // state of splitter ui->splitter->restoreState(Settings->value("SplitterChannelPosts").toByteArray()); } else { @@ -560,6 +572,10 @@ void GxsChannelPostsWidgetWithModel::processSettings(bool load) /* View mode */ //Settings->setValue("viewMode", viewMode()); #endif + // state of files tree + Settings->setValue("PostFilesTree", channelpostfilesheader->saveState()); + Settings->setValue("FilesTree", channelfilesheader->saveState()); + // state of splitter Settings->setValue("SplitterChannelPosts", ui->splitter->saveState()); } From 9e0c24767735c08994c362572b1150ad6ba42d85 Mon Sep 17 00:00:00 2001 From: defnax Date: Wed, 17 Jun 2020 17:19:12 +0200 Subject: [PATCH 105/154] Fixing get work links click on messages & clear the channel details when no channel selected --- .../GxsChannelPostsWidgetWithModel.cpp | 14 +- .../GxsChannelPostsWidgetWithModel.ui | 136 +++++++++--------- 2 files changed, 81 insertions(+), 69 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 90b820d4a..10de9b504 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -955,10 +955,18 @@ void GxsChannelPostsWidgetWithModel::blank() ui->postButton->setEnabled(false); ui->subscribeToolButton->setEnabled(false); - mChannelPostsModel->clear(); - groupNameChanged(QString()); + ui->channelName_LB->setText(tr("No Channel Selected")); + ui->logoLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(":/icons/png/channels.png")); + ui->infoPosts->setText(""); + ui->infoLastPost->setText(""); + ui->infoAdministrator->setText(""); + ui->infoDistribution->setText(""); + ui->infoCreated->setText(""); + ui->infoDescription->setText(""); + + mChannelPostsModel->clear(); + groupNameChanged(QString()); - //ui->infoWidget->hide(); } bool GxsChannelPostsWidgetWithModel::navigate(const RsGxsMessageId &msgId) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index 097f6b298..0a7f3a594 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -161,7 +161,7 @@ - 1 + 0 @@ -199,25 +199,8 @@ - - - - unknown - - - true - - - - - - - unknown - - - - - + + 75 @@ -225,33 +208,14 @@ - Created: + Distribution: - - + + - unknown - - - - - - - - 0 - 0 - - - - - 75 - true - - - - Posts: + unknown @@ -268,21 +232,8 @@
- - - - 0 - - - - - - - - 0 - 0 - - + + 75 @@ -290,14 +241,31 @@ - Last Post: + Created: - - + + - unknown + unknown + + + + + + + 0 + + + + + + + unknown + + + true @@ -314,8 +282,21 @@
- - + + + + unknown + + + + + + + + 0 + 0 + + 75 @@ -323,7 +304,26 @@ - Distribution: + Posts: + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Last Post: @@ -460,7 +460,11 @@ p, li { white-space: pre-wrap; } - + + + true + +
From 9c72797deebf898adb13cc5cdd7af37399e3c6ed Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 17 Jun 2020 20:30:05 +0200 Subject: [PATCH 106/154] removed 1.5 factor that did not really make sense in column size definition --- .../src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 10de9b504..2afd6ccf0 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -270,8 +270,8 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI QHeaderView * channelpostfilesheader = ui->channelPostFiles_TV->header () ; QHeaderView * channelfilesheader = ui->channelFiles_TV->header () ; - channelpostfilesheader->resizeSection (RsGxsChannelPostFilesModel::COLUMN_FILES_NAME, fm.width("RetroShare-v0.6.5-1487-g6714648e5-Windows-x64-portable-20200518-Qt-5.14.2.7z")*1.5); - channelfilesheader->resizeSection (RsGxsChannelPostFilesModel::COLUMN_FILES_NAME, fm.width("RetroShare-v0.6.5-1487-g6714648e5-Windows-x64-portable-20200518-Qt-5.14.2.7z")*1.5); + channelpostfilesheader->resizeSection (RsGxsChannelPostFilesModel::COLUMN_FILES_NAME, fm.width("RetroShare-v0.6.5-1487-g6714648e5-Windows-x64-portable-20200518-Qt-5.14.2.7z")); + channelfilesheader->resizeSection (RsGxsChannelPostFilesModel::COLUMN_FILES_NAME, fm.width("RetroShare-v0.6.5-1487-g6714648e5-Windows-x64-portable-20200518-Qt-5.14.2.7z")); /* Initialize feed widget */ //ui->feedWidget->setSortRole(ROLE_PUBLISH, Qt::DescendingOrder); From fed3dee1d70d152d7dd1ac10e1867040f0a32509 Mon Sep 17 00:00:00 2001 From: defnax Date: Wed, 17 Jun 2020 22:47:44 +0200 Subject: [PATCH 107/154] Clear more fields when blank tree is selected * Clear more fields when blank tree is selected * Fixing spacing * Show different placeholder when message contains no post --- .../GxsChannelPostsWidgetWithModel.cpp | 16 ++- .../GxsChannelPostsWidgetWithModel.ui | 106 +++++++++--------- 2 files changed, 67 insertions(+), 55 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 2afd6ccf0..7bf0bedf1 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -373,6 +373,12 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() { QModelIndex index = ui->postsTree->selectionModel()->currentIndex(); RsGxsChannelPost post = index.data(Qt::UserRole).value() ; + + QTextDocument doc; + doc.setHtml(post.mMsg.c_str()); + + if(doc.toPlainText().trimmed().isEmpty()) + ui->postDetails_TE->setPlaceholderText(tr("No message in this post")); if(post.mMeta.mPublishTs == 0) { @@ -492,7 +498,7 @@ void GxsChannelPostsWidgetWithModel::postChannelPostLoad() //ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE); //ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); ui->channelFiles_TV->setAutoSelect(true); - + ui->postDetails_TE->setPlaceholderText(tr("No post selected")); } @@ -954,7 +960,7 @@ void GxsChannelPostsWidgetWithModel::blank() { ui->postButton->setEnabled(false); ui->subscribeToolButton->setEnabled(false); - + ui->channelName_LB->setText(tr("No Channel Selected")); ui->logoLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(":/icons/png/channels.png")); ui->infoPosts->setText(""); @@ -965,6 +971,12 @@ void GxsChannelPostsWidgetWithModel::blank() ui->infoDescription->setText(""); mChannelPostsModel->clear(); + mChannelPostFilesModel->clear(); + ui->postDetails_TE->clear(); + ui->postDetails_TE->setPlaceholderText(tr("No post selected")); + ui->postLogo_LB->hide(); + ui->postName_LB->hide(); + ui->postTime_LB->hide(); groupNameChanged(QString()); } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index bb12239f2..28687b2df 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -199,19 +199,6 @@
- - - - - 75 - true - - - - Distribution: - - - @@ -219,19 +206,6 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - @@ -245,11 +219,27 @@ - - + + unknown + + true + + + + + + + + 75 + true + + + + Distribution: + @@ -259,14 +249,30 @@ - - + + + + + 0 + 0 + + + + + 75 + true + + + + Last Post: + + + + + unknown - - true - @@ -292,7 +298,7 @@ - + 0 0 @@ -308,27 +314,21 @@ - - - - - 0 - 0 - - - - - 75 - true - - - - Last Post: - - - + + + + Qt::Horizontal + + + + 40 + 20 + + + + From 3354246805f7de7bbe542b18d325afbcf448c00e Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 18 Jun 2020 18:31:17 +0200 Subject: [PATCH 108/154] added publish time column in general channel posts files --- .../gxschannels/GxsChannelPostFilesModel.cpp | 26 ++++++++------- .../gxschannels/GxsChannelPostFilesModel.h | 32 +++++++++++++------ .../gui/gxschannels/GxsChannelPostsModel.cpp | 17 ++++++---- .../gui/gxschannels/GxsChannelPostsModel.h | 5 ++- .../GxsChannelPostsWidgetWithModel.cpp | 21 ++++++++---- 5 files changed, 67 insertions(+), 34 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp index 6b4a4b14d..664071ae0 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp @@ -35,7 +35,7 @@ //#define DEBUG_CHANNEL_MODEL -Q_DECLARE_METATYPE(RsGxsFile) +Q_DECLARE_METATYPE(ChannelPostFileInfo) static std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsewhere @@ -106,7 +106,7 @@ int RsGxsChannelPostFilesModel::columnCount(const QModelIndex &/*parent*/) const // return std::vector >(); // } -bool RsGxsChannelPostFilesModel::getFileData(const QModelIndex& i,RsGxsFile& fmpe) const +bool RsGxsChannelPostFilesModel::getFileData(const QModelIndex& i,ChannelPostFileInfo& fmpe) const { if(!i.isValid()) return true; @@ -249,6 +249,7 @@ QVariant RsGxsChannelPostFilesModel::headerData(int section, Qt::Orientation ori case COLUMN_FILES_FILE: return QString("Status"); case COLUMN_FILES_SIZE: return QString("Size"); case COLUMN_FILES_NAME: return QString("File"); + case COLUMN_FILES_DATE: return QString("Publish date"); default: return QString("[No data]"); } @@ -293,7 +294,7 @@ QVariant RsGxsChannelPostFilesModel::data(const QModelIndex &index, int role) co return QVariant() ; } - const RsGxsFile& fmpe(mFiles[mFilteredFiles[entry]]); + const ChannelPostFileInfo& fmpe(mFiles[mFilteredFiles[entry]]); #ifdef TODO if(role == Qt::FontRole) @@ -376,13 +377,14 @@ class compareOperator public: compareOperator(int column,Qt::SortOrder order): col(column),ord(order) {} - bool operator()(const RsGxsFile& f1,const RsGxsFile& f2) const + bool operator()(const ChannelPostFileInfo& f1,const ChannelPostFileInfo& f2) const { switch(col) { default: case RsGxsChannelPostFilesModel::COLUMN_FILES_NAME: return (ord==Qt::AscendingOrder)?(f1.mNamef2.mName); case RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE: return (ord==Qt::AscendingOrder)?(f1.mSizef2.mSize); + case RsGxsChannelPostFilesModel::COLUMN_FILES_DATE: return (ord==Qt::AscendingOrder)?(f1.mPublishTimef2.mPublishTime); case RsGxsChannelPostFilesModel::COLUMN_FILES_FILE: { FileInfo fi1,fi2; @@ -579,12 +581,13 @@ QVariant RsGxsChannelPostFilesModel::sizeHintRole(int col) const #endif } -QVariant RsGxsChannelPostFilesModel::sortRole(const RsGxsFile& fmpe,int column) const +QVariant RsGxsChannelPostFilesModel::sortRole(const ChannelPostFileInfo& fmpe,int column) const { switch(column) { case COLUMN_FILES_NAME: return QVariant(QString::fromUtf8(fmpe.mName.c_str())); case COLUMN_FILES_SIZE: return QVariant(qulonglong(fmpe.mSize)); + case COLUMN_FILES_DATE: return QVariant(qulonglong(fmpe.mPublishTime)); case COLUMN_FILES_FILE: { FileInfo finfo; @@ -600,13 +603,14 @@ QVariant RsGxsChannelPostFilesModel::sortRole(const RsGxsFile& fmpe,int column) } } -QVariant RsGxsChannelPostFilesModel::displayRole(const RsGxsFile& fmpe,int col) const +QVariant RsGxsChannelPostFilesModel::displayRole(const ChannelPostFileInfo& fmpe,int col) const { switch(col) { - case 0: return QString::fromUtf8(fmpe.mName.c_str()); - case 1: return QString::number(fmpe.mSize); - case 2: { + case COLUMN_FILES_NAME: return QString::fromUtf8(fmpe.mName.c_str()); + case COLUMN_FILES_SIZE: return QString::number(fmpe.mSize); + case COLUMN_FILES_DATE: return QString::number(fmpe.mPublishTime); + case COLUMN_FILES_FILE: { FileInfo finfo; if(rsFiles->FileDetails(fmpe.mHash,RS_FILE_HINTS_DOWNLOAD,finfo)) return qulonglong(finfo.transfered); @@ -659,7 +663,7 @@ QVariant RsGxsChannelPostFilesModel::displayRole(const RsGxsFile& fmpe,int col) return QVariant("[ERROR]"); } -QVariant RsGxsChannelPostFilesModel::userRole(const RsGxsFile& fmpe,int col) const +QVariant RsGxsChannelPostFilesModel::userRole(const ChannelPostFileInfo& fmpe,int col) const { switch(col) { @@ -695,7 +699,7 @@ void RsGxsChannelPostFilesModel::clear() emit channelLoaded(); } -void RsGxsChannelPostFilesModel::setFiles(const std::list& files) +void RsGxsChannelPostFilesModel::setFiles(const std::list &files) { preMods(); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h index 4f0e432ff..d2d4fabf8 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.h @@ -36,6 +36,19 @@ typedef uint32_t ChannelPostFilesModelIndex; class QTimer; +// This class contains the info for a file as well as additional info such as publication date + +struct ChannelPostFileInfo: public RsGxsFile +{ + ChannelPostFileInfo(const RsGxsFile& gxs_file,rstime_t t) + : RsGxsFile(gxs_file),mPublishTime(t) + {} + + ChannelPostFileInfo() : mPublishTime(0) {} + + rstime_t mPublishTime; +}; + // This class is the item model used by Qt to display the information class RsGxsChannelPostFilesModel : public QAbstractItemModel @@ -50,7 +63,8 @@ public: COLUMN_FILES_NAME = 0x00, COLUMN_FILES_SIZE = 0x01, COLUMN_FILES_FILE = 0x02, - COLUMN_FILES_NB_COLUMNS = 0x03 + COLUMN_FILES_DATE = 0x03, + COLUMN_FILES_NB_COLUMNS = 0x04 }; enum Roles{ SortRole = Qt::UserRole+1, @@ -66,7 +80,7 @@ public: QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;} // This method will asynchroneously update the data - void setFiles(const std::list& files); + void setFiles(const std::list& files); void setFilter(const QStringList &strings, uint32_t &count) ; #ifdef TODO @@ -102,11 +116,11 @@ public: // Custom item roles QVariant sizeHintRole (int col) const; - QVariant displayRole (const RsGxsFile& fmpe, int col) const; - QVariant toolTipRole (const RsGxsFile& fmpe, int col) const; - QVariant userRole (const RsGxsFile& fmpe, int col) const; - QVariant sortRole (const RsGxsFile& fmpe, int col) const; - QVariant filterRole (const RsGxsFile& fmpe, int col) const; + QVariant displayRole (const ChannelPostFileInfo& fmpe, int col) const; + QVariant toolTipRole (const ChannelPostFileInfo& fmpe, int col) const; + QVariant userRole (const ChannelPostFileInfo& fmpe, int col) const; + QVariant sortRole (const ChannelPostFileInfo& fmpe, int col) const; + QVariant filterRole (const ChannelPostFileInfo& fmpe, int col) const; #ifdef TODO QVariant decorationRole(const ForumModelPostEntry& fmpe, int col) const; QVariant pinnedRole (const ForumModelPostEntry& fmpe, int col) const; @@ -142,7 +156,7 @@ private: quintptr getParentRow(quintptr ref,int& row) const; quintptr getChildRef(quintptr ref, int index) const; int getChildrenCount(quintptr ref) const; - bool getFileData(const QModelIndex& i,RsGxsFile& fmpe) const; + bool getFileData(const QModelIndex& i, ChannelPostFileInfo &fmpe) const; static bool convertTabEntryToRefPointer(uint32_t entry, quintptr& ref); static bool convertRefPointerToTabEntry(quintptr ref,uint32_t& entry); @@ -153,7 +167,7 @@ private: void initEmptyHierarchy(); std::vector mFilteredFiles ; // store the list of files for the post - std::vector mFiles ; // store the list of files for the post + std::vector mFiles ; // store the list of files for the post QTimer *mTimer; }; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index 9c40f97e3..4732d93c1 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -23,14 +23,17 @@ #include #include +#include "retroshare/rsgxsflags.h" +#include "retroshare/rsgxschannels.h" +#include "retroshare/rsexpr.h" + #include "gui/common/FilesDefs.h" #include "util/qtthreadsutils.h" #include "util/HandleRichText.h" #include "util/DateTime.h" + #include "GxsChannelPostsModel.h" -#include "retroshare/rsgxsflags.h" -#include "retroshare/rsgxschannels.h" -#include "retroshare/rsexpr.h" +#include "GxsChannelPostFilesModel.h" //#define DEBUG_CHANNEL_MODEL @@ -142,15 +145,15 @@ void RsGxsChannelPostsModel::postMods() emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mFilteredPosts.size(),mColumns-1,(void*)NULL)); } -void RsGxsChannelPostsModel::getFilesList(std::list& files) +void RsGxsChannelPostsModel::getFilesList(std::list& files) { // We use an intermediate map so as to remove duplicates - std::map files_map; + std::map files_map; - for(uint32_t i=1;i #include +struct ChannelPostFileInfo; + // This class holds the actual hierarchy of posts, represented by identifiers // It is responsible for auto-updating when necessary and holds a mutex to allow the Model to // safely access the data. @@ -112,7 +115,7 @@ public: // Retrieve the full list of files for all posts. - void getFilesList(std::list& files); + void getFilesList(std::list &files); #ifdef TODO void setSortMode(SortMode mode) ; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 2afd6ccf0..5d3702f9a 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -72,7 +72,7 @@ static const int CHANNEL_TABS_POSTS = 1; #define STAR_OVERLAY_IMAGE ":icons/star_overlay_128.png" -Q_DECLARE_METATYPE(RsGxsFile) +Q_DECLARE_METATYPE(ChannelPostFileInfo) // Delegate used to paint into the table of thumbnails @@ -131,7 +131,7 @@ QSize ChannelPostDelegate::sizeHint(const QStyleOptionViewItem& option, const QM QWidget *ChannelPostFilesDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex& index) const { - RsGxsFile file = index.data(Qt::UserRole).value() ; + ChannelPostFileInfo file = index.data(Qt::UserRole).value() ; if(index.column() == RsGxsChannelPostFilesModel::COLUMN_FILES_FILE) return new GxsChannelFilesStatusWidget(file,parent); @@ -145,7 +145,7 @@ void ChannelPostFilesDelegate::updateEditorGeometry(QWidget *editor, const QStyl void ChannelPostFilesDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { - RsGxsFile file = index.data(Qt::UserRole).value() ; + ChannelPostFileInfo file = index.data(Qt::UserRole).value() ; // prepare painter->save(); @@ -163,6 +163,8 @@ void ChannelPostFilesDelegate::paint(QPainter * painter, const QStyleOptionViewI break; case RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE: painter->drawText(option.rect,Qt::AlignRight | Qt::AlignVCenter,misc::friendlyUnit(qulonglong(file.mSize))); break; + case RsGxsChannelPostFilesModel::COLUMN_FILES_DATE: painter->drawText(option.rect,Qt::AlignLeft | Qt::AlignVCenter,QDateTime::fromMSecsSinceEpoch(file.mPublishTime*1000).toString("MM/dd/yyyy, hh:mm")); + break; case RsGxsChannelPostFilesModel::COLUMN_FILES_FILE: { GxsChannelFilesStatusWidget w(file); @@ -186,7 +188,7 @@ void ChannelPostFilesDelegate::paint(QPainter * painter, const QStyleOptionViewI QSize ChannelPostFilesDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { - RsGxsFile file = index.data(Qt::UserRole).value() ; + ChannelPostFileInfo file = index.data(Qt::UserRole).value() ; QFontMetricsF fm(option.font); @@ -194,6 +196,7 @@ QSize ChannelPostFilesDelegate::sizeHint(const QStyleOptionViewItem& option, con { case RsGxsChannelPostFilesModel::COLUMN_FILES_NAME: return QSize(1.1*fm.width(QString::fromUtf8(file.mName.c_str())),fm.height()); case RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE: return QSize(1.1*fm.width(misc::friendlyUnit(qulonglong(file.mSize))),fm.height()); + case RsGxsChannelPostFilesModel::COLUMN_FILES_DATE: return QSize(1.1*fm.width(QDateTime::fromMSecsSinceEpoch(file.mPublishTime*1000).toString("MM/dd/yyyy, hh:mm")),fm.height()); default: case RsGxsChannelPostFilesModel::COLUMN_FILES_FILE: return QSize(option.rect.width(),GxsChannelFilesStatusWidget(file).height()); } @@ -280,6 +283,8 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI /* load settings */ processSettings(true); + ui->channelPostFiles_TV->setColumnHidden(RsGxsChannelPostFilesModel::COLUMN_FILES_DATE, true); // no need to show this here. + /* Initialize subscribe button */ QIcon icon; icon.addPixmap(QPixmap(":/images/redled.png"), QIcon::Normal, QIcon::On); @@ -396,7 +401,11 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() mSelectedGroup = mGroup.mMeta.mGroupId; mSelectedPost = post.mMeta.mMsgId; - mChannelPostFilesModel->setFiles(post.mFiles); + std::list files; + for(auto& file:post.mFiles) + files.push_back(ChannelPostFileInfo(file,post.mMeta.mPublishTs)); + + mChannelPostFilesModel->setFiles(files); auto all_msgs_versions(post.mOlderVersions); all_msgs_versions.insert(post.mMeta.mMsgId); @@ -484,7 +493,7 @@ void GxsChannelPostsWidgetWithModel::postChannelPostLoad() whileBlocking(ui->postsTree)->setCurrentIndex(index); } - std::list files; + std::list files; mChannelPostsModel->getFilesList(files); mChannelFilesModel->setFiles(files); From 3df54bde53919991b0129a89226e979a7ae5f11f Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 18 Jun 2020 18:35:02 +0200 Subject: [PATCH 109/154] cleaned up unused code --- .../gxschannels/GxsChannelPostFilesModel.cpp | 381 +----------------- .../gui/gxschannels/GxsChannelPostsModel.cpp | 5 - 2 files changed, 13 insertions(+), 373 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp index 664071ae0..28bdb0e37 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp @@ -96,16 +96,6 @@ int RsGxsChannelPostFilesModel::columnCount(const QModelIndex &/*parent*/) const return COLUMN_FILES_NB_COLUMNS ; } -// std::vector > RsGxsChannelPostsModel::getPostVersions(const RsGxsMessageId& mid) const -// { -// auto it = mPostVersions.find(mid); -// -// if(it != mPostVersions.end()) -// return it->second; -// else -// return std::vector >(); -// } - bool RsGxsChannelPostFilesModel::getFileData(const QModelIndex& i,ChannelPostFileInfo& fmpe) const { if(!i.isValid()) @@ -296,38 +286,11 @@ QVariant RsGxsChannelPostFilesModel::data(const QModelIndex &index, int role) co const ChannelPostFileInfo& fmpe(mFiles[mFilteredFiles[entry]]); -#ifdef TODO - if(role == Qt::FontRole) - { - QFont font ; - font.setBold( (fmpe.mPostFlags & (ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN | ForumModelPostEntry::FLAG_POST_IS_PINNED)) || IS_MSG_UNREAD(fmpe.mMsgStatus)); - return QVariant(font); - } - - if(role == UnreadChildrenRole) - return bool(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_HAS_UNREAD_CHILDREN); - -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << " [ok]" << std::endl; -#endif -#endif - switch(role) { case Qt::DisplayRole: return displayRole (fmpe,index.column()) ; case Qt::UserRole: return userRole (fmpe,index.column()) ; case SortRole: return sortRole (fmpe,index.column()) ; -#ifdef TODO - case Qt::DecorationRole: return decorationRole(fmpe,index.column()) ; - case Qt::ToolTipRole: return toolTipRole (fmpe,index.column()) ; - case Qt::TextColorRole: return textColorRole (fmpe,index.column()) ; - case Qt::BackgroundRole: return backgroundRole(fmpe,index.column()) ; - - case FilterRole: return filterRole (fmpe,index.column()) ; - case ThreadPinnedRole: return pinnedRole (fmpe,index.column()) ; - case MissingRole: return missingRole (fmpe,index.column()) ; - case StatusRole: return statusRole (fmpe,index.column()) ; -#endif default: return QVariant(); } @@ -409,176 +372,11 @@ void RsGxsChannelPostFilesModel::sort(int column, Qt::SortOrder order) update(); } -#ifdef TODO -QVariant RsGxsForumModel::textColorRole(const ForumModelPostEntry& fmpe,int /*column*/) const -{ - if( (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING)) - return QVariant(mTextColorMissing); - - if(IS_MSG_UNREAD(fmpe.mMsgStatus) || (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED)) - return QVariant(mTextColorUnread); - else - return QVariant(mTextColorRead); - - return QVariant(); -} - -QVariant RsGxsForumModel::statusRole(const ForumModelPostEntry& fmpe,int column) const -{ - if(column != COLUMN_THREAD_DATA) - return QVariant(); - - return QVariant(fmpe.mMsgStatus); -} - -uint32_t RsGxsForumModel::recursUpdateFilterStatus(ForumModelIndex i,int column,const QStringList& strings) -{ - QString s ; - uint32_t count = 0; - - switch(column) - { - default: - case COLUMN_THREAD_DATE: - case COLUMN_THREAD_TITLE: s = displayRole(mPosts[i],column).toString(); - break; - case COLUMN_THREAD_AUTHOR: - { - QString comment ; - QList icons; - - GxsIdDetails::MakeIdDesc(mPosts[i].mAuthorId, false,s, icons, comment,GxsIdDetails::ICON_TYPE_NONE); - } - break; - } - - if(!strings.empty()) - { - mPosts[i].mPostFlags &= ~(ForumModelPostEntry::FLAG_POST_PASSES_FILTER | ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER); - - for(auto iter(strings.begin()); iter != strings.end(); ++iter) - if(s.contains(*iter,Qt::CaseInsensitive)) - { - mPosts[i].mPostFlags |= ForumModelPostEntry::FLAG_POST_PASSES_FILTER | ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER; - - count++; - break; - } - } - else - { - mPosts[i].mPostFlags |= ForumModelPostEntry::FLAG_POST_PASSES_FILTER |ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER; - count++; - } - - for(uint32_t j=0;j 0) - mPosts[i].mPostFlags |= ForumModelPostEntry::FLAG_POST_CHILDREN_PASSES_FILTER; - } - - return count; -} - - -void RsGxsForumModel::setFilter(int column,const QStringList& strings,uint32_t& count) -{ - preMods(); - - if(!strings.empty()) - { - count = recursUpdateFilterStatus(ForumModelIndex(0),column,strings); - mFilteringEnabled = true; - } - else - { - count=0; - mFilteringEnabled = false; - } - - postMods(); -} - -QVariant RsGxsForumModel::missingRole(const ForumModelPostEntry& fmpe,int /*column*/) const -{ - if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING) - return QVariant(true); - else - return QVariant(false); -} - -QVariant RsGxsForumModel::toolTipRole(const ForumModelPostEntry& fmpe,int column) const -{ - if(column == COLUMN_THREAD_DISTRIBUTION) - switch(fmpe.mReputationWarningLevel) - { - case 3: return QVariant(tr("Information for this identity is currently missing.")) ; - case 2: return QVariant(tr("You have banned this ID. The message will not be\ndisplayed nor forwarded to your friends.")) ; - case 1: return QVariant(tr("You have not set an opinion for this person,\n and your friends do not vote positively: Spam regulation \nprevents the message to be forwarded to your friends.")) ; - case 0: return QVariant(tr("Message will be forwarded to your friends.")) ; - default: - return QVariant("[ERROR: missing reputation level information - contact the developers]"); - } - - if(column == COLUMN_THREAD_AUTHOR) - { - QString str,comment ; - QList icons; - - if(!GxsIdDetails::MakeIdDesc(fmpe.mAuthorId, true, str, icons, comment,GxsIdDetails::ICON_TYPE_AVATAR)) - return QVariant(); - - int S = QFontMetricsF(QApplication::font()).height(); - QImage pix( (*icons.begin()).pixmap(QSize(4*S,4*S)).toImage()); - - QString embeddedImage; - if(RsHtml::makeEmbeddedImage(pix.scaled(QSize(4*S,4*S), Qt::KeepAspectRatio, Qt::SmoothTransformation), embeddedImage, 8*S * 8*S)) - comment = "
" + embeddedImage + "" + comment + "
"; - - return comment; - } - - return QVariant(); -} - -QVariant RsGxsForumModel::pinnedRole(const ForumModelPostEntry& fmpe,int /*column*/) const -{ - if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) - return QVariant(true); - else - return QVariant(false); -} - -QVariant RsGxsForumModel::backgroundRole(const ForumModelPostEntry& fmpe,int /*column*/) const -{ - if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) - return QVariant(QBrush(QColor(255,200,180))); - - if(mFilteringEnabled && (fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_PASSES_FILTER)) - return QVariant(QBrush(QColor(255,240,210))); - - return QVariant(); -} -#endif - QVariant RsGxsChannelPostFilesModel::sizeHintRole(int col) const { float factor = QFontMetricsF(QApplication::font()).height()/14.0f ; return QVariant( QSize(factor * 170, factor*14 )); -#ifdef TODO - switch(col) - { - default: - case COLUMN_THREAD_TITLE: return QVariant( QSize(factor * 170, factor*14 )); - case COLUMN_THREAD_DATE: return QVariant( QSize(factor * 75 , factor*14 )); - case COLUMN_THREAD_AUTHOR: return QVariant( QSize(factor * 75 , factor*14 )); - case COLUMN_THREAD_DISTRIBUTION: return QVariant( QSize(factor * 15 , factor*14 )); - } -#endif } QVariant RsGxsChannelPostFilesModel::sortRole(const ChannelPostFileInfo& fmpe,int column) const @@ -607,57 +405,20 @@ QVariant RsGxsChannelPostFilesModel::displayRole(const ChannelPostFileInfo& fmpe { switch(col) { - case COLUMN_FILES_NAME: return QString::fromUtf8(fmpe.mName.c_str()); - case COLUMN_FILES_SIZE: return QString::number(fmpe.mSize); - case COLUMN_FILES_DATE: return QString::number(fmpe.mPublishTime); - case COLUMN_FILES_FILE: { - FileInfo finfo; - if(rsFiles->FileDetails(fmpe.mHash,RS_FILE_HINTS_DOWNLOAD,finfo)) - return qulonglong(finfo.transfered); - else - return 0; - } - default: - return QString(); -#ifdef TODO - case COLUMN_THREAD_TITLE: if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_REDACTED) - return QVariant(tr("[ ... Redacted message ... ]")); - else if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_PINNED) - return QVariant(tr("[PINNED] ") + QString::fromUtf8(fmpe.mTitle.c_str())); - else - return QVariant(QString::fromUtf8(fmpe.mTitle.c_str())); - - case COLUMN_THREAD_READ:return QVariant(); - case COLUMN_THREAD_DATE:{ - if(fmpe.mPostFlags & ForumModelPostEntry::FLAG_POST_IS_MISSING) - return QVariant(QString()); - - QDateTime qtime; - qtime.setTime_t(fmpe.mPublishTs); - - return QVariant(DateTime::formatDateTime(qtime)); - } - - case COLUMN_THREAD_DISTRIBUTION: - 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(); - if (filterColumn == COLUMN_THREAD_CONTENT) { - // need content for filter - QTextDocument doc; - doc.setHtml(QString::fromUtf8(msg.mMsg.c_str())); - item->setText(COLUMN_THREAD_CONTENT, doc.toPlainText().replace(QString("\n"), QString(" "))); + case COLUMN_FILES_NAME: return QString::fromUtf8(fmpe.mName.c_str()); + case COLUMN_FILES_SIZE: return QString::number(fmpe.mSize); + case COLUMN_FILES_DATE: return QString::number(fmpe.mPublishTime); + case COLUMN_FILES_FILE: { + FileInfo finfo; + if(rsFiles->FileDetails(fmpe.mHash,RS_FILE_HINTS_DOWNLOAD,finfo)) + return qulonglong(finfo.transfered); + else + return 0; + } + default: + return QString(); + } -#endif - } return QVariant("[ERROR]"); @@ -672,23 +433,6 @@ QVariant RsGxsChannelPostFilesModel::userRole(const ChannelPostFileInfo& fmpe,in } } -#ifdef TODO -QVariant RsGxsForumModel::decorationRole(const ForumModelPostEntry& fmpe,int col) const -{ - bool exist=false; - switch(col) - { - case COLUMN_THREAD_DISTRIBUTION: - return QVariant(fmpe.mReputationWarningLevel); - 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(); -} -#endif - void RsGxsChannelPostFilesModel::clear() { preMods(); @@ -714,11 +458,6 @@ void RsGxsChannelPostFilesModel::setFiles(const std::list & for(uint32_t i=0;i & else mTimer->stop(); } - -#ifdef DEBUG_FORUMMODEL -QModelIndex RsGxsChannelPostFilesModel::getIndexOfFile(const RsFileHash& hash) const -{ - // Brutal search. This is not so nice, so dont call that in a loop! If too costly, we'll use a map. - - for(uint32_t i=1;i& entries,ForumModelIndex index,int depth) -{ - const ForumModelPostEntry& e(entries[index]); - - QDateTime qtime; - qtime.setTime_t(e.mPublishTs); - - std::cerr << std::string(depth*2,' ') << index << " : " << e.mAuthorId.toStdString() << " " - << QString("%1").arg((uint32_t)e.mPostFlags,8,16,QChar('0')).toStdString() << " " - << QString("%1").arg((uint32_t)e.mMsgStatus,8,16,QChar('0')).toStdString() << " " - << qtime.toString().toStdString() << " \"" << e.mTitle << "\"" << std::endl; - - for(uint32_t i=0;i= mPosts.size()) - return ; - - std::cerr << "Setting own opinion for author " << mPosts[entry].mAuthorId - << " to " << static_cast(op) << std::endl; - RsGxsId author_id = mPosts[entry].mAuthorId; - - rsReputations->setOwnOpinion(author_id,op) ; - - // update opinions and distribution flags. No need to re-load all posts. - - for(uint32_t i=0;i Date: Thu, 18 Jun 2020 18:54:43 +0200 Subject: [PATCH 110/154] using shorter name for publish column --- retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp index 28bdb0e37..987144162 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostFilesModel.cpp @@ -239,7 +239,7 @@ QVariant RsGxsChannelPostFilesModel::headerData(int section, Qt::Orientation ori case COLUMN_FILES_FILE: return QString("Status"); case COLUMN_FILES_SIZE: return QString("Size"); case COLUMN_FILES_NAME: return QString("File"); - case COLUMN_FILES_DATE: return QString("Publish date"); + case COLUMN_FILES_DATE: return QString("Published"); default: return QString("[No data]"); } From 6a3fe9ebf0b73dbaee39de49f36697f37ee6b9b9 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 19 Jun 2020 23:03:13 +0200 Subject: [PATCH 111/154] added copy link and navigate functions. --- .../GxsChannelPostsWidgetWithModel.cpp | 77 ++++++++++++++++--- .../GxsChannelPostsWidgetWithModel.h | 2 +- .../gui/gxsforums/GxsForumThreadWidget.cpp | 42 +++++----- 3 files changed, 89 insertions(+), 32 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 5d3702f9a..6d51636eb 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "retroshare/rsgxscircles.h" @@ -71,6 +72,7 @@ static const int CHANNEL_TABS_POSTS = 1; #define COLUMN_SIZE_FONT_FACTOR_H 10 #define STAR_OVERLAY_IMAGE ":icons/star_overlay_128.png" +#define IMAGE_COPYLINK ":/images/copyrslink.png" Q_DECLARE_METATYPE(ChannelPostFileInfo) @@ -326,10 +328,43 @@ void GxsChannelPostsWidgetWithModel::postContextMenu(const QPoint&) { QMenu menu(this); + menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyMessageLink())); + if(IS_GROUP_PUBLISHER(mGroup.mMeta.mSubscribeFlags)) - { menu.addAction(FilesDefs::getIconFromQtResourcePath(":/images/edit_16.png"), tr("Edit"), this, SLOT(editPost())); - menu.exec(QCursor::pos()); + + menu.exec(QCursor::pos()); +} + +void GxsChannelPostsWidgetWithModel::copyMessageLink() +{ + try + { + if (groupId().isNull()) + throw std::runtime_error("No channel currently selected!"); + + QModelIndex index = ui->postsTree->selectionModel()->currentIndex(); + + if(!index.isValid()) + throw std::runtime_error("No post under mouse!"); + + RsGxsChannelPost post = index.data(Qt::UserRole).value() ; + + if(post.mMeta.mMsgId.isNull()) + throw std::runtime_error("Post has empty MsgId!"); + + RetroShareLink link = RetroShareLink::createGxsMessageLink(RetroShareLink::TYPE_CHANNEL, groupId(), post.mMeta.mMsgId, QString::fromUtf8(post.mMeta.mMsgName.c_str())); + + if (!link.valid()) + throw std::runtime_error("Link is not valid"); + + QList urls; + urls.push_back(link); + RSLinkClipboard::copyLinks(urls); + } + catch(std::exception& e) + { + QMessageBox::critical(NULL,tr("Link creation error"),tr("Link could not be created: ")+e.what()); } } @@ -386,7 +421,6 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() ui->postName_LB->hide(); ui->postTime_LB->hide(); mChannelPostFilesModel->clear(); - mSelectedGroup.clear(); mSelectedPost.clear(); return; } @@ -398,7 +432,6 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() if(index.row()==0 && index.column()==0) std::cerr << "here" << std::endl; - mSelectedGroup = mGroup.mMeta.mGroupId; mSelectedPost = post.mMeta.mMsgId; std::list files; @@ -454,7 +487,12 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() void GxsChannelPostsWidgetWithModel::updateGroupData() { if(groupId().isNull()) + { + // clear post, files and comment widgets + + showPostDetails(); return; + } RsThread::async([this]() { @@ -486,12 +524,18 @@ void GxsChannelPostsWidgetWithModel::postChannelPostLoad() { std::cerr << "Post channel load..." << std::endl; - if(!mSelectedPost.isNull() && mGroup.mMeta.mGroupId == mSelectedGroup) + if(!mSelectedPost.isNull()) { QModelIndex index = mChannelPostsModel->getIndexOfMessage(mSelectedPost); std::cerr << "Setting current index to " << index.row() << ","<< index.column() << " for current post " << mSelectedPost << std::endl; - whileBlocking(ui->postsTree)->setCurrentIndex(index); + + ui->postsTree->selectionModel()->setCurrentIndex(index,QItemSelectionModel::ClearAndSelect); + ui->postsTree->scrollTo(ui->postsTree->currentIndex());//May change if model reloaded + ui->postsTree->setFocus(); + ui->postsTree->update(); } + else + mSelectedPost.clear(); std::list files; @@ -978,11 +1022,24 @@ void GxsChannelPostsWidgetWithModel::blank() } -bool GxsChannelPostsWidgetWithModel::navigate(const RsGxsMessageId &msgId) +bool GxsChannelPostsWidgetWithModel::navigate(const RsGxsMessageId& msgId) { -#warning TODO - //return ui->feedWidget->scrollTo(feedItem, true); - return true; + QModelIndex index = mChannelPostsModel->getIndexOfMessage(msgId); + + if(!index.isValid()) + { + std::cerr << "(EE) Cannot navigate to msg " << msgId << " in channel " << mGroup.mMeta.mGroupId << ": index unknown. Setting mNavigatePendingMsgId." << std::endl; + + mSelectedPost = msgId; // not found. That means the forum may not be loaded yet. So we keep that post in mind, for after loading. + return true; // we have to return true here, otherwise the caller will intepret the async loading as an error. + } + + ui->postsTree->selectionModel()->setCurrentIndex(index,QItemSelectionModel::ClearAndSelect); + ui->postsTree->scrollTo(ui->postsTree->currentIndex());//May change if model reloaded + ui->postsTree->setFocus(); + ui->postsTree->update(); + + return true; } void GxsChannelPostsWidgetWithModel::subscribeGroup(bool subscribe) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index f278fcf89..86b840fd0 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -141,6 +141,7 @@ private slots: void postChannelPostLoad(); void editPost(); void postContextMenu(const QPoint&); + void copyMessageLink(); public slots: void sortColumnFiles(int col,Qt::SortOrder so); @@ -169,7 +170,6 @@ private: RsGxsChannelPostFilesModel *mChannelFilesModel; RsGxsMessageId mSelectedPost; - RsGxsGroupId mSelectedGroup; /* UI - from Designer */ Ui::GxsChannelPostsWidgetWithModel *ui; diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 5e7e481b3..29cfa5b44 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -123,9 +123,9 @@ public: { default: case 3: - case 0: icon = QIcon(IMAGE_VOID); break; - case 1: icon = QIcon(IMAGE_WARNING_YELLOW); break; - case 2: icon = QIcon(IMAGE_WARNING_RED); break; + case 0: icon = FilesDefs::getIconFromQtResourcePath(IMAGE_VOID); break; + case 1: icon = FilesDefs::getIconFromQtResourcePath(IMAGE_WARNING_YELLOW); break; + case 2: icon = FilesDefs::getIconFromQtResourcePath(IMAGE_WARNING_RED); break; } QPixmap pix = icon.pixmap(r.size()); @@ -172,9 +172,9 @@ public: else { if (unread) - icon = QIcon(":/images/message-state-unread.png"); + icon = FilesDefs::getIconFromQtResourcePath(":/images/message-state-unread.png"); else - icon = QIcon(":/images/message-state-read.png"); + icon = FilesDefs::getIconFromQtResourcePath(":/images/message-state-read.png"); } QPixmap pix = icon.pixmap(r.size()); @@ -462,7 +462,7 @@ QString GxsForumThreadWidget::groupName(bool withUnreadCount) QIcon GxsForumThreadWidget::groupIcon() { if (mNewCount) { - return QIcon(":/images/message-state-new.png"); + return FilesDefs::getIconFromQtResourcePath(":/images/message-state-new.png"); } return QIcon(); @@ -561,35 +561,35 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) #ifdef DEBUG_FORUMS std::cerr << "Clicked on msg " << current_post.mMsgId << std::endl; #endif - QAction *editAct = new QAction(QIcon(IMAGE_MESSAGEEDIT), tr("Edit"), &contextMnu); + QAction *editAct = new QAction(FilesDefs::getIconFromQtResourcePath(IMAGE_MESSAGEEDIT), tr("Edit"), &contextMnu); connect(editAct, SIGNAL(triggered()), this, SLOT(editforummessage())); bool is_pinned = mForumGroup.mPinnedPosts.ids.find(mThreadId) != mForumGroup.mPinnedPosts.ids.end(); - QAction *pinUpPostAct = new QAction(QIcon(IMAGE_PINPOST), (is_pinned?tr("Un-pin this post"):tr("Pin this post up")), &contextMnu); + QAction *pinUpPostAct = new QAction(FilesDefs::getIconFromQtResourcePath(IMAGE_PINPOST), (is_pinned?tr("Un-pin this post"):tr("Pin this post up")), &contextMnu); connect(pinUpPostAct , SIGNAL(triggered()), this, SLOT(togglePinUpPost())); - QAction *replyAct = new QAction(QIcon(IMAGE_REPLY), tr("Reply"), &contextMnu); + QAction *replyAct = new QAction(FilesDefs::getIconFromQtResourcePath(IMAGE_REPLY), tr("Reply"), &contextMnu); connect(replyAct, SIGNAL(triggered()), this, SLOT(replytoforummessage())); - QAction *replyauthorAct = new QAction(QIcon(IMAGE_MESSAGEREPLY), tr("Reply to author with private message"), &contextMnu); + QAction *replyauthorAct = new QAction(FilesDefs::getIconFromQtResourcePath(IMAGE_MESSAGEREPLY), tr("Reply to author with private message"), &contextMnu); connect(replyauthorAct, SIGNAL(triggered()), this, SLOT(reply_with_private_message())); - QAction *flagaspositiveAct = new QAction(QIcon(IMAGE_POSITIVE_OPINION), tr("Give positive opinion"), &contextMnu); + QAction *flagaspositiveAct = new QAction(FilesDefs::getIconFromQtResourcePath(IMAGE_POSITIVE_OPINION), tr("Give positive opinion"), &contextMnu); flagaspositiveAct->setToolTip(tr("This will block/hide messages from this person, and notify friend nodes.")) ; flagaspositiveAct->setData(static_cast(RsOpinion::POSITIVE)); connect(flagaspositiveAct, SIGNAL(triggered()), this, SLOT(flagperson())); - QAction *flagasneutralAct = new QAction(QIcon(IMAGE_NEUTRAL_OPINION), tr("Give neutral opinion"), &contextMnu); + QAction *flagasneutralAct = new QAction(FilesDefs::getIconFromQtResourcePath(IMAGE_NEUTRAL_OPINION), tr("Give neutral opinion"), &contextMnu); flagasneutralAct->setToolTip(tr("Doing this, you trust your friends to decide to forward this message or not.")) ; flagasneutralAct->setData(static_cast(RsOpinion::NEUTRAL)); connect(flagasneutralAct, SIGNAL(triggered()), this, SLOT(flagperson())); - QAction *flagasnegativeAct = new QAction(QIcon(IMAGE_NEGATIVE_OPINION), tr("Give negative opinion"), &contextMnu); + QAction *flagasnegativeAct = new QAction(FilesDefs::getIconFromQtResourcePath(IMAGE_NEGATIVE_OPINION), tr("Give negative opinion"), &contextMnu); flagasnegativeAct->setToolTip(tr("This will block/hide messages from this person, and notify friend nodes.")) ; flagasnegativeAct->setData(static_cast(RsOpinion::NEGATIVE)); connect(flagasnegativeAct, SIGNAL(triggered()), this, SLOT(flagperson())); - QAction *newthreadAct = new QAction(QIcon(IMAGE_MESSAGE), tr("Start New Thread"), &contextMnu); + QAction *newthreadAct = new QAction(FilesDefs::getIconFromQtResourcePath(IMAGE_MESSAGE), tr("Start New Thread"), &contextMnu); newthreadAct->setEnabled (IS_GROUP_SUBSCRIBED(mForumGroup.mMeta.mSubscribeFlags)); connect(newthreadAct , SIGNAL(triggered()), this, SLOT(createthread())); @@ -599,19 +599,19 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) QAction* collapseAll = new QAction(tr( "Collapse all"), &contextMnu); connect(collapseAll, SIGNAL(triggered()), ui->threadTreeWidget, SLOT(collapseAll())); - QAction *markMsgAsRead = new QAction(QIcon(":/images/message-mail-read.png"), tr("Mark as read"), &contextMnu); + QAction *markMsgAsRead = new QAction(FilesDefs::getIconFromQtResourcePath(":/images/message-mail-read.png"), tr("Mark as read"), &contextMnu); connect(markMsgAsRead, SIGNAL(triggered()), this, SLOT(markMsgAsRead())); - QAction *markMsgAsReadChildren = new QAction(QIcon(":/images/message-mail-read.png"), tr("Mark as read") + " (" + tr ("with children") + ")", &contextMnu); + QAction *markMsgAsReadChildren = new QAction(FilesDefs::getIconFromQtResourcePath(":/images/message-mail-read.png"), tr("Mark as read") + " (" + tr ("with children") + ")", &contextMnu); connect(markMsgAsReadChildren, SIGNAL(triggered()), this, SLOT(markMsgAsReadChildren())); - QAction *markMsgAsUnread = new QAction(QIcon(":/images/message-mail.png"), tr("Mark as unread"), &contextMnu); + QAction *markMsgAsUnread = new QAction(FilesDefs::getIconFromQtResourcePath(":/images/message-mail.png"), tr("Mark as unread"), &contextMnu); connect(markMsgAsUnread, SIGNAL(triggered()), this, SLOT(markMsgAsUnread())); - QAction *markMsgAsUnreadChildren = new QAction(QIcon(":/images/message-mail.png"), tr("Mark as unread") + " (" + tr ("with children") + ")", &contextMnu); + QAction *markMsgAsUnreadChildren = new QAction(FilesDefs::getIconFromQtResourcePath(":/images/message-mail.png"), tr("Mark as unread") + " (" + tr ("with children") + ")", &contextMnu); connect(markMsgAsUnreadChildren, SIGNAL(triggered()), this, SLOT(markMsgAsUnreadChildren())); - QAction *showinpeopleAct = new QAction(QIcon(":/images/info16.png"), tr("Show author in people tab"), &contextMnu); + QAction *showinpeopleAct = new QAction(FilesDefs::getIconFromQtResourcePath(":/images/info16.png"), tr("Show author in people tab"), &contextMnu); connect(showinpeopleAct, SIGNAL(triggered()), this, SLOT(showInPeopleTab())); if (IS_GROUP_SUBSCRIBED(mForumGroup.mMeta.mSubscribeFlags)) @@ -664,7 +664,7 @@ void GxsForumThreadWidget::threadListCustomPopupMenu(QPoint /*point*/) contextMnu.addAction(replyAct); contextMnu.addAction(newthreadAct); - QAction* action = contextMnu.addAction(QIcon(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyMessageLink())); + QAction* action = contextMnu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyMessageLink())); action->setEnabled(!groupId().isNull() && !mThreadId.isNull()); contextMnu.addSeparator(); contextMnu.addAction(markMsgAsRead); @@ -756,7 +756,7 @@ void GxsForumThreadWidget::togglethreadview_internal() { // if (ui->expandButton->isChecked()) { ui->postText->setVisible(true); - ui->expandButton->setIcon(QIcon(QString(":/images/edit_remove24.png"))); + ui->expandButton->setIcon(FilesDefs::getIconFromQtResourcePath(QString(":/images/edit_remove24.png"))); ui->expandButton->setToolTip(tr("Hide")); // } else { // ui->postText->setVisible(false); From d0a373c14f12f4025ac9e377e5e4e127624a0980 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 21 Jun 2020 21:43:10 +0200 Subject: [PATCH 112/154] print more debug info and added missing emit to display the channel tab name after loading --- libretroshare/src/services/p3gxscircles.cc | 2 ++ .../GxsChannelPostsWidgetWithModel.cpp | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 92b0c669e..58da554a1 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -1997,7 +1997,9 @@ bool p3GxsCircles::processMembershipRequests(uint32_t token) // now do another sweep and remove all msgs that are older than the latest +#ifdef DEBUG_CIRCLES std::cerr << " Cleaning old messages..." << std::endl; +#endif for(uint32_t i=0;isecond.size();++i) { diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 4a80b220e..8eabbcabf 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -417,9 +417,6 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() QTextDocument doc; doc.setHtml(post.mMsg.c_str()); - if(doc.toPlainText().trimmed().isEmpty()) - ui->postDetails_TE->setPlaceholderText(tr("No message in this post")); - if(post.mMeta.mPublishTs == 0) { ui->postDetails_TE->clear(); @@ -427,6 +424,8 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() ui->postName_LB->hide(); ui->postTime_LB->hide(); mChannelPostFilesModel->clear(); + + std::cerr << "showPostDetails: no valid post. Clearing mSelectedPost." << std::endl; mSelectedPost.clear(); return; } @@ -438,6 +437,7 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() if(index.row()==0 && index.column()==0) std::cerr << "here" << std::endl; + std::cerr << "showPostDetails: setting mSelectedPost to current post Id " << post.mMeta.mMsgId << ". Previous value: " << mSelectedPost << std::endl; mSelectedPost = post.mMeta.mMsgId; std::list files; @@ -522,6 +522,8 @@ void GxsChannelPostsWidgetWithModel::updateGroupData() mChannelPostsModel->updateChannel(groupId()); insertChannelDetails(mGroup); + + emit groupChanged(this); // signals the parent widget to e.g. update the group tab name } ); }); } @@ -533,7 +535,9 @@ void GxsChannelPostsWidgetWithModel::postChannelPostLoad() if(!mSelectedPost.isNull()) { QModelIndex index = mChannelPostsModel->getIndexOfMessage(mSelectedPost); - std::cerr << "Setting current index to " << index.row() << ","<< index.column() << " for current post " << mSelectedPost << std::endl; + + std::cerr << "Setting current index to " << index.row() << ","<< index.column() << " for current post " + << mSelectedPost.toStdString() << std::endl; ui->postsTree->selectionModel()->setCurrentIndex(index,QItemSelectionModel::ClearAndSelect); ui->postsTree->scrollTo(ui->postsTree->currentIndex());//May change if model reloaded @@ -541,7 +545,7 @@ void GxsChannelPostsWidgetWithModel::postChannelPostLoad() ui->postsTree->update(); } else - mSelectedPost.clear(); + std::cerr << "No pre-selected channel post." << std::endl; std::list files; @@ -551,7 +555,6 @@ void GxsChannelPostsWidgetWithModel::postChannelPostLoad() //ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE); //ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE); ui->channelFiles_TV->setAutoSelect(true); - ui->postDetails_TE->setPlaceholderText(tr("No post selected")); } @@ -651,7 +654,7 @@ void GxsChannelPostsWidgetWithModel::settingsChanged() QString GxsChannelPostsWidgetWithModel::groupName(bool) { - return "Group name" ; + return QString::fromUtf8(mGroup.mMeta.mGroupName.c_str()); } void GxsChannelPostsWidgetWithModel::groupNameChanged(const QString &name) @@ -1026,7 +1029,6 @@ void GxsChannelPostsWidgetWithModel::blank() mChannelPostsModel->clear(); mChannelPostFilesModel->clear(); ui->postDetails_TE->clear(); - ui->postDetails_TE->setPlaceholderText(tr("No post selected")); ui->postLogo_LB->hide(); ui->postName_LB->hide(); ui->postTime_LB->hide(); From 6863f4cc7033c0b7a44d6fba5df4b7e76e45e801 Mon Sep 17 00:00:00 2001 From: hunbernd Date: Sun, 21 Jun 2020 21:55:52 +0200 Subject: [PATCH 113/154] Fix hidden node crashing at the startup, caused by calling uninitialized objects. --- libretroshare/src/pqi/p3netmgr.cc | 10 ++++++---- libretroshare/src/pqi/p3netmgr.h | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/libretroshare/src/pqi/p3netmgr.cc b/libretroshare/src/pqi/p3netmgr.cc index 38007c309..cf4ab36fc 100644 --- a/libretroshare/src/pqi/p3netmgr.cc +++ b/libretroshare/src/pqi/p3netmgr.cc @@ -1803,15 +1803,16 @@ void p3NetMgrIMPL::updateNatSetting() #endif #ifdef RS_USE_DHT_STUNNER - switch(natType) - { - case RSNET_NATTYPE_RESTRICTED_CONE: + if (mProxyStunner) { + switch(natType) + { + case RSNET_NATTYPE_RESTRICTED_CONE: { if ((natHole == RSNET_NATHOLE_NONE) || (natHole == RSNET_NATHOLE_UNKNOWN)) { mProxyStunner->setRefreshPeriod(NET_STUNNER_PERIOD_FAST); } - else + else { mProxyStunner->setRefreshPeriod(NET_STUNNER_PERIOD_SLOW); } @@ -1826,6 +1827,7 @@ void p3NetMgrIMPL::updateNatSetting() mProxyStunner->setRefreshPeriod(NET_STUNNER_PERIOD_SLOW); break; + } } #endif // RS_USE_DHT_STUNNER diff --git a/libretroshare/src/pqi/p3netmgr.h b/libretroshare/src/pqi/p3netmgr.h index f7775757d..05c9b743a 100644 --- a/libretroshare/src/pqi/p3netmgr.h +++ b/libretroshare/src/pqi/p3netmgr.h @@ -291,8 +291,8 @@ private: //p3BitDht *mBitDht; #ifdef RS_USE_DHT_STUNNER - pqiAddrAssist *mDhtStunner; - pqiAddrAssist *mProxyStunner; + pqiAddrAssist *mDhtStunner = nullptr; + pqiAddrAssist *mProxyStunner = nullptr; #endif // RS_USE_DHT_STUNNER RsMutex mNetMtx; /* protects below */ From 1c2e094f20e1c8740b2fd7f14daa07ac4c5f1fa7 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 22 Jun 2020 23:52:59 +0200 Subject: [PATCH 114/154] removed tab system temporarily until we fix it --- retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp index 1245c80b2..ed00e16d1 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp @@ -432,12 +432,14 @@ void GxsGroupFrameDialog::groupTreeCustomPopupMenu(QPoint point) QMenu contextMnu(this); QAction *action; +#ifdef TODO if (mMessageWidget) { action = contextMnu.addAction(QIcon(IMAGE_TABNEW), tr("Open in new tab"), this, SLOT(openInNewTab())); if (mGroupId.isNull() || messageWidget(mGroupId, true)) { action->setEnabled(false); } } +#endif if (isSubscribed) { action = contextMnu.addAction(QIcon(IMAGE_UNSUBSCRIBE), tr("Unsubscribe"), this, SLOT(unsubscribeGroup())); @@ -817,7 +819,7 @@ GxsCommentDialog *GxsGroupFrameDialog::commentWidget(const RsGxsMessageId& msgId return NULL; } -void GxsGroupFrameDialog::changedCurrentGroup(const QString &groupId) +void GxsGroupFrameDialog::changedCurrentGroup(const QString& groupId) { if (mInFill) { return; @@ -839,8 +841,10 @@ void GxsGroupFrameDialog::changedCurrentGroup(const QString &groupId) /* search exisiting tab */ GxsMessageFrameWidget *msgWidget = messageWidget(mGroupId, true); - if (!msgWidget) { - if (mMessageWidget) { + if (!msgWidget) + { + if (mMessageWidget) + { /* not found, use standard tab */ msgWidget = mMessageWidget; msgWidget->setGroupId(mGroupId); From 97ad766863108ec390e01dcb1fda6b3790ebb9ab Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 23 Jun 2020 00:44:09 +0200 Subject: [PATCH 115/154] fixed selection of current item from link in channels --- .../src/gui/gxschannels/GxsChannelPostsModel.cpp | 4 ++-- .../gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index 8a78a59ca..47f46bfe9 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -719,7 +719,7 @@ QModelIndex RsGxsChannelPostsModel::getIndexOfMessage(const RsGxsMessageId& mid) quintptr ref ; convertTabEntryToRefPointer(i,ref); // we dont use i+1 here because i is not a row, but an index in the mPosts tab - return createIndex(i%mColumns, i/mColumns,ref); + return createIndex(i/mColumns,i%mColumns, ref); } if(mPosts[mFilteredPosts[i]].mMeta.mMsgId == postId) @@ -727,7 +727,7 @@ QModelIndex RsGxsChannelPostsModel::getIndexOfMessage(const RsGxsMessageId& mid) quintptr ref ; convertTabEntryToRefPointer(i,ref); // we dont use i+1 here because i is not a row, but an index in the mPosts tab - return createIndex(i%mColumns, i/mColumns,ref); + return createIndex(i/mColumns,i%mColumns, ref); } } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 8eabbcabf..7322841cc 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -425,8 +425,6 @@ void GxsChannelPostsWidgetWithModel::showPostDetails() ui->postTime_LB->hide(); mChannelPostFilesModel->clear(); - std::cerr << "showPostDetails: no valid post. Clearing mSelectedPost." << std::endl; - mSelectedPost.clear(); return; } @@ -540,9 +538,8 @@ void GxsChannelPostsWidgetWithModel::postChannelPostLoad() << mSelectedPost.toStdString() << std::endl; ui->postsTree->selectionModel()->setCurrentIndex(index,QItemSelectionModel::ClearAndSelect); - ui->postsTree->scrollTo(ui->postsTree->currentIndex());//May change if model reloaded + ui->postsTree->scrollTo(index);//May change if model reloaded ui->postsTree->setFocus(); - ui->postsTree->update(); } else std::cerr << "No pre-selected channel post." << std::endl; @@ -1049,9 +1046,8 @@ bool GxsChannelPostsWidgetWithModel::navigate(const RsGxsMessageId& msgId) } ui->postsTree->selectionModel()->setCurrentIndex(index,QItemSelectionModel::ClearAndSelect); - ui->postsTree->scrollTo(ui->postsTree->currentIndex());//May change if model reloaded + ui->postsTree->scrollTo(index);//May change if model reloaded ui->postsTree->setFocus(); - ui->postsTree->update(); return true; } From d39b09c5bcb2aafe95adaf67f6730050cccbd93a Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 23 Jun 2020 20:24:14 +0200 Subject: [PATCH 116/154] added zoom of thumbnails on control+wheel --- retroshare-gui/src/gui/common/RSTreeView.cpp | 8 +++ retroshare-gui/src/gui/common/RSTreeView.h | 2 + .../src/gui/gxs/GxsGroupFrameDialog.cpp | 49 ++++++++++--------- .../src/gui/gxs/GxsGroupFrameDialog.h | 5 +- .../src/gui/gxs/GxsMessageFrameWidget.h | 1 + .../GxsChannelPostsWidgetWithModel.cpp | 47 ++++++++++++++++-- .../GxsChannelPostsWidgetWithModel.h | 8 ++- .../GxsChannelPostsWidgetWithModel.ui | 4 +- 8 files changed, 91 insertions(+), 33 deletions(-) diff --git a/retroshare-gui/src/gui/common/RSTreeView.cpp b/retroshare-gui/src/gui/common/RSTreeView.cpp index 36034166f..d54987c3e 100644 --- a/retroshare-gui/src/gui/common/RSTreeView.cpp +++ b/retroshare-gui/src/gui/common/RSTreeView.cpp @@ -27,6 +27,14 @@ RSTreeView::RSTreeView(QWidget *parent) : QTreeView(parent) setMouseTracking(false); // normally the default, but who knows if it's not goign to change in the future. } +void RSTreeView::wheelEvent(QWheelEvent *e) +{ + if(e->modifiers() == Qt::ControlModifier) + emit zoomRequested(e->delta() > 0); + else + QTreeView::wheelEvent(e); +} + void RSTreeView::mouseMoveEvent(QMouseEvent *e) { QModelIndex idx = indexAt(e->pos()); diff --git a/retroshare-gui/src/gui/common/RSTreeView.h b/retroshare-gui/src/gui/common/RSTreeView.h index f7942ef64..116ccac31 100644 --- a/retroshare-gui/src/gui/common/RSTreeView.h +++ b/retroshare-gui/src/gui/common/RSTreeView.h @@ -40,9 +40,11 @@ public: signals: void sizeChanged(QSize); + void zoomRequested(bool zoom_or_unzoom); protected: virtual void mouseMoveEvent(QMouseEvent *e) override; // overriding so as to manage auto-selection + virtual void wheelEvent(QWheelEvent *e) override; // overriding so as to manage zoom virtual void resizeEvent(QResizeEvent *e) override; virtual void paintEvent(QPaintEvent *event) override; diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp index ed00e16d1..a2be34e8b 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp @@ -390,6 +390,7 @@ static uint32_t checkDelay(uint32_t time_in_secs) return 365 * 86400; } + void GxsGroupFrameDialog::groupTreeCustomPopupMenu(QPoint point) { // First separately handle the case of search top level items @@ -433,11 +434,12 @@ void GxsGroupFrameDialog::groupTreeCustomPopupMenu(QPoint point) QAction *action; #ifdef TODO - if (mMessageWidget) { - action = contextMnu.addAction(QIcon(IMAGE_TABNEW), tr("Open in new tab"), this, SLOT(openInNewTab())); - if (mGroupId.isNull() || messageWidget(mGroupId, true)) { + if (mMessageWidget) + { + action = contextMnu.addAction(QIcon(IMAGE_TABNEW), tr("Open new tab"), this, SLOT(openInNewTab())); + + if (mGroupId.isNull() || messageWidget(mGroupId, true)) // dont enable the open in tab if a tab is already here action->setEnabled(false); - } } #endif @@ -841,20 +843,19 @@ void GxsGroupFrameDialog::changedCurrentGroup(const QString& groupId) /* search exisiting tab */ GxsMessageFrameWidget *msgWidget = messageWidget(mGroupId, true); - if (!msgWidget) + // check that we have at least one tab + if(!currentWidget()) + msgWidget = createMessageWidget(RsGxsGroupId(groupId.toStdString())); + + if (msgWidget) + ui->messageTabWidget->setCurrentWidget(msgWidget); + else { - if (mMessageWidget) - { - /* not found, use standard tab */ - msgWidget = mMessageWidget; - msgWidget->setGroupId(mGroupId); - } else { - /* create new tab */ - msgWidget = createMessageWidget(mGroupId); - } + msgWidget = currentWidget(); + msgWidget->setGroupId(mGroupId); } - ui->messageTabWidget->setCurrentWidget(msgWidget); + mMessageWidget = msgWidget; } void GxsGroupFrameDialog::groupTreeMiddleButtonClicked(QTreeWidgetItem *item) @@ -885,18 +886,18 @@ void GxsGroupFrameDialog::openGroupInNewTab(const RsGxsGroupId &groupId) void GxsGroupFrameDialog::messageTabCloseRequested(int index) { - QWidget *widget = ui->messageTabWidget->widget(index); - if (!widget) { + if(ui->messageTabWidget->count() == 1) /* Don't close single tab */ return; - } - GxsMessageFrameWidget *msgWidget = dynamic_cast(widget); - if (msgWidget && msgWidget == mMessageWidget) { - /* Don't close single tab */ - return; - } + GxsMessageFrameWidget *msgWidget = dynamic_cast(ui->messageTabWidget->widget(index)); + delete msgWidget ; - delete(widget); + mMessageWidget = currentWidget(); +} + +GxsMessageFrameWidget *GxsGroupFrameDialog::currentWidget() const +{ + return dynamic_cast(ui->messageTabWidget->widget(ui->messageTabWidget->currentIndex())); } void GxsGroupFrameDialog::messageTabChanged(int index) diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h index 902e49087..e1d088a4b 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h @@ -192,13 +192,16 @@ protected: bool mCountChildMsgs; // Count unread child messages? private: + GxsMessageFrameWidget *currentWidget() const; + bool mInitialized; bool mInFill; bool mDistSyncAllowed; QString mSettingsName; RsGxsGroupId mGroupId; RsGxsIfaceHelper *mInterface; - GxsMessageFrameWidget *mMessageWidget; + + GxsMessageFrameWidget *mMessageWidget; // current widget QTreeWidgetItem *mYourGroups; QTreeWidgetItem *mSubscribedGroups; diff --git a/retroshare-gui/src/gui/gxs/GxsMessageFrameWidget.h b/retroshare-gui/src/gui/gxs/GxsMessageFrameWidget.h index 9b9a8e34e..36c2f4f67 100644 --- a/retroshare-gui/src/gui/gxs/GxsMessageFrameWidget.h +++ b/retroshare-gui/src/gui/gxs/GxsMessageFrameWidget.h @@ -55,6 +55,7 @@ signals: void groupChanged(QWidget *widget); void waitingChanged(QWidget *widget); void loadComment(const RsGxsGroupId &groupId, const QVector& msg_versions,const RsGxsMessageId &msgId, const QString &title); + void groupDataLoaded(); protected: virtual void setAllMessagesReadDo(bool read, uint32_t &token) = 0; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 7322841cc..5c9c70437 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -78,6 +78,21 @@ Q_DECLARE_METATYPE(ChannelPostFileInfo) // Delegate used to paint into the table of thumbnails +int ChannelPostDelegate::cellSize(const QFont& font) const +{ + return mZoom*COLUMN_SIZE_FONT_FACTOR_W*QFontMetricsF(font).height(); +} + +void ChannelPostDelegate::zoom(bool zoom_or_unzoom) +{ + if(zoom_or_unzoom) + mZoom *= 1.02; + else + mZoom /= 1.02; + + std::cerr << "zoom factor: " << mZoom << std::endl; +} + void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { // prepare @@ -101,11 +116,14 @@ void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & w.render(&pixmap,QPoint(),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background + if(mZoom != 1.0) + pixmap = pixmap.scaled(mZoom*pixmap.size(),Qt::KeepAspectRatio,Qt::SmoothTransformation); + if(IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus)) { QPainter p(&pixmap); QFontMetricsF fm(option.font); - p.drawPixmap(QPoint(6.2*fm.height(),6.9*fm.height()),FilesDefs::getPixmapFromQtResourcePath(STAR_OVERLAY_IMAGE).scaled(7*fm.height(),7*fm.height(),Qt::KeepAspectRatio,Qt::SmoothTransformation)); + p.drawPixmap(mZoom*QPoint(6.2*fm.height(),6.9*fm.height()),FilesDefs::getPixmapFromQtResourcePath(STAR_OVERLAY_IMAGE).scaled(mZoom*7*fm.height(),mZoom*7*fm.height(),Qt::KeepAspectRatio,Qt::SmoothTransformation)); } // debug @@ -128,7 +146,7 @@ QSize ChannelPostDelegate::sizeHint(const QStyleOptionViewItem& option, const QM QFontMetricsF fm(option.font); - return QSize(COLUMN_SIZE_FONT_FACTOR_W*fm.height(),COLUMN_SIZE_FONT_FACTOR_H*fm.height()); + return QSize(mZoom*COLUMN_SIZE_FONT_FACTOR_W*fm.height(),mZoom*COLUMN_SIZE_FONT_FACTOR_H*fm.height()); } QWidget *ChannelPostFilesDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex& index) const @@ -213,11 +231,13 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI ui->setupUi(this); ui->postsTree->setModel(mChannelPostsModel = new RsGxsChannelPostsModel()); - ui->postsTree->setItemDelegate(new ChannelPostDelegate()); + ui->postsTree->setItemDelegate(mChannelPostsDelegate = new ChannelPostDelegate()); ui->postsTree->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // prevents bug on w10, since row size depends on widget width ui->postsTree->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);// more beautiful if we scroll at pixel level ui->postsTree->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + connect(ui->postsTree,SIGNAL(zoomRequested(bool)),this,SLOT(updateZoomFactor(bool))); + ui->channelPostFiles_TV->setModel(mChannelPostFilesModel = new RsGxsChannelPostFilesModel(this)); ui->channelPostFiles_TV->setItemDelegate(new ChannelPostFilesDelegate()); ui->channelPostFiles_TV->setPlaceholderText(tr("No files in this post, or no post selected")); @@ -251,7 +271,7 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI QFontMetricsF fm(font()); for(int i=0;icolumnCount();++i) - ui->postsTree->setColumnWidth(i,COLUMN_SIZE_FONT_FACTOR_W*fm.height()); + ui->postsTree->setColumnWidth(i,mChannelPostsDelegate->cellSize(font())); /* Setup UI helper */ @@ -313,6 +333,23 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI }, mEventHandlerId, RsEventType::GXS_CHANNELS ); } +void GxsChannelPostsWidgetWithModel::updateZoomFactor(bool zoom_or_unzoom) +{ + mChannelPostsDelegate->zoom(zoom_or_unzoom); + + for(int i=0;icolumnCount();++i) + ui->postsTree->setColumnWidth(i,mChannelPostsDelegate->cellSize(font())); + + QSize s = ui->postsTree->size(); + + int n_columns = std::max(1,(int)floor(s.width() / (mChannelPostsDelegate->cellSize(font())))); + std::cerr << "nb columns: " << n_columns << std::endl; + + mChannelPostsModel->setNumColumns(n_columns); // forces the update + + ui->postsTree->dataChanged(QModelIndex(),QModelIndex()); +} + void GxsChannelPostsWidgetWithModel::sortColumnPostFiles(int col,Qt::SortOrder so) { std::cerr << "Sorting post files according to col " << col << std::endl; @@ -379,7 +416,7 @@ void GxsChannelPostsWidgetWithModel::editPost() void GxsChannelPostsWidgetWithModel::handlePostsTreeSizeChange(QSize s) { - int n_columns = std::max(1,(int)floor(s.width() / (COLUMN_SIZE_FONT_FACTOR_W*QFontMetricsF(font()).height()))); + int n_columns = std::max(1,(int)floor(s.width() / (mChannelPostsDelegate->cellSize(font())))); std::cerr << "nb columns: " << n_columns << std::endl; if(n_columns != mChannelPostsModel->columnCount()) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h index 86b840fd0..be2ccdf6c 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.h @@ -60,17 +60,21 @@ class ChannelPostDelegate: public QAbstractItemDelegate Q_OBJECT public: - ChannelPostDelegate(QObject *parent=0) : QAbstractItemDelegate(parent){} + ChannelPostDelegate(QObject *parent=0) : QAbstractItemDelegate(parent), mZoom(1.0){} virtual ~ChannelPostDelegate(){} void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const override; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override; + int cellSize(const QFont& font) const; + void zoom(bool zoom_or_unzoom) ; private: static constexpr float IMAGE_MARGIN_FACTOR = 1.0; static constexpr float IMAGE_SIZE_FACTOR_W = 4.0 ; static constexpr float IMAGE_SIZE_FACTOR_H = 6.0 ; static constexpr float IMAGE_ZOOM_FACTOR = 1.0; + + float mZoom; // zoom factor for the whole thumbnail }; class GxsChannelPostsWidgetWithModel: public GxsMessageFrameWidget @@ -142,6 +146,7 @@ private slots: void editPost(); void postContextMenu(const QPoint&); void copyMessageLink(); + void updateZoomFactor(bool zoom_or_unzoom); public slots: void sortColumnFiles(int col,Qt::SortOrder so); @@ -168,6 +173,7 @@ private: RsGxsChannelPostsModel *mChannelPostsModel; RsGxsChannelPostFilesModel *mChannelPostFilesModel; RsGxsChannelPostFilesModel *mChannelFilesModel; + ChannelPostDelegate *mChannelPostsDelegate; RsGxsMessageId mSelectedPost; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index 28687b2df..1f51702a2 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -161,7 +161,7 @@ - 0 + 1 @@ -337,7 +337,7 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:8pt;">Description</span></p></body></html> From b21193e460dc2fb34836daff007be9c49950d8cf Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 23 Jun 2020 21:37:36 +0200 Subject: [PATCH 117/154] tried to improve the logic in tab system. Not finished yet --- .../src/gui/gxs/GxsGroupFrameDialog.cpp | 108 +++++++++--------- .../src/gui/gxs/GxsGroupFrameDialog.h | 5 +- .../GxsChannelPostsWidgetWithModel.cpp | 1 + 3 files changed, 56 insertions(+), 58 deletions(-) diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp index a2be34e8b..890d353d9 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp @@ -89,7 +89,6 @@ GxsGroupFrameDialog::GxsGroupFrameDialog(RsGxsIfaceHelper *ifaceImpl, QWidget *p mSubscribedGroups = NULL; mPopularGroups = NULL; mOtherGroups = NULL; - mMessageWidget = NULL; /* Setup Queue */ mInterface = ifaceImpl; @@ -251,6 +250,13 @@ void GxsGroupFrameDialog::processSettings(bool load) Settings->endGroup(); } +bool GxsGroupFrameDialog::useTabs() +{ + GroupFrameSettings groupFrameSettings; + + return Settings->getGroupFrameSettings(groupFrameSettingsType(), groupFrameSettings) && groupFrameSettings.mOpenAllInNewTab; +} + void GxsGroupFrameDialog::settingsChanged() { GroupFrameSettings groupFrameSettings; @@ -262,17 +268,15 @@ void GxsGroupFrameDialog::settingsChanged() void GxsGroupFrameDialog::setSingleTab(bool singleTab) { - if (singleTab) { - if (!mMessageWidget) { - mMessageWidget = createMessageWidget(RsGxsGroupId()); - // remove close button of the the first tab - ui->messageTabWidget->hideCloseButton(ui->messageTabWidget->indexOf(mMessageWidget)); - } - } else { - if (mMessageWidget) { - delete(mMessageWidget); - mMessageWidget = NULL; - } + if (singleTab) + { + while(ui->messageTabWidget->count() > 1) + { + auto w = ui->messageTabWidget->widget(0) ; + ui->messageTabWidget->removeTab(0); + delete w; + } + ui->messageTabWidget->hideCloseButton(0); } } @@ -433,15 +437,10 @@ void GxsGroupFrameDialog::groupTreeCustomPopupMenu(QPoint point) QMenu contextMnu(this); QAction *action; -#ifdef TODO - if (mMessageWidget) - { - action = contextMnu.addAction(QIcon(IMAGE_TABNEW), tr("Open new tab"), this, SLOT(openInNewTab())); + action = contextMnu.addAction(QIcon(IMAGE_TABNEW), tr("Open in new tab"), this, SLOT(openInNewTab())); - if (mGroupId.isNull() || messageWidget(mGroupId, true)) // dont enable the open in tab if a tab is already here - action->setEnabled(false); - } -#endif + if(mGroupId.isNull()) // dont enable the open in tab if a tab is already here + action->setEnabled(false); if (isSubscribed) { action = contextMnu.addAction(QIcon(IMAGE_UNSUBSCRIBE), tr("Unsubscribe"), this, SLOT(unsubscribeGroup())); @@ -677,7 +676,7 @@ bool GxsGroupFrameDialog::getCurrentGroupName(QString& name) void GxsGroupFrameDialog::markMsgAsRead() { - GxsMessageFrameWidget *msgWidget = messageWidget(mGroupId, false); + GxsMessageFrameWidget *msgWidget = messageWidget(mGroupId); if (msgWidget) { msgWidget->setAllMessagesRead(true); } @@ -685,7 +684,7 @@ void GxsGroupFrameDialog::markMsgAsRead() void GxsGroupFrameDialog::markMsgAsUnread() { - GxsMessageFrameWidget *msgWidget = messageWidget(mGroupId, false); + GxsMessageFrameWidget *msgWidget = messageWidget(mGroupId); if (msgWidget) { msgWidget->setAllMessagesRead(false); } @@ -763,7 +762,7 @@ bool GxsGroupFrameDialog::navigate(const RsGxsGroupId &groupId, const RsGxsMessa changedCurrentGroup(groupIdString); /* search exisiting tab */ - GxsMessageFrameWidget *msgWidget = messageWidget(mGroupId, false); + GxsMessageFrameWidget *msgWidget = messageWidget(mGroupId); if (!msgWidget) { return false; } @@ -775,17 +774,16 @@ bool GxsGroupFrameDialog::navigate(const RsGxsGroupId &groupId, const RsGxsMessa return msgWidget->navigate(msgId); } -GxsMessageFrameWidget *GxsGroupFrameDialog::messageWidget(const RsGxsGroupId &groupId, bool ownTab) +GxsMessageFrameWidget *GxsGroupFrameDialog::messageWidget(const RsGxsGroupId &groupId) { int tabCount = ui->messageTabWidget->count(); - for (int index = 0; index < tabCount; ++index) { + + for (int index = 0; index < tabCount; ++index) + { GxsMessageFrameWidget *childWidget = dynamic_cast(ui->messageTabWidget->widget(index)); - if (ownTab && mMessageWidget && childWidget == mMessageWidget) { - continue; - } - if (childWidget && childWidget->groupId() == groupId) { + + if (childWidget && childWidget->groupId() == groupId) return childWidget; - } } return NULL; @@ -794,9 +792,9 @@ GxsMessageFrameWidget *GxsGroupFrameDialog::messageWidget(const RsGxsGroupId &gr GxsMessageFrameWidget *GxsGroupFrameDialog::createMessageWidget(const RsGxsGroupId &groupId) { GxsMessageFrameWidget *msgWidget = createMessageFrameWidget(groupId); - if (!msgWidget) { + + if (!msgWidget) return NULL; - } int index = ui->messageTabWidget->addTab(msgWidget, msgWidget->groupName(true)); ui->messageTabWidget->setTabIcon(index, msgWidget->groupIcon()); @@ -827,35 +825,38 @@ void GxsGroupFrameDialog::changedCurrentGroup(const QString& groupId) return; } - if (groupId.isEmpty()) { - if (mMessageWidget) { - mMessageWidget->setGroupId(RsGxsGroupId()); - ui->messageTabWidget->setCurrentWidget(mMessageWidget); - } + if (groupId.isEmpty()) + { + auto w = currentWidget(); + + if(w) + w->setGroupId(RsGxsGroupId()); + return; } mGroupId = RsGxsGroupId(groupId.toStdString()); - if (mGroupId.isNull()) { + + if (mGroupId.isNull()) return; - } /* search exisiting tab */ - GxsMessageFrameWidget *msgWidget = messageWidget(mGroupId, true); + GxsMessageFrameWidget *msgWidget = messageWidget(mGroupId); // check that we have at least one tab - if(!currentWidget()) - msgWidget = createMessageWidget(RsGxsGroupId(groupId.toStdString())); - if (msgWidget) + if(msgWidget) ui->messageTabWidget->setCurrentWidget(msgWidget); else { - msgWidget = currentWidget(); - msgWidget->setGroupId(mGroupId); + if(useTabs() || ui->messageTabWidget->count()==0) + { + msgWidget = createMessageWidget(RsGxsGroupId(groupId.toStdString())); + ui->messageTabWidget->setCurrentWidget(msgWidget); + } + else + currentWidget()->setGroupId(mGroupId); } - - mMessageWidget = msgWidget; } void GxsGroupFrameDialog::groupTreeMiddleButtonClicked(QTreeWidgetItem *item) @@ -875,11 +876,10 @@ void GxsGroupFrameDialog::openGroupInNewTab(const RsGxsGroupId &groupId) } /* search exisiting tab */ - GxsMessageFrameWidget *msgWidget = messageWidget(groupId, true); - if (!msgWidget) { - /* not found, create new tab */ + GxsMessageFrameWidget *msgWidget = messageWidget(groupId); + + if (!msgWidget) /* not found, create new tab */ msgWidget = createMessageWidget(groupId); - } ui->messageTabWidget->setCurrentWidget(msgWidget); } @@ -891,8 +891,6 @@ void GxsGroupFrameDialog::messageTabCloseRequested(int index) GxsMessageFrameWidget *msgWidget = dynamic_cast(ui->messageTabWidget->widget(index)); delete msgWidget ; - - mMessageWidget = currentWidget(); } GxsMessageFrameWidget *GxsGroupFrameDialog::currentWidget() const @@ -903,9 +901,9 @@ GxsMessageFrameWidget *GxsGroupFrameDialog::currentWidget() const void GxsGroupFrameDialog::messageTabChanged(int index) { GxsMessageFrameWidget *msgWidget = dynamic_cast(ui->messageTabWidget->widget(index)); - if (!msgWidget) { + + if (!msgWidget) return; - } ui->groupTreeWidget->activateId(QString::fromStdString(msgWidget->groupId().toStdString()), false); } diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h index e1d088a4b..73938584e 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h @@ -181,7 +181,7 @@ private: // subscribe/unsubscribe ack. - GxsMessageFrameWidget *messageWidget(const RsGxsGroupId &groupId, bool ownTab); + GxsMessageFrameWidget *messageWidget(const RsGxsGroupId &groupId); GxsMessageFrameWidget *createMessageWidget(const RsGxsGroupId &groupId); GxsCommentDialog *commentWidget(const RsGxsMessageId &msgId); @@ -193,6 +193,7 @@ protected: private: GxsMessageFrameWidget *currentWidget() const; + bool useTabs(); bool mInitialized; bool mInFill; @@ -201,8 +202,6 @@ private: RsGxsGroupId mGroupId; RsGxsIfaceHelper *mInterface; - GxsMessageFrameWidget *mMessageWidget; // current widget - QTreeWidgetItem *mYourGroups; QTreeWidgetItem *mSubscribedGroups; QTreeWidgetItem *mPopularGroups; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 5c9c70437..690563321 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -558,6 +558,7 @@ void GxsChannelPostsWidgetWithModel::updateGroupData() insertChannelDetails(mGroup); + emit groupDataLoaded(); emit groupChanged(this); // signals the parent widget to e.g. update the group tab name } ); }); From c23d994bfcf55e9c30f5edaccf0ae3a300fce570 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 23 Jun 2020 21:53:03 +0200 Subject: [PATCH 118/154] fixed update of channel data on tabs --- .../src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 690563321..6db53d2b6 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -323,6 +323,7 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI setAutoDownload(false); settingsChanged(); + setGroupId(channelId); mChannelPostsModel->updateChannel(channelId); mEventHandlerId = 0; From 0eb8edf824fca94deb9fb4d0e68c88919b883a94 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 23 Jun 2020 22:00:14 +0200 Subject: [PATCH 119/154] fixed open in new tab system --- retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp index 890d353d9..de528d23e 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp @@ -876,10 +876,7 @@ void GxsGroupFrameDialog::openGroupInNewTab(const RsGxsGroupId &groupId) } /* search exisiting tab */ - GxsMessageFrameWidget *msgWidget = messageWidget(groupId); - - if (!msgWidget) /* not found, create new tab */ - msgWidget = createMessageWidget(groupId); + GxsMessageFrameWidget *msgWidget = createMessageWidget(groupId); ui->messageTabWidget->setCurrentWidget(msgWidget); } From d2b9b9f0949d66bd1f245ed08ac83fcf956cb9c1 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Tue, 23 Jun 2020 23:38:22 +0200 Subject: [PATCH 120/154] Reduce memory usage due to copying in IdDialog::updateCircles Heaptrack reported 141MB of RAM where used by this method most proably due to the group metadata list being copied accross lambdas and threads more then necessary. Use an unique_ptr to safely avoid copying of big structure around. --- retroshare-gui/src/gui/Identity/IdDialog.cpp | 19 +++++++++++++------ retroshare-gui/src/util/qtthreadsutils.h | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index 1a585d532..2c81d2b10 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -47,6 +47,7 @@ #include "util/misc.h" #include "util/QtVersion.h" #include "util/rstime.h" +#include "util/rsdebug.h" #include "retroshare/rsgxsflags.h" #include "retroshare/rsmsgs.h" @@ -55,6 +56,7 @@ #include #include +#include /****** * #define ID_DEBUG 1 @@ -506,21 +508,26 @@ void IdDialog::updateCircles() std::cerr << "Retrieving post data for post " << mThreadId << std::endl; #endif - std::list circle_metas ; + /* This can be big so use a smart pointer to just copy the pointer + * instead of copying the whole list accross the lambdas. + * Heaptrack reported 141MB of RAM where used to copy this around + * before this change. */ + auto circle_metas = std::make_unique>(); - if(!rsGxsCircles->getCirclesSummaries(circle_metas)) + if(!rsGxsCircles->getCirclesSummaries(*circle_metas)) { - std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve circles group info list" << std::endl; + RS_ERR("failed to retrieve circles group info list"); return; - } + } - RsQThreadUtils::postToObject( [circle_metas,this]() + RsQThreadUtils::postToObject( + [circle_metas = std::move(circle_metas), this]() { /* Here it goes any code you want to be executed on the Qt Gui * thread, for example to update the data model with new information * after a blocking call to RetroShare API complete */ - loadCircles(circle_metas); + loadCircles(*circle_metas); }, this ); diff --git a/retroshare-gui/src/util/qtthreadsutils.h b/retroshare-gui/src/util/qtthreadsutils.h index 155b71b7e..689161fde 100644 --- a/retroshare-gui/src/util/qtthreadsutils.h +++ b/retroshare-gui/src/util/qtthreadsutils.h @@ -44,7 +44,7 @@ void postToObject(F &&fun, QObject *obj = qApp) QObject src; auto type = obj->metaObject(); QObject::connect( &src, &QObject::destroyed, obj, - [fun, type, obj] + [fun = std::move(fun), type, obj] { // ensure that the object is not being destructed if (obj->metaObject()->inherits(type)) fun(); From 3b37c1e9ad2e2c2919f9f66cbb4e101d5ac948a6 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Wed, 24 Jun 2020 00:21:33 +0200 Subject: [PATCH 121/154] Remove more copying of big structures in RsQThreadUtils::postToObject --- .../src/gui/Circles/CreateCircleDialog.cpp | 27 +++++++++---------- retroshare-gui/src/gui/Identity/IdDialog.cpp | 18 +++++-------- .../src/gui/Identity/IdEditDialog.cpp | 4 +-- .../src/gui/common/FriendSelectionWidget.cpp | 26 +++++++++--------- .../gui/statistics/GxsTransportStatistics.cpp | 24 +++++++++-------- retroshare-gui/src/util/qtthreadsutils.h | 4 ++- 6 files changed, 50 insertions(+), 53 deletions(-) diff --git a/retroshare-gui/src/gui/Circles/CreateCircleDialog.cpp b/retroshare-gui/src/gui/Circles/CreateCircleDialog.cpp index 59b0da95d..3733c0f1a 100644 --- a/retroshare-gui/src/gui/Circles/CreateCircleDialog.cpp +++ b/retroshare-gui/src/gui/Circles/CreateCircleDialog.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -696,34 +697,32 @@ void CreateCircleDialog::loadIdentities() { RsThread::async([this]() { - std::list ids_meta; + std::list ids_meta; if(!rsIdentity->getIdentitiesSummaries(ids_meta)) { - std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve identities ids for all identities" << std::endl; + RS_ERR("failed to retrieve identities ids for all identities"); return; - } - std::set ids; + } - for(auto& meta:ids_meta) - ids.insert(RsGxsId(meta.mGroupId)) ; + std::set ids; + for(auto& meta:ids_meta) ids.insert(RsGxsId(meta.mGroupId)); - std::vector id_groups; - - if(!rsIdentity->getIdentitiesInfo(ids,id_groups)) + auto id_groups = std::make_unique>(); + if(!rsIdentity->getIdentitiesInfo(ids, *id_groups)) { - std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve identities group info for all identities" << std::endl; + RS_ERR("failed to retrieve identities group info for all identities"); return; - } + } - RsQThreadUtils::postToObject( [id_groups,this]() + RsQThreadUtils::postToObject( + [id_groups = std::move(id_groups), this]() { /* Here it goes any code you want to be executed on the Qt Gui * thread, for example to update the data model with new information * after a blocking call to RetroShare API complete */ - fillIdentitiesList(id_groups) ; - + fillIdentitiesList(*id_groups); }, this ); }); diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index 2c81d2b10..d49e558ec 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -509,9 +509,7 @@ void IdDialog::updateCircles() #endif /* This can be big so use a smart pointer to just copy the pointer - * instead of copying the whole list accross the lambdas. - * Heaptrack reported 141MB of RAM where used to copy this around - * before this change. */ + * instead of copying the whole list accross the lambdas */ auto circle_metas = std::make_unique>(); if(!rsGxsCircles->getCirclesSummaries(*circle_metas)) @@ -1312,19 +1310,17 @@ void IdDialog::updateIdList() return; } - std::map ids_set; + auto ids_set = std::make_unique>(); + for(auto it(groups.begin()); it!=groups.end(); ++it) + (*ids_set)[(*it).mMeta.mGroupId] = *it; - for(auto it(groups.begin());it!=groups.end();++it) - ids_set[(*it).mMeta.mGroupId] = *it; - - RsQThreadUtils::postToObject( [ids_set,this]() + RsQThreadUtils::postToObject( + [ids_set = std::move(ids_set), this] () { /* Here it goes any code you want to be executed on the Qt Gui * thread, for example to update the data model with new information * after a blocking call to RetroShare API complete */ - - loadIdentities(ids_set); - + loadIdentities(*ids_set); }, this ); }); diff --git a/retroshare-gui/src/gui/Identity/IdEditDialog.cpp b/retroshare-gui/src/gui/Identity/IdEditDialog.cpp index bb1ee139a..0f432ba2d 100644 --- a/retroshare-gui/src/gui/Identity/IdEditDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdEditDialog.cpp @@ -210,8 +210,8 @@ void IdEditDialog::setupExistingId(const RsGxsGroupId& keyId) RsThread::async([this,keyId]() { std::vector datavector; - - bool res = rsIdentity->getIdentitiesInfo(std::set({(RsGxsId)keyId}),datavector); + bool res = rsIdentity->getIdentitiesInfo( + std::set({(RsGxsId)keyId}), datavector ); RsQThreadUtils::postToObject( [this,keyId,res,datavector]() { diff --git a/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp b/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp index fa5c439f1..4043fe424 100644 --- a/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp +++ b/retroshare-gui/src/gui/common/FriendSelectionWidget.cpp @@ -36,6 +36,7 @@ #include #include +#include #define COLUMN_NAME 0 #define COLUMN_CHECK 0 @@ -250,24 +251,21 @@ void FriendSelectionWidget::loadIdentities() if(!rsIdentity->getIdentitiesSummaries(ids_meta)) { - std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve identities group info for all identities" << std::endl; + RS_ERR("failed to retrieve identities group info for all identities"); return; - } - std::vector ids; + } - for(auto& meta:ids_meta) - ids.push_back(meta.mGroupId) ; + auto ids = std::make_unique>(); + for(auto& meta: ids_meta) ids->push_back(meta.mGroupId); - RsQThreadUtils::postToObject( [ids,this]() + RsQThreadUtils::postToObject( + [ids = std::move(ids), this]() { - /* Here it goes any code you want to be executed on the Qt Gui - * thread, for example to update the data model with new information - * after a blocking call to RetroShare API complete */ - - gxsIds = ids; // we do that is the GUI thread. Dont try it on another thread! - - fillList() ; - + // We do that is the GUI thread. Dont try it on another thread! + gxsIds = *ids; + /* TODO: To furter optimize away a copy gxsIds could be a unique_ptr + * too */ + fillList(); }, this ); }); } diff --git a/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp b/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp index 4f1605c46..c258cb4bc 100644 --- a/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp +++ b/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -463,24 +464,25 @@ void GxsTransportStatistics::loadGroups() #ifdef DEBUG_FORUMS std::cerr << "Retrieving post data for post " << mThreadId << std::endl; #endif - std::map stats; + auto stats = std::make_unique< + std::map >(); - if(!rsGxsTrans->getGroupStatistics(stats)) - { - RsErr() << "Cannot retrieve group statistics in GxsTransportStatistics" << std::endl; - return; - } + if(!rsGxsTrans->getGroupStatistics(*stats)) + { + RS_ERR("Cannot retrieve group statistics in GxsTransportStatistics"); + return; + } - RsQThreadUtils::postToObject( [stats,this]() + RsQThreadUtils::postToObject( + [stats = std::move(stats), this]() { /* Here it goes any code you want to be executed on the Qt Gui * thread, for example to update the data model with new information * after a blocking call to RetroShare API complete */ - mGroupStats = stats; - - updateContent(); - + // TODO: consider making mGroupStats an unique_ptr to avoid copying + mGroupStats = *stats; + updateContent(); mStateHelper->setLoading(GXSTRANS_GROUP_META, false); }, this ); diff --git a/retroshare-gui/src/util/qtthreadsutils.h b/retroshare-gui/src/util/qtthreadsutils.h index 689161fde..1c377b35d 100644 --- a/retroshare-gui/src/util/qtthreadsutils.h +++ b/retroshare-gui/src/util/qtthreadsutils.h @@ -1,7 +1,7 @@ /******************************************************************************* * util/qthreadutils.h * * * - * Copyright (C) 2018 Gioacchino Mazzurco * + * Copyright (C) 2018-2020 Gioacchino Mazzurco * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU Affero General Public License as * @@ -27,7 +27,9 @@ #include #include + #include +#include namespace RsQThreadUtils { From 7c89140bcccc81f911e911c84c392cc64420f658 Mon Sep 17 00:00:00 2001 From: defnax Date: Thu, 25 Jun 2020 14:28:40 +0200 Subject: [PATCH 122/154] Fixing layout issues on Channel Composer --- .../gui/gxschannels/CreateGxsChannelMsg.ui | 265 +++++++++--------- 1 file changed, 140 insertions(+), 125 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.ui b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.ui index d8baaba24..8912307e3 100644 --- a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.ui +++ b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.ui @@ -6,8 +6,8 @@ 0 0 - 671 - 513 + 736 + 271 @@ -20,7 +20,7 @@ :/images/logo/logo_16.png:/images/logo/logo_16.png - + 0 @@ -33,9 +33,6 @@ 0 - - 0 - @@ -52,40 +49,15 @@ QFrame::Raised - - - - - - Generate mass data - - - - - - - 1 - - - 999 - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - + + 3 + + + 6 + + + 0 + @@ -102,46 +74,73 @@ - - - - - - - 0 - 0 - - - - - 75 - true - - - - Channel Post to: - - - - - - - true - - - true - - - - - + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + 6 + + + QLayout::SetFixedSize + + + 6 + + + + + 6 + + + + + + 0 + 0 + + + + + 75 + true + + + + Channel Post to: + + + + + + + true + + + true + + + + + @@ -209,6 +208,20 @@ p, li { white-space: pre-wrap; } + + + + 6 + + + + + Title + + + + + @@ -217,7 +230,7 @@ p, li { white-space: pre-wrap; } 20 - 40 + 1 @@ -227,26 +240,7 @@ p, li { white-space: pre-wrap; } - - - Message - - - - 0 - - - - - Title - - - - - - - - + @@ -256,7 +250,7 @@ p, li { white-space: pre-wrap; } 0 - 0 + 6 0 @@ -309,7 +303,7 @@ p, li { white-space: pre-wrap; } 0 0 - 635 + 81 24 @@ -383,6 +377,23 @@ p, li { white-space: pre-wrap; } + + + + Channel Post + + + + :/icons/png/comment.png:/icons/png/comment.png + + + + 24 + 24 + + + + @@ -413,35 +424,39 @@ p, li { white-space: pre-wrap; } - - - - Channel Post - - - - :/icons/png/comment.png:/icons/png/comment.png - - - - 24 - 24 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - + + + + + + Generate mass data + + + + + + + 1 + + + 999 + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + From 598f9f196490fcf53ed587c73dd0ee9b79c74bc0 Mon Sep 17 00:00:00 2001 From: defnax Date: Thu, 25 Jun 2020 14:36:38 +0200 Subject: [PATCH 123/154] Fixing margins --- retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.ui | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.ui b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.ui index 8912307e3..c0d28ac5f 100644 --- a/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.ui +++ b/retroshare-gui/src/gui/gxschannels/CreateGxsChannelMsg.ui @@ -33,6 +33,12 @@ 0 + + 6 + + + 0 + @@ -211,7 +217,7 @@ p, li { white-space: pre-wrap; } - 6 + 9 From ec92afa2fe9e6013d723ab42e3d99d6e9b5b418d Mon Sep 17 00:00:00 2001 From: defnax Date: Thu, 25 Jun 2020 16:36:16 +0200 Subject: [PATCH 124/154] Fixed to get work selection color on darkstylesheets * Fixed to get work selection color on dark stylesheets * Show group icon on the tabs --- .../gui/gxschannels/GxsChannelPostThumbnail.h | 2 ++ .../GxsChannelPostsWidgetWithModel.cpp | 16 ++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostThumbnail.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostThumbnail.h index fd5c82d6b..4a0ae5855 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostThumbnail.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostThumbnail.h @@ -36,6 +36,8 @@ class ChannelPostThumbnailView: public QWidget { + Q_OBJECT + public: // This variable determines the zoom factor on the text below thumbnails. 2.0 is mostly correct for all screen. static constexpr float THUMBNAIL_OVERSAMPLE_FACTOR = 2.0; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 6db53d2b6..73508c1e8 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -705,15 +705,15 @@ void GxsChannelPostsWidgetWithModel::groupNameChanged(const QString &name) QIcon GxsChannelPostsWidgetWithModel::groupIcon() { -// if (mStateHelper->isLoading(mTokenTypeGroupData) || mStateHelper->isLoading(mTokenTypeAllPosts)) { -// return QIcon(":/images/kalarm.png"); -// } + /* CHANNEL IMAGE */ + QPixmap chanImage; + if (mGroup.mImage.mData != NULL) { + GxsIdDetails::loadPixmapFromData(mGroup.mImage.mData, mGroup.mImage.mSize, chanImage,GxsIdDetails::ORIGINAL); + } else { + chanImage = FilesDefs::getPixmapFromQtResourcePath(ChannelPostThumbnailView::CHAN_DEFAULT_IMAGE); + } -// if (mNewCount) { -// return QIcon(":/images/message-state-new.png"); -// } - - return QIcon(); + return QIcon(chanImage); } /*************************************************************************************/ From ba486a0029c10ae47e247b55cb00253b8d4eae2d Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 25 Jun 2020 21:15:37 +0200 Subject: [PATCH 125/154] multiple improvements in distant channel search and general display of distant search results --- libretroshare/src/retroshare/rsgxschannels.h | 2 +- libretroshare/src/services/p3gxschannels.cc | 2 +- libretroshare/src/services/p3gxschannels.h | 2 +- .../src/gui/common/GroupTreeWidget.cpp | 3 ++- .../src/gui/gxs/GxsGroupFrameDialog.cpp | 21 +++++++++++++------ .../src/gui/gxs/GxsGroupFrameDialog.h | 1 + .../src/gui/gxschannels/GxsChannelDialog.cpp | 12 ++++++++++- .../src/gui/gxschannels/GxsChannelDialog.h | 7 ++++--- .../gui/gxschannels/GxsChannelPostsWidget.cpp | 5 +++-- .../GxsChannelPostsWidgetWithModel.cpp | 17 +++++++-------- .../GxsChannelPostsWidgetWithModel.ui | 2 +- 11 files changed, 47 insertions(+), 27 deletions(-) diff --git a/libretroshare/src/retroshare/rsgxschannels.h b/libretroshare/src/retroshare/rsgxschannels.h index c03f22970..8fd02a3b1 100644 --- a/libretroshare/src/retroshare/rsgxschannels.h +++ b/libretroshare/src/retroshare/rsgxschannels.h @@ -717,7 +717,7 @@ public: virtual TurtleRequestId turtleGroupRequest(const RsGxsGroupId& group_id)=0; virtual TurtleRequestId turtleSearchRequest(const std::string& match_string)=0; virtual bool clearDistantSearchResults(TurtleRequestId req)=0; - virtual bool retrieveDistantGroup(const RsGxsGroupId& group_id,RsGxsChannelGroup& distant_group)=0; + virtual bool getDistantSearchResultGroupData(const RsGxsGroupId& group_id,RsGxsChannelGroup& distant_group)=0; virtual bool retrieveDistantSearchResults(TurtleRequestId req, std::map &results) =0; ////////////////////////////////////////////////////////////////////////////// diff --git a/libretroshare/src/services/p3gxschannels.cc b/libretroshare/src/services/p3gxschannels.cc index 01ddb4357..bdb1f9981 100644 --- a/libretroshare/src/services/p3gxschannels.cc +++ b/libretroshare/src/services/p3gxschannels.cc @@ -2402,7 +2402,7 @@ bool p3GxsChannels::retrieveDistantSearchResults(TurtleRequestId req,std::mapretrieveDistantSearchResults(req,results); } -bool p3GxsChannels::retrieveDistantGroup(const RsGxsGroupId& group_id,RsGxsChannelGroup& distant_group) +bool p3GxsChannels::getDistantSearchResultGroupData(const RsGxsGroupId& group_id,RsGxsChannelGroup& distant_group) { RsGxsGroupSearchResults gs; diff --git a/libretroshare/src/services/p3gxschannels.h b/libretroshare/src/services/p3gxschannels.h index 12c18d5c4..da274690b 100644 --- a/libretroshare/src/services/p3gxschannels.h +++ b/libretroshare/src/services/p3gxschannels.h @@ -70,7 +70,7 @@ protected: virtual TurtleRequestId turtleSearchRequest(const std::string& match_string); virtual bool retrieveDistantSearchResults(TurtleRequestId req, std::map &results) ; virtual bool clearDistantSearchResults(TurtleRequestId req); - virtual bool retrieveDistantGroup(const RsGxsGroupId& group_id,RsGxsChannelGroup& distant_group); + virtual bool getDistantSearchResultGroupData(const RsGxsGroupId& group_id,RsGxsChannelGroup& distant_group); // Overloaded to cache new groups. virtual RsGenExchange::ServiceCreate_Return service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet); diff --git a/retroshare-gui/src/gui/common/GroupTreeWidget.cpp b/retroshare-gui/src/gui/common/GroupTreeWidget.cpp index 799331e57..c67dfbc20 100644 --- a/retroshare-gui/src/gui/common/GroupTreeWidget.cpp +++ b/retroshare-gui/src/gui/common/GroupTreeWidget.cpp @@ -467,7 +467,8 @@ void GroupTreeWidget::fillGroupItems(QTreeWidgetItem *categoryItem, const QList< while(nullptr != item->takeChild(0)); for(auto str:itemInfo.context_strings) - item->addChild(new QTreeWidgetItem(QStringList(QString::fromUtf8(str.c_str())))); + if(!str.empty()) + item->addChild(new QTreeWidgetItem(QStringList(QString::fromUtf8(str.c_str())))); /* Set last post */ qlonglong lastPost = itemInfo.lastpost.toTime_t(); diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp index 7d5ac1f7c..49b91866d 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp @@ -316,6 +316,8 @@ void GxsGroupFrameDialog::updateSearchResults(const TurtleRequestId& sid) for(auto it3(group_infos.begin());it3!=group_infos.end();++it3) { std::cerr << " adding group " << it3->first << " " << it3->second.mGroupId << " \"" << it3->second.mGroupName << "\"" << std::endl; + for(auto s:it3->second.mSearchContexts) + std::cerr << " Context string \"" << s << "\"" << std::endl; GroupItemInfo i; i.id = QString(it3->second.mGroupId.toStdString().c_str()); @@ -1067,15 +1069,20 @@ void GxsGroupFrameDialog::updateGroupSummary() { RsThread::async([this]() { - std::list groupInfo; + auto groupInfo = new std::list() ; - if(!getGroupData(groupInfo)) + if(!getGroupData(*groupInfo)) { - std::cerr << __PRETTY_FUNCTION__ << " failed to collect group info " << std::endl; + std::cerr << __PRETTY_FUNCTION__ << " failed to collect group info." << std::endl; + delete groupInfo; return; } - if(groupInfo.empty()) + if(groupInfo->empty()) + { + std::cerr << __PRETTY_FUNCTION__ << " no group info collected." << std::endl; + delete groupInfo; return; + } RsQThreadUtils::postToObject( [this,groupInfo]() { @@ -1085,7 +1092,7 @@ void GxsGroupFrameDialog::updateGroupSummary() * Qt::QueuedConnection is important! */ - insertGroupsData(groupInfo); + insertGroupsData(*groupInfo); updateSearchResults(); mStateHelper->setLoading(TOKEN_TYPE_GROUP_SUMMARY, false); @@ -1104,12 +1111,14 @@ void GxsGroupFrameDialog::updateGroupSummary() // now delete the data that is not used anymore - for(auto& g:groupInfo) + for(auto& g:*groupInfo) { mCachedGroupMetas[g->mMeta.mGroupId] = g->mMeta; delete g; } + delete groupInfo; + }, this ); }); } diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h index 5c3385d52..05b311b04 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h @@ -162,6 +162,7 @@ private: virtual RsGxsCommentService *getCommentService() { return NULL; } virtual QWidget *createCommentHeaderWidget(const RsGxsGroupId &/*grpId*/, const RsGxsMessageId &/*msgId*/) { return NULL; } virtual bool getDistantSearchResults(TurtleRequestId /* id */, std::map& /* group_infos */){ return false ;} + virtual RsGxsGenericGroupData *getDistantSearchResultGroupData(const RsGxsGroupId& group_id){ return nullptr ;} void initUi(); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp index 8af68b01e..8cbeccfbc 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp @@ -406,11 +406,21 @@ bool GxsChannelDialog::getDistantSearchResults(TurtleRequestId id, std::mapretrieveDistantSearchResults(id,group_infos); } +RsGxsGenericGroupData *GxsChannelDialog::getDistantSearchResultGroupData(const RsGxsGroupId& group_id) +{ + RsGxsChannelGroup channel_group; + + if(rsGxsChannels->getDistantSearchResultGroupData(group_id,channel_group)) + return new RsGxsGenericGroupData(channel_group); + else + return nullptr; +} + void GxsChannelDialog::checkRequestGroup(const RsGxsGroupId& grpId) { RsGxsChannelGroup distant_group; - if( rsGxsChannels->retrieveDistantGroup(grpId,distant_group)) // normally we should also check that the group meta is not already here. + if( rsGxsChannels->getDistantSearchResultGroupData(grpId,distant_group)) // normally we should also check that the group meta is not already here. { std::cerr << "GxsChannelDialog::checkRequestGroup() sending turtle request for group data for group " << grpId << std::endl; rsGxsChannels->turtleGroupRequest(grpId); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h index e8c23424d..7902b7361 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h @@ -43,10 +43,11 @@ public: protected: /* GxsGroupFrameDialog */ - virtual bool getDistantSearchResults(TurtleRequestId id, std::map &group_infos); + virtual bool getDistantSearchResults(TurtleRequestId id, std::map &group_infos) override; + virtual RsGxsGenericGroupData *getDistantSearchResultGroupData(const RsGxsGroupId& group_id) override; - virtual TurtleRequestId distantSearch(const QString& search_string) ; - virtual void checkRequestGroup(const RsGxsGroupId& grpId) ; + virtual TurtleRequestId distantSearch(const QString& search_string) override; + virtual void checkRequestGroup(const RsGxsGroupId& grpId) override ; // Implementation of some abstract methods in GxsGroupFrameDialog diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp index 5d6974442..bbbb26a42 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp @@ -858,11 +858,12 @@ bool GxsChannelPostsWidget::getGroupData(RsGxsGenericGroupData *& data) { RsGxsChannelGroup distant_group; - if(rsGxsChannels->retrieveDistantGroup(groupId(),distant_group)) + if(rsGxsChannels->getDistantSearchResultGroupData(groupId(),distant_group)) { insertChannelDetails(distant_group); - data = new RsGxsChannelGroup(distant_group); + data = new RsGxsChannelGroup(distant_group); mGroup = distant_group; // make a local copy to pass on to items + return true ; } } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 73508c1e8..6843a80f0 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -538,23 +538,20 @@ void GxsChannelPostsWidgetWithModel::updateGroupData() RsThread::async([this]() { + RsGxsChannelGroup group; std::vector groups; - if(!rsGxsChannels->getChannelsInfo(std::list{ groupId() }, groups)) + if(rsGxsChannels->getChannelsInfo(std::list{ groupId() }, groups) && groups.size()==1) + group = groups[0]; + else if(!rsGxsChannels->getDistantSearchResultGroupData(groupId(),group)) { - std::cerr << __PRETTY_FUNCTION__ << " failed to get autodownload value for channel: " << groupId() << std::endl; + std::cerr << __PRETTY_FUNCTION__ << " failed to get group data for channel: " << groupId() << std::endl; return; } - if(groups.size() != 1) - { - RsErr() << __PRETTY_FUNCTION__ << " cannot retrieve channel data for group ID " << groupId() << ": ERROR." << std::endl; - return; - } - - RsQThreadUtils::postToObject( [this,groups]() + RsQThreadUtils::postToObject( [this,group]() { - mGroup = groups[0]; + mGroup = group; mChannelPostsModel->updateChannel(groupId()); insertChannelDetails(mGroup); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui index 1f51702a2..2886e8dbe 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.ui @@ -161,7 +161,7 @@ - 1 + 0 From c58aa688d164263e070a41fea3d1a4d4192336b7 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 25 Jun 2020 21:25:22 +0200 Subject: [PATCH 126/154] fixed proper display of group for context strings --- retroshare-gui/src/gui/common/GroupTreeWidget.cpp | 6 +++++- .../src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/common/GroupTreeWidget.cpp b/retroshare-gui/src/gui/common/GroupTreeWidget.cpp index c67dfbc20..2fa8de0c0 100644 --- a/retroshare-gui/src/gui/common/GroupTreeWidget.cpp +++ b/retroshare-gui/src/gui/common/GroupTreeWidget.cpp @@ -468,7 +468,11 @@ void GroupTreeWidget::fillGroupItems(QTreeWidgetItem *categoryItem, const QList< for(auto str:itemInfo.context_strings) if(!str.empty()) - item->addChild(new QTreeWidgetItem(QStringList(QString::fromUtf8(str.c_str())))); + { + QTreeWidgetItem *it = new QTreeWidgetItem(QStringList(QString::fromUtf8(str.c_str()))); + it->setData(COLUMN_DATA,ROLE_ID,itemInfo.id); + item->addChild(it); + } /* Set last post */ qlonglong lastPost = itemInfo.lastpost.toTime_t(); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp index 6843a80f0..cc60e003b 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidgetWithModel.cpp @@ -59,6 +59,7 @@ static const int mTokenTypeGroupData = 1; static const int CHANNEL_TABS_DETAILS= 0; static const int CHANNEL_TABS_POSTS = 1; +static const int CHANNEL_TABS_FILES = 2; /* View mode */ #define VIEW_MODE_FEEDS 1 @@ -776,12 +777,14 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou //ui->feedToolButton->setEnabled(true); //ui->fileToolButton->setEnabled(true); ui->channel_TW->setTabEnabled(CHANNEL_TABS_POSTS,true); + ui->channel_TW->setTabEnabled(CHANNEL_TABS_FILES,true); ui->details_TW->setEnabled(true); } else { ui->details_TW->setEnabled(false); ui->channel_TW->setTabEnabled(CHANNEL_TABS_POSTS,false); + ui->channel_TW->setTabEnabled(CHANNEL_TABS_FILES,false); } From 2d01eadd56e5b444286ec91e9ff6cf731e568e61 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Mon, 29 Jun 2020 15:45:53 +0200 Subject: [PATCH 127/154] Fix missing include in i2p common --- libretroshare/src/util/i2pcommon.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libretroshare/src/util/i2pcommon.h b/libretroshare/src/util/i2pcommon.h index 01d655bf9..1fd152079 100644 --- a/libretroshare/src/util/i2pcommon.h +++ b/libretroshare/src/util/i2pcommon.h @@ -3,6 +3,8 @@ #include #include +#include +#include #include "util/rsrandom.h" #include "util/radix32.h" From e7b09ba8ddb51351663f9c733bd9c176f13eddb0 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Mon, 29 Jun 2020 17:26:45 +0200 Subject: [PATCH 128/154] Specify C++ version inn travis macosx --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4fec84f99..cfe2eac21 100644 --- a/.travis.yml +++ b/.travis.yml @@ -57,7 +57,7 @@ before_script: - if [ $TRAVIS_OS_NAME == linux ]; then qmake; fi - > if [ $TRAVIS_OS_NAME == osx ]; then - qmake CONFIG+=rs_macos10.14 + qmake CONFIG+=rs_macos10.14 CONFIG+=c++14 INCLUDEPATH+=$(find /usr/local/Cellar/miniupnpc/*/include | head -n 1) QMAKE_LIBDIR+=$(find /usr/local/Cellar/miniupnpc/*/lib/ | head -n 1) INCLUDEPATH+=$(find /usr/local/Cellar/openssl*/*/include/ | head -n 1) From 9133adbde89975daf8bb264d07a676291b8a0975 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 29 Jun 2020 21:03:17 +0200 Subject: [PATCH 129/154] added anti-clogging strategy in GXS. To be tested. --- libretroshare/src/gxs/rsgxsnetservice.cc | 48 ++++++++++++++++---- libretroshare/src/gxs/rsgxsnetservice.h | 1 + libretroshare/src/rsitems/rsgxsupdateitems.h | 18 +++++++- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index 72a078075..48b12caa5 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -274,7 +274,7 @@ 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_2 1 //#define NXS_NET_DEBUG_3 1 @@ -306,6 +306,7 @@ static const uint32_t GROUP_STATS_UPDATE_DELAY = 240; // static const uint32_t GROUP_STATS_UPDATE_NB_PEERS = 2; // number of peers to which the group stats are asked static const uint32_t MAX_ALLOWED_GXS_MESSAGE_SIZE = 199000; // 200,000 bytes including signature and headers static const uint32_t MIN_DELAY_BETWEEN_GROUP_SEARCH = 40; // dont search same group more than every 40 secs. +static const uint32_t SAFETY_DELAY_FOR_UNSUCCESSFUL_UPDATE = 1800; // avoid re-sending the same msg list to a peer who asks twice for the same update in less than this time static const uint32_t RS_NXS_ITEM_ENCRYPTION_STATUS_UNKNOWN = 0x00 ; static const uint32_t RS_NXS_ITEM_ENCRYPTION_STATUS_NO_ERROR = 0x01 ; @@ -3993,7 +3994,7 @@ bool RsGxsNetService::locked_CanReceiveUpdate(const RsNxsSyncGrpReqItem *item) GXSNETDEBUG_P_(item->PeerId()) << " local modification time stamp: " << std::dec<< time(NULL) - mGrpServerUpdate.grpUpdateTS << " secs ago. Update sent: " << ((item->updateTS < mGrpServerUpdate.grpUpdateTS)?"YES":"NO") << std::endl; #endif - return item->updateTS < mGrpServerUpdate.grpUpdateTS; + return item->updateTS < mGrpServerUpdate.grpUpdateTS && locked_checkResendingOfUpdates(item->PeerId(),RsGxsGroupId(),item->updateTS,mGrpServerUpdate.grpUpdateTsRecords[item->PeerId()]) ; } void RsGxsNetService::handleRecvSyncGroup(RsNxsSyncGrpReqItem *item) @@ -4238,10 +4239,33 @@ bool RsGxsNetService::checkCanRecvMsgFromPeer(const RsPeerId& sslId, const RsGxs return true; } +bool RsGxsNetService::locked_checkResendingOfUpdates(const RsPeerId& pid,const RsGxsGroupId& grpId,rstime_t incoming_ts,RsPeerUpdateTsRecord& rec) +{ + rstime_t now = time(NULL); + + // Now we check if the peer is sending the same outdated TS for the same time in a short while. This would mean the peer + // hasn't finished processing the updates we're sending and we shouldn't send new data anymore. Of course the peer might + // have disconnected or so, which means that we need to be careful about not sending. As a compromise we still send, but + // after waiting for a while (See + + if(rec.mLastTsReceived == incoming_ts && rec.mTs + SAFETY_DELAY_FOR_UNSUCCESSFUL_UPDATE > now) + { +#ifdef NXS_NET_DEBUG_0 + GXSNETDEBUG_PG(pid,grpId) << "(II) peer " << pid << " already sent the same TS " << (long int)now-(long int)rec.mTs << " secs ago for that group ID. Will not send msg list again for a while to prevent clogging..." << std::endl; +#endif + return false; + } + + rec.mLastTsReceived = incoming_ts; + rec.mTs = now; + + return true; +} + bool RsGxsNetService::locked_CanReceiveUpdate(RsNxsSyncMsgReqItem *item,bool& grp_is_known) { // Do we have new updates for this peer? - // Here we compare times in the same clock: the friend's clock, so it should be fine. + // Here we compare times in the same clock: our own clock, so it should be fine. grp_is_known = false ; @@ -4250,7 +4274,7 @@ bool RsGxsNetService::locked_CanReceiveUpdate(RsNxsSyncMsgReqItem *item,bool& gr // Item contains the hashed group ID in order to protect is from friends who don't know it. So we de-hash it using bruteforce over known group IDs for this peer. // We could save the de-hash result. But the cost is quite light, since the number of encrypted groups per service is usually low. - for(ServerMsgMap::const_iterator it(mServerMsgUpdateMap.begin());it!=mServerMsgUpdateMap.end();++it) + for(ServerMsgMap::iterator it(mServerMsgUpdateMap.begin());it!=mServerMsgUpdateMap.end();++it) if(item->grpId == hashGrpId(it->first,item->PeerId())) { item->grpId = it->first ; @@ -4260,20 +4284,25 @@ bool RsGxsNetService::locked_CanReceiveUpdate(RsNxsSyncMsgReqItem *item,bool& gr #endif grp_is_known = true ; - return item->updateTS < it->second.msgUpdateTS ; + // The order of tests below is important because we want to only modify the map of requests records if the request actually is a valid requests instead of + // a simple check that nothing's changed. + + return item->updateTS < it->second.msgUpdateTS && locked_checkResendingOfUpdates(item->PeerId(),item->grpId,item->updateTS,it->second.msgUpdateTsRecords[item->PeerId()]) ; } return false ; } - ServerMsgMap::const_iterator cit = mServerMsgUpdateMap.find(item->grpId); + ServerMsgMap::iterator cit = mServerMsgUpdateMap.find(item->grpId); + if(cit != mServerMsgUpdateMap.end()) { #ifdef NXS_NET_DEBUG_0 GXSNETDEBUG_PG(item->PeerId(),item->grpId) << " local time stamp: " << std::dec<< time(NULL) - cit->second.msgUpdateTS << " secs ago. Update sent: " << (item->updateTS < cit->second.msgUpdateTS) << std::endl; #endif grp_is_known = true ; - return item->updateTS < cit->second.msgUpdateTS ; + + return item->updateTS < cit->second.msgUpdateTS && locked_checkResendingOfUpdates(item->PeerId(),item->grpId,item->updateTS,cit->second.msgUpdateTsRecords[item->PeerId()]) ; } #ifdef NXS_NET_DEBUG_0 @@ -4294,6 +4323,9 @@ void RsGxsNetService::handleRecvSyncMessage(RsNxsSyncMsgReqItem *item,bool item_ bool grp_is_known = false; bool was_circle_protected = item_was_encrypted || bool(item->flag & RsNxsSyncMsgReqItem::FLAG_USE_HASHED_GROUP_ID); + // This call determines if the peer can receive updates from us, meaning that our last TS is larger than what the peer sent. + // It also changes the items' group id into the un-hashed group ID if the group is a distant group. + bool peer_can_receive_update = locked_CanReceiveUpdate(item, grp_is_known); if(item_was_encrypted) @@ -4309,7 +4341,7 @@ void RsGxsNetService::handleRecvSyncMessage(RsNxsSyncMsgReqItem *item,bool item_ // We update suppliers in two cases: // Case 1: the grp is known because it is the hash of an existing group, but it's not yet in the server config map - // Case 2: the gtp is not known, possibly because it was deleted, but there's an entry in mServerGrpConfigMap due to statistics gathering. Still, statistics are only + // Case 2: the grp is not known, possibly because it was deleted, but there's an entry in mServerGrpConfigMap due to statistics gathering. Still, statistics are only // gathered from known suppliers. So statistics never add new suppliers. These are only added here. if(grp_is_known || mServerGrpConfigMap.find(item->grpId)!=mServerGrpConfigMap.end()) diff --git a/libretroshare/src/gxs/rsgxsnetservice.h b/libretroshare/src/gxs/rsgxsnetservice.h index e4056bb06..f7abdc176 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.h +++ b/libretroshare/src/gxs/rsgxsnetservice.h @@ -439,6 +439,7 @@ private: bool locked_CanReceiveUpdate(const RsNxsSyncGrpReqItem *item); bool locked_CanReceiveUpdate(RsNxsSyncMsgReqItem *item, bool &grp_is_known); void locked_resetClientTS(const RsGxsGroupId& grpId); + bool locked_checkResendingOfUpdates(const RsPeerId& pid, const RsGxsGroupId &grpId, rstime_t incoming_ts, RsPeerUpdateTsRecord& rec); static RsGxsGroupId hashGrpId(const RsGxsGroupId& gid,const RsPeerId& pid) ; diff --git a/libretroshare/src/rsitems/rsgxsupdateitems.h b/libretroshare/src/rsitems/rsgxsupdateitems.h index 9e7a194ac..03bd21800 100644 --- a/libretroshare/src/rsitems/rsgxsupdateitems.h +++ b/libretroshare/src/rsitems/rsgxsupdateitems.h @@ -106,12 +106,22 @@ public: RsPeerId peerID; }; +struct RsPeerUpdateTsRecord +{ + RsPeerUpdateTsRecord() : mLastTsReceived(0), mTs(0) {} + + rstime_t mLastTsReceived; // last TS that was sent for this group by this peer ID. + rstime_t mTs; // time at which this TS was sent. +}; + class RsGxsServerGrpUpdate { public: RsGxsServerGrpUpdate() { grpUpdateTS = 0 ; } uint32_t grpUpdateTS; + + std::map grpUpdateTsRecords; }; class RsGxsServerGrpUpdateItem : public RsGxsNetServiceItem, public RsGxsServerGrpUpdate @@ -168,7 +178,13 @@ class RsGxsServerMsgUpdate public: RsGxsServerMsgUpdate() { msgUpdateTS = 0 ;} - uint32_t msgUpdateTS; // local time stamp this group last received a new msg + uint32_t msgUpdateTS; // local time stamp at which this group last received a new msg + + // Now we also store for each peer the last own TS the peer sent and when it did so. This allows to detect when transactions are stuck because of + // outqueues clogging. If that happens, we receive multiple times the same TS from the friend, in which case we do not send the list of msgs + // again until a significant amount of time has passed. These values are obviously initialized to 0. + + std::map msgUpdateTsRecords; }; class RsGxsServerMsgUpdateItem : public RsGxsNetServiceItem, public RsGxsServerMsgUpdate From 8d40224c37a26029f93445f85d3fdd35cc02215e Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 30 Jun 2020 18:10:28 +0200 Subject: [PATCH 130/154] fixed sizes in forums and removed duplicate text on distribution column --- .../src/gui/gxsforums/GxsForumModel.cpp | 8 +++++--- .../gui/gxsforums/GxsForumThreadWidget.cpp | 19 +++++++++++++++++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp index f72649dfc..e4d6f13e9 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumModel.cpp @@ -669,8 +669,11 @@ QVariant RsGxsForumModel::displayRole(const ForumModelPostEntry& fmpe,int col) c return QVariant(DateTime::formatDateTime(qtime)); } - case COLUMN_THREAD_DISTRIBUTION: - case COLUMN_THREAD_AUTHOR:{ + case COLUMN_THREAD_DISTRIBUTION: // passthrough // handled by delegate. + case COLUMN_THREAD_MSGID: + return QVariant(); + case COLUMN_THREAD_AUTHOR: + { QString name; RsGxsId id = RsGxsId(fmpe.mAuthorId.toStdString()); @@ -680,7 +683,6 @@ QVariant RsGxsForumModel::displayRole(const ForumModelPostEntry& fmpe,int col) c return name; return QVariant(tr("[Unknown]")); } - case COLUMN_THREAD_MSGID: return QVariant(); #ifdef TODO if (filterColumn == COLUMN_THREAD_CONTENT) { // need content for filter diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp index 29cfa5b44..fd9c591ca 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumThreadWidget.cpp @@ -134,6 +134,13 @@ public: const QPoint p = QPoint((r.width() - pix.width())/2, (r.height() - pix.height())/2); painter->drawPixmap(r.topLeft() + p, pix); } + + virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override + { + static auto img(FilesDefs::getPixmapFromQtResourcePath(IMAGE_WARNING_YELLOW)); + + return QSize(img.width()*1.2,option.rect.height()); + } }; class ReadStatusItemDelegate: public QStyledItemDelegate @@ -183,6 +190,13 @@ public: const QPoint p = QPoint((r.width() - pix.width())/2, (r.height() - pix.height())/2); painter->drawPixmap(r.topLeft() + p, pix); } + + virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override + { + static auto img(FilesDefs::getPixmapFromQtResourcePath(":/images/message-state-unread.png")); + + return QSize(img.width()*1.2,option.rect.height()); + } }; class ForumPostSortFilterProxyModel: public QSortFilterProxyModel @@ -299,9 +313,10 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget QHeaderView * ttheader = ui->threadTreeWidget->header () ; ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_DATE, 140*f); ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_TITLE, 440*f); - ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION, 24*f); ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_AUTHOR, 150*f); - ttheader->resizeSection (RsGxsForumModel::COLUMN_THREAD_READ, 24*f); + + ui->threadTreeWidget->resizeColumnToContents(RsGxsForumModel::COLUMN_THREAD_DISTRIBUTION); + ui->threadTreeWidget->resizeColumnToContents(RsGxsForumModel::COLUMN_THREAD_READ); QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_TITLE, QHeaderView::Interactive); QHeaderView_setSectionResizeModeColumn(ttheader, RsGxsForumModel::COLUMN_THREAD_DATE, QHeaderView::Interactive); From 6510af7ab6f44fd8341296521fe0e499f6576a75 Mon Sep 17 00:00:00 2001 From: Gioacchino Mazzurco Date: Fri, 3 Jul 2020 18:07:07 +0200 Subject: [PATCH 131/154] Enable JSON API for channel turtle search Add event subtype to RsGxsChannelSearchResultEvent so its type can be recognized from JSON API Remove unused member remnant of the past from RsGxsChannelEvent --- libretroshare/src/retroshare/rsgxschannels.h | 128 +++++++++---------- 1 file changed, 61 insertions(+), 67 deletions(-) diff --git a/libretroshare/src/retroshare/rsgxschannels.h b/libretroshare/src/retroshare/rsgxschannels.h index 8fd02a3b1..106147dc6 100644 --- a/libretroshare/src/retroshare/rsgxschannels.h +++ b/libretroshare/src/retroshare/rsgxschannels.h @@ -122,7 +122,6 @@ struct RsGxsChannelEvent: RsEvent RsChannelEventCode mChannelEventCode; RsGxsGroupId mChannelGroupId; RsGxsMessageId mChannelMsgId; - TurtleRequestId mDistantSearchRequestId; ///* @see RsEvent @see RsSerializable void serial_process( RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) override @@ -132,25 +131,28 @@ struct RsGxsChannelEvent: RsEvent RS_SERIAL_PROCESS(mChannelEventCode); RS_SERIAL_PROCESS(mChannelGroupId); RS_SERIAL_PROCESS(mChannelMsgId); - RS_SERIAL_PROCESS(mDistantSearchRequestId); - } + } }; // This event is used to factor multiple search results notifications in a single event. -struct RsGxsChannelSearchResultEvent: public RsEvent +struct RsGxsChannelSearchResultEvent: RsEvent { - RsGxsChannelSearchResultEvent() : RsEvent(RsEventType::GXS_CHANNELS) {} + RsGxsChannelSearchResultEvent(): + RsEvent(RsEventType::GXS_CHANNELS), + mChannelEventCode(RsChannelEventCode::RECEIVED_DISTANT_SEARCH_RESULT) {} - std::map > mSearchResultsMap; + RsChannelEventCode mChannelEventCode; + std::map > mSearchResultsMap; ///* @see RsEvent @see RsSerializable void serial_process( RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) override { RsEvent::serial_process(j, ctx); + RS_SERIAL_PROCESS(mChannelEventCode); RS_SERIAL_PROCESS(mSearchResultsMap); - } + } }; class RsGxsChannels: public RsGxsIfaceHelper, public RsGxsCommentService @@ -422,49 +424,6 @@ public: */ virtual bool getChannelStatistics(const RsGxsGroupId& channelId,GxsGroupStatistic& stat) =0; -#ifdef TO_REMOVE - /** - * @brief Request remote channels search - * @jsonapi{development} - * @param[in] matchString string to look for in the search - * @param multiCallback function that will be called each time a search - * result is received - * @param[in] maxWait maximum wait time in seconds for search results - * @return false on error, true otherwise - */ - virtual bool turtleSearchRequest( - const std::string& matchString, - const std::function& multiCallback, - rstime_t maxWait = 300 ) = 0; - - /** - * @brief Request remote channel - * @jsonapi{development} - * @param[in] channelId id of the channel to request to distants peers - * @param multiCallback function that will be called each time a result is - * received - * @param[in] maxWait maximum wait time in seconds for search results - * @return false on error, true otherwise - */ - virtual bool turtleChannelRequest( - const RsGxsGroupId& channelId, - const std::function& multiCallback, - rstime_t maxWait = 300 ) = 0; - - /** - * @brief Search local channels - * @jsonapi{development} - * @param[in] matchString string to look for in the search - * @param multiCallback function that will be called for each result - * @param[in] maxWait maximum wait time in seconds for search results - * @return false on error, true otherwise - */ - virtual bool localSearchRequest( - const std::string& matchString, - const std::function& multiCallback, - rstime_t maxWait = 30 ) = 0; -#endif - /// default base URL used for channels links @see exportChannelLink static const std::string DEFAULT_CHANNEL_BASE_URL; @@ -509,6 +468,7 @@ public: /** * @brief Import channel from full link + * @jsonapi{development} * @param[in] link channel link either in radix or link format * @param[out] chanId optional storage for parsed channel id * @param[out] errMsg optional storage for error message, meaningful only in @@ -520,7 +480,58 @@ public: RsGxsGroupId& chanId = RS_DEFAULT_STORAGE_PARAM(RsGxsGroupId), std::string& errMsg = RS_DEFAULT_STORAGE_PARAM(std::string) ) = 0; + /** + * @brief Search the turtle reachable network for matching channels + * @jsonapi{development} + * An @see RsGxsChannelSearchResultEvent is emitted when matching channels + * arrives from the network + * @param[in] matchString string to search into the channels + * @return search id + */ + virtual TurtleRequestId turtleSearchRequest(const std::string& matchString)=0; + /** + * @brief Retrieve available search results + * @jsonapi{development} + * @param[in] searchId search id + * @param[out] results storage for search results + * @return false on error, true otherwise + */ + virtual bool retrieveDistantSearchResults( + TurtleRequestId searchId, + std::map& results ) = 0; + + /** + * @brief Request distant channel details + * @jsonapi{development} + * An @see RsGxsChannelSearchResultEvent is emitted once details are + * retrieved from the network + * @param[in] groupId if of the group to request to the network + * @return search id + */ + virtual TurtleRequestId turtleGroupRequest(const RsGxsGroupId& groupId) = 0; + + /** + * @brief Retrieve previously requested distant group + * @jsonapi{development} + * @param[in] groupId if of teh group + * @param[out] distantGroup storage for group data + * @return false on error, true otherwise + */ + virtual bool getDistantSearchResultGroupData( + const RsGxsGroupId& groupId, RsGxsChannelGroup& distantGroup ) = 0; + + /** + * @brief Clear accumulated search results + * @jsonapi{development} + * @param[in] reqId search id + * @return false on error, true otherwise + */ + virtual bool clearDistantSearchResults(TurtleRequestId reqId) = 0; + + ~RsGxsChannels() override; + + //////////////////////////////////////////////////////////////////////////// /* Following functions are deprecated and should not be considered a safe to * use API */ @@ -706,21 +717,4 @@ public: */ RS_DEPRECATED_FOR(editChannel) virtual bool updateGroup(uint32_t& token, RsGxsChannelGroup& group) = 0; - - ////////////////////////////////////////////////////////////////////////////// - /// Distant synchronisation methods /// - ////////////////////////////////////////////////////////////////////////////// - /// - /// - // This approach is much cleaner than the "multicallback" system. We should keep it and use rsEvents to warn when - // new results are received. - virtual TurtleRequestId turtleGroupRequest(const RsGxsGroupId& group_id)=0; - virtual TurtleRequestId turtleSearchRequest(const std::string& match_string)=0; - virtual bool clearDistantSearchResults(TurtleRequestId req)=0; - virtual bool getDistantSearchResultGroupData(const RsGxsGroupId& group_id,RsGxsChannelGroup& distant_group)=0; - virtual bool retrieveDistantSearchResults(TurtleRequestId req, std::map &results) =0; - - ////////////////////////////////////////////////////////////////////////////// - - ~RsGxsChannels() override; }; From 721fad131e02ecf738080324893bb3e48fa2cbf6 Mon Sep 17 00:00:00 2001 From: Phenom Date: Fri, 3 Jul 2020 22:14:35 +0200 Subject: [PATCH 132/154] Update OBS submodule --- build_scripts/OBS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_scripts/OBS b/build_scripts/OBS index 879d5dfe8..b0d7ae39f 160000 --- a/build_scripts/OBS +++ b/build_scripts/OBS @@ -1 +1 @@ -Subproject commit 879d5dfe8dcd8995be753120cf1b8bab4dd2ec82 +Subproject commit b0d7ae39fe9d9192848bbf7b8902d2188da895c9 From 4d872d5778d8db4670ee0da75ebc14bec414e657 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 3 Jul 2020 22:48:33 +0200 Subject: [PATCH 133/154] added missing cleaning of distant search results in GUI --- retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp | 10 +++++++++- retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h | 1 + .../src/gui/gxschannels/GxsChannelDialog.cpp | 5 +++++ retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp index 49b91866d..069b682ce 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp @@ -359,13 +359,21 @@ void GxsGroupFrameDialog::removeCurrentSearch() mSearchGroupsItems.erase(it); mKnownGroups.erase(search_request_id); + + clearDistantSearchResults(search_request_id); } void GxsGroupFrameDialog::removeAllSearches() { for(auto it(mSearchGroupsItems.begin());it!=mSearchGroupsItems.end();++it) - ui->groupTreeWidget->removeSearchItem(it->second) ; + { + TurtleRequestId search_request_id = 0 ; + if(ui->groupTreeWidget->isSearchRequestItem(point,search_request_id)) + clearDistantSearchResults(search_request_id); + + ui->groupTreeWidget->removeSearchItem(it->second) ; + } mSearchGroupsItems.clear(); mKnownGroups.clear(); } diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h index 05b311b04..006f593a4 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h @@ -162,6 +162,7 @@ private: virtual RsGxsCommentService *getCommentService() { return NULL; } virtual QWidget *createCommentHeaderWidget(const RsGxsGroupId &/*grpId*/, const RsGxsMessageId &/*msgId*/) { return NULL; } virtual bool getDistantSearchResults(TurtleRequestId /* id */, std::map& /* group_infos */){ return false ;} + virtual void clearDistantSearchResults(TurtleRequestId /* id */) {} virtual RsGxsGenericGroupData *getDistantSearchResultGroupData(const RsGxsGroupId& group_id){ return nullptr ;} void initUi(); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp index 8cbeccfbc..5e1c40fe4 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp @@ -396,6 +396,11 @@ void GxsChannelDialog::groupInfoToGroupItemInfo(const RsGxsGenericGroupData *gro groupItemInfo.description = QString::fromUtf8(channelGroupData->mDescription.c_str()); } +void GxsChannelDialog::clearDistantSearchResults(TurtleRequestId id) +{ + rsGxsChannels->clearDistantSearchResults(id); +} + TurtleRequestId GxsChannelDialog::distantSearch(const QString& search_string) { return rsGxsChannels->turtleSearchRequest(search_string.toStdString()) ; diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h index 7902b7361..63b6ba38a 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h @@ -48,6 +48,7 @@ protected: virtual TurtleRequestId distantSearch(const QString& search_string) override; virtual void checkRequestGroup(const RsGxsGroupId& grpId) override ; + virtual void clearDistantSearchResults(TurtleRequestId id) override; // Implementation of some abstract methods in GxsGroupFrameDialog From 07655e287ec1d8e09eb276ec586bf3b8b905729f Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 4 Jul 2020 00:05:29 +0200 Subject: [PATCH 134/154] fixed cleaning up of search results --- retroshare-gui/src/gui/common/GroupTreeWidget.cpp | 13 +++++++++++++ retroshare-gui/src/gui/common/GroupTreeWidget.h | 1 + retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp | 6 ++++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/common/GroupTreeWidget.cpp b/retroshare-gui/src/gui/common/GroupTreeWidget.cpp index 2fa8de0c0..db9b487b4 100644 --- a/retroshare-gui/src/gui/common/GroupTreeWidget.cpp +++ b/retroshare-gui/src/gui/common/GroupTreeWidget.cpp @@ -397,6 +397,19 @@ bool GroupTreeWidget::isSearchRequestResult(QPoint &point,QString& group_id,uint return search_req_id > 0; } +bool GroupTreeWidget::isSearchRequestResultItem(QTreeWidgetItem *item,QString& group_id,uint32_t& search_req_id) +{ + QTreeWidgetItem *parent = item->parent(); + + if(parent == NULL) + return false ; + + search_req_id = parent->data(COLUMN_DATA, ROLE_REQUEST_ID).toUInt(); + group_id = itemId(item) ; + + return search_req_id > 0; +} + bool GroupTreeWidget::isSearchRequestItem(QPoint &point,uint32_t& search_req_id) { QTreeWidgetItem *item = ui->treeWidget->itemAt(point); diff --git a/retroshare-gui/src/gui/common/GroupTreeWidget.h b/retroshare-gui/src/gui/common/GroupTreeWidget.h index 9f8d0ccd4..5b40a9487 100644 --- a/retroshare-gui/src/gui/common/GroupTreeWidget.h +++ b/retroshare-gui/src/gui/common/GroupTreeWidget.h @@ -97,6 +97,7 @@ public: bool isSearchRequestItem(QPoint &point,uint32_t& search_req_id); bool isSearchRequestResult(QPoint &point, QString &group_id, uint32_t& search_req_id); + bool isSearchRequestResultItem(QTreeWidgetItem *item,QString& group_id,uint32_t& search_req_id); QTreeWidgetItem *getItemFromId(const QString &id); QTreeWidgetItem *activateId(const QString &id, bool focus); diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp index 069b682ce..b7f3fcf20 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp @@ -29,6 +29,7 @@ #include "gui/settings/rsharesettings.h" #include "gui/RetroShareLink.h" #include "gui/gxs/GxsGroupShareKey.h" +#include "gui/common/GroupTreeWidget.h" #include "gui/common/RSTreeWidget.h" #include "gui/notifyqt.h" #include "gui/common/UIStateHelper.h" @@ -367,9 +368,10 @@ void GxsGroupFrameDialog::removeAllSearches() { for(auto it(mSearchGroupsItems.begin());it!=mSearchGroupsItems.end();++it) { - TurtleRequestId search_request_id = 0 ; + QString group_id; + TurtleRequestId search_request_id; - if(ui->groupTreeWidget->isSearchRequestItem(point,search_request_id)) + if(ui->groupTreeWidget->isSearchRequestResultItem(it->second,group_id,search_request_id)) clearDistantSearchResults(search_request_id); ui->groupTreeWidget->removeSearchItem(it->second) ; From 79fce47d7505d0ca076e34e313be622638bb5f65 Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 7 Jul 2020 19:45:53 +0200 Subject: [PATCH 135/154] added service mail in identity usage statistics --- retroshare-gui/src/gui/Identity/IdDialog.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index d49e558ec..39cda6920 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -1862,10 +1862,11 @@ QString IdDialog::createUsageString(const RsIdentityUsage& u) const { case RsServiceType::CHANNELS: service_name = tr("Channels") ;service_type = RetroShareLink::TYPE_CHANNEL ; break ; case RsServiceType::FORUMS: service_name = tr("Forums") ; service_type = RetroShareLink::TYPE_FORUM ; break ; - case RsServiceType::POSTED: service_name = tr("Posted") ; service_type = RetroShareLink::TYPE_POSTED ; break ; + case RsServiceType::POSTED: service_name = tr("Boards") ; service_type = RetroShareLink::TYPE_POSTED ; break ; case RsServiceType::CHAT: service_name = tr("Chat") ; service_type = RetroShareLink::TYPE_CHAT_ROOM ; break ; + case RsServiceType::MAIL: service_name = tr("Mail") ; service_type = RetroShareLink::TYPE_MESSAGE ; break ; default: - service_name = tr("Unknown"); service_type = RetroShareLink::TYPE_UNKNOWN ; + service_name = tr("Unknown (service=")+QString::number((int)u.mServiceId,16)+")"; service_type = RetroShareLink::TYPE_UNKNOWN ; } switch(u.mUsageCode) @@ -1888,7 +1889,7 @@ QString IdDialog::createUsageString(const RsIdentityUsage& u) const case RsIdentityUsage::MESSAGE_AUTHOR_KEEP_ALIVE: // Identities are stamped regularly by crawlign the set of messages for all groups. That helps keepign the useful identities in hand. { RetroShareLink l = RetroShareLink::createGxsMessageLink(service_type,u.mGrpId,u.mMsgId,tr("Message/vote/comment")); - return tr("%1 in %2 tab").arg(l.toHtml()).arg(service_name) ; + return tr("%1 in %2 service").arg(l.toHtml()).arg(service_name) ; } case RsIdentityUsage::CHAT_LOBBY_MSG_VALIDATION: // Chat lobby msgs are signed, so each time one comes, or a chat lobby event comes, a signature verificaiton happens. { From 57a1c4bf5d8d1a751a4bd3e4de623603574421dc Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 7 Jul 2020 23:01:20 +0200 Subject: [PATCH 136/154] attempt to improve the info about GXS id usage --- libretroshare/src/gxs/rsgenexchange.cc | 10 +++++-- libretroshare/src/retroshare/rsidentity.h | 8 ++++++ libretroshare/src/services/p3idservice.cc | 7 ++--- retroshare-gui/src/gui/Identity/IdDialog.cpp | 30 ++++++++++++++++---- 4 files changed, 43 insertions(+), 12 deletions(-) diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index e3ef41eb9..7da702925 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -680,7 +680,7 @@ int RsGenExchange::createMsgSignatures(RsTlvKeySignatureSet& signSet, RsTlvBinar if(GxsSecurity::getSignature((char*)msgData.bin_data, msgData.bin_len, authorKey, sign)) { id_ret = SIGN_SUCCESS; - mGixs->timeStampKey(msgMeta.mAuthorId,RsIdentityUsage(mServType,RsIdentityUsage::MESSAGE_AUTHOR_SIGNATURE_CREATION,msgMeta.mGroupId,msgMeta.mMsgId)) ; + mGixs->timeStampKey(msgMeta.mAuthorId,RsIdentityUsage(RsServiceType(mServType),RsIdentityUsage::MESSAGE_AUTHOR_SIGNATURE_CREATION,msgMeta.mGroupId,msgMeta.mMsgId,msgMeta.mParentId,msgMeta.mThreadId)) ; signSet.keySignSet[INDEX_AUTHEN_IDENTITY] = sign; } else @@ -905,7 +905,11 @@ int RsGenExchange::validateMsg(RsNxsMsg *msg, const uint32_t& grpFlag, const uin { RsTlvKeySignature sign = metaData.signSet.keySignSet[INDEX_AUTHEN_IDENTITY]; idValidate &= GxsSecurity::validateNxsMsg(*msg, sign, authorKey); - mGixs->timeStampKey(metaData.mAuthorId,RsIdentityUsage(mServType,RsIdentityUsage::MESSAGE_AUTHOR_SIGNATURE_VALIDATION,metaData.mGroupId,metaData.mMsgId)) ; + mGixs->timeStampKey(metaData.mAuthorId,RsIdentityUsage(RsServiceType(mServType),RsIdentityUsage::MESSAGE_AUTHOR_SIGNATURE_VALIDATION, + metaData.mGroupId, + metaData.mMsgId, + metaData.mParentId, + metaData.mThreadId)) ; } else { @@ -949,7 +953,7 @@ int RsGenExchange::validateMsg(RsNxsMsg *msg, const uint32_t& grpFlag, const uin { std::list peers; peers.push_back(msg->PeerId()); - mGixs->requestKey(metaData.mAuthorId, peers, RsIdentityUsage(serviceType(),RsIdentityUsage::MESSAGE_AUTHOR_SIGNATURE_VALIDATION,metaData.mGroupId,metaData.mMsgId)); + mGixs->requestKey(metaData.mAuthorId, peers, RsIdentityUsage((RsServiceType)serviceType(),RsIdentityUsage::MESSAGE_AUTHOR_SIGNATURE_VALIDATION,metaData.mGroupId,metaData.mMsgId,metaData.mParentId,metaData.mThreadId)); #ifdef GEN_EXCH_DEBUG std::cerr << ", Key missing. Retry later." << std::endl; diff --git a/libretroshare/src/retroshare/rsidentity.h b/libretroshare/src/retroshare/rsidentity.h index d1345461e..ef8a24826 100644 --- a/libretroshare/src/retroshare/rsidentity.h +++ b/libretroshare/src/retroshare/rsidentity.h @@ -259,6 +259,8 @@ struct RsIdentityUsage : RsSerializable RsIdentityUsage::UsageCode code, const RsGxsGroupId& gid = RsGxsGroupId(), const RsGxsMessageId& mid = RsGxsMessageId(), + const RsGxsMessageId& pid = RsGxsMessageId(), + const RsGxsMessageId& tid = RsGxsMessageId(), uint64_t additional_id=0, const std::string& comment = std::string() ); @@ -275,6 +277,12 @@ struct RsIdentityUsage : RsSerializable /// Message ID using the identity RsGxsMessageId mMsgId; + /// Reference message ID. Useful for votes/comments + RsGxsMessageId mParentId; + + /// Reference message ID. Useful for votes/comments + RsGxsMessageId mThreadId; + /// Some additional ID. Can be used for e.g. chat lobbies. uint64_t mAdditionalId; diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index 3ee089a97..a475f5861 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -4819,11 +4819,10 @@ void RsGxsIdGroup::serial_process( RS_SERIAL_PROCESS(mReputation); } -RsIdentityUsage::RsIdentityUsage( - RsServiceType service, RsIdentityUsage::UsageCode code, - const RsGxsGroupId& gid, const RsGxsMessageId& mid, +RsIdentityUsage::RsIdentityUsage(RsServiceType service, RsIdentityUsage::UsageCode code, + const RsGxsGroupId& gid, const RsGxsMessageId& mid, const RsGxsMessageId &pid, const RsGxsMessageId &tid, uint64_t additional_id, const std::string& comment ) : - mServiceId(service), mUsageCode(code), mGrpId(gid), mMsgId(mid), + mServiceId(service), mUsageCode(code), mGrpId(gid), mMsgId(mid),mParentId(pid),mThreadId(tid), mAdditionalId(additional_id), mComment(comment) { /* This is a hack, since it will hash also mHash, but because it is diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index 39cda6920..769b14a94 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -1864,7 +1864,12 @@ QString IdDialog::createUsageString(const RsIdentityUsage& u) const case RsServiceType::FORUMS: service_name = tr("Forums") ; service_type = RetroShareLink::TYPE_FORUM ; break ; case RsServiceType::POSTED: service_name = tr("Boards") ; service_type = RetroShareLink::TYPE_POSTED ; break ; case RsServiceType::CHAT: service_name = tr("Chat") ; service_type = RetroShareLink::TYPE_CHAT_ROOM ; break ; - case RsServiceType::MAIL: service_name = tr("Mail") ; service_type = RetroShareLink::TYPE_MESSAGE ; break ; + case RsServiceType::GXS_TRANS: service_name = tr("GxsMail"); service_type = RetroShareLink::TYPE_MESSAGE ; break ; +#ifdef TODO + // We need a RS link for circles if we want to do that. + // + case RsServiceType::GXSCIRCLE: service_name = tr("GxsCircles"); service_type = RetroShareLink::TYPE_CIRCLES; break ; +#endif default: service_name = tr("Unknown (service=")+QString::number((int)u.mServiceId,16)+")"; service_type = RetroShareLink::TYPE_UNKNOWN ; } @@ -1886,9 +1891,17 @@ QString IdDialog::createUsageString(const RsIdentityUsage& u) const return tr("Group author for group %1 in service %2").arg(QString::fromStdString(u.mGrpId.toStdString())).arg(service_name); break ; case RsIdentityUsage::MESSAGE_AUTHOR_SIGNATURE_VALIDATION: - case RsIdentityUsage::MESSAGE_AUTHOR_KEEP_ALIVE: // Identities are stamped regularly by crawlign the set of messages for all groups. That helps keepign the useful identities in hand. + case RsIdentityUsage::MESSAGE_AUTHOR_KEEP_ALIVE: // Identities are stamped regularly by crawling the set of messages for all groups. That helps keepign the useful identities in hand. { - RetroShareLink l = RetroShareLink::createGxsMessageLink(service_type,u.mGrpId,u.mMsgId,tr("Message/vote/comment")); + RetroShareLink l; + + if(service_type == RetroShareLink::TYPE_CHANNEL && !u.mThreadId.isNull()) + l = RetroShareLink::createGxsMessageLink(service_type,u.mGrpId,u.mThreadId,tr("vote/comment")); + else if(service_type == RetroShareLink::TYPE_POSTED && !u.mThreadId.isNull()) + l = RetroShareLink::createGxsMessageLink(service_type,u.mGrpId,u.mThreadId,tr("vote")); + else + l = RetroShareLink::createGxsMessageLink(service_type,u.mGrpId,u.mMsgId,tr("Message")); + return tr("%1 in %2 service").arg(l.toHtml()).arg(service_name) ; } case RsIdentityUsage::CHAT_LOBBY_MSG_VALIDATION: // Chat lobby msgs are signed, so each time one comes, or a chat lobby event comes, a signature verificaiton happens. @@ -1925,11 +1938,18 @@ QString IdDialog::createUsageString(const RsIdentityUsage& u) const } case RsIdentityUsage::IDENTITY_GENERIC_SIGNATURE_CREATION: // Any signature made by that identity { - return tr("Generic signature."); + return tr("Generic signature creation (e.g. chat room message, global router,...)."); } case RsIdentityUsage::IDENTITY_GENERIC_ENCRYPTION: return tr("Generic encryption."); case RsIdentityUsage::IDENTITY_GENERIC_DECRYPTION: return tr("Generic decryption."); - case RsIdentityUsage::CIRCLE_MEMBERSHIP_CHECK: return tr("Membership verification in circle %1.").arg(QString::fromStdString(u.mGrpId.toStdString())); + case RsIdentityUsage::CIRCLE_MEMBERSHIP_CHECK: + { + RsGxsCircleDetails det; + if(rsGxsCircles->getCircleDetails(RsGxsCircleId(u.mGrpId),det)) + return tr("Membership verification in circle \"%1\" (%2).").arg(QString::fromUtf8(det.mCircleName.c_str())).arg(QString::fromStdString(u.mGrpId.toStdString())); + else + return tr("Membership verification in circle (ID=%1).").arg(QString::fromStdString(u.mGrpId.toStdString())); + } #warning TODO! csoler 2017-01-03: Add the different strings and translations here. default: From 6d665868e8edcab754989ad6f9f188b440282ebe Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 8 Jul 2020 12:56:40 +0200 Subject: [PATCH 137/154] fixed usage info statistics in identities --- libretroshare/src/chat/distributedchat.cc | 16 +++++- .../src/gossipdiscovery/p3gossipdiscovery.cc | 2 +- libretroshare/src/grouter/p3grouter.cc | 2 +- libretroshare/src/gxs/rsgenexchange.cc | 15 +++-- libretroshare/src/gxs/rsgxsutil.cc | 10 +++- libretroshare/src/gxstunnel/p3gxstunnel.cc | 2 +- libretroshare/src/retroshare/rsidentity.h | 29 +++++----- libretroshare/src/services/p3gxscircles.cc | 2 +- libretroshare/src/services/p3idservice.cc | 55 +++---------------- retroshare-gui/src/gui/Identity/IdDialog.cpp | 22 ++++++-- 10 files changed, 75 insertions(+), 80 deletions(-) diff --git a/libretroshare/src/chat/distributedchat.cc b/libretroshare/src/chat/distributedchat.cc index 3f5ecc74e..ca24cac1e 100644 --- a/libretroshare/src/chat/distributedchat.cc +++ b/libretroshare/src/chat/distributedchat.cc @@ -219,7 +219,13 @@ bool DistributedChatService::checkSignature(RsChatLobbyBouncingObject *obj,const // network pre-request key to allow message authentication. - mGixs->requestKey(obj->signature.keyId,peer_list,RsIdentityUsage(RS_SERVICE_TYPE_CHAT,RsIdentityUsage::CHAT_LOBBY_MSG_VALIDATION,RsGxsGroupId(),RsGxsMessageId(),obj->lobby_id)); + mGixs->requestKey(obj->signature.keyId,peer_list,RsIdentityUsage(RsServiceType::CHAT, + RsIdentityUsage::CHAT_LOBBY_MSG_VALIDATION, + RsGxsGroupId(), + RsGxsMessageId(), + RsGxsMessageId(), + RsGxsMessageId(), + obj->lobby_id)); uint32_t size = RsChatSerialiser(RsSerializationFlags::SIGNATURE) .size(dynamic_cast(obj)); @@ -238,7 +244,13 @@ bool DistributedChatService::checkSignature(RsChatLobbyBouncingObject *obj,const } uint32_t error_status ; - RsIdentityUsage use_info(RS_SERVICE_TYPE_CHAT,RsIdentityUsage::CHAT_LOBBY_MSG_VALIDATION,RsGxsGroupId(),RsGxsMessageId(),obj->lobby_id) ; + RsIdentityUsage use_info(RsServiceType::CHAT, + RsIdentityUsage::CHAT_LOBBY_MSG_VALIDATION, + RsGxsGroupId(), + RsGxsMessageId(), + RsGxsMessageId(), + RsGxsMessageId(), + obj->lobby_id) ; if(!mGixs->validateData(memory,size,obj->signature,false,use_info,error_status)) { diff --git a/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc index c4f80436a..fc1c17f85 100644 --- a/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc +++ b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc @@ -450,7 +450,7 @@ void p3discovery2::recvIdentityList(const RsPeerId& pid,const std::list std::cerr << "p3discovery2::recvIdentityList(): from peer " << pid << ": " << ids.size() << " identities" << std::endl; #endif - RsIdentityUsage use_info(RS_SERVICE_TYPE_DISC,RsIdentityUsage::IDENTITY_DATA_UPDATE); + RsIdentityUsage use_info(RsServiceType::GOSSIP_DISCOVERY,RsIdentityUsage::IDENTITY_NEW_FROM_DISCOVERY); for(auto it(ids.begin());it!=ids.end();++it) { diff --git a/libretroshare/src/grouter/p3grouter.cc b/libretroshare/src/grouter/p3grouter.cc index d34a1349f..16148d508 100644 --- a/libretroshare/src/grouter/p3grouter.cc +++ b/libretroshare/src/grouter/p3grouter.cc @@ -2108,7 +2108,7 @@ bool p3GRouter::verifySignedDataItem(const RsGRouterAbstractMsgItem *item,const if(!signature_serializer.serialise(const_cast(item),data,&data_size)) throw std::runtime_error("Cannot serialise signed data."); - RsIdentityUsage use(RS_SERVICE_TYPE_GROUTER,info); + RsIdentityUsage use(RsServiceType::GROUTER,info); if(!mGixs->validateData( data, data_size, item->signature, true, use, error_status )) { diff --git a/libretroshare/src/gxs/rsgenexchange.cc b/libretroshare/src/gxs/rsgenexchange.cc index 7da702925..bd51875c8 100644 --- a/libretroshare/src/gxs/rsgenexchange.cc +++ b/libretroshare/src/gxs/rsgenexchange.cc @@ -512,7 +512,7 @@ int RsGenExchange::createGroupSignatures(RsTlvKeySignatureSet& signSet, RsTlvBin if(GxsSecurity::getSignature((char*)grpData.bin_data, grpData.bin_len, authorKey, sign)) { id_ret = SIGN_SUCCESS; - mGixs->timeStampKey(grpMeta.mAuthorId,RsIdentityUsage(mServType,RsIdentityUsage::GROUP_AUTHOR_SIGNATURE_CREATION,grpMeta.mGroupId)) ; + mGixs->timeStampKey(grpMeta.mAuthorId,RsIdentityUsage(RsServiceType(mServType),RsIdentityUsage::GROUP_AUTHOR_SIGNATURE_CREATION,grpMeta.mGroupId)) ; signSet.keySignSet[INDEX_AUTHEN_IDENTITY] = sign; } else @@ -953,7 +953,12 @@ int RsGenExchange::validateMsg(RsNxsMsg *msg, const uint32_t& grpFlag, const uin { std::list peers; peers.push_back(msg->PeerId()); - mGixs->requestKey(metaData.mAuthorId, peers, RsIdentityUsage((RsServiceType)serviceType(),RsIdentityUsage::MESSAGE_AUTHOR_SIGNATURE_VALIDATION,metaData.mGroupId,metaData.mMsgId,metaData.mParentId,metaData.mThreadId)); + mGixs->requestKey(metaData.mAuthorId, peers, RsIdentityUsage((RsServiceType)serviceType(), + RsIdentityUsage::MESSAGE_AUTHOR_SIGNATURE_VALIDATION, + metaData.mGroupId, + metaData.mMsgId, + metaData.mParentId, + metaData.mThreadId)); #ifdef GEN_EXCH_DEBUG std::cerr << ", Key missing. Retry later." << std::endl; @@ -1030,7 +1035,7 @@ int RsGenExchange::validateGrp(RsNxsGrp* grp) #ifdef GEN_EXCH_DEBUG std::cerr << " key ID validation result: " << idValidate << std::endl; #endif - mGixs->timeStampKey(metaData.mAuthorId,RsIdentityUsage(mServType,RsIdentityUsage::GROUP_AUTHOR_SIGNATURE_VALIDATION,metaData.mGroupId)); + mGixs->timeStampKey(metaData.mAuthorId,RsIdentityUsage(RsServiceType(mServType),RsIdentityUsage::GROUP_AUTHOR_SIGNATURE_VALIDATION,metaData.mGroupId)); } else { @@ -1048,7 +1053,7 @@ int RsGenExchange::validateGrp(RsNxsGrp* grp) #endif std::list peers; peers.push_back(grp->PeerId()); - mGixs->requestKey(metaData.mAuthorId, peers,RsIdentityUsage(mServType,RsIdentityUsage::GROUP_AUTHOR_SIGNATURE_VALIDATION,metaData.mGroupId)); + mGixs->requestKey(metaData.mAuthorId, peers,RsIdentityUsage(RsServiceType(mServType),RsIdentityUsage::GROUP_AUTHOR_SIGNATURE_VALIDATION,metaData.mGroupId)); return VALIDATE_FAIL_TRY_LATER; } } @@ -3350,7 +3355,7 @@ bool RsGenExchange::updateValid(const RsGxsGrpMetaData& oldGrpMeta, const RsNxsG // also check this is the latest published group bool latest = newGrp.metaData->mPublishTs > oldGrpMeta.mPublishTs; - mGixs->timeStampKey(newGrp.metaData->mAuthorId, RsIdentityUsage(mServType,RsIdentityUsage::GROUP_ADMIN_SIGNATURE_CREATION, oldGrpMeta.mGroupId)) ; + mGixs->timeStampKey(newGrp.metaData->mAuthorId, RsIdentityUsage(RsServiceType(mServType),RsIdentityUsage::GROUP_ADMIN_SIGNATURE_CREATION, oldGrpMeta.mGroupId)) ; return GxsSecurity::validateNxsGrp(newGrp, adminSign, keyMit->second) && latest; } diff --git a/libretroshare/src/gxs/rsgxsutil.cc b/libretroshare/src/gxs/rsgxsutil.cc index 951476403..79ae187bd 100644 --- a/libretroshare/src/gxs/rsgxsutil.cc +++ b/libretroshare/src/gxs/rsgxsutil.cc @@ -215,7 +215,8 @@ bool RsGxsIntegrityCheck::check() rsReputations->overallReputationLevel( grp->metaData->mAuthorId ) > RsReputationLevel::LOCALLY_NEGATIVE ) - used_gxs_ids.insert(std::make_pair(grp->metaData->mAuthorId, RsIdentityUsage(mGenExchangeClient->serviceType(), RsIdentityUsage::GROUP_AUTHOR_KEEP_ALIVE,grp->grpId))); + used_gxs_ids.insert(std::make_pair(grp->metaData->mAuthorId, RsIdentityUsage(RsServiceType(mGenExchangeClient->serviceType()), + RsIdentityUsage::GROUP_AUTHOR_KEEP_ALIVE,grp->grpId))); } } } @@ -404,7 +405,12 @@ bool RsGxsIntegrityCheck::check() rsReputations->overallReputationLevel( msg->metaData->mAuthorId ) > RsReputationLevel::LOCALLY_NEGATIVE ) - used_gxs_ids.insert(std::make_pair(msg->metaData->mAuthorId,RsIdentityUsage(mGenExchangeClient->serviceType(),RsIdentityUsage::MESSAGE_AUTHOR_KEEP_ALIVE,msg->metaData->mGroupId,msg->metaData->mMsgId))) ; + used_gxs_ids.insert(std::make_pair(msg->metaData->mAuthorId,RsIdentityUsage(RsServiceType(mGenExchangeClient->serviceType()), + RsIdentityUsage::MESSAGE_AUTHOR_KEEP_ALIVE, + msg->metaData->mGroupId, + msg->metaData->mMsgId, + msg->metaData->mParentId, + msg->metaData->mThreadId))) ; } } diff --git a/libretroshare/src/gxstunnel/p3gxstunnel.cc b/libretroshare/src/gxstunnel/p3gxstunnel.cc index 543817ffc..2909238ea 100644 --- a/libretroshare/src/gxstunnel/p3gxstunnel.cc +++ b/libretroshare/src/gxstunnel/p3gxstunnel.cc @@ -976,7 +976,7 @@ void p3GxsTunnelService::handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) std::cerr << "(SS) Signature was verified and it doesn't check! This is a security issue!" << std::endl; return ; } - mGixs->timeStampKey(item->signature.keyId,RsIdentityUsage(RS_SERVICE_TYPE_GXS_TUNNEL,RsIdentityUsage::GXS_TUNNEL_DH_SIGNATURE_CHECK)); + mGixs->timeStampKey(item->signature.keyId,RsIdentityUsage(RsServiceType::GXS_TUNNEL,RsIdentityUsage::GXS_TUNNEL_DH_SIGNATURE_CHECK)); #ifdef DEBUG_GXS_TUNNEL std::cerr << " Signature checks! Sender's ID = " << senders_id << std::endl; diff --git a/libretroshare/src/retroshare/rsidentity.h b/libretroshare/src/retroshare/rsidentity.h index ef8a24826..7fa23697a 100644 --- a/libretroshare/src/retroshare/rsidentity.h +++ b/libretroshare/src/retroshare/rsidentity.h @@ -234,33 +234,30 @@ struct RsIdentityUsage : RsSerializable GXS_TUNNEL_DH_SIGNATURE_CHECK = 0x0c, GXS_TUNNEL_DH_SIGNATURE_CREATION = 0x0d, + /// Identity received through GXS sync + IDENTITY_NEW_FROM_GXS_SYNC = 0x0e, /// Group update on that identity data. Can be avatar, name, etc. - IDENTITY_DATA_UPDATE = 0x0e, + IDENTITY_NEW_FROM_DISCOVERY = 0x0f, + /// Explicit request to friend + IDENTITY_NEW_FROM_EXPLICIT_REQUEST = 0x10, /// Any signature verified for that identity - IDENTITY_GENERIC_SIGNATURE_CHECK = 0x0f, + IDENTITY_GENERIC_SIGNATURE_CHECK = 0x11, /// Any signature made by that identity - IDENTITY_GENERIC_SIGNATURE_CREATION = 0x10, + IDENTITY_GENERIC_SIGNATURE_CREATION = 0x12, - IDENTITY_GENERIC_ENCRYPTION = 0x11, - IDENTITY_GENERIC_DECRYPTION = 0x12, - CIRCLE_MEMBERSHIP_CHECK = 0x13 + IDENTITY_GENERIC_ENCRYPTION = 0x13, + IDENTITY_GENERIC_DECRYPTION = 0x14, + CIRCLE_MEMBERSHIP_CHECK = 0x15 } ; - RS_DEPRECATED - RsIdentityUsage( uint16_t service, const RsIdentityUsage::UsageCode& code, - const RsGxsGroupId& gid = RsGxsGroupId(), - const RsGxsMessageId& mid = RsGxsMessageId(), - uint64_t additional_id=0, - const std::string& comment = std::string() ); - RsIdentityUsage( RsServiceType service, RsIdentityUsage::UsageCode code, const RsGxsGroupId& gid = RsGxsGroupId(), - const RsGxsMessageId& mid = RsGxsMessageId(), - const RsGxsMessageId& pid = RsGxsMessageId(), - const RsGxsMessageId& tid = RsGxsMessageId(), + const RsGxsMessageId& message_id = RsGxsMessageId(), + const RsGxsMessageId& parent_id = RsGxsMessageId(), + const RsGxsMessageId& thread_id = RsGxsMessageId(), uint64_t additional_id=0, const std::string& comment = std::string() ); diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index 58da554a1..e0d210f0f 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -1468,7 +1468,7 @@ bool p3GxsCircles::locked_processLoadingCacheEntry(RsGxsCircleCache& cache) rsPeers->getOnlineList(peers) ; } - mIdentities->requestKey(pit->first, peers,RsIdentityUsage(serviceType(),RsIdentityUsage::CIRCLE_MEMBERSHIP_CHECK,RsGxsGroupId(cache.mCircleId))); + mIdentities->requestKey(pit->first, peers,RsIdentityUsage(RsServiceType::GXSCIRCLE,RsIdentityUsage::CIRCLE_MEMBERSHIP_CHECK,RsGxsGroupId(cache.mCircleId))); all_ids_here = false; } diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index a475f5861..0f23883b8 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -641,7 +641,7 @@ void p3IdService::notifyChanges(std::vector &changes) rsEvents->postEvent(ev); // also time_stamp the key that this group represents - timeStampKey(RsGxsId(gid),RsIdentityUsage(serviceType(),RsIdentityUsage::IDENTITY_DATA_UPDATE)) ; + timeStampKey(RsGxsId(gid),RsIdentityUsage(RsServiceType(serviceType()),RsIdentityUsage::IDENTITY_NEW_FROM_GXS_SYNC)) ; should_subscribe = true; } break; @@ -654,7 +654,7 @@ void p3IdService::notifyChanges(std::vector &changes) rsEvents->postEvent(ev); // also time_stamp the key that this group represents - timeStampKey(RsGxsId(gid),RsIdentityUsage(serviceType(),RsIdentityUsage::IDENTITY_DATA_UPDATE)) ; + timeStampKey(RsGxsId(gid),RsIdentityUsage(RsServiceType(serviceType()),RsIdentityUsage::IDENTITY_NEW_FROM_GXS_SYNC)) ; should_subscribe = true; } break; @@ -1214,8 +1214,7 @@ bool p3IdService::requestIdentity( return false; } - RsIdentityUsage usageInfo( RsServiceType::GXSID, - RsIdentityUsage::IDENTITY_DATA_UPDATE ); + RsIdentityUsage usageInfo( RsServiceType::GXSID, RsIdentityUsage::IDENTITY_NEW_FROM_EXPLICIT_REQUEST ); return requestKey(id, askPeersList, usageInfo); } @@ -1360,7 +1359,7 @@ bool p3IdService::signData(const uint8_t *data,uint32_t data_size,const RsGxsId& return false ; } error_status = RS_GIXS_ERROR_NO_ERROR ; - timeStampKey(own_gxs_id,RsIdentityUsage(serviceType(),RsIdentityUsage::IDENTITY_GENERIC_SIGNATURE_CREATION)) ; + timeStampKey(own_gxs_id,RsIdentityUsage(RsServiceType(serviceType()),RsIdentityUsage::IDENTITY_GENERIC_SIGNATURE_CREATION)) ; return true ; } @@ -1433,7 +1432,7 @@ bool p3IdService::encryptData( const uint8_t *decrypted_data, return false ; } error_status = RS_GIXS_ERROR_NO_ERROR ; - timeStampKey(encryption_key_id,RsIdentityUsage(serviceType(),RsIdentityUsage::IDENTITY_GENERIC_ENCRYPTION)) ; + timeStampKey(encryption_key_id,RsIdentityUsage(RsServiceType::GXSID,RsIdentityUsage::IDENTITY_GENERIC_ENCRYPTION)) ; return true ; } @@ -1522,7 +1521,7 @@ bool p3IdService::encryptData( const uint8_t* decrypted_data, { timeStampKey( *it, RsIdentityUsage( - serviceType(), + RsServiceType::GXSID, RsIdentityUsage::IDENTITY_GENERIC_ENCRYPTION ) ); } @@ -1563,7 +1562,7 @@ bool p3IdService::decryptData( const uint8_t *encrypted_data, error_status = RS_GIXS_ERROR_NO_ERROR; timeStampKey( key_id, RsIdentityUsage( - serviceType(), + RsServiceType::GXSID, RsIdentityUsage::IDENTITY_GENERIC_DECRYPTION) ); return true ; @@ -1656,7 +1655,7 @@ bool p3IdService::decryptData( const uint8_t* encrypted_data, { timeStampKey( *it, RsIdentityUsage( - serviceType(), + RsServiceType::GXSID, RsIdentityUsage::IDENTITY_GENERIC_DECRYPTION ) ); } @@ -3223,7 +3222,7 @@ bool p3IdService::cachetest_handlerequest(uint32_t token) if (!haveKey(*vit)) { std::list nullpeers; - requestKey(*vit, nullpeers,RsIdentityUsage(serviceType(),RsIdentityUsage::UNKNOWN_USAGE)); + requestKey(*vit, nullpeers,RsIdentityUsage(RsServiceType::GXSID,RsIdentityUsage::UNKNOWN_USAGE)); #ifdef DEBUG_IDS std::cerr << "p3IdService::cachetest_request() Requested Key Id: " << *vit; @@ -4840,42 +4839,6 @@ RsIdentityUsage::RsIdentityUsage(RsServiceType service, RsIdentityUsage::UsageCo mHash = hs.hash(); } -RsIdentityUsage::RsIdentityUsage( - uint16_t service, const RsIdentityUsage::UsageCode& code, - const RsGxsGroupId& gid, const RsGxsMessageId& mid, - uint64_t additional_id,const std::string& comment ) : - mServiceId(static_cast(service)), mUsageCode(code), - mGrpId(gid), mMsgId(mid), mAdditionalId(additional_id), mComment(comment) -{ -#ifdef DEBUG_IDS - std::cerr << "New identity usage: " << std::endl; - std::cerr << " service=" << std::hex << service << std::endl; - std::cerr << " code =" << std::hex << code << std::endl; - std::cerr << " grpId =" << std::hex << gid << std::endl; - std::cerr << " msgId =" << std::hex << mid << std::endl; - std::cerr << " add id =" << std::hex << additional_id << std::endl; - std::cerr << " commnt =\"" << std::hex << comment << "\"" << std::endl; -#endif - - /* This is a hack, since it will hash also mHash, but because it is - * initialized to 0, and only computed in the constructor here, it should - * be ok. */ - librs::crypto::HashStream hs(librs::crypto::HashStream::SHA1) ; - - hs << (uint32_t)service ; // G10h4ck: Why uint32 if it's 16 bits? - hs << (uint8_t)code ; - hs << gid ; - hs << mid ; - hs << (uint64_t)additional_id ; - hs << comment ; - - mHash = hs.hash(); - -#ifdef DEBUG_IDS - std::cerr << " hash =\"" << std::hex << mHash << "\"" << std::endl; -#endif -} - RsIdentityUsage::RsIdentityUsage() : mServiceId(RsServiceType::NONE), mUsageCode(UNKNOWN_USAGE), mAdditionalId(0) {} diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index 769b14a94..d87f1d6e7 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -1864,7 +1864,8 @@ QString IdDialog::createUsageString(const RsIdentityUsage& u) const case RsServiceType::FORUMS: service_name = tr("Forums") ; service_type = RetroShareLink::TYPE_FORUM ; break ; case RsServiceType::POSTED: service_name = tr("Boards") ; service_type = RetroShareLink::TYPE_POSTED ; break ; case RsServiceType::CHAT: service_name = tr("Chat") ; service_type = RetroShareLink::TYPE_CHAT_ROOM ; break ; - case RsServiceType::GXS_TRANS: service_name = tr("GxsMail"); service_type = RetroShareLink::TYPE_MESSAGE ; break ; + + case RsServiceType::GXS_TRANS: return tr("GxsMail author "); #ifdef TODO // We need a RS link for circles if we want to do that. // @@ -1895,10 +1896,17 @@ QString IdDialog::createUsageString(const RsIdentityUsage& u) const { RetroShareLink l; + std::cerr << "Signature validation/keep alive signature:" << std::endl; + std::cerr << " service ID = " << std::hex << (uint16_t)u.mServiceId << std::dec << std::endl; + std::cerr << " u.mGrpId = " << u.mGrpId << std::endl; + std::cerr << " u.mMsgId = " << u.mMsgId << std::endl; + std::cerr << " u.mParentId = " << u.mParentId << std::endl; + std::cerr << " u.mThreadId = " << u.mThreadId << std::endl; + if(service_type == RetroShareLink::TYPE_CHANNEL && !u.mThreadId.isNull()) - l = RetroShareLink::createGxsMessageLink(service_type,u.mGrpId,u.mThreadId,tr("vote/comment")); + l = RetroShareLink::createGxsMessageLink(service_type,u.mGrpId,u.mThreadId,tr("Vote/comment")); else if(service_type == RetroShareLink::TYPE_POSTED && !u.mThreadId.isNull()) - l = RetroShareLink::createGxsMessageLink(service_type,u.mGrpId,u.mThreadId,tr("vote")); + l = RetroShareLink::createGxsMessageLink(service_type,u.mGrpId,u.mThreadId,tr("Vote")); else l = RetroShareLink::createGxsMessageLink(service_type,u.mGrpId,u.mMsgId,tr("Message")); @@ -1928,9 +1936,13 @@ QString IdDialog::createUsageString(const RsIdentityUsage& u) const { return tr("Signature in distant tunnel system."); } - case RsIdentityUsage::IDENTITY_DATA_UPDATE: // Group update on that identity data. Can be avatar, name, etc. + case RsIdentityUsage::IDENTITY_NEW_FROM_GXS_SYNC: // Group update on that identity data. Can be avatar, name, etc. { - return tr("Update of identity data."); + return tr("Received from GXS sync."); + } + case RsIdentityUsage::IDENTITY_NEW_FROM_DISCOVERY: // Own friend sended his own ids + { + return tr("Friend node identity received through discovery."); } case RsIdentityUsage::IDENTITY_GENERIC_SIGNATURE_CHECK: // Any signature verified for that identity { From bac8e0be70e062ab385ea3d56475758a408e5fc0 Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 8 Jul 2020 23:35:44 +0200 Subject: [PATCH 138/154] added widget for displaying info about identities. Not ready yet --- .../src/gui/statistics/Histogram.cpp | 51 +++++++++++++++++++ retroshare-gui/src/gui/statistics/Histogram.h | 43 ++++++++++++++++ .../src/gui/statistics/StatisticsWindow.cpp | 7 ++- .../src/gui/statistics/StatisticsWindow.h | 2 + retroshare-gui/src/retroshare-gui.pro | 5 ++ 5 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 retroshare-gui/src/gui/statistics/Histogram.cpp create mode 100644 retroshare-gui/src/gui/statistics/Histogram.h diff --git a/retroshare-gui/src/gui/statistics/Histogram.cpp b/retroshare-gui/src/gui/statistics/Histogram.cpp new file mode 100644 index 000000000..6c03e7aaa --- /dev/null +++ b/retroshare-gui/src/gui/statistics/Histogram.cpp @@ -0,0 +1,51 @@ +/******************************************************************************* + * gui/statistics/Histogram.cpp * + * * + * Copyright (c) 2020 Retroshare Team * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include + +#include "Histogram.h" + +Histogram::Histogram(double start, double end, int bins) + : mStart(start),mEnd(end),mBins(bins,0) +{ + if(mEnd <= mStart) + std::cerr << "Null histogram created! Please check your parameters" << std::endl; +} + +void Histogram::draw(QPainter *painter) const +{ +} + +void Histogram::insert(double val) +{ + long int bin = (uint32_t)floor((val - mStart)/(mEnd - mStart) * mBins.size()); + + if(bin >= 0 && bin < mBins.size()) + ++mBins[bin]; +} + +std::ostream& operator<<(std::ostream& o,const Histogram& h) +{ + o << "Histogram: [" << h.mStart << "..." << h.mEnd << "] " << h.mBins.size() << " bins." << std::endl; + for(uint32_t i=0;i * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include +#include + +class QPainter; + +class Histogram +{ + public: + Histogram(double start, double end, int bins); + + void draw(QPainter *painter) const ; + + void insert(double val); + + private: + double mStart; + double mEnd; + + std::vector mBins; + + friend std::ostream& operator<<(std::ostream& o,const Histogram& h); +}; + diff --git a/retroshare-gui/src/gui/statistics/StatisticsWindow.cpp b/retroshare-gui/src/gui/statistics/StatisticsWindow.cpp index bbda5101a..50c947822 100644 --- a/retroshare-gui/src/gui/statistics/StatisticsWindow.cpp +++ b/retroshare-gui/src/gui/statistics/StatisticsWindow.cpp @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -52,6 +53,7 @@ #define IMAGE_DHT ":/icons/DHT128.png" #define IMAGE_TURTLE ":/icons/turtle128.png" +#define IMAGE_IDENTITIES ":/icons/avatar_128.png" #define IMAGE_BWGRAPH ":/icons/bandwidth128.png" #define IMAGE_GLOBALROUTER ":/icons/GRouter128.png" #define IMAGE_GXSTRANSPORT ":/icons/transport128.png" @@ -143,6 +145,9 @@ void StatisticsWindow::initStackedPage() ui->stackPages->add(trsdlg = new TurtleRouterStatistics(ui->stackPages), action = createPageAction(QIcon(IMAGE_TURTLE), tr("Turtle Router"), grp)); + ui->stackPages->add(gxsiddlg = new GxsIdStatistics(ui->stackPages), + action = createPageAction(QIcon(IMAGE_IDENTITIES), tr("Identities"), grp)); + ui->stackPages->add(grsdlg = new GlobalRouterStatistics(ui->stackPages), action = createPageAction(QIcon(IMAGE_GLOBALROUTER), tr("Global Router"), grp)); @@ -150,7 +155,7 @@ void StatisticsWindow::initStackedPage() action = createPageAction(QIcon(IMAGE_GXSTRANSPORT), tr("Gxs Transport"), grp)); ui->stackPages->add(rttdlg = new RttStatistics(ui->stackPages), - action = createPageAction(QIcon(IMAGE_RTT), tr("RTT Statistics"), grp)); + action = createPageAction(QIcon(IMAGE_RTT), tr("RTT Statistics"), grp)); bool showdht = true; RsPeerDetails detail; diff --git a/retroshare-gui/src/gui/statistics/StatisticsWindow.h b/retroshare-gui/src/gui/statistics/StatisticsWindow.h index db2d75939..2450812d7 100644 --- a/retroshare-gui/src/gui/statistics/StatisticsWindow.h +++ b/retroshare-gui/src/gui/statistics/StatisticsWindow.h @@ -38,6 +38,7 @@ class TurtleRouterStatistics; class GlobalRouterStatistics; class GxsTransportStatistics; class RttStatistics; +class GxsIdStatistics; class StatisticsWindow : public QMainWindow { Q_OBJECT @@ -57,6 +58,7 @@ public: BwCtrlWindow *bwdlg; TurtleRouterStatistics *trsdlg; RttStatistics *rttdlg; + GxsIdStatistics *gxsiddlg; public slots: diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index bf76f36a2..b60edbce6 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -437,7 +437,9 @@ HEADERS += rshare.h \ gui/FileTransfer/BannedFilesDialog.h \ gui/statistics/TurtleRouterDialog.h \ gui/statistics/TurtleRouterStatistics.h \ + gui/statistics/GxsIdStatistics.h \ gui/statistics/dhtgraph.h \ + gui/statistics/Histogram.h \ gui/statistics/BandwidthGraphWindow.h \ gui/statistics/turtlegraph.h \ gui/statistics/BandwidthStatsWidget.h \ @@ -755,6 +757,7 @@ FORMS += gui/StartDialog.ui \ gui/statistics/DhtWindow.ui \ gui/statistics/TurtleRouterDialog.ui \ gui/statistics/TurtleRouterStatistics.ui \ + gui/statistics/GxsIdStatistics.ui \ gui/statistics/GlobalRouterStatistics.ui \ gui/statistics/GxsTransportStatistics.ui \ gui/statistics/StatisticsWindow.ui \ @@ -995,8 +998,10 @@ SOURCES += main.cpp \ gui/statistics/BandwidthGraphWindow.cpp \ gui/statistics/BandwidthStatsWidget.cpp \ gui/statistics/DhtWindow.cpp \ + gui/statistics/Histogram.cpp \ gui/statistics/TurtleRouterDialog.cpp \ gui/statistics/TurtleRouterStatistics.cpp \ + gui/statistics/GxsIdStatistics.cpp \ gui/statistics/GlobalRouterStatistics.cpp \ gui/statistics/GxsTransportStatistics.cpp \ gui/statistics/StatisticsWindow.cpp \ From fcf8c5734555a12f96262ffbb88d7e47c8a6d349 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 9 Jul 2020 22:03:09 +0200 Subject: [PATCH 139/154] started display widget for GxsId statistics --- .../src/gui/statistics/GxsIdStatistics.cpp | 433 ++++++++++++++++++ .../src/gui/statistics/GxsIdStatistics.h | 85 ++++ .../src/gui/statistics/GxsIdStatistics.ui | 49 ++ 3 files changed, 567 insertions(+) create mode 100644 retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp create mode 100644 retroshare-gui/src/gui/statistics/GxsIdStatistics.h create mode 100644 retroshare-gui/src/gui/statistics/GxsIdStatistics.ui diff --git a/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp b/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp new file mode 100644 index 000000000..173b82506 --- /dev/null +++ b/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp @@ -0,0 +1,433 @@ +/******************************************************************************* + * gui/statistics/GlobalRouterStatistics.cpp * + * * + * Copyright (c) 2011 Retroshare Team * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "GxsIdStatistics.h" + +#include "util/DateTime.h" +#include "util/QtVersion.h" +#include "util/misc.h" + +static QColor colorScale(float f) +{ + if(f == 0) + return QColor::fromHsv(0,0,192) ; + else + return QColor::fromHsv((int)((1.0-f)*280),200,255) ; +} + +GxsIdStatistics::GxsIdStatistics(QWidget *parent) + : RsAutoUpdatePage(4000,parent) +{ + setupUi(this) ; + + _stats_F->setWidget(_tst_CW = new GxsIdStatisticsWidget); + m_bProcessSettings = false; + + // load settings + processSettings(true); +} + +GxsIdStatistics::~GxsIdStatistics() +{ + // save settings + processSettings(false); +} + +void GxsIdStatistics::processSettings(bool bLoad) +{ + m_bProcessSettings = true; + + Settings->beginGroup(QString("GlobalRouterStatistics")); + + if (bLoad) { + // load settings + + // state of splitter + //splitter->restoreState(Settings->value("Splitter").toByteArray()); + } else { + // save settings + + // state of splitter + //Settings->setValue("Splitter", splitter->saveState()); + + } + + Settings->endGroup(); + + m_bProcessSettings = false; +} + +void GxsIdStatistics::updateDisplay() +{ + _tst_CW->updateContent() ; +} + +static QString getUsageStatisticsName(RsIdentityUsage::UsageCode code) +{ + switch(code) + { + default: + case RsIdentityUsage::UNKNOWN_USAGE : return QObject::tr("Unknown"); + case RsIdentityUsage::GROUP_ADMIN_SIGNATURE_CREATION : return QObject::tr("Group admin signature creation"); + case RsIdentityUsage::GROUP_ADMIN_SIGNATURE_VALIDATION : return QObject::tr("Group admin signature validation"); + case RsIdentityUsage::GROUP_AUTHOR_SIGNATURE_CREATION : return QObject::tr("Group author signature creation"); + case RsIdentityUsage::GROUP_AUTHOR_SIGNATURE_VALIDATION : return QObject::tr("Group author signature validation"); + case RsIdentityUsage::MESSAGE_AUTHOR_SIGNATURE_CREATION : return QObject::tr("Message author signature creation"); + case RsIdentityUsage::MESSAGE_AUTHOR_SIGNATURE_VALIDATION : return QObject::tr("Message author signature validation"); + case RsIdentityUsage::GROUP_AUTHOR_KEEP_ALIVE : return QObject::tr("Routine group author signature check."); + case RsIdentityUsage::MESSAGE_AUTHOR_KEEP_ALIVE : return QObject::tr("Routine message author signature check"); + case RsIdentityUsage::CHAT_LOBBY_MSG_VALIDATION : return QObject::tr("Chat room signature validation"); + case RsIdentityUsage::GLOBAL_ROUTER_SIGNATURE_CHECK : return QObject::tr("Global router message validation"); + case RsIdentityUsage::GLOBAL_ROUTER_SIGNATURE_CREATION : return QObject::tr("Global router message creation"); + case RsIdentityUsage::GXS_TUNNEL_DH_SIGNATURE_CHECK : return QObject::tr("DH Key exchange validation for GXS tunnel"); + case RsIdentityUsage::GXS_TUNNEL_DH_SIGNATURE_CREATION : return QObject::tr("DH Key exchange creation for GXS tunnel"); + case RsIdentityUsage::IDENTITY_NEW_FROM_GXS_SYNC : return QObject::tr("New identity from GXS sync"); + case RsIdentityUsage::IDENTITY_NEW_FROM_DISCOVERY : return QObject::tr("New friend identity from discovery"); + case RsIdentityUsage::IDENTITY_NEW_FROM_EXPLICIT_REQUEST : return QObject::tr("New identity requested from friend node"); + case RsIdentityUsage::IDENTITY_GENERIC_SIGNATURE_CHECK : return QObject::tr("Generic signature validation"); + case RsIdentityUsage::IDENTITY_GENERIC_SIGNATURE_CREATION : return QObject::tr("Generic signature creation"); + case RsIdentityUsage::IDENTITY_GENERIC_ENCRYPTION : return QObject::tr("Generic data decryption"); + case RsIdentityUsage::IDENTITY_GENERIC_DECRYPTION : return QObject::tr("Generic data encryption"); + case RsIdentityUsage::CIRCLE_MEMBERSHIP_CHECK : return QObject::tr("Circle membership checking"); + } +} + +void GxsIdStatisticsWidget::updateContent() +{ + // get the info, stats, histograms and pass them + + std::list ids; + rsIdentity->getIdentitiesSummaries(ids) ; + + time_t now = time(NULL); + + Histogram publish_date_hist(now - 5*365*86400,now,20); + Histogram last_used_hist(now - 15*86400,now,20); + uint32_t total_identities = 0; + std::map usage_map; + + for(auto& meta:ids) + { + RsIdentityDetails det; + + if(!rsIdentity->getIdDetails(RsGxsId(meta.mGroupId),det)) + continue; + + publish_date_hist.insert((double)meta.mPublishTs); + last_used_hist.insert((double)det.mLastUsageTS); + + for(auto it:det.mUseCases) + { + auto it2 = usage_map.find(it.first.mUsageCode); + if(it2 == usage_map.end()) + usage_map[it.first.mUsageCode] = 0 ; + + ++usage_map[it.first.mUsageCode]; + } + + ++total_identities; + } + + std::cerr << "Identities statistics:" << std::endl; + + std::cerr << " Usage map:" << std::endl; + for(auto it:usage_map) + std::cerr << std::hex << (int)it.first << " : " << std::dec << it.second << std::endl; + + std::cerr << " Total identities: " << total_identities << std::endl; + std::cerr << " Last used hist: " << std::endl; + std::cerr << last_used_hist << std::endl; + std::cerr << " Publish date hist: " << std::endl; + std::cerr << publish_date_hist << std::endl; + + // Now draw the info int the widget's pixmap + + float size = QFontMetricsF(font()).height() ; + float fact = size/14.0 ; + + QPixmap tmppixmap(mMaxWidth, mMaxHeight); + tmppixmap.fill(Qt::transparent); + setFixedHeight(mMaxHeight); + + QPainter painter(&tmppixmap); + painter.initFrom(this); + painter.setPen(QColor::fromRgb(0,0,0)) ; + + QFont times_f(font());//"Times") ; + QFont monospace_f("Monospace") ; + monospace_f.setStyleHint(QFont::TypeWriter) ; + monospace_f.setPointSize(font().pointSize()) ; + + QFontMetricsF fm_monospace(monospace_f) ; + QFontMetricsF fm_times(times_f) ; + + int cellx = fm_monospace.width(QString(" ")) ; + int celly = fm_monospace.height() ; + + // Display general statistics + + int ox=5*fact,oy=15*fact ; + + painter.setFont(times_f) ; + painter.drawText(ox,oy,tr("Total identities: ")+QString::number(total_identities)) ; oy += celly*2 ; + + painter.setFont(times_f) ; + painter.drawText(ox,oy,tr("Usage types: ")) ; oy += 2*celly ; + + for(auto it:usage_map) + { + painter.drawText(ox+2*cellx,oy, getUsageStatisticsName(it.first) + ": " + QString::number(it.second)) ; + oy += celly ; + } + oy += celly ; + + // Display per-service statistics + + painter.setFont(times_f) ; + painter.drawText(ox,oy,tr("Usage per service: ")) ; oy += celly; + painter.drawText(ox+2*cellx,oy,tr("[TODO]")) ; oy += celly*2 ; + + // Draw the creation time histogram + + painter.setFont(times_f) ; + painter.drawText(ox,oy,tr("Creation times: ")) ; oy += celly ; + painter.drawText(ox+2*cellx,oy,tr("[TODO]")) ; oy += celly*2 ; + + // Last used histogram + + painter.setFont(times_f) ; + painter.drawText(ox,oy,tr("Last usage: ")) ; oy += celly ; + painter.drawText(ox+2*cellx,oy,tr("[TODO]")) ; oy += celly*2 ; + + // set the pixmap + + pixmap = tmppixmap; + mMaxHeight = oy; +} + + +GxsIdStatisticsWidget::GxsIdStatisticsWidget(QWidget *parent) + : QWidget(parent) +{ + float size = QFontMetricsF(font()).height() ; + float fact = size/14.0 ; + + mMaxWidth = 400*fact ; + mMaxHeight = 0 ; + //mCurrentN = PARTIAL_VIEW_SIZE/2+1 ; +} + +#ifdef TODO +void GxsIdStatisticsWidget::updateContent() +{ + // 1 - get info + + // 2 - draw histograms + + float size = QFontMetricsF(font()).height() ; + float fact = size/14.0 ; + + // What do we need to draw? + // + // Routing matrix + // Key [][][][][][][][][][] + // + // -> each [] shows a square (one per friend node) that is the routing probabilities for all connected friends + // computed using the "computeRoutingProbabilitites()" method. + // + // Own key ids + // key service id description + // + // Data items + // Msg id Local origin Destination Time Status + // + QPixmap tmppixmap(maxWidth, maxHeight); + tmppixmap.fill(Qt::transparent); + setFixedHeight(maxHeight); + + QPainter painter(&tmppixmap); + painter.initFrom(this); + painter.setPen(QColor::fromRgb(0,0,0)) ; + + QFont times_f(font());//"Times") ; + QFont monospace_f("Monospace") ; + monospace_f.setStyleHint(QFont::TypeWriter) ; + monospace_f.setPointSize(font().pointSize()) ; + + QFontMetricsF fm_monospace(monospace_f) ; + QFontMetricsF fm_times(times_f) ; + + static const int cellx = fm_monospace.width(QString(" ")) ; + static const int celly = fm_monospace.height() ; + + maxHeight = 500*fact ; + + // std::cerr << "Drawing into pixmap of size " << maxWidth << "x" << maxHeight << std::endl; + // draw... + int ox=5*fact,oy=5*fact ; + + + painter.setFont(times_f) ; + painter.drawText(ox,oy+celly,tr("Managed keys")+":" + QString::number(matrix_info.published_keys.size())) ; oy += celly*2 ; + + painter.setFont(monospace_f) ; + for(std::map::const_iterator it(matrix_info.published_keys.begin());it!=matrix_info.published_keys.end();++it) + { + QString packet_string ; + packet_string += QString::fromStdString(it->second.authentication_key.toStdString()) ; + packet_string += tr(" : Service ID =")+" "+QString::number(it->second.service_id,16) ; + packet_string += " \""+QString::fromUtf8(it->second.description_string.c_str()) + "\"" ; + + painter.drawText(ox+2*cellx,oy+celly,packet_string ) ; oy += celly ; + } + oy += celly ; + + + std::map > tos ; + + // Now draw the matrix + + QString prob_string ; + painter.setFont(times_f) ; + QString Q = tr("Routing matrix (") ; + + painter.drawText(ox+0*cellx,oy+fm_times.height(),Q) ; + + // draw scale + + for(int i=0;i<100*fact;++i) + { + painter.setPen(colorScale(i/100.0/fact)) ; + painter.drawLine(ox+fm_times.width(Q)+i,oy+fm_times.height()*0.5,ox+fm_times.width(Q)+i,oy+fm_times.height()) ; + } + painter.setPen(QColor::fromRgb(0,0,0)) ; + + painter.drawText(ox+fm_times.width(Q) + 102*fact,oy+celly,")") ; + + oy += celly ; + oy += celly ; + + //static const int MaxKeySize = 20*fact ; + painter.setFont(monospace_f) ; + + int n=0; + QString ids; + std::vector current_probs ; + int current_oy = 0 ; + + mMinWheelZoneX = ox+2*cellx ; + mMinWheelZoneY = oy ; + + RsGxsId current_id ; + float current_width=0 ; + + for(std::map >::const_iterator it(matrix_info.per_friend_probabilities.begin());it!=matrix_info.per_friend_probabilities.end();++it,++n) + if(n >= mCurrentN-PARTIAL_VIEW_SIZE/2 && n <= mCurrentN+PARTIAL_VIEW_SIZE/2) + { + ids = QString::fromStdString(it->first.toStdString())+" : " ; + painter.drawText(ox+2*cellx,oy+celly,ids) ; + + for(uint32_t i=0;isecond[i])) ; + + if(n == mCurrentN) + { + current_probs = it->second ; + current_oy = oy ; + current_id = it->first ; + current_width = ox+matrix_info.friend_ids.size()*cellx+fm_monospace.width(ids); + } + + oy += celly ; + } + mMaxWheelZoneX = ox+matrix_info.friend_ids.size()*cellx + fm_monospace.width(ids); + + RsIdentityDetails iddetails ; + if(rsIdentity->getIdDetails(current_id,iddetails)) + painter.drawText(current_width+cellx, current_oy+celly, QString::fromUtf8(iddetails.mNickname.c_str())) ; + else + painter.drawText(current_width+cellx, current_oy+celly, tr("[Unknown identity]")) ; + + mMaxWheelZoneY = oy+celly ; + + painter.setPen(QColor::fromRgb(0,0,0)) ; + + painter.setPen(QColor::fromRgb(127,127,127)); + painter.drawRect(ox+2*cellx,current_oy+0.15*celly,fm_monospace.width(ids)+cellx*matrix_info.friend_ids.size()- 2*cellx,celly) ; + + float total_length = (matrix_info.friend_ids.size()+2)*cellx ; + + if(!current_probs.empty()) + for(uint32_t i=0;igetPeerDetails(matrix_info.friend_ids[i], peer_ssl_details); + + painter.drawLine(x1,y1,x1,y2); + painter.drawLine(x1,y2,x1 + total_length - i*cellx,y2) ; + painter.drawText(cellx+ x1 + total_length - i*cellx,y2+(0.35)*celly, QString::fromUtf8(peer_ssl_details.name.c_str()) + " - " + QString::fromUtf8(peer_ssl_details.location.c_str()) + " ("+QString::number(current_probs[i])+")"); + } + oy += celly * (2+matrix_info.friend_ids.size()); + + oy += celly ; + oy += celly ; + + // update the pixmap + // + pixmap = tmppixmap; + maxHeight = oy ; +} +#endif + +void GxsIdStatisticsWidget::paintEvent(QPaintEvent */*event*/) +{ + QStylePainter(this).drawPixmap(0, 0, pixmap); +} + +void GxsIdStatisticsWidget::resizeEvent(QResizeEvent *event) +{ + QRect rect = geometry(); + + mMaxWidth = rect.width(); + mMaxHeight = rect.height() ; + + QWidget::resizeEvent(event); + updateContent(); +} diff --git a/retroshare-gui/src/gui/statistics/GxsIdStatistics.h b/retroshare-gui/src/gui/statistics/GxsIdStatistics.h new file mode 100644 index 000000000..5263bb9e9 --- /dev/null +++ b/retroshare-gui/src/gui/statistics/GxsIdStatistics.h @@ -0,0 +1,85 @@ +/******************************************************************************* + * gui/statistics/GxsIdStatistics.h * + * * + * Copyright (c) 2011 Retroshare Team * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Affero General Public License for more details. * + * * + * You should have received a copy of the GNU Affero General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +#pragma once + +#include +#include +#include + +#include "RsAutoUpdatePage.h" +#include "Histogram.h" +#include "ui_GxsIdStatistics.h" + +// In this statistics panel we show: +// +// - histograms +// * age histogram of GXS ids (creation time) +// * last usage histogram +// * number of IDs used in each service as reported by UsageStatistics +// +// (note: we could use that histogram class for packets statistics, so we made a separate class) +// +// And general statistics: +// +// - total number of IDs +// - total number of signed IDs +// - total number of own IDs +// +class GxsIdStatisticsWidget ; + +class GxsIdStatistics: public RsAutoUpdatePage, public Ui::GxsIdStatistics +{ + Q_OBJECT + + public: + GxsIdStatistics(QWidget *parent = NULL) ; + ~GxsIdStatistics(); + + void updateContent() ; + + private: + + void processSettings(bool bLoad); + bool m_bProcessSettings; + + virtual void updateDisplay() ; + + GxsIdStatisticsWidget *_tst_CW ; +} ; + +class GxsIdStatisticsWidget: public QWidget +{ + Q_OBJECT + + public: + GxsIdStatisticsWidget(QWidget *parent = NULL) ; + + virtual void paintEvent(QPaintEvent *event) ; + virtual void resizeEvent(QResizeEvent *event); + + void updateContent() ; + private: + static QString speedString(float f) ; + + QPixmap pixmap ; + int mMaxWidth,mMaxHeight ; +}; + diff --git a/retroshare-gui/src/gui/statistics/GxsIdStatistics.ui b/retroshare-gui/src/gui/statistics/GxsIdStatistics.ui new file mode 100644 index 000000000..0c42ab780 --- /dev/null +++ b/retroshare-gui/src/gui/statistics/GxsIdStatistics.ui @@ -0,0 +1,49 @@ + + + GxsIdStatistics + + + + 0 + 0 + 1468 + 659 + + + + Router Statistics + + + + + + Qt::Vertical + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 1450 + 641 + + + + + + + + + + + From a1c901e22ac285020746eabfcf48d85a41dbbd21 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 10 Jul 2020 22:39:17 +0200 Subject: [PATCH 140/154] added per-service stats --- .../src/gui/statistics/GxsIdStatistics.cpp | 58 ++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp b/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp index 173b82506..ab83a869c 100644 --- a/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp +++ b/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp @@ -33,6 +33,7 @@ #include #include +#include #include "GxsIdStatistics.h" @@ -95,6 +96,47 @@ void GxsIdStatistics::updateDisplay() _tst_CW->updateContent() ; } +static QString getServiceName(uint32_t s) +{ + switch(s) + { + default: + case 0x0011 /* GOSSIP_DISCOVERY */ : return QObject::tr("Discovery"); + case 0x0012 /* CHAT */ : return QObject::tr("Chat"); + case 0x0013 /* MSG */ : return QObject::tr("Messages"); + case 0x0014 /* TURTLE */ : return QObject::tr("Turtle"); + case 0x0016 /* HEARTBEAT */ : return QObject::tr("Heartbeat"); + case 0x0017 /* FILE_TRANSFER */ : return QObject::tr("File transfer"); + case 0x0018 /* GROUTER */ : return QObject::tr("Global router"); + case 0x0019 /* FILE_DATABASE */ : return QObject::tr("File database"); + case 0x0020 /* SERVICEINFO */ : return QObject::tr("Service info"); + case 0x0021 /* BANDWIDTH_CONTROL */ : return QObject::tr("Bandwidth control"); + case 0x0022 /* MAIL */ : return QObject::tr("Mail"); + case 0x0023 /* DIRECT_MAIL */ : return QObject::tr("Mail"); + case 0x0024 /* DISTANT_MAIL */ : return QObject::tr("Distant mail"); + case 0x0026 /* SERVICE_CONTROL */ : return QObject::tr("Service control"); + case 0x0027 /* DISTANT_CHAT */ : return QObject::tr("Distant chat"); + case 0x0028 /* GXS_TUNNEL */ : return QObject::tr("GXS Tunnel"); + case 0x0101 /* BANLIST */ : return QObject::tr("Ban list"); + case 0x0102 /* STATUS */ : return QObject::tr("Status"); + case 0x0200 /* NXS */ : return QObject::tr("NXS"); + case 0x0211 /* GXSID */ : return QObject::tr("Identities"); + case 0x0212 /* PHOTO */ : return QObject::tr("GXS Photo"); + case 0x0213 /* WIKI */ : return QObject::tr("GXS Wiki"); + case 0x0214 /* WIRE */ : return QObject::tr("GXS TheWire"); + case 0x0215 /* FORUMS */ : return QObject::tr("Forums"); + case 0x0216 /* POSTED */ : return QObject::tr("Boards"); + case 0x0217 /* CHANNELS */ : return QObject::tr("Channels"); + case 0x0218 /* GXSCIRCLE */ : return QObject::tr("Circles"); + /// entiti not gxs, but used with :dentities. + case 0x0219 /* REPUTATION */ : return QObject::tr("Reputation"); + case 0x0220 /* GXS_RECOGN */ : return QObject::tr("Recogn"); + case 0x0230 /* GXS_TRANS */ : return QObject::tr("GXS Transport"); + case 0x0240 /* JSONAPI */ : return QObject::tr("JSon API"); + + } +} + static QString getUsageStatisticsName(RsIdentityUsage::UsageCode code) { switch(code) @@ -138,6 +180,7 @@ void GxsIdStatisticsWidget::updateContent() Histogram last_used_hist(now - 15*86400,now,20); uint32_t total_identities = 0; std::map usage_map; + std::map per_service_usage_map; for(auto& meta:ids) { @@ -156,6 +199,13 @@ void GxsIdStatisticsWidget::updateContent() usage_map[it.first.mUsageCode] = 0 ; ++usage_map[it.first.mUsageCode]; + + uint32_t s = static_cast(it.first.mServiceId); + auto it3 = per_service_usage_map.find(s); + if(it3 == per_service_usage_map.end()) + per_service_usage_map[s] = 0; + + ++per_service_usage_map[s]; } ++total_identities; @@ -218,7 +268,13 @@ void GxsIdStatisticsWidget::updateContent() painter.setFont(times_f) ; painter.drawText(ox,oy,tr("Usage per service: ")) ; oy += celly; - painter.drawText(ox+2*cellx,oy,tr("[TODO]")) ; oy += celly*2 ; + + for(auto it:per_service_usage_map) + { + painter.drawText(ox+2*cellx,oy, getServiceName(it.first) + ": " + QString::number(it.second)) ; + oy += celly ; + } + oy += celly ; // Draw the creation time histogram From de6b986c0112703c0d0d61c6b9b33fdbc4edb32f Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 11 Jul 2020 16:16:06 +0200 Subject: [PATCH 141/154] added histograms --- .../src/gui/statistics/GxsIdStatistics.cpp | 89 ++++++++++++++++--- retroshare-gui/src/gui/statistics/Histogram.h | 3 +- 2 files changed, 81 insertions(+), 11 deletions(-) diff --git a/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp b/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp index ab83a869c..ba1ec0811 100644 --- a/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp +++ b/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp @@ -18,14 +18,16 @@ * * *******************************************************************************/ -#include +#include +#include + #include + +#include #include #include #include #include -#include - #include #include #include @@ -175,9 +177,11 @@ void GxsIdStatisticsWidget::updateContent() rsIdentity->getIdentitiesSummaries(ids) ; time_t now = time(NULL); + uint32_t nb_weeks = 52; + uint32_t nb_hours = 52; - Histogram publish_date_hist(now - 5*365*86400,now,20); - Histogram last_used_hist(now - 15*86400,now,20); + Histogram publish_date_hist(now - nb_weeks*7*86400,now,nb_weeks); + Histogram last_used_hist(now - 3600*nb_hours,now,nb_hours); uint32_t total_identities = 0; std::map usage_map; std::map per_service_usage_map; @@ -267,7 +271,7 @@ void GxsIdStatisticsWidget::updateContent() // Display per-service statistics painter.setFont(times_f) ; - painter.drawText(ox,oy,tr("Usage per service: ")) ; oy += celly; + painter.drawText(ox,oy,tr("Usage per service: ")) ; oy += 2*celly; for(auto it:per_service_usage_map) { @@ -279,14 +283,79 @@ void GxsIdStatisticsWidget::updateContent() // Draw the creation time histogram painter.setFont(times_f) ; - painter.drawText(ox,oy,tr("Creation times: ")) ; oy += celly ; - painter.drawText(ox+2*cellx,oy,tr("[TODO]")) ; oy += celly*2 ; + painter.drawText(ox,oy,tr("Identity age (in weeks):")) ; oy += celly ; + + uint32_t hist_height = 10; + oy += hist_height*celly; + + painter.drawLine(QPoint(ox+4*cellx,oy),QPoint(ox+4*cellx+cellx*nb_weeks*2,oy)); + painter.drawLine(QPoint(ox+4*cellx,oy),QPoint(ox+4*cellx,oy-celly*hist_height)); + + uint32_t max_entry=0; + for(int i=0;i& entries() const { return mBins; } + private: double mStart; double mEnd; From 6ea6e7f89ede31637432f09fd32c9ee98a4c6993 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 11 Jul 2020 20:54:58 +0200 Subject: [PATCH 142/154] added count for per usage and per service uses --- .../src/gui/statistics/GxsIdStatistics.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp b/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp index ba1ec0811..5659179a3 100644 --- a/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp +++ b/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp @@ -215,6 +215,7 @@ void GxsIdStatisticsWidget::updateContent() ++total_identities; } +#ifdef DEBUG_GXSID_STATISTICS std::cerr << "Identities statistics:" << std::endl; std::cerr << " Usage map:" << std::endl; @@ -226,6 +227,7 @@ void GxsIdStatisticsWidget::updateContent() std::cerr << last_used_hist << std::endl; std::cerr << " Publish date hist: " << std::endl; std::cerr << publish_date_hist << std::endl; +#endif // Now draw the info int the widget's pixmap @@ -258,8 +260,12 @@ void GxsIdStatisticsWidget::updateContent() painter.setFont(times_f) ; painter.drawText(ox,oy,tr("Total identities: ")+QString::number(total_identities)) ; oy += celly*2 ; + uint32_t total_per_type = 0; + for(auto it:usage_map) + total_per_type += it.second; + painter.setFont(times_f) ; - painter.drawText(ox,oy,tr("Usage types: ")) ; oy += 2*celly ; + painter.drawText(ox,oy,tr("Usage types") + "(" + QString::number(total_per_type) + " identities actually used): ") ; oy += 2*celly; for(auto it:usage_map) { @@ -270,8 +276,12 @@ void GxsIdStatisticsWidget::updateContent() // Display per-service statistics + uint32_t total_per_service = 0; + for(auto it:per_service_usage_map) + total_per_service += it.second; + painter.setFont(times_f) ; - painter.drawText(ox,oy,tr("Usage per service: ")) ; oy += 2*celly; + painter.drawText(ox,oy,tr("Usage per service") + "(" + QString::number(total_per_service) + " identities actually used): ") ; oy += 2*celly; for(auto it:per_service_usage_map) { From 4af3f3742a05879a2932329093d9d9dc27b2f76d Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 11 Jul 2020 21:35:33 +0200 Subject: [PATCH 143/154] fixed text --- retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp b/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp index 5659179a3..bab6c2e9a 100644 --- a/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp +++ b/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp @@ -265,7 +265,7 @@ void GxsIdStatisticsWidget::updateContent() total_per_type += it.second; painter.setFont(times_f) ; - painter.drawText(ox,oy,tr("Usage types") + "(" + QString::number(total_per_type) + " identities actually used): ") ; oy += 2*celly; + painter.drawText(ox,oy,tr("Usage types") + "(" + QString::number(total_per_type) + " hits): ") ; oy += 2*celly; for(auto it:usage_map) { @@ -281,7 +281,7 @@ void GxsIdStatisticsWidget::updateContent() total_per_service += it.second; painter.setFont(times_f) ; - painter.drawText(ox,oy,tr("Usage per service") + "(" + QString::number(total_per_service) + " identities actually used): ") ; oy += 2*celly; + painter.drawText(ox,oy,tr("Usage per service") + "(" + QString::number(total_per_service) + " hits): ") ; oy += 2*celly; for(auto it:per_service_usage_map) { From 7d12a7a0858d9d9ba7064cbb013c179730b35a74 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 11 Jul 2020 22:26:24 +0200 Subject: [PATCH 144/154] switched to async loading of ids statistics --- .../src/gui/statistics/GxsIdStatistics.cpp | 168 ++++++++++-------- .../src/gui/statistics/GxsIdStatistics.h | 9 + .../src/gui/statistics/Histogram.cpp | 4 + retroshare-gui/src/gui/statistics/Histogram.h | 1 + 4 files changed, 108 insertions(+), 74 deletions(-) diff --git a/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp b/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp index bab6c2e9a..a09053deb 100644 --- a/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp +++ b/retroshare-gui/src/gui/statistics/GxsIdStatistics.cpp @@ -42,6 +42,7 @@ #include "util/DateTime.h" #include "util/QtVersion.h" #include "util/misc.h" +#include "util/qtthreadsutils.h" static QColor colorScale(float f) { @@ -96,6 +97,15 @@ void GxsIdStatistics::processSettings(bool bLoad) void GxsIdStatistics::updateDisplay() { _tst_CW->updateContent() ; + + static rstime_t last_data_update_time = 0; + rstime_t now = time(NULL); + + if(now > last_data_update_time + 60) + { + last_data_update_time = now; + _tst_CW->updateData(); + } } static QString getServiceName(uint32_t s) @@ -169,66 +179,73 @@ static QString getUsageStatisticsName(RsIdentityUsage::UsageCode code) } } -void GxsIdStatisticsWidget::updateContent() +void GxsIdStatisticsWidget::updateData() { - // get the info, stats, histograms and pass them + // get the info, stats, histograms and pass them - std::list ids; - rsIdentity->getIdentitiesSummaries(ids) ; + RsThread::async([this]() + { + // 1 - get group data - time_t now = time(NULL); - uint32_t nb_weeks = 52; - uint32_t nb_hours = 52; - - Histogram publish_date_hist(now - nb_weeks*7*86400,now,nb_weeks); - Histogram last_used_hist(now - 3600*nb_hours,now,nb_hours); - uint32_t total_identities = 0; - std::map usage_map; - std::map per_service_usage_map; - - for(auto& meta:ids) - { - RsIdentityDetails det; - - if(!rsIdentity->getIdDetails(RsGxsId(meta.mGroupId),det)) - continue; - - publish_date_hist.insert((double)meta.mPublishTs); - last_used_hist.insert((double)det.mLastUsageTS); - - for(auto it:det.mUseCases) - { - auto it2 = usage_map.find(it.first.mUsageCode); - if(it2 == usage_map.end()) - usage_map[it.first.mUsageCode] = 0 ; - - ++usage_map[it.first.mUsageCode]; - - uint32_t s = static_cast(it.first.mServiceId); - auto it3 = per_service_usage_map.find(s); - if(it3 == per_service_usage_map.end()) - per_service_usage_map[s] = 0; - - ++per_service_usage_map[s]; - } - - ++total_identities; - } - -#ifdef DEBUG_GXSID_STATISTICS - std::cerr << "Identities statistics:" << std::endl; - - std::cerr << " Usage map:" << std::endl; - for(auto it:usage_map) - std::cerr << std::hex << (int)it.first << " : " << std::dec << it.second << std::endl; - - std::cerr << " Total identities: " << total_identities << std::endl; - std::cerr << " Last used hist: " << std::endl; - std::cerr << last_used_hist << std::endl; - std::cerr << " Publish date hist: " << std::endl; - std::cerr << publish_date_hist << std::endl; +#ifdef DEBUG_FORUMS + std::cerr << "Retrieving post data for post " << mThreadId << std::endl; #endif + auto pids = new std::list() ; + rsIdentity->getIdentitiesSummaries(*pids) ; + + RsQThreadUtils::postToObject( [pids,this]() + { + /* Here it goes any code you want to be executed on the Qt Gui + * thread, for example to update the data model with new information + * after a blocking call to RetroShare API complete */ + + const auto& ids(*pids); + + time_t now = time(NULL); + mPublishDateHist = Histogram(now - mNbWeeks*7*86400,now,mNbWeeks); + mLastUsedHist = Histogram(now - 3600*mNbHours,now,mNbHours); + mTotalIdentities = 0; + mUsageMap.clear(); + mPerServiceUsageMap.clear(); + + for(auto& meta:ids) + { + RsIdentityDetails det; + + if(!rsIdentity->getIdDetails(RsGxsId(meta.mGroupId),det)) + continue; + + mPublishDateHist.insert((double)meta.mPublishTs); + mLastUsedHist.insert((double)det.mLastUsageTS); + + for(auto it:det.mUseCases) + { + auto it2 = mUsageMap.find(it.first.mUsageCode); + if(it2 == mUsageMap.end()) + mUsageMap[it.first.mUsageCode] = 0 ; + + ++mUsageMap[it.first.mUsageCode]; + + uint32_t s = static_cast(it.first.mServiceId); + auto it3 = mPerServiceUsageMap.find(s); + if(it3 == mPerServiceUsageMap.end()) + mPerServiceUsageMap[s] = 0; + + ++mPerServiceUsageMap[s]; + } + + ++mTotalIdentities; + } + + delete pids; + + }, this ); + }); +} + +void GxsIdStatisticsWidget::updateContent() +{ // Now draw the info int the widget's pixmap float size = QFontMetricsF(font()).height() ; @@ -258,16 +275,16 @@ void GxsIdStatisticsWidget::updateContent() int ox=5*fact,oy=15*fact ; painter.setFont(times_f) ; - painter.drawText(ox,oy,tr("Total identities: ")+QString::number(total_identities)) ; oy += celly*2 ; + painter.drawText(ox,oy,tr("Total identities: ")+QString::number(mTotalIdentities)) ; oy += celly*2 ; uint32_t total_per_type = 0; - for(auto it:usage_map) + for(auto it:mUsageMap) total_per_type += it.second; painter.setFont(times_f) ; painter.drawText(ox,oy,tr("Usage types") + "(" + QString::number(total_per_type) + " hits): ") ; oy += 2*celly; - for(auto it:usage_map) + for(auto it:mUsageMap) { painter.drawText(ox+2*cellx,oy, getUsageStatisticsName(it.first) + ": " + QString::number(it.second)) ; oy += celly ; @@ -277,13 +294,13 @@ void GxsIdStatisticsWidget::updateContent() // Display per-service statistics uint32_t total_per_service = 0; - for(auto it:per_service_usage_map) + for(auto it:mPerServiceUsageMap) total_per_service += it.second; painter.setFont(times_f) ; painter.drawText(ox,oy,tr("Usage per service") + "(" + QString::number(total_per_service) + " hits): ") ; oy += 2*celly; - for(auto it:per_service_usage_map) + for(auto it:mPerServiceUsageMap) { painter.drawText(ox+2*cellx,oy, getServiceName(it.first) + ": " + QString::number(it.second)) ; oy += celly ; @@ -298,23 +315,23 @@ void GxsIdStatisticsWidget::updateContent() uint32_t hist_height = 10; oy += hist_height*celly; - painter.drawLine(QPoint(ox+4*cellx,oy),QPoint(ox+4*cellx+cellx*nb_weeks*2,oy)); + painter.drawLine(QPoint(ox+4*cellx,oy),QPoint(ox+4*cellx+cellx*mNbWeeks*2,oy)); painter.drawLine(QPoint(ox+4*cellx,oy),QPoint(ox+4*cellx,oy-celly*hist_height)); uint32_t max_entry=0; - for(int i=0;i mUsageMap; + std::map mPerServiceUsageMap; }; diff --git a/retroshare-gui/src/gui/statistics/Histogram.cpp b/retroshare-gui/src/gui/statistics/Histogram.cpp index 6c03e7aaa..6cd1c4906 100644 --- a/retroshare-gui/src/gui/statistics/Histogram.cpp +++ b/retroshare-gui/src/gui/statistics/Histogram.cpp @@ -22,6 +22,10 @@ #include "Histogram.h" +Histogram::Histogram() + : mStart(0),mEnd(1.0),mBins(10,0) +{} + Histogram::Histogram(double start, double end, int bins) : mStart(start),mEnd(end),mBins(bins,0) { diff --git a/retroshare-gui/src/gui/statistics/Histogram.h b/retroshare-gui/src/gui/statistics/Histogram.h index 56eeddf65..ca71d3b82 100644 --- a/retroshare-gui/src/gui/statistics/Histogram.h +++ b/retroshare-gui/src/gui/statistics/Histogram.h @@ -26,6 +26,7 @@ class QPainter; class Histogram { public: + Histogram(); Histogram(double start, double end, int bins); void draw(QPainter *painter) const ; From 94918dc1a3150dd5e12c50472a7ee418eef2d2cb Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 15 Jul 2020 21:22:02 +0200 Subject: [PATCH 145/154] fixed error in parsing identity service string. --- libretroshare/src/services/p3idservice.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index 0f23883b8..85be9c077 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -49,6 +49,7 @@ * #define DEBUG_OPINION 1 * #define GXSID_GEN_DUMMY_DATA 1 ****/ +#define DEBUG_IDS 1 #define ID_REQUEST_LIST 0x0001 #define ID_REQUEST_IDENTITY 0x0002 @@ -616,11 +617,11 @@ void p3IdService::notifyChanges(std::vector &changes) std::cerr << "p3IdService::notifyChanges() Found Group Change Notification"; std::cerr << std::endl; #endif + const RsGxsGroupId& gid(groupChange->mGroupId); #ifdef DEBUG_IDS - std::cerr << "p3IdService::notifyChanges() Auto Subscribe to Incoming Groups: " << *git; + std::cerr << "p3IdService::notifyChanges() Auto Subscribe to Incoming Groups: " << gid; std::cerr << std::endl; #endif - const RsGxsGroupId& gid(groupChange->mGroupId); if(!rsReputations->isIdentityBanned(RsGxsId(gid))) { @@ -2291,7 +2292,7 @@ bool SSGxsIdGroup::load(const std::string &input) char scorestr[RSGXSID_MAX_SERVICE_STRING]; // split into parts. - if (3 != sscanf(input.c_str(), "v2 {P:%[^}]} {T:%[^}]} {R:%[^}]}", pgpstr, recognstr, scorestr)) + if (3 != sscanf(input.c_str(), "v2 {P:%[^}]}{T:%[^}]}{R:%[^}]}", pgpstr, recognstr, scorestr)) { #ifdef DEBUG_IDS std::cerr << "SSGxsIdGroup::load() Failed to extract 4 Parts"; From b3ab99bd4946199c83b4aaa7a0d16225329f28ef Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 15 Jul 2020 22:07:31 +0200 Subject: [PATCH 146/154] added last minute check to avoid re-requesting IDs that have been loaded in cache after they where foundmissing --- libretroshare/src/services/p3idservice.cc | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index 85be9c077..c15002a33 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -657,6 +657,8 @@ void p3IdService::notifyChanges(std::vector &changes) // also time_stamp the key that this group represents timeStampKey(RsGxsId(gid),RsIdentityUsage(RsServiceType(serviceType()),RsIdentityUsage::IDENTITY_NEW_FROM_GXS_SYNC)) ; should_subscribe = true; + + std::cerr << "Received new identity " << gid << " and subscribing to it" << std::endl; } break; @@ -2954,9 +2956,19 @@ void p3IdService::requestIdsFromNet() for(cit = mIdsNotPresent.begin(); cit != mIdsNotPresent.end();) { #ifdef DEBUG_IDS - Dbg2() << __PRETTY_FUNCTION__ << " Processing missing key RsGxsId: " - << cit->first << std::endl; + Dbg2() << __PRETTY_FUNCTION__ << " Processing missing key RsGxsId: " << cit->first << std::endl; #endif + RsGxsIdCache data; + + if(!mKeyCache.fetch(cit->first,data)) + { + std::cerr << __PRETTY_FUNCTION__ << ". Dropping request for ID " << cit->first << " at last minute, because it was found in cache"<< std::endl; + auto tmp(cit); + ++tmp; + mIdsNotPresent.erase(cit); + cit = tmp; + continue; + } const RsGxsId& gxsId = cit->first; const std::list& peers = cit->second; @@ -3011,8 +3023,7 @@ void p3IdService::requestIdsFromNet() { const RsPeerId& peer = cit2->first; std::list grpIds; - for( std::list::const_iterator gxs_id_it = cit2->second.begin(); - gxs_id_it != cit2->second.end(); ++gxs_id_it ) + for( std::list::const_iterator gxs_id_it = cit2->second.begin(); gxs_id_it != cit2->second.end(); ++gxs_id_it ) { #ifdef DEBUG_IDS Dbg2() << __PRETTY_FUNCTION__ << " passing RsGxsId: " << *gxs_id_it From 6e52804547bd636f294cd06f1122db922a35a72a Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 16 Jul 2020 21:33:26 +0200 Subject: [PATCH 147/154] fixed bug causing banned GXS id to be still added to sync list --- libretroshare/src/gxs/rsgxsnetservice.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index 79be6fb95..e7dbe21ac 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -324,8 +324,8 @@ static const uint32_t RS_NXS_ITEM_ENCRYPTION_STATUS_GXS_KEY_MISSING = 0x05 ; || defined(NXS_NET_DEBUG_8) || defined(NXS_NET_DEBUG_9) 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 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 RsGxsGroupId group_id_to_print = RsGxsGroupId();//std::string("66052380f5d1d0c5992e2b55dc402ce6")) ; // use this to allow to this group id only, or "" for all IDs +static const uint32_t service_to_print = RS_SERVICE_GXS_TYPE_GXSID; // 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) class nullstream: public std::ostream {}; @@ -3183,7 +3183,8 @@ void RsGxsNetService::locked_genReqGrpTransaction(NxsTransaction* tr) { grpItemL.push_back(item); grpMetaMap[item->grpId] = NULL; - }else + } + else { #ifdef NXS_NET_DEBUG_0 GXSNETDEBUG_PG(tr->mTransaction->PeerId(),item->grpId) << "RsGxsNetService::genReqGrpTransaction(): item failed to caste to RsNxsSyncMsgItem* " << std::endl; @@ -3238,18 +3239,21 @@ void RsGxsNetService::locked_genReqGrpTransaction(NxsTransaction* tr) // FIXTESTS global variable rsReputations not available in unittests! #warning csoler 2016-12-23: Update the code below to correctly send/recv dependign on reputation - if( !grpSyncItem->authorId.isNull() && - mReputations->overallReputationLevel(grpSyncItem->authorId) == - RsReputationLevel::LOCALLY_NEGATIVE ) + if( mReputations->overallReputationLevel(grpSyncItem->grpId) == RsReputationLevel::LOCALLY_NEGATIVE ) { #ifdef NXS_NET_DEBUG_0 - GXSNETDEBUG_PG(tr->mTransaction->PeerId(),grpId) << " Identity " << grpSyncItem->authorId << " is banned. Not syncing group." << std::endl; + GXSNETDEBUG_PG(tr->mTransaction->PeerId(),grpId) << " Identity " << grpSyncItem->grpId << " is banned. Not GXS-syncing group." << std::endl; #endif continue ; } if( (mGrpAutoSync && !haveItem) || latestVersion) + { +#ifdef NXS_NET_DEBUG_0 + GXSNETDEBUG_PG(tr->mTransaction->PeerId(),grpId) << " Identity " << grpId << " will be sync-ed using GXS. mGrpAutoSync:" << mGrpAutoSync << " haveItem:" << haveItem << " latest_version: " << std::endl; +#endif addGroupItemToList(tr, grpId, transN, reqList); + } } if(!reqList.empty()) From 1a2e25da71a9e2e5f55c147efec739a8d9438ba5 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 16 Jul 2020 21:41:01 +0200 Subject: [PATCH 148/154] disabled syncWithPeers group sync broadcast when mGrpAutoSync is false --- libretroshare/src/gxs/rsgxsnetservice.cc | 41 ++++++++++++------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index e7dbe21ac..557b3c36a 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -593,32 +593,33 @@ void RsGxsNetService::syncWithPeers() return; } - std::set::iterator sit = peers.begin(); + if(mGrpAutoSync) + { + // for now just grps + for(auto sit = peers.begin(); sit != peers.end(); ++sit) + { - // for now just grps - for(; sit != peers.end(); ++sit) - { + const RsPeerId peerId = *sit; - const RsPeerId peerId = *sit; + ClientGrpMap::const_iterator cit = mClientGrpUpdateMap.find(peerId); + uint32_t updateTS = 0; - ClientGrpMap::const_iterator cit = mClientGrpUpdateMap.find(peerId); - uint32_t updateTS = 0; - - if(cit != mClientGrpUpdateMap.end()) - { - const RsGxsGrpUpdate *gui = &cit->second; - updateTS = gui->grpUpdateTS; - } - RsNxsSyncGrpReqItem *grp = new RsNxsSyncGrpReqItem(mServType); - grp->clear(); - grp->PeerId(*sit); - grp->updateTS = updateTS; + if(cit != mClientGrpUpdateMap.end()) + { + const RsGxsGrpUpdate *gui = &cit->second; + updateTS = gui->grpUpdateTS; + } + RsNxsSyncGrpReqItem *grp = new RsNxsSyncGrpReqItem(mServType); + grp->clear(); + grp->PeerId(*sit); + grp->updateTS = updateTS; #ifdef NXS_NET_DEBUG_5 - GXSNETDEBUG_P_(*sit) << "Service "<< std::hex << ((mServiceInfo.mServiceType >> 8)& 0xffff) << std::dec << " sending global group TS of peer id: " << *sit << " ts=" << nice_time_stamp(time(NULL),updateTS) << " (secs ago) to himself" << std::endl; + GXSNETDEBUG_P_(*sit) << "Service "<< std::hex << ((mServiceInfo.mServiceType >> 8)& 0xffff) << std::dec << " sending global group TS of peer id: " << *sit << " ts=" << nice_time_stamp(time(NULL),updateTS) << " (secs ago) to himself" << std::endl; #endif - generic_sendItem(grp); - } + generic_sendItem(grp); + } + } if(!mAllowMsgSync) return ; From 6f636fd8161b0923c4196f32a6bfcabfccc82c3a Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 16 Jul 2020 21:51:37 +0200 Subject: [PATCH 149/154] fixed compilation and re-enabled sync grp broadcast because it is necessary for grp updates --- libretroshare/src/gxs/rsgxsnetservice.cc | 46 +++++++++++------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index 557b3c36a..d4e5dcdee 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -593,32 +593,29 @@ void RsGxsNetService::syncWithPeers() return; } - if(mGrpAutoSync) + // for now just grps + for(auto sit = peers.begin(); sit != peers.end(); ++sit) { - // for now just grps - for(auto sit = peers.begin(); sit != peers.end(); ++sit) + + const RsPeerId peerId = *sit; + + ClientGrpMap::const_iterator cit = mClientGrpUpdateMap.find(peerId); + uint32_t updateTS = 0; + + if(cit != mClientGrpUpdateMap.end()) { - - const RsPeerId peerId = *sit; - - ClientGrpMap::const_iterator cit = mClientGrpUpdateMap.find(peerId); - uint32_t updateTS = 0; - - if(cit != mClientGrpUpdateMap.end()) - { - const RsGxsGrpUpdate *gui = &cit->second; - updateTS = gui->grpUpdateTS; - } - RsNxsSyncGrpReqItem *grp = new RsNxsSyncGrpReqItem(mServType); - grp->clear(); - grp->PeerId(*sit); - grp->updateTS = updateTS; + const RsGxsGrpUpdate *gui = &cit->second; + updateTS = gui->grpUpdateTS; + } + RsNxsSyncGrpReqItem *grp = new RsNxsSyncGrpReqItem(mServType); + grp->clear(); + grp->PeerId(*sit); + grp->updateTS = updateTS; #ifdef NXS_NET_DEBUG_5 - GXSNETDEBUG_P_(*sit) << "Service "<< std::hex << ((mServiceInfo.mServiceType >> 8)& 0xffff) << std::dec << " sending global group TS of peer id: " << *sit << " ts=" << nice_time_stamp(time(NULL),updateTS) << " (secs ago) to himself" << std::endl; + GXSNETDEBUG_P_(*sit) << "Service "<< std::hex << ((mServiceInfo.mServiceType >> 8)& 0xffff) << std::dec << " sending global group TS of peer id: " << *sit << " ts=" << nice_time_stamp(time(NULL),updateTS) << " (secs ago) to himself" << std::endl; #endif - generic_sendItem(grp); - } + generic_sendItem(grp); } if(!mAllowMsgSync) @@ -645,15 +642,13 @@ void RsGxsNetService::syncWithPeers() } } - sit = peers.begin(); - // Synchronise group msg for groups which we're subscribed to // For each peer and each group, we send to the peer the time stamp of the most // recent modification the peer has sent. If the peer has more recent messages he will send them, because its latest // modifications will be more recent. This ensures that we always compare timestamps all taken in the same // computer (the peer's computer in this case) - for(; sit != peers.end(); ++sit) + for(auto sit = peers.begin(); sit != peers.end(); ++sit) { const RsPeerId& peerId = *sit; @@ -3239,8 +3234,7 @@ void RsGxsNetService::locked_genReqGrpTransaction(NxsTransaction* tr) } // FIXTESTS global variable rsReputations not available in unittests! -#warning csoler 2016-12-23: Update the code below to correctly send/recv dependign on reputation - if( mReputations->overallReputationLevel(grpSyncItem->grpId) == RsReputationLevel::LOCALLY_NEGATIVE ) + if( mReputations->overallReputationLevel(RsGxsId(grpSyncItem->grpId)) == RsReputationLevel::LOCALLY_NEGATIVE ) { #ifdef NXS_NET_DEBUG_0 GXSNETDEBUG_PG(tr->mTransaction->PeerId(),grpId) << " Identity " << grpSyncItem->grpId << " is banned. Not GXS-syncing group." << std::endl; From 016e6445a325a114d3564026c46445e1db66b88a Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 17 Jul 2020 00:26:14 +0200 Subject: [PATCH 150/154] fixed bug causing dataservice to return a non null group when the DB doesnt contain the requested group, causing rsgxsnetservice to still sync new groups in no mGrpAutoSync mode, causing identities to spread like hell --- libretroshare/src/gxs/rsdataservice.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libretroshare/src/gxs/rsdataservice.cc b/libretroshare/src/gxs/rsdataservice.cc index bd22a8aa9..5d09fee5d 100644 --- a/libretroshare/src/gxs/rsdataservice.cc +++ b/libretroshare/src/gxs/rsdataservice.cc @@ -502,6 +502,9 @@ RsGxsGrpMetaData* RsDataService::locked_getGrpMeta(RetroCursor &c, int colOffset RsGxsGrpMetaData* grpMeta ; RsGxsGroupId grpId(tempId) ; + if(grpId.isNull()) // not in the DB! + return nullptr; + if(use_cache) grpMeta = mGrpMetaDataCache.getOrCreateMeta(grpId); else @@ -659,8 +662,10 @@ RsGxsMsgMetaData* RsDataService::locked_getMsgMeta(RetroCursor &c, int colOffset std::string temp; c.getString(mColMsgMeta_MsgId + colOffset, temp); msg_id = RsGxsMessageId(temp); + // without these, a msg is meaningless - ok &= (!group_id.isNull()) && (!msg_id.isNull()); + if(group_id.isNull() || msg_id.isNull()) + return nullptr; RsGxsMsgMetaData* msgMeta = nullptr; @@ -1432,7 +1437,7 @@ int RsDataService::retrieveGxsGrpMetaData(RsGxsGrpMetaTemporaryMap& grp) RsGxsGrpMetaData *meta = mGrpMetaDataCache.getMeta(mit->first) ; if(meta) - grp[mit->first] = meta; + mit->second = meta; else { #ifdef RS_DATA_SERVICE_DEBUG_CACHE @@ -1446,7 +1451,7 @@ int RsDataService::retrieveGxsGrpMetaData(RsGxsGrpMetaTemporaryMap& grp) RsGxsGrpMetaData* meta = locked_getGrpMeta(*c, 0,true); if(meta) - grp[mit->first] = meta; + mit->second = meta; #ifdef RS_DATA_SERVICE_DEBUG_TIME ++resultCount; From e4d9194073dc6a241cb20d7f98e1d8b8b964d093 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 17 Jul 2020 00:27:09 +0200 Subject: [PATCH 151/154] fixed bug causing to not request identities correctly to friends --- libretroshare/src/gxs/rsgxsnetservice.cc | 4 ++-- libretroshare/src/services/p3idservice.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index d4e5dcdee..6762998a9 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -3223,7 +3223,7 @@ void RsGxsNetService::locked_genReqGrpTransaction(NxsTransaction* tr) RsNxsSyncGrpItem*& grpSyncItem = *llit; const RsGxsGroupId& grpId = grpSyncItem->grpId; - std::map::const_iterator metaIter = grpMetaMap.find(grpId); + std::map::const_iterator metaIter = grpMetaMap.find(grpId); bool haveItem = false; bool latestVersion = false; @@ -3245,7 +3245,7 @@ void RsGxsNetService::locked_genReqGrpTransaction(NxsTransaction* tr) if( (mGrpAutoSync && !haveItem) || latestVersion) { #ifdef NXS_NET_DEBUG_0 - GXSNETDEBUG_PG(tr->mTransaction->PeerId(),grpId) << " Identity " << grpId << " will be sync-ed using GXS. mGrpAutoSync:" << mGrpAutoSync << " haveItem:" << haveItem << " latest_version: " << std::endl; + GXSNETDEBUG_PG(tr->mTransaction->PeerId(),grpId) << " Identity " << grpId << " will be sync-ed using GXS. mGrpAutoSync:" << mGrpAutoSync << " haveItem:" << haveItem << " latest_version: " << latestVersion << std::endl; #endif addGroupItemToList(tr, grpId, transN, reqList); } diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index c15002a33..54488b5a0 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -2960,7 +2960,7 @@ void p3IdService::requestIdsFromNet() #endif RsGxsIdCache data; - if(!mKeyCache.fetch(cit->first,data)) + if(mKeyCache.fetch(cit->first,data)) { std::cerr << __PRETTY_FUNCTION__ << ". Dropping request for ID " << cit->first << " at last minute, because it was found in cache"<< std::endl; auto tmp(cit); From 120eb02638c94d11d116e82bb6d16a16c59447ff Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 17 Jul 2020 21:56:57 +0200 Subject: [PATCH 152/154] disabled debug output --- libretroshare/src/gxs/rsgxsnetservice.cc | 2 +- libretroshare/src/services/p3idservice.cc | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index 6762998a9..8ed657bfb 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -275,7 +275,7 @@ NXS_NET_DEBUG_9 gxs distant search ***/ -#define NXS_NET_DEBUG_0 1 +//#define NXS_NET_DEBUG_0 1 //#define NXS_NET_DEBUG_1 1 //#define NXS_NET_DEBUG_2 1 //#define NXS_NET_DEBUG_3 1 diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index 54488b5a0..edc33056c 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -49,7 +49,6 @@ * #define DEBUG_OPINION 1 * #define GXSID_GEN_DUMMY_DATA 1 ****/ -#define DEBUG_IDS 1 #define ID_REQUEST_LIST 0x0001 #define ID_REQUEST_IDENTITY 0x0002 From 7d21390d034268211076ecc1be36acfe9d23811f Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 23 Jul 2020 21:59:35 +0200 Subject: [PATCH 153/154] increased GxsId size to 15000 --- libretroshare/src/services/p3idservice.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index edc33056c..b325d9560 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -55,7 +55,7 @@ #define ID_REQUEST_REPUTATION 0x0003 #define ID_REQUEST_OPINION 0x0004 -#define GXSID_MAX_CACHE_SIZE 5000 +#define GXSID_MAX_CACHE_SIZE 15000 // unused keys are deleted according to some heuristic that should favor known keys, signed keys etc. From ed0e0f1da1576c01eafb09621f8f8927a847b873 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 23 Jul 2020 22:05:45 +0200 Subject: [PATCH 154/154] removed more debug info --- libretroshare/src/services/p3gxscircles.cc | 2 ++ libretroshare/src/services/p3idservice.cc | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index e0d210f0f..80f5fa290 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -1463,7 +1463,9 @@ bool p3GxsCircles::locked_processLoadingCacheEntry(RsGxsCircleCache& cache) } else { +#ifdef DEBUG_CIRCLES std::cerr << " (WW) cache entry for circle " << cache.mCircleId << " has empty originator. Asking info for GXS id " << pit->first << " to all connected friends." << std::endl; +#endif rsPeers->getOnlineList(peers) ; } diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index b325d9560..609dd8ad6 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -1251,8 +1251,9 @@ bool p3IdService::requestKey(const RsGxsId &id, const std::list& peers if( info.mOverallReputationLevel == RsReputationLevel::LOCALLY_NEGATIVE ) { - RsInfo() << __PRETTY_FUNCTION__ << " not requesting Key " << id - << " because it has been banned." << std::endl; +#ifdef DEBUG_IDS + RsInfo() << __PRETTY_FUNCTION__ << " not requesting Key " << id << " because it has been banned." << std::endl; +#endif RS_STACK_MUTEX(mIdMtx); mIdsNotPresent.erase(id); @@ -2961,7 +2962,9 @@ void p3IdService::requestIdsFromNet() if(mKeyCache.fetch(cit->first,data)) { +#ifdef DEBUG_IDS std::cerr << __PRETTY_FUNCTION__ << ". Dropping request for ID " << cit->first << " at last minute, because it was found in cache"<< std::endl; +#endif auto tmp(cit); ++tmp; mIdsNotPresent.erase(cit);