diff --git a/libretroshare/src/chat/p3chatservice.cc b/libretroshare/src/chat/p3chatservice.cc index 2f5df22fe..28ade2674 100644 --- a/libretroshare/src/chat/p3chatservice.cc +++ b/libretroshare/src/chat/p3chatservice.cc @@ -156,9 +156,17 @@ class p3ChatService::AvatarInfo void init(const unsigned char *jpeg_data,int size) { - _image_size = size ; - _image_data = (unsigned char*)rs_malloc(size) ; - memcpy(_image_data,jpeg_data,size) ; + if(size == 0) + { + _image_size = 0; + _image_data = nullptr; + } + else + { + _image_size = size ; + _image_data = (unsigned char*)rs_malloc(size) ; + memcpy(_image_data,jpeg_data,size) ; + } } AvatarInfo(const unsigned char *jpeg_data,int size) { diff --git a/libretroshare/src/file_sharing/directory_updater.cc b/libretroshare/src/file_sharing/directory_updater.cc index 254c9ebe3..406c44024 100644 --- a/libretroshare/src/file_sharing/directory_updater.cc +++ b/libretroshare/src/file_sharing/directory_updater.cc @@ -107,10 +107,13 @@ void LocalDirectoryUpdater::threadTick() } } -void LocalDirectoryUpdater::forceUpdate() +void LocalDirectoryUpdater::forceUpdate(bool add_safe_delay) { mForceUpdate = true ; - mLastSweepTime = 0 ; + mLastSweepTime = rstime_t(time(NULL)) - rstime_t(mDelayBetweenDirectoryUpdates) ; + + if(add_safe_delay) + mLastSweepTime += rstime_t(MIN_TIME_AFTER_LAST_MODIFICATION); if(mHashCache != NULL && mHashCache->hashingProcessPaused()) mHashCache->togglePauseHashingProcess(); @@ -363,7 +366,7 @@ void LocalDirectoryUpdater::setFollowSymLinks(bool b) mFollowSymLinks = b ; - forceUpdate(); + forceUpdate(false); } bool LocalDirectoryUpdater::followSymLinks() const diff --git a/libretroshare/src/file_sharing/directory_updater.h b/libretroshare/src/file_sharing/directory_updater.h index 4b95daabe..b7d72b3a9 100644 --- a/libretroshare/src/file_sharing/directory_updater.h +++ b/libretroshare/src/file_sharing/directory_updater.h @@ -35,7 +35,7 @@ public: LocalDirectoryUpdater(HashStorage *hash_cache,LocalDirectoryStorage *lds) ; virtual ~LocalDirectoryUpdater() {} - void forceUpdate(); + void forceUpdate(bool add_safe_delay); bool inDirectoryCheck() const ; void togglePauseHashingProcess(); bool hashingProcessPaused(); diff --git a/libretroshare/src/file_sharing/file_sharing_defaults.h b/libretroshare/src/file_sharing/file_sharing_defaults.h index 75f19075a..92ff43947 100644 --- a/libretroshare/src/file_sharing/file_sharing_defaults.h +++ b/libretroshare/src/file_sharing/file_sharing_defaults.h @@ -48,7 +48,7 @@ static const std::string LOCAL_SHARED_DIRS_FILE_NAME = "local_dir_hierarchy.bin" static const uint32_t MIN_INTERVAL_BETWEEN_HASH_CACHE_SAVE = 20 ; // never save hash cache more often than every 20 secs. static const uint32_t MIN_INTERVAL_BETWEEN_REMOTE_DIRECTORY_SAVE = 23 ; // never save remote directories more often than this -static const uint32_t MIN_TIME_AFTER_LAST_MODIFICATION = 20 ; // never hash a file that is just being modified, otherwise we end up with a corrupted hash +static const uint32_t MIN_TIME_AFTER_LAST_MODIFICATION = 10 ; // never hash a file that is just being modified, otherwise we end up with a corrupted hash static const uint32_t MAX_DIR_SYNC_RESPONSE_DATA_SIZE = 20000 ; // Maximum RsItem data size in bytes for serialised directory transmission static const uint32_t DEFAULT_HASH_STORAGE_DURATION_DAYS = 30 ; // remember deleted/inaccessible files for 30 days diff --git a/libretroshare/src/file_sharing/p3filelists.cc b/libretroshare/src/file_sharing/p3filelists.cc index e4ea57dc7..c7db78b0f 100644 --- a/libretroshare/src/file_sharing/p3filelists.cc +++ b/libretroshare/src/file_sharing/p3filelists.cc @@ -114,7 +114,7 @@ void p3FileDatabase::setSharedDirectories(const std::list& shared RS_STACK_MUTEX(mFLSMtx) ; mLocalSharedDirs->setSharedDirectoryList(shared_dirs) ; - mLocalDirWatcher->forceUpdate(); + mLocalDirWatcher->forceUpdate(false); } @@ -1231,9 +1231,9 @@ uint32_t p3FileDatabase::getType(void *ref,FileSearchFlags flags) const } } -void p3FileDatabase::forceDirectoryCheck() // Force re-sweep the directories and see what's changed +void p3FileDatabase::forceDirectoryCheck(bool add_safe_delay) // Force re-sweep the directories and see what's changed { - mLocalDirWatcher->forceUpdate(); + mLocalDirWatcher->forceUpdate(add_safe_delay); } void p3FileDatabase::togglePauseHashingProcess() { diff --git a/libretroshare/src/file_sharing/p3filelists.h b/libretroshare/src/file_sharing/p3filelists.h index 7ddc6d282..41e8cbeaf 100644 --- a/libretroshare/src/file_sharing/p3filelists.h +++ b/libretroshare/src/file_sharing/p3filelists.h @@ -168,7 +168,7 @@ class p3FileDatabase: public p3Service, public p3Config, public ftSearch //, pub // interfact for directory parsing - void forceDirectoryCheck(); // Force re-sweep the directories and see what's changed + void forceDirectoryCheck(bool add_safe_delay); // Force re-sweep the directories and see what's changed bool inDirectoryCheck(); void togglePauseHashingProcess(); bool hashingProcessPaused(); diff --git a/libretroshare/src/ft/ftcontroller.cc b/libretroshare/src/ft/ftcontroller.cc index d682caba7..45fc70845 100644 --- a/libretroshare/src/ft/ftcontroller.cc +++ b/libretroshare/src/ft/ftcontroller.cc @@ -821,7 +821,7 @@ bool ftController::completeFile(const RsFileHash& hash) RsServer::notify()->notifyDownloadComplete(hash.toStdString()); RsServer::notify()->notifyDownloadCompleteCount(completeCount); - rsFiles->ForceDirectoryCheck() ; + rsFiles->ForceDirectoryCheck(true) ; IndicateConfigChanged(); /* completed transfer -> save */ return true; diff --git a/libretroshare/src/ft/ftserver.cc b/libretroshare/src/ft/ftserver.cc index 293da6d51..256543da6 100644 --- a/libretroshare/src/ft/ftserver.cc +++ b/libretroshare/src/ft/ftserver.cc @@ -791,9 +791,9 @@ void ftServer::updateSinceGroupPermissionsChanged() { mFileDatabase->forceSyncWithPeers(); } -void ftServer::ForceDirectoryCheck() +void ftServer::ForceDirectoryCheck(bool add_safe_delay) { - mFileDatabase->forceDirectoryCheck(); + mFileDatabase->forceDirectoryCheck(add_safe_delay); return; } diff --git a/libretroshare/src/ft/ftserver.h b/libretroshare/src/ft/ftserver.h index 0cc88d6aa..6f719c04e 100644 --- a/libretroshare/src/ft/ftserver.h +++ b/libretroshare/src/ft/ftserver.h @@ -275,7 +275,7 @@ public: * Utility Functions ***/ virtual bool ConvertSharedFilePath(std::string path, std::string &fullpath); - virtual void ForceDirectoryCheck(); + virtual void ForceDirectoryCheck(bool add_safe_delay); virtual void updateSinceGroupPermissionsChanged() ; virtual bool InDirectoryCheck(); virtual bool copyFile(const std::string& source, const std::string& dest); diff --git a/libretroshare/src/gxstrans/p3gxstrans.cc b/libretroshare/src/gxstrans/p3gxstrans.cc index d6d6069b4..44ecccbd1 100644 --- a/libretroshare/src/gxstrans/p3gxstrans.cc +++ b/libretroshare/src/gxstrans/p3gxstrans.cc @@ -656,8 +656,7 @@ void p3GxsTrans::notifyChanges(std::vector& changes) #ifdef DEBUG_GXSTRANS std::cout << "p3GxsTrans::notifyChanges(...)" << std::endl; #endif - for( std::vector::const_iterator it = changes.begin(); - it != changes.end(); ++it ) + for( auto it = changes.begin(); it != changes.end(); ++it ) { RsGxsGroupChange* grpChange = dynamic_cast(*it); RsGxsMsgChange* msgChange = dynamic_cast(*it); @@ -697,8 +696,8 @@ void p3GxsTrans::notifyChanges(std::vector& changes) } #endif } + delete *it; } - RsGxsIfaceHelper::receiveChanges(changes); } uint32_t p3GxsTrans::AuthenPolicy() diff --git a/libretroshare/src/retroshare/rsevents.h b/libretroshare/src/retroshare/rsevents.h index 7d6d24505..d89846e1a 100644 --- a/libretroshare/src/retroshare/rsevents.h +++ b/libretroshare/src/retroshare/rsevents.h @@ -85,6 +85,9 @@ enum class RsEventType : uint32_t /// @see RsGxsPostedEvent GXS_POSTED = 11, + /// @see RsGxsPostedEvent + GXS_IDENTITY = 12, + MAX /// Used to detect invalid event type passed }; diff --git a/libretroshare/src/retroshare/rsfiles.h b/libretroshare/src/retroshare/rsfiles.h index daa83d3bc..e0793d8b7 100644 --- a/libretroshare/src/retroshare/rsfiles.h +++ b/libretroshare/src/retroshare/rsfiles.h @@ -591,9 +591,10 @@ public: /** * @brief Force shared directories check + * @param[in] add_safe_delay Schedule the check 20 seconds from now, to ensure to capture files written just now. * @jsonapi{development} */ - virtual void ForceDirectoryCheck() = 0; + virtual void ForceDirectoryCheck(bool add_safe_delay=false) = 0; virtual void updateSinceGroupPermissionsChanged() = 0; virtual bool InDirectoryCheck() = 0; diff --git a/libretroshare/src/retroshare/rsgxschannels.h b/libretroshare/src/retroshare/rsgxschannels.h index 8e6939672..9fa2f8638 100644 --- a/libretroshare/src/retroshare/rsgxschannels.h +++ b/libretroshare/src/retroshare/rsgxschannels.h @@ -122,6 +122,10 @@ enum class RsChannelEventCode: uint8_t /// subscription for channel mChannelGroupId changed. SUBSCRIBE_STATUS_CHANGED = 0x06, + + /// existing message has been read or set to unread + READ_STATUS_CHANGED = 0x07, + }; struct RsGxsChannelEvent: RsEvent diff --git a/libretroshare/src/retroshare/rsgxscircles.h b/libretroshare/src/retroshare/rsgxscircles.h index 5ef69fda8..ed38f5c2d 100644 --- a/libretroshare/src/retroshare/rsgxscircles.h +++ b/libretroshare/src/retroshare/rsgxscircles.h @@ -182,9 +182,11 @@ enum class RsGxsCircleEventCode: uint8_t /// mCircleId contains the circle id and mGxsId is the id of the new member CIRCLE_MEMBERSHIP_JOIN = 0x04, - /** mCircleId contains the circle id and mGxsId is the id that was revoqued - * by admin */ + /** mCircleId contains the circle id and mGxsId is the id that was revoqued * by admin */ CIRCLE_MEMBERSHIP_REVOQUED= 0x05, + + /** mCircleId contains the circle id */ + NEW_CIRCLE = 0x06, }; struct RsGxsCircleEvent: RsEvent diff --git a/libretroshare/src/retroshare/rsgxsforums.h b/libretroshare/src/retroshare/rsgxsforums.h index 1ce658ab3..becddb329 100644 --- a/libretroshare/src/retroshare/rsgxsforums.h +++ b/libretroshare/src/retroshare/rsgxsforums.h @@ -110,15 +110,10 @@ enum class RsForumEventCode: uint8_t UNKNOWN = 0x00, NEW_FORUM = 0x01, /// emitted when new forum is received UPDATED_FORUM = 0x02, /// emitted when existing forum is updated - - /// new message reeived in a particular forum - NEW_MESSAGE = 0x03, - - /// existing message has been updated in a particular forum - UPDATED_MESSAGE = 0x04, - - /// forum was subscribed or unsubscribed - SUBSCRIBE_STATUS_CHANGED = 0x05, + NEW_MESSAGE = 0x03, /// new message reeived in a particular forum + UPDATED_MESSAGE = 0x04, /// existing message has been updated in a particular forum + SUBSCRIBE_STATUS_CHANGED = 0x05, /// forum was subscribed or unsubscribed + READ_STATUS_CHANGED = 0x06, /// msg was read or marked unread }; struct RsGxsForumEvent: RsEvent diff --git a/libretroshare/src/retroshare/rsidentity.h b/libretroshare/src/retroshare/rsidentity.h index 67844cde0..2874ccc91 100644 --- a/libretroshare/src/retroshare/rsidentity.h +++ b/libretroshare/src/retroshare/rsidentity.h @@ -304,6 +304,32 @@ private: RsIdentityUsage(); }; +enum class RsGxsIdentityEventCode: uint8_t +{ + UNKNOWN = 0x00, + NEW_IDENTITY = 0x01, + DELETED_IDENTITY = 0x02, +}; + +struct RsGxsIdentityEvent: public RsEvent +{ + RsGxsIdentityEvent() + : RsEvent(RsEventType::GXS_IDENTITY), + mIdentityEventCode(RsGxsIdentityEventCode::UNKNOWN) {} + + RsGxsIdentityEventCode mIdentityEventCode; + RsGxsGroupId mIdentityId; + + ///* @see RsEvent @see RsSerializable + void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx ) override + { + RsEvent::serial_process(j, ctx); + RS_SERIAL_PROCESS(mIdentityEventCode); + RS_SERIAL_PROCESS(mIdentityId); + } + + ~RsGxsIdentityEvent() override = default; +}; struct RsIdentityDetails : RsSerializable { diff --git a/libretroshare/src/retroshare/rsposted.h b/libretroshare/src/retroshare/rsposted.h index 211f67bb1..a1dbdf83c 100644 --- a/libretroshare/src/retroshare/rsposted.h +++ b/libretroshare/src/retroshare/rsposted.h @@ -70,9 +70,13 @@ std::ostream &operator<<(std::ostream &out, const RsPostedPost &post); enum class RsPostedEventCode: uint8_t { - UNKNOWN = 0x00, - NEW_POSTED_GROUP = 0x01, - NEW_MESSAGE = 0x02 + UNKNOWN = 0x00, + NEW_POSTED_GROUP = 0x01, + NEW_MESSAGE = 0x02, + SUBSCRIBE_STATUS_CHANGED = 0x03, + UPDATED_POSTED_GROUP = 0x04, + UPDATED_MESSAGE = 0x05, + READ_STATUS_CHANGED = 0x06, }; diff --git a/libretroshare/src/services/p3gxschannels.cc b/libretroshare/src/services/p3gxschannels.cc index 800c148f4..0ccdafc03 100644 --- a/libretroshare/src/services/p3gxschannels.cc +++ b/libretroshare/src/services/p3gxschannels.cc @@ -364,13 +364,11 @@ void p3GxsChannels::notifyChanges(std::vector &changes) } /* shouldn't need to worry about groups - as they need to be subscribed to */ + delete *it; } if(!unprocessedGroups.empty()) request_SpecificSubscribedGroups(unprocessedGroups); - - // the call below deletes changes and its content. - RsGxsIfaceHelper::receiveChanges(changes); } void p3GxsChannels::service_tick() @@ -1764,8 +1762,17 @@ void p3GxsChannels::setMessageReadStatus( uint32_t& token, if (read) status = 0; setMsgStatusFlags(token, msgId, status, mask); -} + if (rsEvents) + { + auto ev = std::make_shared(); + + ev->mChannelMsgId = msgId.second; + ev->mChannelGroupId = msgId.first; + ev->mChannelEventCode = RsChannelEventCode::READ_STATUS_CHANGED; + rsEvents->postEvent(ev); + } +} /********************************************************************************************/ /********************************************************************************************/ diff --git a/libretroshare/src/services/p3gxscircles.cc b/libretroshare/src/services/p3gxscircles.cc index b5b7ae9ad..cb3b4a3ff 100644 --- a/libretroshare/src/services/p3gxscircles.cc +++ b/libretroshare/src/services/p3gxscircles.cc @@ -477,8 +477,8 @@ void p3GxsCircles::notifyChanges(std::vector &changes) #endif p3Notify *notify = RsServer::notify(); - std::vector::iterator it; - for(it = changes.begin(); it != changes.end(); ++it) + + for(auto it = changes.begin(); it != changes.end(); ++it) { RsGxsGroupChange *groupChange = dynamic_cast(*it); RsGxsMsgChange *msgChange = dynamic_cast(*it); @@ -602,11 +602,26 @@ void p3GxsCircles::notifyChanges(std::vector &changes) } #endif + + if(rsEvents && (c->getType() == RsGxsNotify::TYPE_RECEIVED_NEW|| c->getType() == RsGxsNotify::TYPE_PUBLISHED) ) + { + auto ev = std::make_shared(); + ev->mCircleId = RsGxsCircleId(*git); + ev->mCircleEventType = RsGxsCircleEventCode::NEW_CIRCLE; + rsEvents->postEvent(ev); + } + + // reset circle from cache since the number of invitee may have changed. + { + RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/ + mCircleCache.erase(RsGxsCircleId(*git)); + } + } } + delete *it; } - RsGxsIfaceHelper::receiveChanges(changes); // this clear up the vector and delete its elements } /********************************************************************************/ diff --git a/libretroshare/src/services/p3gxsforums.cc b/libretroshare/src/services/p3gxsforums.cc index 6ef0dae34..b8c414df0 100644 --- a/libretroshare/src/services/p3gxsforums.cc +++ b/libretroshare/src/services/p3gxsforums.cc @@ -315,9 +315,9 @@ void p3GxsForums::notifyChanges(std::vector &changes) } /* shouldn't need to worry about groups - as they need to be subscribed to */ - } - RsGxsIfaceHelper::receiveChanges(changes); + delete *it; + } } void p3GxsForums::service_tick() @@ -861,12 +861,19 @@ void p3GxsForums::setMessageReadStatus(uint32_t& token, const RsGxsGrpMsgIdPair& uint32_t mask = GXS_SERV::GXS_MSG_STATUS_GUI_NEW | GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD; uint32_t status = GXS_SERV::GXS_MSG_STATUS_GUI_UNREAD; if (read) - { status = 0; - } setMsgStatusFlags(token, msgId, status, mask); + if (rsEvents) + { + auto ev = std::make_shared(); + + ev->mForumMsgId = msgId.second; + ev->mForumGroupId = msgId.first; + ev->mForumEventCode = RsForumEventCode::READ_STATUS_CHANGED; + rsEvents->postEvent(ev); + } } /********************************************************************************************/ diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index 85de0abcb..861c5c224 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -603,7 +603,6 @@ void p3IdService::notifyChanges(std::vector &changes) for(uint32_t i = 0;i(changes[i]); RsGxsMsgChange *msgChange = dynamic_cast(changes[i]); if (msgChange && !msgChange->metaChange()) @@ -614,8 +613,8 @@ void p3IdService::notifyChanges(std::vector &changes) #endif std::map > &msgChangeMap = msgChange->msgChangeMap; - std::map >::iterator mit; - for(mit = msgChangeMap.begin(); mit != msgChangeMap.end(); ++mit) + + for(auto mit = msgChangeMap.begin(); mit != msgChangeMap.end(); ++mit) { #ifdef DEBUG_IDS std::cerr << "p3IdService::notifyChanges() Msgs for Group: " << mit->first; @@ -624,7 +623,8 @@ void p3IdService::notifyChanges(std::vector &changes) } } - /* shouldn't need to worry about groups - as they need to be subscribed to */ + RsGxsGroupChange *groupChange = dynamic_cast(changes[i]); + if (groupChange && !groupChange->metaChange()) { #ifdef DEBUG_IDS @@ -632,9 +632,8 @@ void p3IdService::notifyChanges(std::vector &changes) std::cerr << std::endl; #endif std::list &groupList = groupChange->mGrpIdList; - std::list::iterator git; - for(git = groupList.begin(); git != groupList.end();) + for(auto git = groupList.begin(); git != groupList.end();++git) { #ifdef DEBUG_IDS std::cerr << "p3IdService::notifyChanges() Auto Subscribe to Incoming Groups: " << *git; @@ -649,21 +648,29 @@ void p3IdService::notifyChanges(std::vector &changes) timeStampKey(RsGxsId(*git),RsIdentityUsage(serviceType(),RsIdentityUsage::IDENTITY_DATA_UPDATE)) ; - ++git; - } - else - git = groupList.erase(git) ; - } + // notify that a new identity is received, if needed - if(groupList.empty()) - { - delete changes[i] ; - changes[i] = NULL ; + switch(groupChange->getType()) + { + case RsGxsNotify::TYPE_PUBLISHED: + case RsGxsNotify::TYPE_RECEIVED_NEW: + { + auto ev = std::make_shared(); + ev->mIdentityId = *git; + ev->mIdentityEventCode = RsGxsIdentityEventCode::NEW_IDENTITY; + rsEvents->postEvent(ev); + } + break; + + default: + break; + } + } } } - } - RsGxsIfaceHelper::receiveChanges(changes); + delete changes[i]; + } } /********************************************************************************/ @@ -1070,6 +1077,14 @@ bool p3IdService::deleteIdentity(RsGxsId& id) return false; } + if(rsEvents) + { + auto ev = std::make_shared(); + ev->mIdentityId = grouId; + ev->mIdentityEventCode = RsGxsIdentityEventCode::DELETED_IDENTITY; + rsEvents->postEvent(ev); + } + return true; } diff --git a/libretroshare/src/services/p3postbase.cc b/libretroshare/src/services/p3postbase.cc index 12799c4f7..309c3ee16 100644 --- a/libretroshare/src/services/p3postbase.cc +++ b/libretroshare/src/services/p3postbase.cc @@ -87,12 +87,10 @@ void p3PostBase::notifyChanges(std::vector &changes) std::cerr << std::endl; #endif - std::vector::iterator it; - - for(it = changes.begin(); it != changes.end(); ++it) + for(auto it = changes.begin(); it != changes.end(); ++it) { - RsGxsGroupChange *groupChange = dynamic_cast(*it); RsGxsMsgChange *msgChange = dynamic_cast(*it); + if (msgChange) { #ifdef POSTBASE_DEBUG @@ -124,34 +122,58 @@ void p3PostBase::notifyChanges(std::vector &changes) } } + RsGxsGroupChange *grpChange = dynamic_cast(*it); + /* pass on Group Changes to GUI */ - if (groupChange) + if (grpChange && rsEvents) { #ifdef POSTBASE_DEBUG std::cerr << "p3PostBase::notifyChanges() Found Group Change Notification"; std::cerr << std::endl; #endif - std::list &groupList = groupChange->mGrpIdList; - - for(auto git = groupList.begin(); git != groupList.end(); ++git) + switch(grpChange->getType()) + { + default: + case RsGxsNotify::TYPE_PROCESSED: // happens when the group is subscribed { -#ifdef POSTBASE_DEBUG - std::cerr << "p3PostBase::notifyChanges() Incoming Group: " << *git; - std::cerr << std::endl; -#endif - - if (rsEvents && groupChange->getType() == RsGxsNotify::TYPE_RECEIVED_NEW) + std::list &grpList = grpChange->mGrpIdList; + std::list::iterator git; + for (git = grpList.begin(); git != grpList.end(); ++git) { + auto ev = std::make_shared(); + ev->mPostedGroupId = *git; + ev->mPostedEventCode = RsPostedEventCode::SUBSCRIBE_STATUS_CHANGED; + rsEvents->postEvent(ev); + } + + } + break; + + case RsGxsNotify::TYPE_PUBLISHED: + case RsGxsNotify::TYPE_RECEIVED_NEW: + { + /* group received */ + const std::list& grpList = grpChange->mGrpIdList; + + for (auto git = grpList.begin(); git != grpList.end(); ++git) + { +#ifdef POSTBASE_DEBUG + std::cerr << "p3PostBase::notifyChanges() Incoming Group: " << *git; + std::cerr << std::endl; +#endif auto ev = std::make_shared(); ev->mPostedGroupId = *git; ev->mPostedEventCode = RsPostedEventCode::NEW_POSTED_GROUP; rsEvents->postEvent(ev); } - } + } + break; + } } + + delete *it; } - receiveHelperChanges(changes); #ifdef POSTBASE_DEBUG std::cerr << "p3PostBase::notifyChanges() -> receiveChanges()"; @@ -183,6 +205,15 @@ void p3PostBase::setMessageReadStatus(uint32_t& token, const RsGxsGrpMsgIdPair& setMsgStatusFlags(token, msgId, status, mask); + if (rsEvents) + { + auto ev = std::make_shared(); + + ev->mPostedMsgId = msgId.second; + ev->mPostedGroupId = msgId.first; + ev->mPostedEventCode = RsPostedEventCode::READ_STATUS_CHANGED; + rsEvents->postEvent(ev); + } } diff --git a/libretroshare/src/util/rsdir.cc b/libretroshare/src/util/rsdir.cc index a890ed8f1..1b794f982 100644 --- a/libretroshare/src/util/rsdir.cc +++ b/libretroshare/src/util/rsdir.cc @@ -254,7 +254,13 @@ int RsDirUtil::breakupDirList(const std::string& path, /**** Copied and Tweaked from ftcontroller ***/ bool RsDirUtil::fileExists(const std::string& filename) { +#ifdef WINDOWS_SYS + std::wstring wfilename; + librs::util::ConvertUtf8ToUtf16(filename, wfilename); + return ( _waccess( wfilename.c_str(), F_OK ) != -1 ); +#else return ( access( filename.c_str(), F_OK ) != -1 ); +#endif } bool RsDirUtil::moveFile(const std::string& source,const std::string& dest) diff --git a/plugins/FeedReader/gui/FeedReaderDialog.cpp b/plugins/FeedReader/gui/FeedReaderDialog.cpp index ca86715e2..5a00cdd6d 100644 --- a/plugins/FeedReader/gui/FeedReaderDialog.cpp +++ b/plugins/FeedReader/gui/FeedReaderDialog.cpp @@ -133,7 +133,7 @@ FeedReaderDialog::~FeedReaderDialog() } } -UserNotify *FeedReaderDialog::getUserNotify(QObject *parent) +UserNotify *FeedReaderDialog::createUserNotify(QObject *parent) { return new FeedReaderUserNotify(this, mFeedReader, mNotify, parent); } diff --git a/plugins/FeedReader/gui/FeedReaderDialog.h b/plugins/FeedReader/gui/FeedReaderDialog.h index 80b6d25a3..a064df811 100644 --- a/plugins/FeedReader/gui/FeedReaderDialog.h +++ b/plugins/FeedReader/gui/FeedReaderDialog.h @@ -42,11 +42,10 @@ public: FeedReaderDialog(RsFeedReader *feedReader, FeedReaderNotify *notify, QWidget *parent = 0); ~FeedReaderDialog(); - virtual UserNotify *getUserNotify(QObject *parent); - static QIcon iconFromFeed(const FeedInfo &feedInfo); protected: + virtual UserNotify *createUserNotify(QObject *parent) override; virtual void showEvent(QShowEvent *event); bool eventFilter(QObject *obj, QEvent *ev); diff --git a/retroshare-gui/src/gui/ChatLobbyWidget.cpp b/retroshare-gui/src/gui/ChatLobbyWidget.cpp index 1c5201343..b139d0113 100644 --- a/retroshare-gui/src/gui/ChatLobbyWidget.cpp +++ b/retroshare-gui/src/gui/ChatLobbyWidget.cpp @@ -226,12 +226,11 @@ ChatLobbyWidget::~ChatLobbyWidget() } } -UserNotify *ChatLobbyWidget::getUserNotify(QObject *parent) +UserNotify *ChatLobbyWidget::createUserNotify(QObject *parent) { - if (!myChatLobbyUserNotify){ - myChatLobbyUserNotify = new ChatLobbyUserNotify(parent); - connect(myChatLobbyUserNotify, SIGNAL(countChanged(ChatLobbyId, unsigned int)), this, SLOT(updateNotify(ChatLobbyId, unsigned int))); - } + myChatLobbyUserNotify = new ChatLobbyUserNotify(parent); + connect(myChatLobbyUserNotify, SIGNAL(countChanged(ChatLobbyId, unsigned int)), this, SLOT(updateNotify(ChatLobbyId, unsigned int))); + return myChatLobbyUserNotify; } diff --git a/retroshare-gui/src/gui/ChatLobbyWidget.h b/retroshare-gui/src/gui/ChatLobbyWidget.h index 39422ec6a..8c6f07081 100644 --- a/retroshare-gui/src/gui/ChatLobbyWidget.h +++ b/retroshare-gui/src/gui/ChatLobbyWidget.h @@ -63,7 +63,7 @@ public: virtual QString pageName() const { return tr("Chats") ; } //MainPage virtual QString helpText() const { return ""; } //MainPage - virtual UserNotify *getUserNotify(QObject *parent); //MainPage + virtual UserNotify *createUserNotify(QObject *parent) override; //MainPage virtual void updateDisplay(); @@ -137,7 +137,7 @@ private: QAction* showTopicAct; int getNumColVisible(); - ChatLobbyUserNotify* myChatLobbyUserNotify; + ChatLobbyUserNotify* myChatLobbyUserNotify; // local copy that avoids dynamic casts QAbstractButton* myInviteYesButton; GxsIdChooser* myInviteIdChooser; diff --git a/retroshare-gui/src/gui/Circles/CirclesDialog.cpp b/retroshare-gui/src/gui/Circles/CirclesDialog.cpp index 8be03e718..64dff16df 100644 --- a/retroshare-gui/src/gui/Circles/CirclesDialog.cpp +++ b/retroshare-gui/src/gui/Circles/CirclesDialog.cpp @@ -62,9 +62,6 @@ CirclesDialog::CirclesDialog(QWidget *parent) mStateHelper->addWidget(CIRCLESDIALOG_GROUPMETA, ui.pushButton_editCircle); mStateHelper->addWidget(CIRCLESDIALOG_GROUPMETA, ui.treeWidget_membership, UISTATE_ACTIVE_ENABLED); -// mStateHelper->addWidget(CIRCLESDIALOG_GROUPMETA, ui.treeWidget_friends, UISTATE_ACTIVE_ENABLED); -// mStateHelper->addWidget(CIRCLESDIALOG_GROUPMETA, ui.treeWidget_category, UISTATE_ACTIVE_ENABLED); - mStateHelper->setWidgetEnabled(ui.pushButton_editCircle, false); /* Connect signals */ @@ -74,19 +71,13 @@ CirclesDialog::CirclesDialog(QWidget *parent) connect(ui.todoPushButton, SIGNAL(clicked()), this, SLOT(todo())); connect(ui.treeWidget_membership, SIGNAL(itemSelectionChanged()), this, SLOT(circle_selected())); -// connect(ui.treeWidget_friends, SIGNAL(itemSelectionChanged()), this, SLOT(friend_selected())); -// connect(ui.treeWidget_category, SIGNAL(itemSelectionChanged()), this, SLOT(category_selected())); /* Setup TokenQueue */ mCircleQueue = new TokenQueue(rsGxsCircles->getTokenService(), this); /* Set header resize modes and initial section sizes */ - QHeaderView * membership_header = ui.treeWidget_membership->header () ; - membership_header->resizeSection ( CIRCLEGROUP_CIRCLE_COL_GROUPNAME, 200 ); - -// QHeaderView * friends_header = ui.treeWidget_friends->header () ; -// friends_header->resizeSection ( CIRCLEGROUP_FRIEND_COL_NAME, 200 ); - + QHeaderView * membership_header = ui.treeWidget_membership->header () ; + membership_header->resizeSection ( CIRCLEGROUP_CIRCLE_COL_GROUPNAME, 200 ); } CirclesDialog::~CirclesDialog() diff --git a/retroshare-gui/src/gui/Circles/CirclesDialog.h b/retroshare-gui/src/gui/Circles/CirclesDialog.h index 7c96febad..ecaff3f29 100644 --- a/retroshare-gui/src/gui/Circles/CirclesDialog.h +++ b/retroshare-gui/src/gui/Circles/CirclesDialog.h @@ -58,35 +58,9 @@ private slots: void friend_selected(); void category_selected(); -#if 0 - void OpenOrShowAddPageDialog(); - void OpenOrShowAddGroupDialog(); - void OpenOrShowEditDialog(); - void OpenOrShowRepublishDialog(); - - void groupTreeChanged(); - - void newGroup(); - void showGroupDetails(); - void editGroupDetails(); - - void insertWikiGroups(); -#endif - private: void reloadAll(); -#if 0 - voidclearWikiPage(); - void clearGroupTree(); - - void updateWikiPage(const RsWikiSnapshot &page); - - bool getSelectedPage(std::string &groupId, std::string &pageId, std::string &origPageId); - std::string getSelectedPage(); - std::string getSelectedGroup(); -#endif - void requestGroupMeta(); void loadGroupMeta(const uint32_t &token); diff --git a/retroshare-gui/src/gui/FileTransfer/TransfersDialog.cpp b/retroshare-gui/src/gui/FileTransfer/TransfersDialog.cpp index 15b57e6d8..855d74ecb 100644 --- a/retroshare-gui/src/gui/FileTransfer/TransfersDialog.cpp +++ b/retroshare-gui/src/gui/FileTransfer/TransfersDialog.cpp @@ -1114,7 +1114,7 @@ void TransfersDialog::activatePage(TransfersDialog::Page page) } } -UserNotify *TransfersDialog::getUserNotify(QObject *parent) +UserNotify *TransfersDialog::createUserNotify(QObject *parent) { return new TransferUserNotify(parent); } diff --git a/retroshare-gui/src/gui/FileTransfer/TransfersDialog.h b/retroshare-gui/src/gui/FileTransfer/TransfersDialog.h index eb39df9b9..83da19c5c 100644 --- a/retroshare-gui/src/gui/FileTransfer/TransfersDialog.h +++ b/retroshare-gui/src/gui/FileTransfer/TransfersDialog.h @@ -67,7 +67,7 @@ public: virtual QString pageName() const { return tr("Files") ; } //MainPage virtual QString helpText() const { return ""; } //MainPage - virtual UserNotify *getUserNotify(QObject *parent); + virtual UserNotify *createUserNotify(QObject *parent) override; void activatePage(TransfersDialog::Page page) ; diff --git a/retroshare-gui/src/gui/FriendsDialog.cpp b/retroshare-gui/src/gui/FriendsDialog.cpp index 152d3a96d..660f13fa7 100644 --- a/retroshare-gui/src/gui/FriendsDialog.cpp +++ b/retroshare-gui/src/gui/FriendsDialog.cpp @@ -163,7 +163,7 @@ void FriendsDialog::activatePage(FriendsDialog::Page page) } } -UserNotify *FriendsDialog::getUserNotify(QObject *parent) +UserNotify *FriendsDialog::createUserNotify(QObject *parent) { return new ChatUserNotify(parent); } diff --git a/retroshare-gui/src/gui/FriendsDialog.h b/retroshare-gui/src/gui/FriendsDialog.h index 6eb9cdf7a..bd8979224 100644 --- a/retroshare-gui/src/gui/FriendsDialog.h +++ b/retroshare-gui/src/gui/FriendsDialog.h @@ -55,7 +55,7 @@ public: virtual QString pageName() const { return tr("Network") ; } //MainPage virtual QString helpText() const { return ""; } //MainPage - virtual UserNotify *getUserNotify(QObject *parent); + virtual UserNotify *createUserNotify(QObject *parent) override; static bool isGroupChatActive(); static void groupChatActivate(); diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index 5d8c45804..ffb29664a 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -35,10 +35,12 @@ #include "gui/chat/ChatDialog.h" #include "gui/Circles/CreateCircleDialog.h" #include "gui/common/UIStateHelper.h" +#include "gui/common/UserNotify.h" #include "gui/gxs/GxsIdDetails.h" #include "gui/gxs/RsGxsUpdateBroadcastBase.h" #include "gui/msgs/MessageComposer.h" #include "gui/settings/rsharesettings.h" +#include "util/qtthreadsutils.h" #include "retroshare-gui/RsAutoUpdatePage.h" #include "util/misc.h" #include "util/QtVersion.h" @@ -148,6 +150,12 @@ IdDialog::IdDialog(QWidget *parent) : mIdQueue = NULL; + mEventHandlerId_identity = 0; + rsEvents->registerEventsHandler(RsEventType::GXS_IDENTITY, [this](std::shared_ptr event) { RsQThreadUtils::postToObject( [=]() { handleEvent_main_thread(event); }, this ); }, mEventHandlerId_identity ); + + mEventHandlerId_circles = 0; + rsEvents->registerEventsHandler(RsEventType::GXS_CIRCLES, [this](std::shared_ptr event) { RsQThreadUtils::postToObject( [=]() { handleEvent_main_thread(event); }, this ); }, mEventHandlerId_circles ); + // This is used to grab the broadcast of changes from p3GxsCircles, which is discarded by the current dialog, since it expects data for p3Identity only. mCirclesBroadcastBase = new RsGxsUpdateBroadcastBase(rsGxsCircles, this); connect(mCirclesBroadcastBase, SIGNAL(fillDisplay(bool)), this, SLOT(updateCirclesDisplay(bool))); @@ -398,6 +406,49 @@ IdDialog::IdDialog(QWidget *parent) : tmer->start(10000) ; // update every 10 secs. } +void IdDialog::handleEvent_main_thread(std::shared_ptr event) +{ + if(event->mType == RsEventType::GXS_IDENTITY) + { + const RsGxsIdentityEvent *e = dynamic_cast(event.get()); + + if(!e) + return; + + switch(e->mIdentityEventCode) + { + case RsGxsIdentityEventCode::DELETED_IDENTITY: + case RsGxsIdentityEventCode::NEW_IDENTITY: + + requestIdList(); + default: + break; + } + } + else if(event->mType == RsEventType::GXS_CIRCLES) + { + const RsGxsCircleEvent *e = dynamic_cast(event.get()); + + if(!e) + return; + + switch(e->mCircleEventType) + { + case RsGxsCircleEventCode::NEW_CIRCLE: + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REQUEST: + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_INVITE: + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_LEAVE: + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_JOIN: + case RsGxsCircleEventCode::CIRCLE_MEMBERSHIP_REVOQUED: + + requestCircleGroupMeta(); + default: + break; + } + + } +} + void IdDialog::clearPerson() { QFontMetricsF f(ui->avLabel_Person->font()) ; @@ -701,7 +752,7 @@ void IdDialog::loadCircleGroupMeta(const uint32_t &token) for(std::map::const_iterator it(details.mSubscriptionFlags.begin());it!=details.mSubscriptionFlags.end();++it) { #ifdef ID_DEBUG - std::cerr << " ID " << *it << ": " ; + std::cerr << " ID " << it->first << ": " ; #endif bool is_own_id = rsIdentity->isOwnId(it->first) ; bool invited ( it->second & GXS_EXTERNAL_CIRCLE_FLAGS_IN_ADMIN_LIST ); @@ -2095,7 +2146,7 @@ void IdDialog::modifyReputation() rsReputations->setOwnOpinion(id,op); #ifdef ID_DEBUG - std::cerr << "IdDialog::modifyReputation() ID: " << id << " Mod: " << op; + std::cerr << "IdDialog::modifyReputation() ID: " << id << " Mod: " << static_cast(op); std::cerr << std::endl; #endif diff --git a/retroshare-gui/src/gui/Identity/IdDialog.h b/retroshare-gui/src/gui/Identity/IdDialog.h index 30f2d0641..e4c73229d 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.h +++ b/retroshare-gui/src/gui/Identity/IdDialog.h @@ -158,6 +158,10 @@ private: RsGxsGroupId mIdToNavigate; int filter; + void handleEvent_main_thread(std::shared_ptr event); + RsEventsHandlerId_t mEventHandlerId_identity; + RsEventsHandlerId_t mEventHandlerId_circles; + /* UI - Designer */ Ui::IdDialog *ui; }; diff --git a/retroshare-gui/src/gui/MainPage.cpp b/retroshare-gui/src/gui/MainPage.cpp index 087655572..545f1270e 100644 --- a/retroshare-gui/src/gui/MainPage.cpp +++ b/retroshare-gui/src/gui/MainPage.cpp @@ -31,6 +31,15 @@ MainPage::MainPage(QWidget *parent , Qt::WindowFlags flags ) : QWidget(parent, f mIcon = QIcon(); mName = ""; mHelp = ""; + mUserNotify = nullptr; +} + +UserNotify *MainPage::getUserNotify() +{ + if(!mUserNotify) + mUserNotify = createUserNotify(this); + + return mUserNotify; } void MainPage::registerHelpButton(QToolButton *button, const QString& help_html_text, const QString &code_name) diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index 6ec0c22f7..63a563dc4 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -469,7 +469,7 @@ void MainWindow::initStackedPage() //List All notify before Setting was created QList > >::iterator notifyIt; for (notifyIt = notify.begin(); notifyIt != notify.end(); ++notifyIt) { - UserNotify *userNotify = notifyIt->first->getUserNotify(this); + UserNotify *userNotify = notifyIt->first->getUserNotify(); if (userNotify) { userNotify->initialize(ui->toolBarPage, notifyIt->second.first, notifyIt->second.second); connect(userNotify, SIGNAL(countChanged()), this, SLOT(updateTrayCombine())); diff --git a/retroshare-gui/src/gui/NewsFeed.cpp b/retroshare-gui/src/gui/NewsFeed.cpp index c64c758ea..2f70340be 100644 --- a/retroshare-gui/src/gui/NewsFeed.cpp +++ b/retroshare-gui/src/gui/NewsFeed.cpp @@ -141,7 +141,7 @@ NewsFeed::~NewsFeed() } } -UserNotify *NewsFeed::getUserNotify(QObject *parent) +UserNotify *NewsFeed::createUserNotify(QObject *parent) { return new NewsFeedUserNotify(this, parent); } diff --git a/retroshare-gui/src/gui/NewsFeed.h b/retroshare-gui/src/gui/NewsFeed.h index ec9aabcb5..9f43c0df8 100644 --- a/retroshare-gui/src/gui/NewsFeed.h +++ b/retroshare-gui/src/gui/NewsFeed.h @@ -70,7 +70,7 @@ public: virtual QString pageName() const { return tr("Log") ; } //MainPage virtual QString helpText() const { return ""; } //MainPage - virtual UserNotify *getUserNotify(QObject *parent); + virtual UserNotify *createUserNotify(QObject *parent) override; /* FeedHolder Functions (for FeedItem functionality) */ virtual QScrollArea *getScrollArea(); diff --git a/retroshare-gui/src/gui/Posted/PhotoView.cpp b/retroshare-gui/src/gui/Posted/PhotoView.cpp new file mode 100644 index 000000000..839e5f4d3 --- /dev/null +++ b/retroshare-gui/src/gui/Posted/PhotoView.cpp @@ -0,0 +1,103 @@ +/******************************************************************************* + * retroshare-gui/src/gui/Posted/PhotoView.cpp * + * * + * Copyright (C) 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 . * + * * + *******************************************************************************/ + +#include "PhotoView.h" + +#include +#include +#include + +#include "gui/gxs/GxsIdDetails.h" +#include "gui/RetroShareLink.h" + +#include +#include + +/** Constructor */ +PhotoView::PhotoView(QWidget *parent) +: QDialog(parent, Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint), + ui(new Ui::PhotoView) +{ + /* Invoke the Qt Designer generated object setup routine */ + ui->setupUi(this); + + setAttribute(Qt::WA_DeleteOnClose, true); + + connect(ui->shareButton, SIGNAL(clicked()), this, SLOT(copyMessageLink())); +} + +/** Destructor */ +PhotoView::~PhotoView() +{ + delete ui; +} + +void PhotoView::setPixmap(const QPixmap& pixmap) +{ + ui->photoLabel->setPixmap(pixmap); + this->adjustSize(); +} + +void PhotoView::setTitle(const QString& text) +{ + ui->titleLabel->setText(text); +} + +void PhotoView::setName(const RsGxsId& authorID) +{ + ui->nameLabel->setId(authorID); + + RsIdentityDetails idDetails ; + rsIdentity->getIdDetails(authorID,idDetails); + + QPixmap pixmap ; + + if(idDetails.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idDetails.mAvatar.mData, idDetails.mAvatar.mSize, pixmap,GxsIdDetails::SMALL)) + pixmap = GxsIdDetails::makeDefaultIcon(authorID,GxsIdDetails::SMALL); + + ui->avatarWidget->setPixmap(pixmap); +} + +void PhotoView::setTime(const QString& text) +{ + ui->timeLabel->setText(text); +} + +void PhotoView::setGroupId(const RsGxsGroupId &groupId) +{ + mGroupId = groupId; +} + +void PhotoView::setMessageId(const RsGxsMessageId& messageId) +{ + mMessageId = messageId ; +} + +void PhotoView::copyMessageLink() +{ + RetroShareLink link = RetroShareLink::createGxsMessageLink(RetroShareLink::TYPE_POSTED, mGroupId, mMessageId, ui->titleLabel->text()); + + if (link.valid()) { + QList urls; + urls.push_back(link); + RSLinkClipboard::copyLinks(urls); + QMessageBox::information(NULL,tr("information"),tr("The Retrohare link was copied to your clipboard.")) ; + } +} diff --git a/retroshare-gui/src/gui/Posted/PhotoView.h b/retroshare-gui/src/gui/Posted/PhotoView.h new file mode 100644 index 000000000..d44406af3 --- /dev/null +++ b/retroshare-gui/src/gui/Posted/PhotoView.h @@ -0,0 +1,65 @@ +/******************************************************************************* + * retroshare-gui/src/gui/Posted/PhotoView.h * + * * + * Copyright (C) 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 . * + * * + *******************************************************************************/ + +#ifndef _PHOTO_VIEW_H +#define _PHOTO_VIEW_H + +#include "ui_PhotoView.h" + +#include + +namespace Ui { + class PhotoView; +} + +class PhotoView : public QDialog +{ + Q_OBJECT + +public: + /** Default Constructor */ + PhotoView(QWidget *parent = 0); + + /** Default Destructor */ + ~PhotoView(); + + +public slots: + void setPixmap(const QPixmap& pixmap); + void setTitle (const QString &text); + void setName(const RsGxsId& authorID); + void setTime(const QString& text); + void setGroupId(const RsGxsGroupId &groupId); + void setMessageId(const RsGxsMessageId& messageId); + +private slots: + void copyMessageLink(); + +private: + RsGxsMessageId mMessageId; + RsGxsGroupId mGroupId; + + /** Qt Designer generated object */ + Ui::PhotoView *ui; + +}; + +#endif + diff --git a/retroshare-gui/src/gui/Posted/PhotoView.ui b/retroshare-gui/src/gui/Posted/PhotoView.ui new file mode 100644 index 000000000..e0d4dce64 --- /dev/null +++ b/retroshare-gui/src/gui/Posted/PhotoView.ui @@ -0,0 +1,229 @@ + + + PhotoView + + + + 0 + 0 + 490 + 316 + + + + Photo View + + + Qt::LeftToRight + + + + + + + MS Sans Serif + 11 + 75 + true + + + + TextLabel + + + true + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + + + + MS Sans Serif + 9 + 50 + false + + + + Posted by + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + + MS Sans Serif + 9 + + + + TextLabel + + + + + + + + MS Sans Serif + 9 + + + + TextLabel + + + + + + + + MS Sans Serif + 9 + + + + ago + + + + + + + Qt::Horizontal + + + + 0 + 20 + + + + + + + + Copy RetroShare link + + + Share + + + + :/images/share.png:/images/share.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + + + + GxsIdLabel + QLabel +
gui/gxs/GxsIdLabel.h
+
+ + AvatarWidget + QWidget +
gui/common/AvatarWidget.h
+ 1 +
+ + AspectRatioPixmapLabel + QLabel +
util/AspectRatioPixmapLabel.h
+
+
+ + + + +
diff --git a/retroshare-gui/src/gui/Posted/PostedCardView.cpp b/retroshare-gui/src/gui/Posted/PostedCardView.cpp new file mode 100644 index 000000000..1fef4f160 --- /dev/null +++ b/retroshare-gui/src/gui/Posted/PostedCardView.cpp @@ -0,0 +1,553 @@ +/******************************************************************************* + * retroshare-gui/src/gui/Posted/PostedCardView.cpp * + * * + * Copyright (C) 2019 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 "rshare.h" +#include "PostedCardView.h" +#include "gui/feeds/FeedHolder.h" +#include "gui/gxs/GxsIdDetails.h" +#include "util/misc.h" +#include "util/HandleRichText.h" + +#include "ui_PostedCardView.h" + +#include +#include + +#define LINK_IMAGE ":/images/thumb-link.png" + +/** Constructor */ + +PostedCardView::PostedCardView(FeedHolder *feedHolder, uint32_t feedId, const RsGxsGroupId &groupId, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate) : + GxsFeedItem(feedHolder, feedId, groupId, messageId, isHome, rsPosted, autoUpdate) +{ + setup(); + + requestGroup(); + requestMessage(); + requestComment(); +} + +PostedCardView::PostedCardView(FeedHolder *feedHolder, uint32_t feedId, const RsPostedGroup &group, const RsPostedPost &post, bool isHome, bool autoUpdate) : + GxsFeedItem(feedHolder, feedId, post.mMeta.mGroupId, post.mMeta.mMsgId, isHome, rsPosted, autoUpdate) +{ + setup(); + + mMessageId = post.mMeta.mMsgId; + + + setGroup(group, false); + setPost(post); + requestComment(); +} + +PostedCardView::PostedCardView(FeedHolder *feedHolder, uint32_t feedId, const RsPostedPost &post, bool isHome, bool autoUpdate) : + GxsFeedItem(feedHolder, feedId, post.mMeta.mGroupId, post.mMeta.mMsgId, isHome, rsPosted, autoUpdate) +{ + setup(); + + requestGroup(); + setPost(post); + requestComment(); +} + +PostedCardView::~PostedCardView() +{ + delete(ui); +} + +void PostedCardView::setup() +{ + /* Invoke the Qt Designer generated object setup routine */ + ui = new Ui::PostedCardView; + ui->setupUi(this); + + setAttribute(Qt::WA_DeleteOnClose, true); + + mInFill = false; + + /* clear ui */ + ui->titleLabel->setText(tr("Loading")); + ui->dateLabel->clear(); + ui->fromLabel->clear(); + ui->siteLabel->clear(); + + /* general ones */ + connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(removeItem())); + + /* specific */ + connect(ui->readAndClearButton, SIGNAL(clicked()), this, SLOT(readAndClearItem())); + + connect(ui->commentButton, SIGNAL( clicked()), this, SLOT(loadComments())); + connect(ui->voteUpButton, SIGNAL(clicked()), this, SLOT(makeUpVote())); + connect(ui->voteDownButton, SIGNAL(clicked()), this, SLOT( makeDownVote())); + connect(ui->readButton, SIGNAL(toggled(bool)), this, SLOT(readToggled(bool))); + + QAction *CopyLinkAction = new QAction(QIcon(""),tr("Copy RetroShare Link"), this); + connect(CopyLinkAction, SIGNAL(triggered()), this, SLOT(copyMessageLink())); + + + int S = QFontMetricsF(font()).height() ; + + ui->voteUpButton->setIconSize(QSize(S*1.5,S*1.5)); + ui->voteDownButton->setIconSize(QSize(S*1.5,S*1.5)); + ui->commentButton->setIconSize(QSize(S*1.5,S*1.5)); + ui->readButton->setIconSize(QSize(S*1.5,S*1.5)); + ui->shareButton->setIconSize(QSize(S*1.5,S*1.5)); + + QMenu *menu = new QMenu(); + menu->addAction(CopyLinkAction); + ui->shareButton->setMenu(menu); + + ui->clearButton->hide(); + ui->readAndClearButton->hide(); +} + +bool PostedCardView::setGroup(const RsPostedGroup &group, bool doFill) +{ + if (groupId() != group.mMeta.mGroupId) { + std::cerr << "PostedCardView::setGroup() - Wrong id, cannot set post"; + std::cerr << std::endl; + return false; + } + + mGroup = group; + + if (doFill) { + fill(); + } + + return true; +} + +bool PostedCardView::setPost(const RsPostedPost &post, bool doFill) +{ + if (groupId() != post.mMeta.mGroupId || messageId() != post.mMeta.mMsgId) { + std::cerr << "PostedCardView::setPost() - Wrong id, cannot set post"; + std::cerr << std::endl; + return false; + } + + mPost = post; + + if (doFill) { + fill(); + } + + return true; +} + +void PostedCardView::loadGroup(const uint32_t &token) +{ + std::vector groups; + if (!rsPosted->getGroupData(token, groups)) + { + std::cerr << "PostedCardView::loadGroup() ERROR getting data"; + std::cerr << std::endl; + return; + } + + if (groups.size() != 1) + { + std::cerr << "PostedCardView::loadGroup() Wrong number of Items"; + std::cerr << std::endl; + return; + } + + setGroup(groups[0]); +} + +void PostedCardView::loadMessage(const uint32_t &token) +{ + std::vector posts; + std::vector cmts; + if (!rsPosted->getPostData(token, posts, cmts)) + { + std::cerr << "GxsChannelPostItem::loadMessage() ERROR getting data"; + std::cerr << std::endl; + return; + } + + if (posts.size() == 1) + { + setPost(posts[0]); + } + else if (cmts.size() == 1) + { + RsGxsComment cmt = cmts[0]; + + //ui->newCommentLabel->show(); + //ui->commLabel->show(); + //ui->commLabel->setText(QString::fromUtf8(cmt.mComment.c_str())); + + //Change this item to be uploaded with thread element. + setMessageId(cmt.mMeta.mThreadId); + requestMessage(); + } + else + { + std::cerr << "GxsChannelPostItem::loadMessage() Wrong number of Items. Remove It."; + std::cerr << std::endl; + removeItem(); + return; + } +} + +void PostedCardView::loadComment(const uint32_t &token) +{ + std::vector cmts; + if (!rsPosted->getRelatedComments(token, cmts)) + { + std::cerr << "GxsChannelPostItem::loadComment() ERROR getting data"; + std::cerr << std::endl; + return; + } + + size_t comNb = cmts.size(); + QString sComButText = tr("Comment"); + if (comNb == 1) { + sComButText = sComButText.append("(1)"); + } else if (comNb > 1) { + sComButText = " " + tr("Comments").append(" (%1)").arg(comNb); + } + ui->commentButton->setText(sComButText); +} + +void PostedCardView::fill() +{ + if (isLoading()) { + /* Wait for all requests */ + return; + } + + 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); + //score += " New" + QString::number(post.mNewScore); + + QString score = QString::number(mPost.mTopScore); + + ui->scoreLabel->setText(score); + + // FIX THIS UP LATER. + ui->notes->setText(RsHtml().formatText(NULL, QString::fromUtf8(mPost.mNotes.c_str()), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); + + QTextDocument doc; + doc.setHtml(ui->notes->text()); + + if(doc.toPlainText().trimmed().isEmpty()) + ui->notes->hide(); + // differences between Feed or Top of Comment. + if (mFeedHolder) + { + // feed. + //frame_comment->show(); + ui->commentButton->show(); + + if (mPost.mComments) + { + QString commentText = QString::number(mPost.mComments); + commentText += " "; + commentText += tr("Comments"); + ui->commentButton->setText(commentText); + } + else + { + ui->commentButton->setText(tr("Comment")); + } + + setReadStatus(IS_MSG_NEW(mPost.mMeta.mMsgStatus), IS_MSG_UNREAD(mPost.mMeta.mMsgStatus) || IS_MSG_NEW(mPost.mMeta.mMsgStatus)); + } + else + { + // no feed. + //frame_comment->hide(); + ui->commentButton->hide(); + + ui->readButton->hide(); + ui->newLabel->hide(); + } + + if (mIsHome) + { + ui->clearButton->hide(); + ui->readAndClearButton->hide(); + } + else + { + ui->clearButton->show(); + ui->readAndClearButton->show(); + } + + // disable voting buttons - if they have already voted. + if (mPost.mMeta.mMsgStatus & GXS_SERV::GXS_MSG_STATUS_VOTE_MASK) + { + ui->voteUpButton->setEnabled(false); + ui->voteDownButton->setEnabled(false); + } + +#if 0 + uint32_t up, down, nComments; + + bool ok = rsPosted->retrieveScores(mPost.mMeta.mServiceString, up, down, nComments); + + if(ok) + { + int32_t vote = up - down; + scoreLabel->setText(QString::number(vote)); + + numCommentsLabel->setText("

# Comments: " + + QString::number(nComments) + "

"); + } +#endif + + mInFill = false; + + emit sizeChanged(this); +} + +const RsPostedPost &PostedCardView::getPost() const +{ + return mPost; +} + +RsPostedPost &PostedCardView::post() +{ + return mPost; +} + +QString PostedCardView::groupName() +{ + return QString::fromUtf8(mGroup.mMeta.mGroupName.c_str()); +} + +QString PostedCardView::messageName() +{ + return QString::fromUtf8(mPost.mMeta.mMsgName.c_str()); +} + +void PostedCardView::makeDownVote() +{ + RsGxsGrpMsgIdPair msgId; + msgId.first = mPost.mMeta.mGroupId; + msgId.second = mPost.mMeta.mMsgId; + + ui->voteUpButton->setEnabled(false); + ui->voteDownButton->setEnabled(false); + + emit vote(msgId, false); +} + +void PostedCardView::makeUpVote() +{ + RsGxsGrpMsgIdPair msgId; + msgId.first = mPost.mMeta.mGroupId; + msgId.second = mPost.mMeta.mMsgId; + + ui->voteUpButton->setEnabled(false); + ui->voteDownButton->setEnabled(false); + + emit vote(msgId, true); +} + +void PostedCardView::loadComments() +{ + std::cerr << "PostedCardView::loadComments()"; + std::cerr << std::endl; + + if (mFeedHolder) + { + QString title = QString::fromUtf8(mPost.mMeta.mMsgName.c_str()); + +#warning (csoler) Posted item versions not handled yet. When it is the case, start here. + + QVector post_versions ; + post_versions.push_back(mPost.mMeta.mMsgId) ; + + mFeedHolder->openComments(0, mPost.mMeta.mGroupId, post_versions,mPost.mMeta.mMsgId, title); + } +} + +void PostedCardView::setReadStatus(bool isNew, bool isUnread) +{ + if (isUnread) + { + ui->readButton->setChecked(true); + ui->readButton->setIcon(QIcon(":/images/message-state-unread.png")); + } + else + { + ui->readButton->setChecked(false); + ui->readButton->setIcon(QIcon(":/images/message-state-read.png")); + } + + ui->newLabel->setVisible(isNew); + + ui->mainFrame->setProperty("new", isNew); + ui->mainFrame->style()->unpolish(ui->mainFrame); + ui->mainFrame->style()->polish( ui->mainFrame); +} + +void PostedCardView::readToggled(bool checked) +{ + if (mInFill) { + return; + } + + RsGxsGrpMsgIdPair msgPair = std::make_pair(groupId(), messageId()); + + uint32_t token; + rsPosted->setMessageReadStatus(token, msgPair, !checked); + + setReadStatus(false, checked); +} + +void PostedCardView::readAndClearItem() +{ +#ifdef DEBUG_ITEM + std::cerr << "PostedCardView::readAndClearItem()"; + std::cerr << std::endl; +#endif + + readToggled(false); + removeItem(); +} + + +void PostedCardView::doExpand(bool open) +{ + /*if (open) + { + + } + else + { + + } + + emit sizeChanged(this);*/ + +} + +void PostedCardView::copyMessageLink() +{ + if (groupId().isNull() || mMessageId.isNull()) { + return; + } + + RetroShareLink link = RetroShareLink::createGxsMessageLink(RetroShareLink::TYPE_POSTED, groupId(), mMessageId, messageName()); + + if (link.valid()) { + QList urls; + urls.push_back(link); + RSLinkClipboard::copyLinks(urls); + } +} diff --git a/retroshare-gui/src/gui/Posted/PostedCardView.h b/retroshare-gui/src/gui/Posted/PostedCardView.h new file mode 100644 index 000000000..7fc303680 --- /dev/null +++ b/retroshare-gui/src/gui/Posted/PostedCardView.h @@ -0,0 +1,98 @@ +/******************************************************************************* + * retroshare-gui/src/gui/Posted/PostedCardView.h * + * * + * Copyright (C) 2019 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 . * + * * + *******************************************************************************/ + +#ifndef _POSTED_CARDVIEW_H +#define _POSTED_CARDVIEW_H + +#include + +#include +#include "gui/gxs/GxsFeedItem.h" + +namespace Ui { +class PostedCardView; +} + +class FeedHolder; +class RsPostedPost; + +class PostedCardView : public GxsFeedItem +{ + Q_OBJECT + +public: + PostedCardView(FeedHolder *parent, uint32_t feedId, const RsGxsGroupId &groupId, const RsGxsMessageId &messageId, bool isHome, bool autoUpdate); + PostedCardView(FeedHolder *parent, uint32_t feedId, const RsPostedGroup &group, const RsPostedPost &post, bool isHome, bool autoUpdate); + PostedCardView(FeedHolder *parent, uint32_t feedId, const RsPostedPost &post, bool isHome, bool autoUpdate); + virtual ~PostedCardView(); + + bool setGroup(const RsPostedGroup& group, bool doFill = true); + bool setPost(const RsPostedPost& post, bool doFill = true); + + const RsPostedPost &getPost() const; + RsPostedPost &post(); + + uint64_t uniqueIdentifier() const override { return hash_64bits("PostedItem " + mMessageId.toStdString()); } + +protected: + /* FeedItem */ + virtual void doExpand(bool open); + +private slots: + void loadComments(); + void makeUpVote(); + void makeDownVote(); + void readToggled(bool checked); + void readAndClearItem(); + void copyMessageLink(); + +signals: + void vote(const RsGxsGrpMsgIdPair& msgId, bool up); + +protected: + /* GxsGroupFeedItem */ + virtual QString groupName(); + virtual void loadGroup(const uint32_t &token); + virtual RetroShareLink::enumType getLinkType() { return RetroShareLink::TYPE_UNKNOWN; } + + /* GxsFeedItem */ + virtual QString messageName(); + virtual void loadMessage(const uint32_t &token); + virtual void loadComment(const uint32_t &token); + +private: + void setup(); + void fill(); + void setReadStatus(bool isNew, bool isUnread); + +private: + bool mInFill; + + RsPostedGroup mGroup; + RsPostedPost mPost; + RsGxsMessageId mMessageId; + + /** Qt Designer generated object */ + Ui::PostedCardView *ui; +}; + +//Q_DECLARE_METATYPE(RsPostedPost) + +#endif diff --git a/retroshare-gui/src/gui/Posted/PostedCardView.ui b/retroshare-gui/src/gui/Posted/PostedCardView.ui new file mode 100644 index 000000000..8cbbd4d56 --- /dev/null +++ b/retroshare-gui/src/gui/Posted/PostedCardView.ui @@ -0,0 +1,526 @@ + + + PostedCardView + + + + 0 + 0 + 614 + 182 + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + false + + + QFrame::Box + + + QFrame::Sunken + + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 6 + + + + + + 0 + 0 + + + + + Arial + 10 + 75 + true + + + + This is a very very very very loooooooooooooooonnnnnnnnnnnnnnnnng title don't you think? Yes it is and should wrap around I hope + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + 0 + 0 + + + + site + + + true + + + + + + + 5 + + + 0 + + + 6 + + + + + + 0 + 0 + + + + + 50 + false + + + + Posted by + + + + + + + + 0 + 0 + + + + Signed by + + + true + + + + + + + + 0 + 0 + + + + You eyes only + + + true + + + + + + + + 24 + 16777215 + + + + Qt::NoFocus + + + Toggle Message Read Status + + + + :/images/message-state-unread.png:/images/message-state-unread.png + + + true + + + false + + + true + + + + + + + New + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 70 + 20 + + + + + + + + + + + 37 + 0 + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + Vote up + + + + + + + :/images/up-arrow.png:/images/up-arrow.png + + + true + + + + + + + + 9 + + + + 0 + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + Vote down + + + + + + \/ + + + + :/images/down-arrow.png:/images/down-arrow.png + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 5 + + + + + + + + + + + + + Comments + + + + :/images/comments.png:/images/comments.png + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + Share + + + + :/images/share.png:/images/share.png + + + true + + + + + + + Qt::Horizontal + + + + 308 + 20 + + + + + + + + + 24 + 16777215 + + + + Qt::NoFocus + + + Set as read and remove item + + + + :/icons/png/correct.png:/icons/png/correct.png + + + + + + + + 24 + 16777215 + + + + Qt::NoFocus + + + Remove Item + + + + :/icons/png/exit2.png:/icons/png/exit2.png + + + + + + + + + + + + true + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + PictureLabel + + + true + + + + + + + Qt::Horizontal + + + + 268 + 17 + + + + + + + + + + + + + + + StyledLabel + QLabel +
gui/common/StyledLabel.h
+
+ + GxsIdLabel + QLabel +
gui/gxs/GxsIdLabel.h
+
+
+ + + + + + +
diff --git a/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.cpp b/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.cpp index c822bb492..ddacd4895 100644 --- a/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.cpp +++ b/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.cpp @@ -20,6 +20,8 @@ #include #include +#include +#include #include "PostedCreatePostDialog.h" #include "ui_PostedCreatePostDialog.h" @@ -34,6 +36,10 @@ #include +#include + +#include + PostedCreatePostDialog::PostedCreatePostDialog(TokenQueue* tokenQ, RsPosted *posted, const RsGxsGroupId& grpId, QWidget *parent): QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint), mTokenQueue(tokenQ), mPosted(posted), mGrpId(grpId), @@ -44,7 +50,7 @@ PostedCreatePostDialog::PostedCreatePostDialog(TokenQueue* tokenQ, RsPosted *pos connect(ui->submitButton, SIGNAL(clicked()), this, SLOT(createPost())); connect(ui->buttonBox, SIGNAL(rejected()), this, SLOT(close())); - connect(ui->pushButton, SIGNAL(clicked() ), this , SLOT(addPicture())); + connect(ui->addPicButton, SIGNAL(clicked() ), this , SLOT(addPicture())); ui->headerFrame->setHeaderImage(QPixmap(":/icons/png/postedlinks.png")); ui->headerFrame->setHeaderText(tr("Create a new Post")); @@ -52,19 +58,59 @@ PostedCreatePostDialog::PostedCreatePostDialog(TokenQueue* tokenQ, RsPosted *pos setAttribute ( Qt::WA_DeleteOnClose, true ); ui->RichTextEditWidget->setPlaceHolderTextPosted(); + + ui->hashBox->setAutoHide(true); + ui->hashBox->setDefaultTransferRequestFlags(RS_FILE_REQ_ANONYMOUS_ROUTING); + connect(ui->hashBox, SIGNAL(fileHashingFinished(QList)), this, SLOT(fileHashingFinished(QList))); + ui->sizeWarningLabel->setText(QString("Post size is limited to %1 KB, pictures will be downscaled.").arg(MAXMESSAGESIZE / 1024)); /* fill in the available OwnIds for signing */ ui->idChooser->loadIds(IDCHOOSER_ID_REQUIRED, RsGxsId()); + + ui->removeButton->hide(); + + /* load settings */ + processSettings(true); } PostedCreatePostDialog::~PostedCreatePostDialog() { Settings->saveWidgetInformation(this); + + // save settings + processSettings(false); + delete ui; } +void PostedCreatePostDialog::processSettings(bool load) +{ + Settings->beginGroup(QString("PostedCreatePostDialog")); + + if (load) { + // load settings + + // state of ID Chooser combobox + int index = Settings->value("IDChooser", 0).toInt(); + ui->idChooser->setCurrentIndex(index); + } else { + // save settings + + // state of ID Chooser combobox + Settings->setValue("IDChooser", ui->idChooser->currentIndex()); + } + + Settings->endGroup(); +} + void PostedCreatePostDialog::createPost() { + if(ui->titleEdit->text().isEmpty()) { + /* error message */ + QMessageBox::warning(this, "RetroShare", tr("Please add a Title"), QMessageBox::Ok, QMessageBox::Ok); + return; //Don't add a empty title!! + } + RsGxsId authorId; switch (ui->idChooser->getChosenId(authorId)) { case GxsIdChooser::KnowId: @@ -85,37 +131,27 @@ void PostedCreatePostDialog::createPost() post.mMeta.mGroupId = mGrpId; post.mLink = std::string(ui->linkEdit->text().toUtf8()); - QString text; - text = ui->RichTextEditWidget->toHtml(); - post.mNotes = std::string(text.toUtf8()); + if(!ui->RichTextEditWidget->toPlainText().trimmed().isEmpty()) { + QString text; + text = ui->RichTextEditWidget->toHtml(); + post.mNotes = std::string(text.toUtf8()); + } post.mMeta.mAuthorId = authorId; - - if(!ui->titleEdit->text().isEmpty()) - { - post.mMeta.mMsgName = std::string(ui->titleEdit->text().toUtf8()); - }else - { - post.mMeta.mMsgName = std::string(ui->titleEditLink->text().toUtf8()); - } - - QByteArray ba; - QBuffer buffer(&ba); + post.mMeta.mMsgName = std::string(ui->titleEdit->text().toUtf8()); - if(!picture.isNull()) + if(imagebytes.size() > 0) { // send posted image + post.mImage.copy((uint8_t *) imagebytes.data(), imagebytes.size()); + } - buffer.open(QIODevice::WriteOnly); - picture.save(&buffer, "PNG"); // writes image into ba in PNG format - post.mImage.copy((uint8_t *) ba.data(), ba.size()); + int msgsize = post.mLink.length() + post.mMeta.mMsgName.length() + post.mNotes.length() + imagebytes.size(); + if(msgsize > MAXMESSAGESIZE) { + QString errormessage = QString(tr("Message is too large.
actual size: %1 bytes, maximum size: %2 bytes.")).arg(msgsize).arg(MAXMESSAGESIZE); + QMessageBox::warning(this, "RetroShare", errormessage, QMessageBox::Ok, QMessageBox::Ok); + return; } - - if(ui->titleEdit->text().isEmpty()&& ui->titleEditLink->text().isEmpty()) { - /* error message */ - QMessageBox::warning(this, "RetroShare", tr("Please add a Title"), QMessageBox::Ok, QMessageBox::Ok); - return; //Don't add a empty title!! - }//if(ui->titleEdit->text().isEmpty()) uint32_t token; mPosted->createPost(token, post); @@ -124,17 +160,66 @@ void PostedCreatePostDialog::createPost() accept(); } -void PostedCreatePostDialog::addPicture() +void PostedCreatePostDialog::fileHashingFinished(QList hashedFiles) { - QPixmap img = misc::getOpenThumbnailedPicture(this, tr("Load thumbnail picture"), 800, 600); + if(hashedFiles.length() > 0) { //It seems like it returns 0 if hashing cancelled + HashedFile hashedFile = hashedFiles[0]; //Should be exactly one file + RetroShareLink link; + link = RetroShareLink::createFile(hashedFile.filename, hashedFile.size, QString::fromStdString(hashedFile.hash.toStdString())); + ui->linkEdit->setText(link.toString()); + } + ui->submitButton->setEnabled(true); + ui->addPicButton->setEnabled(true); +} - if (img.isNull()) - return; +void PostedCreatePostDialog::addPicture() +{ + imagefilename = ""; + imagebytes.clear(); + QPixmap empty; + ui->imageLabel->setPixmap(empty); - picture = img; + // select a picture file + if (misc::getOpenFileName(window(), RshareSettings::LASTDIR_IMAGES, tr("Load Picture File"), "Pictures (*.png *.xpm *.jpg *.jpeg *.gif *.webp )", imagefilename)) { + QString encodedImage; + QImage image; + if (image.load(imagefilename) == false) { + fprintf (stderr, "RsHtml::makeEmbeddedImage() - image \"%s\" can't be load\n", imagefilename.toLatin1().constData()); + imagefilename = ""; + return; + } + + QImage opt; + if(ImageUtil::optimizeSizeBytes(imagebytes, image, opt, 640*480, MAXMESSAGESIZE - 2000)) { //Leave space for other stuff + ui->imageLabel->setPixmap(QPixmap::fromImage(opt)); + ui->stackedWidgetPicture->setCurrentIndex(1); + ui->removeButton->show(); + } else { + imagefilename = ""; + imagebytes.clear(); + return; + } + } + + //Do we need to hash the image? + QMessageBox::StandardButton answer; + answer = QMessageBox::question(this, tr("Post image"), tr("Do you want to share and link the original image?"), QMessageBox::Yes|QMessageBox::No); + if (answer == QMessageBox::Yes) { + if(!ui->linkEdit->text().trimmed().isEmpty()) { + answer = QMessageBox::question(this, tr("Post image"), tr("You already added a link.
Do you want to replace it?"), QMessageBox::Yes|QMessageBox::No); + } + } + + //If still yes then link it + if(answer == QMessageBox::Yes) { + ui->submitButton->setEnabled(false); + ui->addPicButton->setEnabled(false); + QStringList files; + files.append(imagefilename); + ui->hashBox->addAttachments(files,RS_FILE_REQ_ANONYMOUS_ROUTING); + } + - // to show the selected - ui->imageLabel->setPixmap(picture); } void PostedCreatePostDialog::on_postButton_clicked() @@ -151,3 +236,13 @@ void PostedCreatePostDialog::on_linkButton_clicked() { ui->stackedWidget->setCurrentIndex(2); } + +void PostedCreatePostDialog::on_removeButton_clicked() +{ + imagefilename = ""; + imagebytes.clear(); + QPixmap empty; + ui->imageLabel->setPixmap(empty); + ui->removeButton->hide(); + ui->stackedWidgetPicture->setCurrentIndex(0); +} diff --git a/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.h b/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.h index de13358fb..5aed59950 100644 --- a/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.h +++ b/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.h @@ -22,6 +22,7 @@ #define POSTEDCREATEPOSTDIALOG_H #include +#include #include "retroshare/rsposted.h" #include "util/RichTextEdit.h" @@ -43,7 +44,10 @@ public: explicit PostedCreatePostDialog(TokenQueue* tokenQ, RsPosted* posted, const RsGxsGroupId& grpId, QWidget *parent = 0); ~PostedCreatePostDialog(); - QPixmap picture; +private: + QString imagefilename; + QByteArray imagebytes; + const int MAXMESSAGESIZE = 199000; private slots: void createPost(); @@ -51,8 +55,12 @@ private slots: void on_postButton_clicked(); void on_imageButton_clicked(); void on_linkButton_clicked(); + void on_removeButton_clicked(); + void fileHashingFinished(QList hashedFiles); private: + void processSettings(bool load); + QString mLink; QString mNotes; TokenQueue* mTokenQueue; diff --git a/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.ui b/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.ui index d64c3ad01..50abd48a2 100644 --- a/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.ui +++ b/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.ui @@ -7,7 +7,7 @@ 0 0 575 - 429 + 518 @@ -48,6 +48,427 @@ QFrame::Raised + + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + true + + + + + + + Preview + + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 + + + + + + + 9 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Add Picture + + + + :/icons/png/add-image.png:/icons/png/add-image.png + + + + 24 + 24 + + + + + + + + Post size is limited to 32 KB, pictures will be downscaled. + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 267 + 138 + + + + + + + + + + 2 + + + 2 + + + 0 + + + 2 + + + + + + 800 + 200 + + + + + + + true + + + + + + + Qt::Horizontal + + + + 188 + 17 + + + + + + + + Remove image + + + + :/images/trashcan.png:/images/trashcan.png + + + + 24 + 24 + + + + true + + + + + + + + + + + + + + + + 0 + + + 6 + + + 0 + + + + + Url + + + + + + + Qt::Vertical + + + + 20 + 248 + + + + + + + + + + + + + + + 0 + 0 + + + + Post as + + + + + + + + 0 + 0 + + + + + + + + + + + 0 + 0 + + + + + + + Post + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel + + + + + + + 2 + + + + + Post + + + + :/images/post.png:/images/post.png + + + + 24 + 24 + + + + + + + + Image + + + + :/images/photo.png:/images/photo.png + + + + 24 + 24 + + + + + + + + Link + + + + :/images/link.png:/images/link.png + + + + 24 + 24 + + + + + + + + Qt::Horizontal + + + + 298 + 20 + + + + + + @@ -128,105 +549,7 @@ - - - - 2 - - - - - Post - - - - :/images/post.png:/images/post.png - - - - 24 - 24 - - - - - - - - Image - - - - :/images/photo.png:/images/photo.png - - - - 24 - 24 - - - - - - - - Link - - - - :/images/link.png:/images/link.png - - - - 24 - 24 - - - - - - - - Qt::Horizontal - - - - 298 - 20 - - - - - - - - - - - - - 0 - 0 - - - - Post as - - - - - - - - 0 - 0 - - - - - - - + Qt::Horizontal @@ -242,207 +565,28 @@ - - - - - 0 - 0 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel - - - - - - 0 + + + 6 - - - - 0 + + + + + 0 + 0 + - - 6 + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - 0 + + Title - - 0 - - - - - - - - Title - - - - - - - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 447 - 20 - - - - - - - - Preview - - - - - - - 250 - 200 - - - - - 800 - 200 - - - - - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - Add Picture - - - - - - - Picture size is limited to 34 KB - - - - - - - - - 0 - - - 6 - - - 0 - - - - - Url - - - - - - - Qt::Vertical - - - - 20 - 248 - - - - - - - - Title - - - - - - - - - - - - 0 - 0 - - - - - - - Post - - + + + @@ -455,6 +599,12 @@ QLabel
gui/common/StyledLabel.h
+ + HashBox + QScrollArea +
gui/common/HashBox.h
+ 1 +
HeaderFrame QFrame @@ -475,7 +625,6 @@ - diff --git a/retroshare-gui/src/gui/Posted/PostedDialog.cpp b/retroshare-gui/src/gui/Posted/PostedDialog.cpp index edf09ff20..5e743b957 100644 --- a/retroshare-gui/src/gui/Posted/PostedDialog.cpp +++ b/retroshare-gui/src/gui/Posted/PostedDialog.cpp @@ -26,6 +26,7 @@ #include "gui/gxs/GxsGroupShareKey.h" #include "gui/settings/rsharesettings.h" #include "gui/common/GroupTreeWidget.h" +#include "util/qtthreadsutils.h" #include @@ -43,13 +44,48 @@ public: PostedDialog::PostedDialog(QWidget *parent) : GxsGroupFrameDialog(rsPosted, parent) { + mEventHandlerId = 0; + // Needs to be asynced because this function is likely to be called by another thread! + + rsEvents->registerEventsHandler(RsEventType::GXS_POSTED, [this](std::shared_ptr event) { RsQThreadUtils::postToObject( [=]() { handleEvent_main_thread(event); }, this ); }, mEventHandlerId ); } +void PostedDialog::handleEvent_main_thread(std::shared_ptr event) +{ + if(event->mType == RsEventType::GXS_POSTED) + { + const RsGxsPostedEvent *e = dynamic_cast(event.get()); + if(!e) return; + + switch(e->mPostedEventCode) + { + case RsPostedEventCode::NEW_MESSAGE: + updateMessageSummaryList(e->mPostedGroupId); + break; + + case RsPostedEventCode::UPDATED_MESSAGE: // [[fallthrough]]; + updateDisplay(false); + break; + + case RsPostedEventCode::READ_STATUS_CHANGED: // [[fallthrough]]; + updateMessageSummaryList(e->mPostedGroupId); + break; + + case RsPostedEventCode::NEW_POSTED_GROUP: // [[fallthrough]]; + case RsPostedEventCode::SUBSCRIBE_STATUS_CHANGED: // [[fallthrough]]; + updateDisplay(true); + break; + default: break; + } + } +} + + PostedDialog::~PostedDialog() { } -UserNotify *PostedDialog::getUserNotify(QObject *parent) +UserNotify *PostedDialog::createUserNotify(QObject *parent) { return new PostedUserNotify(rsPosted, parent); } diff --git a/retroshare-gui/src/gui/Posted/PostedDialog.h b/retroshare-gui/src/gui/Posted/PostedDialog.h index e3f681aa8..7f23ee24f 100644 --- a/retroshare-gui/src/gui/Posted/PostedDialog.h +++ b/retroshare-gui/src/gui/Posted/PostedDialog.h @@ -40,9 +40,8 @@ public: virtual QString pageName() const { return tr("Links") ; } //MainPage virtual QString helpText() const { return ""; } //MainPage - virtual UserNotify *getUserNotify(QObject *parent); - protected: + virtual UserNotify *createUserNotify(QObject *parent) override; virtual QString getHelpString() const ; virtual RetroShareLink::enumType getLinkType() { return RetroShareLink::TYPE_POSTED; } virtual GroupFrameSettings::Type groupFrameSettingsType() { return GroupFrameSettings::Posted; } @@ -61,6 +60,9 @@ private: virtual QWidget *createCommentHeaderWidget(const RsGxsGroupId &grpId, const RsGxsMessageId &msgId); virtual uint32_t requestGroupSummaryType() { return GXS_REQUEST_TYPE_GROUP_DATA; } // request complete group data virtual void loadGroupSummaryToken(const uint32_t &token, std::list &groupInfo, RsUserdata* &userdata); + + void handleEvent_main_thread(std::shared_ptr event); + RsEventsHandlerId_t mEventHandlerId; }; #endif diff --git a/retroshare-gui/src/gui/Posted/PostedItem.cpp b/retroshare-gui/src/gui/Posted/PostedItem.cpp index 5d4e00a93..b09452a8e 100644 --- a/retroshare-gui/src/gui/Posted/PostedItem.cpp +++ b/retroshare-gui/src/gui/Posted/PostedItem.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "rshare.h" #include "PostedItem.h" @@ -28,7 +29,7 @@ #include "gui/gxs/GxsIdDetails.h" #include "util/misc.h" #include "util/HandleRichText.h" - +#include "PhotoView.h" #include "ui_PostedItem.h" #include @@ -109,11 +110,12 @@ void PostedItem::setup() connect(ui->notesButton, SIGNAL(clicked()), this, SLOT( toggleNotes())); connect(ui->readButton, SIGNAL(toggled(bool)), this, SLOT(readToggled(bool))); - + connect(ui->thumbnailLabel, SIGNAL(clicked()), this, SLOT(viewPicture())); + QAction *CopyLinkAction = new QAction(QIcon(""),tr("Copy RetroShare Link"), this); connect(CopyLinkAction, SIGNAL(triggered()), this, SLOT(copyMessageLink())); - - + + int S = QFontMetricsF(font()).height() ; ui->voteUpButton->setIconSize(QSize(S*1.5,S*1.5)); @@ -302,6 +304,11 @@ void PostedItem::fill() } + if (urlarray.isEmpty()) + { + ui->siteLabel->hide(); + } + ui->siteLabel->setText(sitestr); if(mPost.mImage.mData != NULL) @@ -312,7 +319,15 @@ void PostedItem::fill() QPixmap sqpixmap = pixmap.scaled(desired_width,desired_height, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); ui->thumbnailLabel->setPixmap(sqpixmap); - ui->pictureLabel->setPixmap(pixmap); + 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)) { @@ -337,7 +352,10 @@ void PostedItem::fill() // FIX THIS UP LATER. ui->notes->setText(RsHtml().formatText(NULL, QString::fromUtf8(mPost.mNotes.c_str()), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS)); - if(ui->notes->text().isEmpty()) + QTextDocument doc; + doc.setHtml(ui->notes->text()); + + if(doc.toPlainText().trimmed().isEmpty()) ui->notesButton->hide(); // differences between Feed or Top of Comment. if (mFeedHolder) @@ -569,3 +587,28 @@ void PostedItem::toggleNotes() } } + +void PostedItem::viewPicture() +{ + if(mPost.mImage.mData == NULL) { + return; + } + + QString timestamp = misc::timeRelativeToNow(mPost.mMeta.mPublishTs); + QPixmap pixmap; + GxsIdDetails::loadPixmapFromData(mPost.mImage.mData, mPost.mImage.mSize, pixmap,GxsIdDetails::ORIGINAL); + RsGxsId authorID = mPost.mMeta.mAuthorId; + + PhotoView *PView = new PhotoView(this); + + PView->setPixmap(pixmap); + PView->setTitle(messageName()); + PView->setName(authorID); + PView->setTime(timestamp); + PView->setGroupId(groupId()); + PView->setMessageId(mMessageId); + + PView->show(); + + /* window will destroy itself! */ +} diff --git a/retroshare-gui/src/gui/Posted/PostedItem.h b/retroshare-gui/src/gui/Posted/PostedItem.h index aa855d72b..97b6974d0 100644 --- a/retroshare-gui/src/gui/Posted/PostedItem.h +++ b/retroshare-gui/src/gui/Posted/PostedItem.h @@ -63,6 +63,7 @@ private slots: void toggle() override; void copyMessageLink(); void toggleNotes(); + void viewPicture(); signals: void vote(const RsGxsGrpMsgIdPair& msgId, bool up); diff --git a/retroshare-gui/src/gui/Posted/PostedItem.ui b/retroshare-gui/src/gui/Posted/PostedItem.ui index 164ba1a89..f470fea00 100644 --- a/retroshare-gui/src/gui/Posted/PostedItem.ui +++ b/retroshare-gui/src/gui/Posted/PostedItem.ui @@ -7,7 +7,7 @@ 0 0 825 - 339 + 337 @@ -109,6 +109,9 @@ Vote up + + + @@ -148,8 +151,8 @@ Vote down - - \/ + + @@ -185,7 +188,7 @@ 6 - + 0 @@ -267,6 +270,9 @@ true + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + @@ -415,6 +421,9 @@ + + Expand + @@ -428,7 +437,7 @@ - + 24 @@ -451,7 +460,7 @@ false - + true @@ -482,6 +491,18 @@ + + + 0 + 0 + + + + + 0 + 22 + + Share @@ -489,6 +510,9 @@ :/images/share.png:/images/share.png + + false + true @@ -529,24 +553,6 @@ - - - 0 - 0 - - - - - 50 - 44 - - - - - 50 - 44 - - Qt::NoFocus @@ -561,24 +567,6 @@ - - - 0 - 0 - - - - - 50 - 44 - - - - - 50 - 44 - - Qt::NoFocus @@ -634,6 +622,9 @@ true + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + @@ -714,11 +705,16 @@ QLabel
gui/gxs/GxsIdLabel.h
+ + ClickableLabel + QLabel +
util/ClickableLabel.h
+
- - + + diff --git a/retroshare-gui/src/gui/Posted/PostedListWidget.cpp b/retroshare-gui/src/gui/Posted/PostedListWidget.cpp index 9c86a2f9a..0d7960804 100644 --- a/retroshare-gui/src/gui/Posted/PostedListWidget.cpp +++ b/retroshare-gui/src/gui/Posted/PostedListWidget.cpp @@ -19,17 +19,21 @@ *******************************************************************************/ #include +#include #include "PostedListWidget.h" #include "ui_PostedListWidget.h" +#include "util/qtthreadsutils.h" #include "gui/gxs/GxsIdDetails.h" #include "PostedCreatePostDialog.h" #include "PostedItem.h" +#include "PostedCardView.h" #include "gui/common/UIStateHelper.h" #include "gui/RetroShareLink.h" #include "util/HandleRichText.h" #include "util/DateTime.h" +#include "gui/settings/rsharesettings.h" #include #include "retroshare/rsgxscircles.h" @@ -41,6 +45,10 @@ #define TOPIC_DEFAULT_IMAGE ":/icons/png/posted.png" +/* View mode */ +#define VIEW_MODE_CLASSIC 1 +#define VIEW_MODE_CARD 2 + /** Constructor */ PostedListWidget::PostedListWidget(const RsGxsGroupId &postedId, QWidget *parent) : GxsMessageFramePostWidget(rsPosted, parent), @@ -63,6 +71,12 @@ PostedListWidget::PostedListWidget(const RsGxsGroupId &postedId, QWidget *parent connect(ui->comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(getRankings(int))); + QSignalMapper *signalMapper = new QSignalMapper(this); + connect(ui->classicViewButton, SIGNAL(clicked()), signalMapper, SLOT(map())); + connect(ui->cardViewButton, SIGNAL(clicked()), signalMapper, SLOT(map())); + signalMapper->setMapping(ui->classicViewButton, VIEW_MODE_CLASSIC); + signalMapper->setMapping(ui->cardViewButton, VIEW_MODE_CARD); + connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(setViewMode(int))); // default sort method. mSortMethod = RsPosted::HotRankType; @@ -94,7 +108,6 @@ PostedListWidget::PostedListWidget(const RsGxsGroupId &postedId, QWidget *parent /* Initialize GUI */ setGroupId(postedId); } - PostedListWidget::~PostedListWidget() { // save settings @@ -103,17 +116,23 @@ PostedListWidget::~PostedListWidget() delete(ui); } -void PostedListWidget::processSettings(bool /*load*/) +void PostedListWidget::processSettings(bool load) { -// Settings->beginGroup(QString("PostedListWidget")); -// -// if (load) { -// // load settings -// } else { -// // save settings -// } -// -// Settings->endGroup(); + Settings->beginGroup(QString("PostedListWidget")); + + if (load) { + // load settings + + /* View mode */ + setViewMode(Settings->value("viewMode", VIEW_MODE_CLASSIC).toInt()); + } else { + // save settings + + /* View mode */ + Settings->setValue("viewMode", viewMode()); + } + + Settings->endGroup(); } QIcon PostedListWidget::groupIcon() @@ -143,6 +162,12 @@ QScrollArea *PostedListWidget::getScrollArea() return ui->scrollArea; } +// Overloaded from FeedHolder. +/*QScrollArea *PostedListWidget::getScrollArea() +{ + return ui->scrollAreaCardView; +}*/ + void PostedListWidget::deleteFeedItem(FeedItem *, uint32_t /*type*/) { #ifdef DEBUG_POSTED_LIST_WIDGET @@ -414,11 +439,23 @@ void PostedListWidget::loadPost(const RsPostedPost &post) PostedItem *item = new PostedItem(this, 0, dummyGroup, post, true, false); connect(item, SIGNAL(vote(RsGxsGrpMsgIdPair,bool)), this, SLOT(submitVote(RsGxsGrpMsgIdPair,bool))); mPosts.insert(post.mMeta.mMsgId, item); - //QLayout *alayout = ui.scrollAreaWidgetContents->layout(); - //alayout->addWidget(item); + mPostItems.push_back(item); } +void PostedListWidget::loadPostCardView(const RsPostedPost &post) +{ + /* Group is not always available because of the TokenQueue */ + RsPostedGroup dummyGroup; + dummyGroup.mMeta.mGroupId = groupId(); + + PostedCardView *cvitem = new PostedCardView(this, 0, dummyGroup, post, true, false); + connect(cvitem, SIGNAL(vote(RsGxsGrpMsgIdPair,bool)), this, SLOT(submitVote(RsGxsGrpMsgIdPair,bool))); + mCVPosts.insert(post.mMeta.mMsgId, cvitem); + + mPostCardView.push_back(cvitem); +} + static bool CmpPIHot(const GxsFeedItem *a, const GxsFeedItem *b) { const PostedItem *aa = dynamic_cast(a); @@ -471,6 +508,58 @@ static bool CmpPINew(const GxsFeedItem *a, const GxsFeedItem *b) return (aa->getPost().mNewScore > bb->getPost().mNewScore); } +static bool CVHot(const GxsFeedItem *a, const GxsFeedItem *b) +{ + const PostedCardView *aa = dynamic_cast(a); + const PostedCardView *bb = dynamic_cast(b); + + if (!aa || !bb) { + return true; + } + + const RsPostedPost &postA = aa->getPost(); + const RsPostedPost &postB = bb->getPost(); + + if (postA.mHotScore == postB.mHotScore) + { + return (postA.mNewScore > postB.mNewScore); + } + + return (postA.mHotScore > postB.mHotScore); +} + +static bool CVTop(const GxsFeedItem *a, const GxsFeedItem *b) +{ + const PostedCardView *aa = dynamic_cast(a); + const PostedCardView *bb = dynamic_cast(b); + + if (!aa || !bb) { + return true; + } + + const RsPostedPost &postA = aa->getPost(); + const RsPostedPost &postB = bb->getPost(); + + if (postA.mTopScore == postB.mTopScore) + { + return (postA.mNewScore > postB.mNewScore); + } + + return (postA.mTopScore > postB.mTopScore); +} + +static bool CVNew(const GxsFeedItem *a, const GxsFeedItem *b) +{ + const PostedCardView *aa = dynamic_cast(a); + const PostedCardView *bb = dynamic_cast(b); + + if (!aa || !bb) { + return true; + } + + return (aa->getPost().mNewScore > bb->getPost().mNewScore); +} + void PostedListWidget::applyRanking() { /* uses current settings to sort posts, then add to layout */ @@ -491,6 +580,7 @@ void PostedListWidget::applyRanking() std::cerr << std::endl; #endif qSort(mPostItems.begin(), mPostItems.end(), CmpPIHot); + qSort(mPostCardView.begin(), mPostCardView.end(), CVHot); break; case RsPosted::NewRankType: #ifdef DEBUG_POSTED_LIST_WIDGET @@ -498,6 +588,7 @@ void PostedListWidget::applyRanking() std::cerr << std::endl; #endif qSort(mPostItems.begin(), mPostItems.end(), CmpPINew); + qSort(mPostCardView.begin(), mPostCardView.end(), CVNew); break; case RsPosted::TopRankType: #ifdef DEBUG_POSTED_LIST_WIDGET @@ -505,6 +596,7 @@ void PostedListWidget::applyRanking() std::cerr << std::endl; #endif qSort(mPostItems.begin(), mPostItems.end(), CmpPITop); + qSort(mPostCardView.begin(), mPostCardView.end(), CVTop); break; } mLastSortMethod = mSortMethod; @@ -516,8 +608,11 @@ void PostedListWidget::applyRanking() /* go through list (skipping out-of-date items) to get */ QLayout *alayout = ui->scrollAreaWidgetContents->layout(); + + int counter = 0; time_t min_ts = 0; + foreach (PostedItem *item, mPostItems) { #ifdef DEBUG_POSTED_LIST_WIDGET @@ -564,6 +659,46 @@ void PostedListWidget::applyRanking() ++counter; } + // Card View + counter = 0; + QLayout *cviewlayout = ui->scrollAreaWidgetContentsCardView->layout(); + + foreach (PostedCardView *item, mPostCardView) + { + std::cerr << "PostedListWidget::applyRanking() Item: " << item; + std::cerr << std::endl; + + if (item->getPost().mMeta.mPublishTs < min_ts) + { + std::cerr << "\t Skipping OLD"; + std::cerr << std::endl; + item->hide(); + continue; + } + + if (counter >= mPostIndex + mPostShow) + { + std::cerr << "\t END - Counter too high"; + std::cerr << std::endl; + item->hide(); + } + else if (counter >= mPostIndex) + { + std::cerr << "\t Adding to Layout"; + std::cerr << std::endl; + /* add it in! */ + cviewlayout->addWidget(item); + item->show(); + } + else + { + std::cerr << "\t Skipping to Low"; + std::cerr << std::endl; + item->hide(); + } + ++counter; + } + #ifdef DEBUG_POSTED_LIST_WIDGET std::cerr << "PostedListWidget::applyRanking() Loaded New Order"; std::cerr << std::endl; @@ -571,6 +706,8 @@ void PostedListWidget::applyRanking() // trigger a redraw. ui->scrollAreaWidgetContents->update(); + ui->scrollAreaWidgetContentsCardView->update(); + } void PostedListWidget::blank() @@ -580,10 +717,17 @@ void PostedListWidget::blank() } void PostedListWidget::clearPosts() { - /* clear all messages */ + /* clear all classic view messages */ foreach (PostedItem *item, mPostItems) { delete(item); } + + /* clear all card view messages */ + foreach (PostedCardView *item, mPostCardView) { + delete(item); + } + + mPostCardView.clear(); mPostItems.clear(); mPosts.clear(); } @@ -641,6 +785,45 @@ void PostedListWidget::shallowClearPosts() PostedItem *item = *pit; alayout->removeWidget(item); } + + + //Posted Card view + + std::list postedCardViewItems; + std::list::iterator pcvit; + + QLayout *cviewlayout = ui->scrollAreaWidgetContentsCardView->layout(); + int countcv = cviewlayout->count(); + for(int i = 0; i < countcv; ++i) + { + QLayoutItem *litem = cviewlayout->itemAt(i); + if (!litem) + { + std::cerr << "PostedListWidget::shallowClearPosts() missing litem"; + std::cerr << std::endl; + continue; + } + + PostedCardView *item = dynamic_cast(litem->widget()); + if (item) + { + std::cerr << "PostedListWidget::shallowClearPosts() item: " << item; + std::cerr << std::endl; + + postedCardViewItems.push_back(item); + } + else + { + std::cerr << "PostedListWidget::shallowClearPosts() Found Child, which is not a PostedItem???"; + std::cerr << std::endl; + } + } + + for(pcvit = postedCardViewItems.begin(); pcvit != postedCardViewItems.end(); ++pcvit) + { + PostedCardView *item = *pcvit; + cviewlayout->removeWidget(item); + } } bool PostedListWidget::insertGroupData(const uint32_t &token, RsGroupMetaData &metaData) @@ -668,6 +851,7 @@ void PostedListWidget::insertAllPosts(const uint32_t &token, GxsMessageFramePost { RsPostedPost& p = *vit; loadPost(p); + loadPostCardView(p); } applyRanking(); @@ -701,6 +885,7 @@ void PostedListWidget::insertPosts(const uint32_t &token) #endif /* insert new entry */ loadPost(p); + loadPostCardView(p); } } @@ -767,3 +952,39 @@ void PostedListWidget::loadRequest(const TokenQueue *queue, const TokenRequest & GxsMessageFramePostWidget::loadRequest(queue, req); } + +int PostedListWidget::viewMode() +{ + if (ui->classicViewButton->isChecked()) { + return VIEW_MODE_CLASSIC; + } else if (ui->cardViewButton->isChecked()) { + return VIEW_MODE_CARD; + } + + /* Default */ + return VIEW_MODE_CLASSIC; +} + +void PostedListWidget::setViewMode(int viewMode) +{ + switch (viewMode) { + case VIEW_MODE_CLASSIC: + ui->stackedWidget->setCurrentIndex(0); + + + ui->classicViewButton->setChecked(true); + ui->cardViewButton->setChecked(false); + + break; + case VIEW_MODE_CARD: + ui->stackedWidget->setCurrentIndex(1); + + ui->cardViewButton->setChecked(true); + ui->classicViewButton->setChecked(false); + + break; + default: + setViewMode(VIEW_MODE_CLASSIC); + return; + } +} diff --git a/retroshare-gui/src/gui/Posted/PostedListWidget.h b/retroshare-gui/src/gui/Posted/PostedListWidget.h index cf05e9d4c..fa9f25c8e 100644 --- a/retroshare-gui/src/gui/Posted/PostedListWidget.h +++ b/retroshare-gui/src/gui/Posted/PostedListWidget.h @@ -29,6 +29,7 @@ class RsPostedGroup; class RsPostedPost; class PostedItem; +class PostedCardView; namespace Ui { class PostedListWidget; @@ -79,16 +80,21 @@ private slots: void showNext(); void showPrev(); + void setViewMode(int viewMode); + private: void processSettings(bool load); void updateShowText(); + int viewMode(); + /*! * Only removes it from layout */ void shallowClearPosts(); void loadPost(const RsPostedPost &post); + void loadPostCardView(const RsPostedPost &post); void insertPostedDetails(const RsPostedGroup &group); @@ -115,6 +121,9 @@ private: QMap mPosts; QList mPostItems; + QMap mCVPosts; + QList mPostCardView; + /* UI - from Designer */ Ui::PostedListWidget *ui; }; diff --git a/retroshare-gui/src/gui/Posted/PostedListWidget.ui b/retroshare-gui/src/gui/Posted/PostedListWidget.ui index cb9b906ef..304a79c76 100644 --- a/retroshare-gui/src/gui/Posted/PostedListWidget.ui +++ b/retroshare-gui/src/gui/Posted/PostedListWidget.ui @@ -7,16 +7,13 @@ 0 0 616 - 428 + 595 Form - - - 3 - + 0 @@ -29,7 +26,10 @@ 0 - + + 0 + + QFrame::Box @@ -37,12 +37,9 @@ QFrame::Sunken - - - 6 - + - 4 + 6 2 @@ -164,6 +161,59 @@ + + + + 0 + + + + + Classic view + + + + :/images/classic.png:/images/classic.png + + + + 24 + 24 + + + + true + + + true + + + + + + + Card View + + + + :/images/card.png:/images/card.png + + + + 24 + 24 + + + + true + + + true + + + + + @@ -205,7 +255,7 @@ - + QFrame::StyledPanel @@ -478,30 +528,13 @@ p, li { white-space: pre-wrap; } - - - - true + + + + 1 - - - - 0 - 0 - 614 - 16 - - - - - 0 - 0 - - - - - 0 - + + 0 @@ -514,6 +547,102 @@ p, li { white-space: pre-wrap; } 0 + + + + true + + + + + 0 + 0 + 614 + 16 + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + + + 0 + 0 + 614 + 16 + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + diff --git a/retroshare-gui/src/gui/Posted/Posted_images.qrc b/retroshare-gui/src/gui/Posted/Posted_images.qrc index 8c713b53f..9c2be0db4 100644 --- a/retroshare-gui/src/gui/Posted/Posted_images.qrc +++ b/retroshare-gui/src/gui/Posted/Posted_images.qrc @@ -1,6 +1,6 @@ - images/posted_16.png + images/posted_16.png images/posted_24.png images/posted_32.png images/posted_48.png @@ -21,7 +21,13 @@ images/share.png images/notes.png images/link.png + images/linkext.png images/post.png images/photo.png + images/classic.png + images/card.png + images/down-hover.png + images/up-hover.png + images/trashcan.png diff --git a/retroshare-gui/src/gui/Posted/images/card.png b/retroshare-gui/src/gui/Posted/images/card.png new file mode 100644 index 000000000..47cc72d0a Binary files /dev/null and b/retroshare-gui/src/gui/Posted/images/card.png differ diff --git a/retroshare-gui/src/gui/Posted/images/classic.png b/retroshare-gui/src/gui/Posted/images/classic.png new file mode 100644 index 000000000..b85e0a119 Binary files /dev/null and b/retroshare-gui/src/gui/Posted/images/classic.png differ diff --git a/retroshare-gui/src/gui/Posted/images/down-arrow.png b/retroshare-gui/src/gui/Posted/images/down-arrow.png index b6c7fcc06..1e531f03d 100644 Binary files a/retroshare-gui/src/gui/Posted/images/down-arrow.png and b/retroshare-gui/src/gui/Posted/images/down-arrow.png differ diff --git a/retroshare-gui/src/gui/Posted/images/down-hover.png b/retroshare-gui/src/gui/Posted/images/down-hover.png new file mode 100644 index 000000000..b822a0d87 Binary files /dev/null and b/retroshare-gui/src/gui/Posted/images/down-hover.png differ diff --git a/retroshare-gui/src/gui/Posted/images/linkext.png b/retroshare-gui/src/gui/Posted/images/linkext.png new file mode 100644 index 000000000..8fa5953a0 Binary files /dev/null and b/retroshare-gui/src/gui/Posted/images/linkext.png differ diff --git a/retroshare-gui/src/gui/Posted/images/notes.png b/retroshare-gui/src/gui/Posted/images/notes.png index a73a03968..800eec492 100644 Binary files a/retroshare-gui/src/gui/Posted/images/notes.png and b/retroshare-gui/src/gui/Posted/images/notes.png differ diff --git a/retroshare-gui/src/gui/Posted/images/trashcan.png b/retroshare-gui/src/gui/Posted/images/trashcan.png new file mode 100644 index 000000000..d812bcfe5 Binary files /dev/null and b/retroshare-gui/src/gui/Posted/images/trashcan.png differ diff --git a/retroshare-gui/src/gui/Posted/images/up-arrow.png b/retroshare-gui/src/gui/Posted/images/up-arrow.png index 728ccf068..7f276af8f 100644 Binary files a/retroshare-gui/src/gui/Posted/images/up-arrow.png and b/retroshare-gui/src/gui/Posted/images/up-arrow.png differ diff --git a/retroshare-gui/src/gui/Posted/images/up-hover.png b/retroshare-gui/src/gui/Posted/images/up-hover.png new file mode 100644 index 000000000..6e1144f96 Binary files /dev/null and b/retroshare-gui/src/gui/Posted/images/up-hover.png differ diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp index a3984ae53..d2aa30ce3 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.cpp @@ -32,6 +32,7 @@ #include "gui/common/RSTreeWidget.h" #include "gui/notifyqt.h" #include "gui/common/UIStateHelper.h" +#include "gui/common/UserNotify.h" #include "GxsCommentDialog.h" //#define DEBUG_GROUPFRAMEDIALOG @@ -1173,6 +1174,8 @@ void GxsGroupFrameDialog::loadGroupStatistics(const uint32_t &token) } ui->groupTreeWidget->setUnreadCount(item, mCountChildMsgs ? (stats.mNumThreadMsgsUnread + stats.mNumChildMsgsUnread) : stats.mNumThreadMsgsUnread); + + getUserNotify()->updateIcon(); } /*********************** **** **** **** ***********************/ diff --git a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h index 4e77ccb44..cc1fa7843 100644 --- a/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h +++ b/retroshare-gui/src/gui/gxs/GxsGroupFrameDialog.h @@ -96,6 +96,8 @@ protected: virtual void groupInfoToGroupItemInfo(const RsGroupMetaData &groupInfo, GroupItemInfo &groupItemInfo, const RsUserdata *userdata); virtual void checkRequestGroup(const RsGxsGroupId& /* grpId */) {} // overload this one in order to retrieve full group data when the group is browsed + void updateMessageSummaryList(RsGxsGroupId groupId); + private slots: void todo(); @@ -153,7 +155,6 @@ private: void initUi(); - void updateMessageSummaryList(RsGxsGroupId groupId); void updateSearchResults(); void openGroupInNewTab(const RsGxsGroupId &groupId); diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp index 2e1b6dc7e..f031772b3 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp @@ -64,8 +64,23 @@ void GxsChannelDialog::handleEvent_main_thread(std::shared_ptr ev switch(e->mChannelEventCode) { - case RsChannelEventCode::SUBSCRIBE_STATUS_CHANGED: updateDisplay(true); + case RsChannelEventCode::NEW_MESSAGE: + updateMessageSummaryList(e->mChannelGroupId); break; + + case RsChannelEventCode::UPDATED_MESSAGE: // [[fallthrough]]; + updateDisplay(false); + break; + + case RsChannelEventCode::READ_STATUS_CHANGED: + updateMessageSummaryList(e->mChannelGroupId); + break; + + case RsChannelEventCode::NEW_CHANNEL: // [[fallthrough]]; + case RsChannelEventCode::SUBSCRIBE_STATUS_CHANGED: + updateDisplay(true); + break; + default: break; } @@ -92,7 +107,7 @@ QString GxsChannelDialog::getHelpString() const return hlp_str ; } -UserNotify *GxsChannelDialog::getUserNotify(QObject *parent) +UserNotify *GxsChannelDialog::createUserNotify(QObject *parent) { return new GxsChannelUserNotify(rsGxsChannels, parent); } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h index 5d80be518..4c9c6eb95 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.h @@ -39,8 +39,6 @@ public: virtual QString pageName() const { return tr("Channels") ; } //MainPage virtual QString helpText() const { return ""; } //MainPage - virtual UserNotify *getUserNotify(QObject *parent); - void shareOnChannel(const RsGxsGroupId& channel_id, const QList& file_link) ; protected: @@ -54,6 +52,7 @@ protected: virtual TurtleRequestId distantSearch(const QString& search_string) ; virtual void checkRequestGroup(const RsGxsGroupId& grpId) ; + virtual UserNotify *createUserNotify(QObject *parent) override; private slots: void toggleAutoDownload(); void setDefaultDirectory(); diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumsDialog.cpp b/retroshare-gui/src/gui/gxsforums/GxsForumsDialog.cpp index 2282db1bb..7d5889e4d 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumsDialog.cpp +++ b/retroshare-gui/src/gui/gxsforums/GxsForumsDialog.cpp @@ -59,7 +59,21 @@ void GxsForumsDialog::handleEvent_main_thread(std::shared_ptr eve switch(e->mForumEventCode) { - case RsForumEventCode::SUBSCRIBE_STATUS_CHANGED: updateDisplay(true); + case RsForumEventCode::NEW_MESSAGE: + updateMessageSummaryList(e->mForumGroupId); + break; + + case RsForumEventCode::UPDATED_MESSAGE: // [[fallthrough]]; + updateDisplay(false); + break; + + case RsForumEventCode::READ_STATUS_CHANGED: + updateMessageSummaryList(e->mForumGroupId); + break; + + case RsForumEventCode::NEW_FORUM: // [[fallthrough]]; + case RsForumEventCode::SUBSCRIBE_STATUS_CHANGED: + updateDisplay(true); break; default: break; @@ -102,7 +116,7 @@ void GxsForumsDialog::shareInMessage(const RsGxsGroupId& forum_id,const QListshow(); } -UserNotify *GxsForumsDialog::getUserNotify(QObject *parent) +UserNotify *GxsForumsDialog::createUserNotify(QObject *parent) { return new GxsForumUserNotify(rsGxsForums, parent); } diff --git a/retroshare-gui/src/gui/gxsforums/GxsForumsDialog.h b/retroshare-gui/src/gui/gxsforums/GxsForumsDialog.h index 6a21c8de9..9b6da9d00 100644 --- a/retroshare-gui/src/gui/gxsforums/GxsForumsDialog.h +++ b/retroshare-gui/src/gui/gxsforums/GxsForumsDialog.h @@ -37,11 +37,11 @@ public: virtual QString pageName() const { return tr("Forums") ; } //MainPage virtual QString helpText() const { return ""; } //MainPage - virtual UserNotify *getUserNotify(QObject *parent); - void shareInMessage(const RsGxsGroupId& forum_id, const QList& file_link) ; protected: + virtual UserNotify *createUserNotify(QObject *parent) override; + virtual QString getHelpString() const ; virtual RetroShareLink::enumType getLinkType() { return RetroShareLink::TYPE_FORUM; } virtual GroupFrameSettings::Type groupFrameSettingsType() { return GroupFrameSettings::Forum; } diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp index fca0e8cbf..62a027a51 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.cpp @@ -325,7 +325,7 @@ MessagesDialog::~MessagesDialog() processSettings(false); } -UserNotify *MessagesDialog::getUserNotify(QObject *parent) +UserNotify *MessagesDialog::createUserNotify(QObject *parent) { return new MessageUserNotify(parent); } diff --git a/retroshare-gui/src/gui/msgs/MessagesDialog.h b/retroshare-gui/src/gui/msgs/MessagesDialog.h index 1671df268..a8115d466 100644 --- a/retroshare-gui/src/gui/msgs/MessagesDialog.h +++ b/retroshare-gui/src/gui/msgs/MessagesDialog.h @@ -50,8 +50,6 @@ public: virtual QString pageName() const { return tr("Mail") ; } //MainPage virtual QString helpText() const { return ""; } //MainPage - virtual UserNotify *getUserNotify(QObject *parent); - // replaced by shortcut // virtual void keyPressEvent(QKeyEvent *) ; @@ -64,6 +62,7 @@ signals: void messagesLoaded(); protected: + virtual UserNotify *createUserNotify(QObject *parent) override; bool eventFilter(QObject *obj, QEvent *ev); int getSelectedMessages(QList& mid); diff --git a/retroshare-gui/src/gui/qss/stylesheet/Standard.qss b/retroshare-gui/src/gui/qss/stylesheet/Standard.qss index 282f4917f..3e9a063cf 100644 --- a/retroshare-gui/src/gui/qss/stylesheet/Standard.qss +++ b/retroshare-gui/src/gui/qss/stylesheet/Standard.qss @@ -396,11 +396,6 @@ GxsChannelPostItem QLabel#newLabel { border-radius: 3px; } -GxsChannelPostItem QFrame#msgFrame { - border: 2px solid #238; - border-radius: 10px; -} - GxsChannelPostItem QLabel#logoLabel { border: 2px solid #D3D3D3; } @@ -430,12 +425,6 @@ ForumMsgItem QFrame#prevFrame { border-radius: 10px; } -SubFileItem > QFrame#frame { - border: 2px solid #238; - background: white; - border-radius: 10px; -} - SubFileItem QProgressBar#progressBar { border: 1px solid black; text-align: center; @@ -857,6 +846,22 @@ PostedItem QLabel#fromBoldLabel, QLabel#fromLabel, QLabel#dateLabel, QLabel#site color: #787c7e; } +PostedItem QLabel#newLabel { + border: 1px solid #167BE7; + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #2291E0, stop: 1 #3EB3FF); + border-radius: 3px; +} + +PostedCardView QLabel#newLabel { + border: 1px solid #167BE7; + background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #2291E0, stop: 1 #3EB3FF); + border-radius: 3px; +} + +PostedCardView QFrame#voteFrame { + background: #f8f9fa; +} + GxsCommentDialog QComboBox#sortBox { font: bold; color: #0099cc; diff --git a/retroshare-gui/src/qss/qdarkstyle-v2.qss b/retroshare-gui/src/qss/qdarkstyle-v2.qss index 90324f9ab..c9e951921 100644 --- a/retroshare-gui/src/qss/qdarkstyle-v2.qss +++ b/retroshare-gui/src/qss/qdarkstyle-v2.qss @@ -934,6 +934,7 @@ QPushButton::menu-indicator { subcontrol-origin: padding; subcontrol-position: bottom right; bottom: 4px; + } QPushButton:pressed { @@ -1836,6 +1837,7 @@ QToolBox QScrollArea QWidget QWidget { QFrame { border-radius: 4px; border: 1px solid #32414B; + } QFrame[frameShape="0"] { @@ -2045,4 +2047,95 @@ GxsChannelPostsWidget QToolButton#subscribeToolButton::menu-arrow { GxsChannelPostsWidget QToolButton#subscribeToolButton::menu-button { image: none; -} \ No newline at end of file +} + +QTabBar#smTab::tab{ + height: 32px; + width: 32px; +} + +PostedCreatePostDialog QPushButton#submitButton { + font: bold; + font-size: 15px; + color: white; + background: #0099cc; + border-radius: 4px; + min-width: 2em; + +} + +PostedCreatePostDialog QPushButton#submitButton:hover { + background: #03b1f3; + border-radius: 4px; + min-width: 2em; + +} + +PostedItem QFrame#mainFrame { + border-radius: 4px; + border: 1px solid #32414B; + background-color: #19232D; + +} + +GxsChannelPostItem QFrame#mainFrame { + border-radius: 4px; + border: 1px solid #32414B; + background-color: #19232D; + +} + +PostedItem QPushButton#shareButton +{ + background-color: transparent; + min-width: 80px; + max-height: 22px; + +} + +PostedItem QLabel#scoreLabel +{ + background-color: transparent; + +} + +PostedItem QFrame#voteFrame { + background: #141415; +} + +PostedItem QToolButton#voteDownButton, QToolButton#voteUpButton +{ + border: none; + +} + +PostedItem QLabel#thumbnailLabel{ + border: 2px solid #CCCCCC; + border-radius: 3px; +} + +PostedCardView QPushButton#shareButton +{ + background-color: transparent; + min-width: 80px; + max-height: 22px; + +} + +PostedCardView QFrame#voteFrame { + background: #141415; +} + +PostedCardView QFrame#mainFrame { + + background-color: #19232D; + +} + +PostedCardView QFrame#mainFrame [new=false]{ + background: #19232D; +} + +PostedCardView > QFrame#mainFrame[new=true] { + background-color: #005000; +} diff --git a/retroshare-gui/src/qss/qdarkstyle.qss b/retroshare-gui/src/qss/qdarkstyle.qss index 3e0927975..ef8495956 100644 --- a/retroshare-gui/src/qss/qdarkstyle.qss +++ b/retroshare-gui/src/qss/qdarkstyle.qss @@ -996,7 +996,7 @@ QToolButton::menu-arrow:open { QPushButton::menu-indicator { subcontrol-origin: padding; subcontrol-position: bottom right; - left: 8px; + } QTableView @@ -1209,3 +1209,85 @@ GxsChannelPostsWidget QToolButton#subscribeToolButton::menu-button { image: none; } + +QTabBar#smTab::tab{ + height: 32px; + width: 32px; +} + +PostedCreatePostDialog QPushButton#submitButton { + font: bold; + font-size: 15px; + color: white; + background: #0099cc; + border-radius: 4px; + min-width: 2em; + +} + +PostedCreatePostDialog QPushButton#submitButton:hover { + background: #03b1f3; + border-radius: 4px; + min-width: 2em; + +} + +GxsForumThreadWidget QLabel#forumName +{ + qproperty-fontSizeFactor: 140; + color: #0099cc; + font-size: 15px; + font: bold; +} + +PostedItem QPushButton#shareButton +{ + background-color: transparent; + border: none; + min-width: 75px; + max-height: 22px; +} + +PostedCardView QPushButton#shareButton +{ + background-color: transparent; + border: none; + min-width: 75px; +} + +PostedItem QFrame#voteFrame { + background: #141415; +} + +PostedCardView QFrame#voteFrame { + background: #141415; +} + +QPushButton#shareButton:hover, QPushButton#shareButton::menu-button:hover { + background-color: #4A4949; + border: 1px solid gray; +} + +PostedItem QToolButton#voteDownButton, QToolButton#voteUpButton, QToolButton#expandButton, QToolButton#readButton, +QToolButton#commentButton, QToolButton#notesButton +{ + border: none; +} + +PostedItem QLabel#thumbnailLabel{ + border: 2px solid #CCCCCC; + border-radius: 3px; +} + +PostedCardView QToolButton#voteDownButton, QToolButton#voteUpButton +{ + border: none; +} + +PostedCardView QFrame#mainFrame [new=false]{ + background: #302F2F; +} + +PostedCardView > QFrame#mainFrame[new=true] { + background-color: #005000; +} diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 188bd9546..37d8aa335 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -469,6 +469,8 @@ HEADERS += rshare.h \ util/QtVersion.h \ util/RsFile.h \ util/qtthreadsutils.h \ + util/ClickableLabel.h \ + util/AspectRatioPixmapLabel.h \ gui/profile/ProfileWidget.h \ gui/profile/ProfileManager.h \ gui/profile/StatusMessage.h \ @@ -828,6 +830,8 @@ SOURCES += main.cpp \ util/ObjectPainter.cpp \ util/RsFile.cpp \ util/RichTextEdit.cpp \ + util/ClickableLabel.cpp \ + util/AspectRatioPixmapLabel.cpp \ gui/profile/ProfileWidget.cpp \ gui/profile/StatusMessage.cpp \ gui/profile/ProfileManager.cpp \ @@ -1344,9 +1348,11 @@ posted { HEADERS += gui/Posted/PostedDialog.h \ gui/Posted/PostedListWidget.h \ gui/Posted/PostedItem.h \ + gui/Posted/PostedCardView.h \ gui/Posted/PostedGroupDialog.h \ gui/feeds/PostedGroupItem.h \ gui/Posted/PostedCreatePostDialog.h \ + gui/Posted/PhotoView.h \ gui/Posted/PostedUserNotify.h #gui/Posted/PostedCreateCommentDialog.h \ @@ -1355,8 +1361,9 @@ posted { FORMS += gui/Posted/PostedListWidget.ui \ gui/feeds/PostedGroupItem.ui \ gui/Posted/PostedItem.ui \ + gui/Posted/PostedCardView.ui \ gui/Posted/PostedCreatePostDialog.ui \ - + gui/Posted/PhotoView.ui #gui/Posted/PostedDialog.ui \ #gui/Posted/PostedComments.ui \ #gui/Posted/PostedCreateCommentDialog.ui @@ -1365,8 +1372,10 @@ posted { gui/Posted/PostedListWidget.cpp \ gui/feeds/PostedGroupItem.cpp \ gui/Posted/PostedItem.cpp \ + gui/Posted/PostedCardView.cpp \ gui/Posted/PostedGroupDialog.cpp \ gui/Posted/PostedCreatePostDialog.cpp \ + gui/Posted/PhotoView.cpp \ gui/Posted/PostedUserNotify.cpp #gui/Posted/PostedDialog.cpp \ diff --git a/retroshare-gui/src/retroshare-gui/mainpage.h b/retroshare-gui/src/retroshare-gui/mainpage.h index dc1853556..c96706e7e 100644 --- a/retroshare-gui/src/retroshare-gui/mainpage.h +++ b/retroshare-gui/src/retroshare-gui/mainpage.h @@ -55,14 +55,19 @@ public: void setHelpText(QString help) { mHelp = help; } virtual void retranslateUi() {} - virtual UserNotify *getUserNotify(QObject */*parent*/) { return NULL; } + + // Override this if needed. + virtual UserNotify *createUserNotify(QObject */*parent*/) { return NULL; } // Call this to add some help info to the page. The way the info is // shown is handled by showHelp() below; // void registerHelpButton(QToolButton *button, const QString& help_html_text, const QString &code_name) ; + UserNotify *getUserNotify() ; + protected: + virtual void showEvent(QShowEvent *); private: @@ -71,6 +76,8 @@ private: QString mName; QString mHelp; QString mHelpCodeName; + + UserNotify *mUserNotify; }; #endif diff --git a/retroshare-gui/src/util/AspectRatioPixmapLabel.cpp b/retroshare-gui/src/util/AspectRatioPixmapLabel.cpp new file mode 100644 index 000000000..08ecf18c6 --- /dev/null +++ b/retroshare-gui/src/util/AspectRatioPixmapLabel.cpp @@ -0,0 +1,59 @@ +/******************************************************************************* + * retroshare-gui/src/util/AspectRatioPixmapLabel.cpp * + * * + * Copyright (C) 2019 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 "AspectRatioPixmapLabel.h" +#include + +AspectRatioPixmapLabel::AspectRatioPixmapLabel(QWidget *parent) : + QLabel(parent) +{ + this->setMinimumSize(1,1); + setScaledContents(false); +} + +void AspectRatioPixmapLabel::setPixmap ( const QPixmap & p) +{ + pix = p; + QLabel::setPixmap(pix); + //std::cout << "Information size: " << pix.width() << 'x' << pix.height() << std::endl; +} + +int AspectRatioPixmapLabel::heightForWidth( int width ) const +{ + return pix.isNull() ? this->height() : ((qreal)pix.height()*width)/pix.width(); +} + +QSize AspectRatioPixmapLabel::sizeHint() const +{ + return QSize(pix.width(), pix.height()); +} + +QPixmap AspectRatioPixmapLabel::scaledPixmap() const +{ + return pix.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); +} + +void AspectRatioPixmapLabel::resizeEvent(QResizeEvent * e) +{ + if(!pix.isNull()) + QLabel::setPixmap(scaledPixmap()); + QLabel::resizeEvent(e); + //std::cout << "Information resized: " << e->oldSize().width() << 'x' << e->oldSize().height() << " to " << e->size().width() << 'x' << e->size().height() << std::endl; +} diff --git a/retroshare-gui/src/util/AspectRatioPixmapLabel.h b/retroshare-gui/src/util/AspectRatioPixmapLabel.h new file mode 100644 index 000000000..ad7c40e4c --- /dev/null +++ b/retroshare-gui/src/util/AspectRatioPixmapLabel.h @@ -0,0 +1,44 @@ +/******************************************************************************* + * retroshare-gui/src/util/AspectRatioPixmapLabel.h * + * * + * Copyright (C) 2019 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 . * + * * + *******************************************************************************/ + +#ifndef ASPECTRATIOPIXMAPLABEL_H +#define ASPECTRATIOPIXMAPLABEL_H + +#include +#include +#include + +class AspectRatioPixmapLabel : public QLabel +{ + Q_OBJECT +public: + explicit AspectRatioPixmapLabel(QWidget *parent = nullptr); + virtual int heightForWidth( int width ) const override; + virtual QSize sizeHint() const override; + QPixmap scaledPixmap() const; +public slots: + void setPixmap ( const QPixmap & ); +protected: + void resizeEvent(QResizeEvent *event) override; +private: + QPixmap pix; +}; + +#endif // ASPECTRATIOPIXMAPLABEL_H diff --git a/retroshare-gui/src/util/ClickableLabel.cpp b/retroshare-gui/src/util/ClickableLabel.cpp new file mode 100644 index 000000000..7b7ccb5fb --- /dev/null +++ b/retroshare-gui/src/util/ClickableLabel.cpp @@ -0,0 +1,35 @@ +/******************************************************************************* + * retroshare-gui/src/util/ClickableLabel.cpp * + * * + * Copyright (C) 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 . * + * * + *******************************************************************************/ + +#include "ClickableLabel.h" + +/** Constructor */ +ClickableLabel::ClickableLabel(QWidget* parent, Qt::WindowFlags f) + : QLabel(parent) { + +} + +ClickableLabel::~ClickableLabel() { + +} + +void ClickableLabel::mousePressEvent(QMouseEvent* event) { + emit clicked(); +} \ No newline at end of file diff --git a/retroshare-gui/src/util/ClickableLabel.h b/retroshare-gui/src/util/ClickableLabel.h new file mode 100644 index 000000000..ec1c66b8d --- /dev/null +++ b/retroshare-gui/src/util/ClickableLabel.h @@ -0,0 +1,47 @@ +/******************************************************************************* + * retroshare-gui/src/util/ClickableLabel.h * + * * + * Copyright (C) 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 . * + * * + *******************************************************************************/ + +#ifndef CLICKABLELABEL_H +#define CLICKABLELABEL_H + +#include +#include +#include + +class ClickableLabel : public QLabel { + Q_OBJECT + +public: + explicit ClickableLabel(QWidget* parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()); + ~ClickableLabel(); + +signals: + void clicked(); + +protected: + void mousePressEvent(QMouseEvent* event); + + void enterEvent(QEvent *ev) override { setStyleSheet("QLabel { border: 1px solid #3A3939; }");} + + void leaveEvent(QEvent *ev) override { setStyleSheet("QLabel { border: 2px solid #CCCCCC; border-radius: 3px; }");} + +}; + +#endif // CLICKABLELABEL_H \ No newline at end of file diff --git a/retroshare-gui/src/util/HandleRichText.cpp b/retroshare-gui/src/util/HandleRichText.cpp index 7818c984d..c500a6bb9 100644 --- a/retroshare-gui/src/util/HandleRichText.cpp +++ b/retroshare-gui/src/util/HandleRichText.cpp @@ -1185,7 +1185,7 @@ bool RsHtml::makeEmbeddedImage(const QImage &originalImage, QString &embeddedIma { rstime::RsScopeTimer s("Embed image"); QImage opt; - return ImageUtil::optimizeSize(embeddedImage, originalImage, opt, maxPixels, maxBytes); + return ImageUtil::optimizeSizeHtml(embeddedImage, originalImage, opt, maxPixels, maxBytes); } QString RsHtml::plainText(const QString &text) diff --git a/retroshare-gui/src/util/RichTextEdit.cpp b/retroshare-gui/src/util/RichTextEdit.cpp index 541e6c3eb..613aa1c19 100644 --- a/retroshare-gui/src/util/RichTextEdit.cpp +++ b/retroshare-gui/src/util/RichTextEdit.cpp @@ -585,7 +585,7 @@ void RichTextEdit::setText(const QString& text) { void RichTextEdit::insertImage() { QString file; - if (misc::getOpenFileName(window(), RshareSettings::LASTDIR_IMAGES, tr("Load Picture File"), "Pictures (*.png *.xpm *.jpg *.jpeg)", file)) { + if (misc::getOpenFileName(window(), RshareSettings::LASTDIR_IMAGES, tr("Load Picture File"), "Pictures (*.png *.xpm *.jpg *.jpeg *.gif *.webp)", file)) { QString encodedImage; if (RsHtml::makeEmbeddedImage(file, encodedImage, 640*480, MAX_ALLOWED_GXS_MESSAGE_SIZE - 200)) { QTextDocumentFragment fragment = QTextDocumentFragment::fromHtml(encodedImage); diff --git a/retroshare-gui/src/util/imageutil.cpp b/retroshare-gui/src/util/imageutil.cpp index c507bfa05..47029505e 100644 --- a/retroshare-gui/src/util/imageutil.cpp +++ b/retroshare-gui/src/util/imageutil.cpp @@ -68,12 +68,12 @@ void ImageUtil::extractImage(QWidget *window, QTextCursor cursor, QString file) } } -bool ImageUtil::optimizeSize(QString &html, const QImage& original, QImage &optimized, int maxPixels, int maxBytes) +bool ImageUtil::optimizeSizeBytes(QByteArray &bytearray, const QImage &original, QImage &optimized, int maxPixels, int maxBytes) { //nothing to do if it fits into the limits optimized = original; if ((maxPixels <= 0) || (optimized.width()*optimized.height() <= maxPixels)) { - int s = checkSize(html, optimized, maxBytes); + int s = checkSize(bytearray, optimized); if((maxBytes <= 0) || (s <= maxBytes)) { return true; } @@ -92,7 +92,7 @@ bool ImageUtil::optimizeSize(QString &html, const QImage& original, QImage &opti //if maxBytes not defined, do not reduce color space, just downscale if(maxBytes <= 0) { - checkSize(html, optimized = original.scaledToWidth(maxwidth, Qt::SmoothTransformation), maxBytes); + checkSize(bytearray, optimized = original.scaledToWidth(maxwidth, Qt::SmoothTransformation)); return true; } @@ -100,9 +100,9 @@ bool ImageUtil::optimizeSize(QString &html, const QImage& original, QImage &opti quantization(original, ct); //Use binary search to find a suitable image size + linear regression to guess the file size - double maxsize = (double)checkSize(html, optimized = original.scaledToWidth(maxwidth, Qt::SmoothTransformation).convertToFormat(QImage::Format_Indexed8, ct, Qt::ThresholdDither), maxBytes); + double maxsize = (double)checkSize(bytearray, optimized = original.scaledToWidth(maxwidth, Qt::SmoothTransformation).convertToFormat(QImage::Format_Indexed8, ct, Qt::ThresholdDither)); if(maxsize <= maxBytes) return true; //success - double minsize = (double)checkSize(html, optimized = original.scaledToWidth(minwidth, Qt::SmoothTransformation).convertToFormat(QImage::Format_Indexed8, ct, Qt::ThresholdDither), maxBytes); + double minsize = (double)checkSize(bytearray, optimized = original.scaledToWidth(minwidth, Qt::SmoothTransformation).convertToFormat(QImage::Format_Indexed8, ct, Qt::ThresholdDither)); if(minsize > maxBytes) return false; //impossible // std::cout << "maxS: " << maxsize << " minS: " << minsize << std::endl; @@ -115,7 +115,7 @@ bool ImageUtil::optimizeSize(QString &html, const QImage& original, QImage &opti double b = maxsize - m * ((double)maxwidth * (double)maxwidth / whratio); double a = ((double)(maxBytes - region/2) - b) / m; //maxBytes - region/2 target the center of the accepted region int nextwidth = (int)sqrt(a * whratio); - int nextsize = checkSize(html, optimized = original.scaledToWidth(nextwidth, Qt::SmoothTransformation).convertToFormat(QImage::Format_Indexed8, ct, Qt::ThresholdDither), maxBytes); + int nextsize = checkSize(bytearray, optimized = original.scaledToWidth(nextwidth, Qt::SmoothTransformation).convertToFormat(QImage::Format_Indexed8, ct, Qt::ThresholdDither)); if(nextsize <= maxBytes) { minsize = nextsize; minwidth = nextwidth; @@ -137,34 +137,41 @@ bool ImageUtil::optimizeSize(QString &html, const QImage& original, QImage &opti //std::cout << html.toStdString() << std::endl; } -int ImageUtil::checkSize(QString &embeddedImage, const QImage &img, int maxBytes) +bool ImageUtil::optimizeSizeHtml(QString &html, const QImage& original, QImage &optimized, int maxPixels, int maxBytes) +{ + QByteArray bytearray; + if(maxBytes > 0){ + maxBytes = maxBytes * 3/4 - 50; //base64 and html stuff + if(maxBytes < 1) maxBytes = 1; + } + + if(optimizeSizeBytes(bytearray, original, optimized, maxPixels, maxBytes)) + { + QByteArray encodedByteArray = bytearray.toBase64(); + html = ""); + return true; + } + return false; +} + +int ImageUtil::checkSize(QByteArray &bytearray, const QImage &img) { rstime::RsScopeTimer st("Check size"); - QByteArray bytearray; + bytearray.clear(); QBuffer buffer(&bytearray); int size = 0; //std::cout << QString("Trying image: format PNG, size %1x%2, colors %3\n").arg(img.width()).arg(img.height()).arg(img.colorCount()).toStdString(); if (buffer.open(QIODevice::WriteOnly)) { if (img.save(&buffer, "PNG", 0)) { - size = bytearray.length() * 4/3; - if((maxBytes > 0) && (size > maxBytes)) // *4/3 for base64 - { - //std::cout << QString("\tToo large, size: %1, limit: %2 bytes\n").arg(bytearray.length() * 4/3).arg(maxBytes).toStdString(); - }else{ - //std::cout << QString("\tOK, size: %1, limit: %2 bytes\n").arg(bytearray.length() * 4/3).arg(maxBytes).toStdString(); - QByteArray encodedByteArray = bytearray.toBase64(); - //embeddedImage = ""); - } + size = bytearray.length(); } else { std::cerr << "ImageUtil: image can't be saved to buffer" << std::endl; } buffer.close(); - bytearray.clear(); } else { std::cerr << "ImageUtil: buffer can't be opened" << std::endl; } diff --git a/retroshare-gui/src/util/imageutil.h b/retroshare-gui/src/util/imageutil.h index a6ff19b88..1a9658e13 100644 --- a/retroshare-gui/src/util/imageutil.h +++ b/retroshare-gui/src/util/imageutil.h @@ -23,6 +23,7 @@ #include #include +#include #include class ImageUtil @@ -31,10 +32,11 @@ public: ImageUtil(); static void extractImage(QWidget *window, QTextCursor cursor, QString file = ""); - static bool optimizeSize(QString &html, const QImage& original, QImage &optimized, int maxPixels = -1, int maxBytes = -1); + static bool optimizeSizeHtml(QString &html, const QImage& original, QImage &optimized, int maxPixels = -1, int maxBytes = -1); + static bool optimizeSizeBytes(QByteArray &bytearray, const QImage& original, QImage &optimized, int maxPixels = -1, int maxBytes = -1); private: - static int checkSize(QString& embeddedImage, const QImage& img, int maxBytes = -1); + static int checkSize(QByteArray& embeddedImage, const QImage& img); static void quantization(const QImage& img, QVector& palette); static void quantization(QList::iterator begin, QList::iterator end, int depth, QVector& palette); static void avgbucket(QList::iterator begin, QList::iterator end, QVector& palette);