fixed conflict

This commit is contained in:
csoler 2017-10-24 21:53:19 +02:00
commit f959218a24
77 changed files with 1795 additions and 944 deletions

View File

@ -1,15 +1,13 @@
Compile Retroshare for Android
==============================
== Introduction
Compiling an application for Android is not as easy as one would imagine,
expecially one like RetroShare that has a big codebase and is not well
documented.
This document is aimed to empower the reader so she can hopefully succed or at
least have a significant help in compiling her own RetroShare APK package
documented. This document is aimed to empower the reader so she can hopefully
succed or at least have a significant help in compiling her own RetroShare APK
installable on Android.
== Preparing The Environement
First of all setup your Qt for Android development environement following the
@ -21,7 +19,7 @@ on your Android phone Qt for Android examples.
But RetroShare is not as simple to compile as those examples. The good news is
that Android NDK ships all the necessary to build a custom toolchain that is
suitable to build RetroShare.
In order to build the toolchain with needed library RetroShare provides the
In order to build the toolchain with needed libraries RetroShare provides the
+android-prepare-toolchain.sh+ script; before you execute it you should define
some variables the script cannot determine in an easy and reliable manner by
itself in your terminal.
@ -33,7 +31,7 @@ export ANDROID_NDK_PATH="/opt/android-ndk/"
## The path where your fresh compiled toolchain will be installed, make sure
## the parent exists
export NDK_TOOLCHAIN_PATH="/home/$(whoami)/Development/android-toolchains/retroshare-android/"
export NDK_TOOLCHAIN_PATH="${HOME}/Builds/android-toolchains/retroshare-android/"
## The CPU architecture of the Android device you want to target
export ANDROID_NDK_ARCH="arm"

View File

@ -5,7 +5,7 @@
[ -z ${ANDROID_NDK_ARCH+x} ] && export ANDROID_NDK_ARCH="arm"
[ -z ${ANDROID_NDK_ABI_VER+x} ] && export ANDROID_NDK_ABI_VER="4.9"
[ -z ${ANDROID_PLATFORM_VER+x} ] && export ANDROID_PLATFORM_VER="18"
[ -z ${NDK_TOOLCHAIN_PATH+x} ] && export NDK_TOOLCHAIN_PATH="/home/$(whoami)/Development/android-toolchains/retroshare-android-${ANDROID_PLATFORM_VER}-${ANDROID_NDK_ARCH}-abi${ANDROID_NDK_ABI_VER}/"
[ -z ${NDK_TOOLCHAIN_PATH+x} ] && export NDK_TOOLCHAIN_PATH="${HOME}/Builds/android-toolchains/retroshare-android-${ANDROID_PLATFORM_VER}-${ANDROID_NDK_ARCH}-abi${ANDROID_NDK_ABI_VER}/"
[ -z ${HOST_NUM_CPU+x} ] && export HOST_NUM_CPU=4
runDir="$(pwd)"

View File

@ -1,5 +1,46 @@
retroshare (0.6.3-1.XXXXXX~YYYYYY) YYYYYY; urgency=low
d61a5cd csoler Mon, 2 Oct 2017 22:23:26 +0200 attempt at fixing the re-hash bug. Now only using canonicalized filenames in hash cache
22942dc csoler Sun, 1 Oct 2017 20:20:26 +0200 fixed bug causing suffix/prefix lists to contain an empty string
bc05aaa csoler Sat, 30 Sep 2017 18:58:31 +0200 switched tokenQueue speed to 10 calls/sec, thus improving loading speeds. Still need to test for CPU load
65977c0 csoler Sat, 30 Sep 2017 18:29:29 +0200 Merge pull request #1054 from PhenomRetroShare/Fix_GccWarningd
06ebaa5 csoler Sat, 30 Sep 2017 18:28:24 +0200 Merge pull request #1055 from felisucoibi/master
06063c5 felisu Sat, 30 Sep 2017 11:34:18 +0200 removed extra space
b84c898 felisu Sat, 30 Sep 2017 00:29:07 +0200 Removed ... from text
ef6fd38 felisu Thu, 28 Sep 2017 22:42:30 +0200 Changed prefixes and sifixes for startign with and ending with to be understandable.
7f851f6 Phenom Thu, 28 Sep 2017 19:24:26 +0200 Fix Gcc Warning in p3banlist
e66c0d1 csoler Wed, 27 Sep 2017 22:26:14 +0200 removed updateTotals() method. Replaced it with costless on-the-fly update of totals
a00d2c9 csoler Tue, 26 Sep 2017 21:12:17 +0200 changed lobby to char room in chat system msgs
8eae374 csoler Mon, 25 Sep 2017 22:14:34 +0200 Merge pull request #1053 from csoler/v0.6-FT
0d9b6e7 csoler Mon, 25 Sep 2017 22:09:35 +0200 fixd broken layout
cbeefda csoler Mon, 25 Sep 2017 21:35:59 +0200 Merge pull request #744 from RetroPooh/tunnel-names
f98f16f Pooh Mon, 25 Sep 2017 22:31:49 +0300 Update TransfersDialog.cpp
5970ff2 csoler Mon, 25 Sep 2017 21:14:30 +0200 Merge pull request #1052 from csoler/v0.6-FT
40cda11 csoler Mon, 25 Sep 2017 21:05:42 +0200 removed delay when calling forceUpdate() on directories
b969f31 csoler Mon, 25 Sep 2017 20:59:32 +0200 Merge pull request #1050 from csoler/v0.6-FT
d8cb3fe csoler Mon, 25 Sep 2017 20:56:35 +0200 fixed not rehashing files that already exist in a different directory pointed by a symlink
72dc1c7 Pooh Mon, 25 Sep 2017 21:50:12 +0300 Update TransfersDialog.cpp
c47e6f6 Pooh Mon, 25 Sep 2017 21:43:41 +0300 Merge branch 'master' into tunnel-names
4766a89 csoler Sun, 24 Sep 2017 23:51:47 +0200 added an additional hard limit to directory depth, just in case
f497905 csoler Sun, 24 Sep 2017 23:43:52 +0200 fixed limitation of directory depth when indexing files
abd7e25 csoler Sun, 24 Sep 2017 18:14:45 +0200 added checks for mMaxShareDepth and mIgnoreDuplicates
2a99df4 csoler Sun, 24 Sep 2017 17:53:06 +0200 added UI and parameters for two new options in shared files: max share depth and ignore duplicates
932eb49 csoler Sat, 23 Sep 2017 13:49:53 +0200 Merge pull request #1049 from Steve-V/minor-spelling-fix
82c9c95 Steve- Fri, 22 Sep 2017 19:58:13 -0500 spelling fix ommitted -> omitted
73cbf6c csoler Thu, 21 Sep 2017 23:47:11 +0200 Merge pull request #1047 from csoler/v0.6-FT
a2ccf97 csoler Wed, 20 Sep 2017 22:57:32 +0200 removed the 4M files limit on 64bits systems
308f8ca defnax Tue, 19 Sep 2017 18:34:58 +0200 update qrc file
58ccf0b csoler Mon, 18 Sep 2017 22:50:35 +0200 Merge pull request #1045 from csoler/v0.6-FT
bc2c9d5 csoler Mon, 18 Sep 2017 22:49:51 +0200 adding pending transfers 100 at a time instead of 1 at a time when loading
52ca6d0 defnax Mon, 18 Sep 2017 20:49:40 +0200 Added Crystall Ball to emote file
bf7d346 csoler Sun, 17 Sep 2017 20:27:44 +0200 Merge pull request #1043 from csoler/v0.6-FT
e21dec4 csoler Sun, 17 Sep 2017 20:26:46 +0200 Merge pull request #1038 from PhenomRetroShare/Add_UploadUserColumn
d8f621e csoler Sun, 17 Sep 2017 20:14:45 +0200 make forceDirectoryCheck() to desactivate the pause, in case it was left activated
-- Retroshare Dev Team <contact@retroshare.net> Sat, 14 Oct 2017 15:00:00 +0100
retroshare (0.6.3-1.20170917.c2f321d7~trusty) trusty; urgency=low
46d26bf csoler Tue, 12 Sep 2017 21:05:59 +0200 updated ubuntu packagign script
f3c627d csoler Sat, 16 Sep 2017 22:13:53 +0200 Merge pull request #1042 from csoler/v0.6-FT
8189d66 csoler Sat, 16 Sep 2017 22:13:15 +0200 fixed bug causing anon FT to not resume when restarting RS when the server enforces encryption

View File

@ -0,0 +1,46 @@
Source: retroshare
Section: devel
Priority: standard
Maintainer: Cyril Soler <csoler@users.sourceforge.net>
Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libopencv-dev, tcl8.6, libsqlcipher-dev, libmicrohttpd-dev, libavcodec-dev, qtmultimedia5-dev, qttools5-dev, libqt5x11extras5-dev, qt5-default
Standards-Version: 3.9.6
Homepage: http://retroshare.sourceforge.net
Package: retroshare-voip-plugin
Architecture: any
Conflicts: retroshare06-voip-plugin
Depends: ${shlibs:Depends}, ${misc:Depends}, retroshare, libspeex1, libspeexdsp1, libqt5multimedia5
Description: RetroShare VOIP plugin
This package provides a plugin for RetroShare, a secured Friend-to-Friend communication
plateform. The plugin adds voice-over-IP functionality to the private chat window. Both
friends chatting together need the plugin installed to be able to talk together.
Package: retroshare-feedreader-plugin
Architecture: any
Conflicts: retroshare06-feedreader-plugin
Depends: ${shlibs:Depends}, ${misc:Depends}, retroshare
Description: RetroShare FeedReader plugin
This package provides a plugin for RetroShare, a secured Friend-to-Friend communication
plateform. The plugin adds a RSS feed reader tab to retroshare.
Package: retroshare-nogui
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, gnome-keyring
Conflicts: retroshare,retroshare06-nogui
Description: Secure communication with friends
This is the command-line client for RetroShare network. This client
can be contacted and talked-to using SSL. Clients exist for portable
devices running e.g. Android.
Package: retroshare
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, gnome-keyring
Conflicts: retroshare-nogui,retroshare06
Description: Secure communication with friends
RetroShare is a Open Source cross-platform, private and secure decentralised
commmunication platform. It lets you to securely chat and share files with your
friends and family, using a web-of-trust to authenticate peers and OpenSSL to
encrypt all communication. RetroShare provides filesharing, chat, messages,
forums and channels.

View File

@ -55,7 +55,7 @@ while [ ${#} -gt 0 ]; do
done
if test "${dist}" = "" ; then
dist="precise trusty vivid xenial zesty"
dist="precise trusty xenial zesty artful"
fi
echo Attempting to get revision number...
@ -121,23 +121,11 @@ for i in ${dist}; do
echo copying changelog for ${i}
sed -e s/XXXXXX/"${rev}"/g -e s/YYYYYY/"${i}"/g ../changelog > debian/changelog
if test "${i}" = "lucid" ; then
cp ../control.ubuntu_lucid debian/control
elif test "${i}" = "zesty" ; then
cp ../control.zesty debian/control
elif test "${i}" = "squeeze" ; then
cp ../control.squeeze_bubba3 debian/control
elif test "${i}" = "precise" ; then
cp ../control.precise debian/control
elif test "${i}" = "xenial" ; then
cp ../control.xenial debian/control
elif test "${i}" = "yakkety" ; then
cp ../control.yakkety debian/control
elif test "${i}" = "stretch" ; then
cp ../control.${i} debian/control
elif test "${i}" = "jessie" ; then
cp ../control.${i} debian/control
if test -f ../control."${i}" ; then
echo \/\!\\ Using specific control file for distribution "${i}"
cp ../control."${i}" debian/control
else
echo Using standard control file control."${i}" for distribution "${i}"
cp ../debian/control debian/control
fi

View File

@ -31,32 +31,32 @@ CONTRIBUTE
TODO
----
[ ] make stylesheets or find reusable sass/css components
- [ ] make stylesheets or find reusable sass/css components
google material design has nice rules for color, spacing and everything: https://www.google.de/design/spec/material-design/introduction.html
[ ] find icons, maybe use google material design iconfont
[X] use urls/mithril routing for the menu. urls could replace state stored in rs.content
[X] drag and drop private key upload and import
[X] link from peer location to chat (use urls and mithril routing)
[X] add/remove friend, own cert
[X] downloads, search
[ ] make reusable infinite list controller, the js part to load data from Pagination.h (tweak Pagination.h to make everything work)
- [ ] find icons, maybe use google material design iconfont
- [X] use urls/mithril routing for the menu. urls could replace state stored in rs.content
- [X] drag and drop private key upload and import
- [X] link from peer location to chat (use urls and mithril routing)
- [X] add/remove friend, own cert
- [X] downloads, search
- [ ] make reusable infinite list controller, the js part to load data from Pagination.h (tweak Pagination.h to make everything work)
should provide forward, backward and follow-list-end
[ ] backend: view/create identities
[ ] backend: chat lobby participants list
[X] chat: send_message
[ ] backend: chat typing notifications
[ ] make routines to handle retroshare links
[ ] backend: edit shared folders
[ ] backend: view shared files
[ ] redirect if a url is not usable in the current runstate (e.g. redirect from login page to home page, after login)
[X] sort friendslist
- [ ] backend: view/create identities
- [ ] backend: chat lobby participants list
- [X] chat: send_message
- [ ] backend: chat typing notifications
- [ ] make routines to handle retroshare links
- [ ] backend: edit shared folders
- [ ] backend: view shared files
- [ ] redirect if a url is not usable in the current runstate (e.g. redirect from login page to home page, after login)
- [X] sort friendslist
need 4 master
-------------
[X] unsubscribe lobby
[X] unread chat message counter in menu
[X] list chat-lobby participants
[X] creating app.js on build (no need for npm on regulary build)
- [X] unsubscribe lobby
- [X] unread chat message counter in menu
- [X] list chat-lobby participants
- [X] creating app.js on build (no need for npm on regulary build)
url-handling (brainstorming)
----------------------------

View File

@ -35,6 +35,8 @@
//#define DEBUG_DIRECTORY_STORAGE 1
typedef FileListIO::read_error read_error;
/******************************************************************************************************************/
/* Internal File Hierarchy Storage */
/******************************************************************************************************************/
@ -1041,22 +1043,6 @@ bool InternalFileHierarchyStorage::save(const std::string& fname)
}
}
class read_error
{
public:
read_error(unsigned char *sec,uint32_t size,uint32_t offset,uint8_t expected_tag)
{
std::ostringstream s ;
s << "At offset " << offset << "/" << size << ": expected section tag " << std::hex << (int)expected_tag << std::dec << " but got " << RsUtil::BinToHex(&sec[offset],std::min((int)size-(int)offset, 15)) << "..." << std::endl;
err_string = s.str();
}
read_error(const std::string& s) : err_string(s) {}
const std::string& what() const { return err_string ; }
private:
std::string err_string ;
};
bool InternalFileHierarchyStorage::load(const std::string& fname)
{
unsigned char *buffer = NULL ;

View File

@ -0,0 +1,298 @@
#include <iomanip>
#include <util/radix64.h>
#include <util/rsdir.h>
#include "file_sharing_defaults.h"
#include "filelist_io.h"
#include "file_tree.h"
std::string FileTreeImpl::toRadix64() const
{
unsigned char *buff = NULL ;
uint32_t size = 0 ;
serialise(buff,size) ;
std::string res ;
Radix64::encode(buff,size,res) ;
free(buff) ;
return res ;
}
FileTree *FileTree::create(const std::string& radix64_string)
{
FileTreeImpl *ft = new FileTreeImpl ;
std::vector<uint8_t> mem = Radix64::decode(radix64_string);
ft->deserialise(mem.data(),mem.size()) ;
return ft ;
}
void FileTreeImpl::recurs_buildFileTree(FileTreeImpl& ft,uint32_t index,const DirDetails& dd,bool remote,bool remove_top_dirs)
{
if(ft.mDirs.size() <= index)
ft.mDirs.resize(index+1) ;
if(remove_top_dirs)
ft.mDirs[index].name = RsDirUtil::getTopDir(dd.name) ;
else
ft.mDirs[index].name = dd.name ;
ft.mDirs[index].subfiles.clear();
ft.mDirs[index].subdirs.clear();
DirDetails dd2 ;
FileSearchFlags flags = remote?RS_FILE_HINTS_REMOTE:RS_FILE_HINTS_LOCAL ;
for(uint32_t i=0;i<dd.children.size();++i)
if(rsFiles->RequestDirDetails(dd.children[i].ref,dd2,flags))
{
if(dd.children[i].type == DIR_TYPE_FILE)
{
FileTree::FileData f ;
f.name = dd2.name ;
f.size = dd2.count ;
f.hash = dd2.hash ;
ft.mDirs[index].subfiles.push_back(ft.mFiles.size()) ;
ft.mFiles.push_back(f) ;
ft.mTotalFiles++ ;
ft.mTotalSize += f.size ;
}
else if(dd.children[i].type == DIR_TYPE_DIR)
{
ft.mDirs[index].subdirs.push_back(ft.mDirs.size());
recurs_buildFileTree(ft,ft.mDirs.size(),dd2,remote,remove_top_dirs) ;
}
else
std::cerr << "(EE) Unsupported DirDetails type." << std::endl;
}
else
std::cerr << "(EE) Cannot request dir details for pointer " << dd.children[i].ref << std::endl;
}
bool FileTreeImpl::getDirectoryContent(uint32_t index,std::string& name,std::vector<uint32_t>& subdirs,std::vector<FileData>& subfiles) const
{
if(index >= mDirs.size())
return false ;
name = mDirs[index].name;
subdirs = mDirs[index].subdirs ;
subfiles.clear() ;
for(uint32_t i=0;i<mDirs[index].subfiles.size();++i)
subfiles.push_back(mFiles[mDirs[index].subfiles[i]]);
return true ;
}
FileTree *FileTree::create(const DirDetails& dd, bool remote,bool remove_top_dirs)
{
FileTreeImpl *ft = new FileTreeImpl ;
FileTreeImpl::recurs_buildFileTree(*ft,0,dd,remote,remove_top_dirs) ;
return ft ;
}
typedef FileListIO::read_error read_error ;
bool FileTreeImpl::deserialise(unsigned char *buffer,uint32_t buffer_size)
{
uint32_t buffer_offset = 0 ;
mTotalFiles = 0;
mTotalSize = 0;
try
{
// Read some header
uint32_t version,n_dirs,n_files ;
if(!FileListIO::readField(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_LOCAL_DIRECTORY_VERSION,version)) throw read_error(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_LOCAL_DIRECTORY_VERSION) ;
if(version != (uint32_t) FILE_LIST_IO_LOCAL_DIRECTORY_TREE_VERSION_0001) throw std::runtime_error("Wrong version number") ;
if(!FileListIO::readField(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_RAW_NUMBER,n_files)) throw read_error(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_RAW_NUMBER) ;
if(!FileListIO::readField(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_RAW_NUMBER,n_dirs)) throw read_error(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_RAW_NUMBER) ;
// Write all file/dir entries
mFiles.resize(n_files) ;
mDirs.resize(n_dirs) ;
unsigned char *node_section_data = NULL ;
uint32_t node_section_size = 0 ;
for(uint32_t i=0;i<mFiles.size() && buffer_offset < buffer_size;++i) // only the 2nd condition really is needed. The first one ensures that the loop wont go forever.
{
uint32_t node_section_offset = 0 ;
#ifdef DEBUG_DIRECTORY_STORAGE
std::cerr << "reading node " << i << ", offset " << buffer_offset << " : " << RsUtil::BinToHex(&buffer[buffer_offset],std::min((int)buffer_size - (int)buffer_offset,100)) << "..." << std::endl;
#endif
if(FileListIO::readField(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_LOCAL_FILE_ENTRY,node_section_data,node_section_size))
{
if(!FileListIO::readField(node_section_data,node_section_size,node_section_offset,FILE_LIST_IO_TAG_FILE_NAME ,mFiles[i].name )) throw read_error(node_section_data,node_section_size,node_section_offset,FILE_LIST_IO_TAG_FILE_NAME ) ;
if(!FileListIO::readField(node_section_data,node_section_size,node_section_offset,FILE_LIST_IO_TAG_FILE_SIZE ,mFiles[i].size )) throw read_error(node_section_data,node_section_size,node_section_offset,FILE_LIST_IO_TAG_FILE_SIZE ) ;
if(!FileListIO::readField(node_section_data,node_section_size,node_section_offset,FILE_LIST_IO_TAG_FILE_SHA1_HASH,mFiles[i].hash )) throw read_error(node_section_data,node_section_size,node_section_offset,FILE_LIST_IO_TAG_FILE_SHA1_HASH) ;
mTotalFiles++ ;
mTotalSize += mFiles[i].size ;
}
else
throw read_error(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_LOCAL_FILE_ENTRY) ;
}
for(uint32_t i=0;i<mDirs.size() && buffer_offset < buffer_size;++i)
{
uint32_t node_section_offset = 0 ;
if(FileListIO::readField(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_LOCAL_DIR_ENTRY,node_section_data,node_section_size))
{
DirData& de(mDirs[i]) ;
if(!FileListIO::readField(node_section_data,node_section_size,node_section_offset,FILE_LIST_IO_TAG_FILE_NAME,de.name )) throw read_error(node_section_data,node_section_size,node_section_offset,FILE_LIST_IO_TAG_FILE_NAME ) ;
uint32_t n_subdirs = 0 ;
uint32_t n_subfiles = 0 ;
if(!FileListIO::readField(node_section_data,node_section_size,node_section_offset,FILE_LIST_IO_TAG_RAW_NUMBER,n_subdirs)) throw read_error(node_section_data,node_section_size,node_section_offset,FILE_LIST_IO_TAG_RAW_NUMBER) ;
for(uint32_t j=0;j<n_subdirs;++j)
{
uint32_t di = 0 ;
if(!FileListIO::readField(node_section_data,node_section_size,node_section_offset,FILE_LIST_IO_TAG_RAW_NUMBER,di)) throw read_error(node_section_data,node_section_size,node_section_offset,FILE_LIST_IO_TAG_RAW_NUMBER) ;
de.subdirs.push_back(di) ;
}
if(!FileListIO::readField(node_section_data,node_section_size,node_section_offset,FILE_LIST_IO_TAG_RAW_NUMBER,n_subfiles)) throw read_error(node_section_data,node_section_size,node_section_offset,FILE_LIST_IO_TAG_RAW_NUMBER) ;
for(uint32_t j=0;j<n_subfiles;++j)
{
uint32_t fi = 0 ;
if(!FileListIO::readField(node_section_data,node_section_size,node_section_offset,FILE_LIST_IO_TAG_RAW_NUMBER,fi)) throw read_error(node_section_data,node_section_size,node_section_offset,FILE_LIST_IO_TAG_RAW_NUMBER) ;
de.subfiles.push_back(fi) ;
}
}
else
throw read_error(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_LOCAL_DIR_ENTRY) ;
}
free(node_section_data) ;
return true ;
}
catch(read_error& e)
{
#ifdef DEBUG_DIRECTORY_STORAGE
std::cerr << "Error while reading: " << e.what() << std::endl;
#endif
return false;
}
return true ;
}
bool FileTreeImpl::serialise(unsigned char *& buffer,uint32_t& buffer_size) const
{
buffer = 0 ;
uint32_t buffer_offset = 0 ;
unsigned char *tmp_section_data = (unsigned char*)rs_malloc(FL_BASE_TMP_SECTION_SIZE) ;
if(!tmp_section_data)
return false;
uint32_t tmp_section_size = FL_BASE_TMP_SECTION_SIZE ;
try
{
// Write some header
if(!FileListIO::writeField(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_LOCAL_DIRECTORY_VERSION,(uint32_t) FILE_LIST_IO_LOCAL_DIRECTORY_TREE_VERSION_0001)) throw std::runtime_error("Write error") ;
if(!FileListIO::writeField(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_RAW_NUMBER,(uint32_t) mFiles.size())) throw std::runtime_error("Write error") ;
if(!FileListIO::writeField(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_RAW_NUMBER,(uint32_t) mDirs.size())) throw std::runtime_error("Write error") ;
// Write all file/dir entries
for(uint32_t i=0;i<mFiles.size();++i)
{
const FileData& fe(mFiles[i]) ;
uint32_t file_section_offset = 0 ;
if(!FileListIO::writeField(tmp_section_data,tmp_section_size,file_section_offset,FILE_LIST_IO_TAG_FILE_NAME ,fe.name )) throw std::runtime_error("Write error") ;
if(!FileListIO::writeField(tmp_section_data,tmp_section_size,file_section_offset,FILE_LIST_IO_TAG_FILE_SIZE ,fe.size )) throw std::runtime_error("Write error") ;
if(!FileListIO::writeField(tmp_section_data,tmp_section_size,file_section_offset,FILE_LIST_IO_TAG_FILE_SHA1_HASH,fe.hash )) throw std::runtime_error("Write error") ;
if(!FileListIO::writeField(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_LOCAL_FILE_ENTRY,tmp_section_data,file_section_offset)) throw std::runtime_error("Write error") ;
}
for(uint32_t i=0;i<mDirs.size();++i)
{
const DirData& de(mDirs[i]) ;
uint32_t dir_section_offset = 0 ;
if(!FileListIO::writeField(tmp_section_data,tmp_section_size,dir_section_offset,FILE_LIST_IO_TAG_FILE_NAME ,de.name )) throw std::runtime_error("Write error") ;
if(!FileListIO::writeField(tmp_section_data,tmp_section_size,dir_section_offset,FILE_LIST_IO_TAG_RAW_NUMBER,(uint32_t)de.subdirs.size())) throw std::runtime_error("Write error") ;
for(uint32_t j=0;j<de.subdirs.size();++j)
if(!FileListIO::writeField(tmp_section_data,tmp_section_size,dir_section_offset,FILE_LIST_IO_TAG_RAW_NUMBER,(uint32_t)de.subdirs[j])) throw std::runtime_error("Write error") ;
if(!FileListIO::writeField(tmp_section_data,tmp_section_size,dir_section_offset,FILE_LIST_IO_TAG_RAW_NUMBER,(uint32_t)de.subfiles.size())) throw std::runtime_error("Write error") ;
for(uint32_t j=0;j<de.subfiles.size();++j)
if(!FileListIO::writeField(tmp_section_data,tmp_section_size,dir_section_offset,FILE_LIST_IO_TAG_RAW_NUMBER,(uint32_t)de.subfiles[j])) throw std::runtime_error("Write error") ;
if(!FileListIO::writeField(buffer,buffer_size,buffer_offset,FILE_LIST_IO_TAG_LOCAL_DIR_ENTRY,tmp_section_data,dir_section_offset)) throw std::runtime_error("Write error") ;
}
free(tmp_section_data) ;
buffer_size = buffer_offset;
return true ;
}
catch(std::exception& e)
{
std::cerr << "Error while writing: " << e.what() << std::endl;
if(buffer != NULL)
free(buffer) ;
if(tmp_section_data != NULL)
free(tmp_section_data) ;
return false;
}
}
void FileTreeImpl::print() const
{
std::cerr << "File hierarchy: name=" << mDirs[0].name << " size=" << mTotalSize << std::endl;
recurs_print(0," ") ;
}
void FileTreeImpl::recurs_print(uint32_t index,const std::string& indent) const
{
if(index >= mDirs.size())
{
std::cerr << "(EE) inconsistent FileTree structure" << std::endl;
return;
}
std::cerr << indent << mDirs[index].name << std::endl;
for(uint32_t i=0;i<mDirs[index].subdirs.size();++i)
recurs_print(mDirs[index].subdirs[i],indent+" ") ;
for(uint32_t i=0;i<mDirs[index].subfiles.size();++i)
{
const FileData& fd(mFiles[mDirs[index].subfiles[i]]) ;
std::cerr << indent << " " << fd.hash << " " << std::setprecision(8) << fd.size << " " << fd.name << std::endl;
}
}

View File

@ -0,0 +1,33 @@
#include "retroshare/rsfiles.h"
class FileTreeImpl: public FileTree
{
public:
FileTreeImpl()
{
mTotalFiles = 0 ;
mTotalSize = 0 ;
}
virtual std::string toRadix64() const ;
virtual bool getDirectoryContent(uint32_t index,std::string& name,std::vector<uint32_t>& subdirs,std::vector<FileData>& subfiles) const ;
virtual void print() const ;
bool serialise(unsigned char *& data,uint32_t& data_size) const ;
bool deserialise(unsigned char* data, uint32_t data_size) ;
protected:
void recurs_print(uint32_t index,const std::string& indent) const;
static void recurs_buildFileTree(FileTreeImpl& ft, uint32_t index, const DirDetails& dd, bool remote, bool remove_top_dirs);
struct DirData {
std::string name;
std::vector<uint32_t> subdirs ;
std::vector<uint32_t> subfiles ;
};
std::vector<FileData> mFiles ;
std::vector<DirData> mDirs ;
friend class FileTree ;
};

View File

@ -22,12 +22,22 @@
* Please report all bugs and problems to "retroshare.project@gmail.com".
*
*/
#include <sstream>
#include "retroshare/rsids.h"
#include "pqi/authssl.h"
#include "util/rsdir.h"
#include "util/rsprint.h"
#include "serialiser/rsbaseserial.h"
#include "filelist_io.h"
FileListIO::read_error::read_error(unsigned char *sec,uint32_t size,uint32_t offset,uint8_t expected_tag)
{
std::ostringstream s ;
s << "At offset " << offset << "/" << size << ": expected section tag " << std::hex << (int)expected_tag << std::dec << " but got " << RsUtil::BinToHex(&sec[offset],std::min((int)size-(int)offset, 15)) << "..." << std::endl;
err_string = s.str();
}
template<> bool FileListIO::serialise(unsigned char *buff,uint32_t size,uint32_t& offset,const uint32_t & val) { return setRawUInt32(buff,size,&offset,val) ; }
template<> bool FileListIO::serialise(unsigned char *buff,uint32_t size,uint32_t& offset,const uint64_t & val) { return setRawUInt64(buff,size,&offset,val) ; }
template<> bool FileListIO::serialise(unsigned char *buff,uint32_t size,uint32_t& offset,const std::string & val) { return setRawString(buff,size,&offset,val) ; }

View File

@ -36,6 +36,7 @@
// WARNING: the encoding is system-dependent, so this should *not* be used to exchange data between computers.
static const uint32_t FILE_LIST_IO_LOCAL_DIRECTORY_STORAGE_VERSION_0001 = 0x00000001 ;
static const uint32_t FILE_LIST_IO_LOCAL_DIRECTORY_TREE_VERSION_0001 = 0x00010001 ;
static const uint8_t FILE_LIST_IO_TAG_UNKNOWN = 0x00 ;
static const uint8_t FILE_LIST_IO_TAG_LOCAL_DIRECTORY_VERSION = 0x01 ;
@ -65,6 +66,7 @@ static const uint8_t FILE_LIST_IO_TAG_RAW_NUMBER = 0x62 ;
static const uint32_t SECTION_HEADER_MAX_SIZE = 6 ; // section tag (1 byte) + size (max = 5 bytes)
class FileListIO
{
public:
@ -93,7 +95,19 @@ public:
return deserialise(buff,buff_size,offset,val);
}
static bool writeField( unsigned char*&buff,uint32_t& buff_size,uint32_t& offset,uint8_t section_tag,const unsigned char * val,uint32_t size) ;
class read_error
{
public:
read_error(unsigned char *sec,uint32_t size,uint32_t offset,uint8_t expected_tag);
read_error(const std::string& s) : err_string(s) {}
const std::string& what() const { return err_string ; }
private:
std::string err_string ;
};
static bool writeField( unsigned char*&buff,uint32_t& buff_size,uint32_t& offset,uint8_t section_tag,const unsigned char * val,uint32_t size) ;
static bool readField (const unsigned char *buff,uint32_t buff_size,uint32_t& offset,uint8_t check_section_tag, unsigned char *& val,uint32_t& size) ;
template<class T> static bool serialise(unsigned char *buff,uint32_t size,uint32_t& offset,const T& val) ;

View File

@ -47,6 +47,7 @@ file_lists {
file_sharing/directory_updater.h \
file_sharing/rsfilelistitems.h \
file_sharing/dir_hierarchy.h \
file_sharing/file_tree.h \
file_sharing/file_sharing_defaults.h
SOURCES *= file_sharing/p3filelists.cc \
@ -55,6 +56,7 @@ file_lists {
file_sharing/directory_storage.cc \
file_sharing/directory_updater.cc \
file_sharing/dir_hierarchy.cc \
file_sharing/file_tree.cc \
file_sharing/rsfilelistitems.cc
}
@ -916,7 +918,7 @@ test_bitdht {
################################# Android #####################################
android-g++ {
## ifaddrs is missing on Android add them don't use the one from
## ifaddrs is missing on Android to add them don't use the one from
## https://github.com/morristech/android-ifaddrs
## because they crash, use QNetworkInterface from Qt instead
CONFIG *= qt

View File

@ -134,6 +134,38 @@ struct SharedDirStats
uint64_t total_shared_size ;
};
// This class represents a tree of directories and files, only with their names size and hash. It is used to create collection links in the GUI
// and to transmit directory information between services. This class is independent from the existing FileHierarchy classes used in storage because
// we need a very copact serialization and storage size since we create links with it. Besides, we cannot afford to risk the leak of other local information
// by using the orignal classes.
class FileTree
{
public:
virtual ~FileTree() {}
static FileTree *create(const DirDetails& dd, bool remote, bool remove_top_dirs = true) ;
static FileTree *create(const std::string& radix64_string) ;
virtual std::string toRadix64() const =0 ;
// These methods allow the user to browse the hierarchy
struct FileData {
std::string name ;
uint64_t size ;
RsFileHash hash ;
};
virtual uint32_t root() const { return 0;}
virtual bool getDirectoryContent(uint32_t index,std::string& name,std::vector<uint32_t>& subdirs,std::vector<FileData>& subfiles) const = 0;
virtual void print() const=0;
uint32_t mTotalFiles ;
uint64_t mTotalSize ;
};
class RsFiles
{
public:

View File

@ -803,7 +803,8 @@ static bool checkAccount(std::string accountdir, AccountDetails &account,std::ma
/* Use RetroShare's exe dir */
dataDirectory = ".";
#elif defined(ANDROID)
dataDirectory = defaultBaseDirectory()+"/usr/share/retroshare";
#elif defined(DATA_DIR)
dataDirectory = DATA_DIR;
// For all other OS the data directory must be set in libretroshare.pro

View File

@ -30,7 +30,7 @@
#include "gui/RetroShareLink.h"
#include "retroshare-gui/RsAutoUpdatePage.h"
#include "gui/msgs/MessageComposer.h"
#include "gui/common/RsCollectionFile.h"
#include "gui/common/RsCollection.h"
#include "gui/common/FilesDefs.h"
#include "gui/common/RsUrlHandler.h"
#include "gui/settings/rsharesettings.h"
@ -345,7 +345,7 @@ void SearchDialog::searchResultWidgetCustomPopupMenu( QPoint /*point*/ )
QList<QTreeWidgetItem*> item =ui.searchResultWidget->selectedItems() ;
if (item.at(0)->data(SR_DATA_COL, SR_ROLE_LOCAL).toBool()) {
contextMnu.addAction(QIcon(IMAGE_OPENFOLDER), tr("Open Folder"), this, SLOT(openFolderSearch())) ;
if (item.at(0)->text(SR_NAME_COL).endsWith(RsCollectionFile::ExtensionString)) {
if (item.at(0)->text(SR_NAME_COL).endsWith(RsCollection::ExtensionString)) {
add_CollActions = true ;
}//if (item.at(0)->text(SR_NAME_COL).endsWith(RsCollectionFile::ExtensionString))
}//if (item.at(0)->data(SR_DATA_COL, SR_ROLE_LOCAL).toBool())
@ -448,7 +448,7 @@ void SearchDialog::collCreate()
}//if (!item->text(SR_HASH_COL).isEmpty())
}//for (int i = 0; i < numdls; ++i)
RsCollectionFile(dirVec).openNewColl(this);
RsCollection(dirVec).openNewColl(this);
}
void SearchDialog::collModif()
@ -476,8 +476,8 @@ void SearchDialog::collModif()
QFileInfo qinfo;
qinfo.setFile(QString::fromUtf8(path.c_str()));
if (qinfo.exists()) {
if (qinfo.absoluteFilePath().endsWith(RsCollectionFile::ExtensionString)) {
RsCollectionFile collection;
if (qinfo.absoluteFilePath().endsWith(RsCollection::ExtensionString)) {
RsCollection collection;
collection.openColl(qinfo.absoluteFilePath());
}//if (qinfo.absoluteFilePath().endsWith(RsCollectionFile::ExtensionString))
}//if (qinfo.exists())
@ -508,8 +508,8 @@ void SearchDialog::collView()
QFileInfo qinfo;
qinfo.setFile(QString::fromUtf8(path.c_str()));
if (qinfo.exists()) {
if (qinfo.absoluteFilePath().endsWith(RsCollectionFile::ExtensionString)) {
RsCollectionFile collection;
if (qinfo.absoluteFilePath().endsWith(RsCollection::ExtensionString)) {
RsCollection collection;
collection.openColl(qinfo.absoluteFilePath(), true);
}//if (qinfo.absoluteFilePath().endsWith(RsCollectionFile::ExtensionString))
}//if (qinfo.exists())
@ -540,8 +540,8 @@ void SearchDialog::collOpen()
QFileInfo qinfo;
qinfo.setFile(QString::fromUtf8(path.c_str()));
if (qinfo.exists()) {
if (qinfo.absoluteFilePath().endsWith(RsCollectionFile::ExtensionString)) {
RsCollectionFile collection;
if (qinfo.absoluteFilePath().endsWith(RsCollection::ExtensionString)) {
RsCollection collection;
if (collection.load(qinfo.absoluteFilePath())) {
collection.downloadFiles();
return;
@ -552,7 +552,7 @@ void SearchDialog::collOpen()
}
}
RsCollectionFile collection;
RsCollection collection;
if (collection.load(this)) {
collection.downloadFiles();
}//if (collection.load(this))

View File

@ -33,13 +33,15 @@
#include "SharedFilesDialog.h"
#include "gui/notifyqt.h"
#include "gui/MainWindow.h"
#include "gui/RemoteDirModel.h"
#include "gui/RetroShareLink.h"
#include "gui/ShareManager.h"
#include "gui/common/PeerDefs.h"
#include "gui/common/RsCollectionFile.h"
#include "gui/common/RsCollection.h"
#include "gui/msgs/MessageComposer.h"
#include "gui/settings/AddFileAssociationDialog.h"
#include "gui/gxschannels/GxsChannelDialog.h"
#include "gui/settings/rsharesettings.h"
#include "util/QtVersion.h"
#include "util/RsAction.h"
@ -61,6 +63,7 @@
#define IMAGE_OPENFOLDER ":/images/folderopen.png"
#define IMAGE_OPENFILE ":/images/fileopen.png"
#define IMAGE_LIBRARY ":/images/library.png"
#define IMAGE_CHANNEL ":/images/channels32.png"
#define IMAGE_COLLCREATE ":/images/library_add.png"
#define IMAGE_COLLMODIF ":/images/library_edit.png"
#define IMAGE_COLLVIEW ":/images/library_view.png"
@ -154,9 +157,6 @@ SharedFilesDialog::SharedFilesDialog(RetroshareDirModel *_tree_model,RetroshareD
connect(notify, SIGNAL(filesPreModChanged(bool)), this, SLOT(preModDirectories(bool)));
connect(notify, SIGNAL(filesPostModChanged(bool)), this, SLOT(postModDirectories(bool)));
//== connect(ui.localButton, SIGNAL(toggled(bool)), this, SLOT(showFrame(bool)));
//== connect(ui.remoteButton, SIGNAL(toggled(bool)), this, SLOT(showFrameRemote(bool)));
//== connect(ui.splittedButton, SIGNAL(toggled(bool)), this, SLOT(showFrameSplitted(bool)));
connect(ui.viewType_CB, SIGNAL(currentIndexChanged(int)), this, SLOT(changeCurrentViewModel(int)));
connect( ui.dirTreeView, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( spawnCustomPopupMenu( QPoint ) ) );
@ -499,36 +499,24 @@ void RemoteSharedFilesDialog::spawnCustomPopupMenu( QPoint point )
QMenu contextMnu( this ) ;
//bool bIsRsColl = currentFile.endsWith(RsCollectionFile::ExtensionString);
collCreateAct->setEnabled(true);
//collModifAct->setEnabled(bIsRsColl);
//collViewAct->setEnabled(bIsRsColl);
collOpenAct->setEnabled(true);
QMenu collectionMenu(tr("Collection"), this);
collectionMenu.setIcon(QIcon(IMAGE_LIBRARY));
collectionMenu.addAction(collCreateAct);
//collectionMenu.addAction(collModifAct);
//collectionMenu.addAction(collViewAct);
collectionMenu.addAction(collOpenAct);
QAction *downloadAct = new QAction(QIcon(IMAGE_DOWNLOAD), tr( "Download" ), &contextMnu ) ;
connect( downloadAct , SIGNAL( triggered() ), this, SLOT( downloadRemoteSelected() ) ) ;
contextMnu.addAction( downloadAct) ;
if ( type == DIR_TYPE_FILE ) {
//QAction *copyremotelinkAct = new QAction(QIcon(IMAGE_COPYLINK), tr( "Copy retroshare Link" ), &contextMnu ) ;
//connect( copyremotelinkAct , SIGNAL( triggered() ), this, SLOT( copyLink() ) ) ;
contextMnu.addSeparator() ;//------------------------------------
contextMnu.addAction( copylinkAct) ;
contextMnu.addAction( sendlinkAct) ;
contextMnu.addSeparator() ;//------------------------------------
contextMnu.addAction(QIcon(IMAGE_MSG), tr("Recommend in a message to..."), this, SLOT(recommendFilesToMsg())) ;
//QAction *sendremotelinkAct = new QAction(QIcon(IMAGE_COPYLINK), tr( "Send retroshare Link" ), &contextMnu ) ;
//connect( sendremotelinkAct , SIGNAL( triggered() ), this, SLOT( sendremoteLinkTo( ) ) ) ;
contextMnu.addSeparator() ;//------------------------------------
contextMnu.addAction( copylinkAct) ;
contextMnu.addAction( sendlinkAct) ;
contextMnu.addSeparator() ;//------------------------------------
contextMnu.addAction(QIcon(IMAGE_MSG), tr("Recommend in a message to"), this, SLOT(recommendFilesToMsg())) ;
}//if (type == DIR_TYPE_FILE)
contextMnu.addSeparator() ;//------------------------------------
contextMnu.addMenu(&collectionMenu) ;
@ -542,7 +530,7 @@ QModelIndexList SharedFilesDialog::getSelected()
QModelIndexList proxyList ;
for (QModelIndexList::iterator index = list.begin(); index != list.end(); ++index ) {
proxyList.append(proxyModel->mapToSource(*index)) ;
}//for (QModelIndexList::iterator index
}
return proxyList ;
}
@ -567,62 +555,59 @@ void RemoteSharedFilesDialog::downloadRemoteSelected()
model -> downloadSelected(lst) ;
}
void SharedFilesDialog::copyLink (const QModelIndexList& lst, bool remote)
void SharedFilesDialog::copyLinks(const QModelIndexList& lst, bool remote,QList<RetroShareLink>& urls,bool& has_unhashed_files)
{
std::vector<DirDetails> dirVec;
std::vector<DirDetails> dirVec;
model->getDirDetailsFromSelect(lst, dirVec);
model->getDirDetailsFromSelect(lst, dirVec);
QList<RetroShareLink> urls ;
has_unhashed_files = false;
bool has_unhashed_files = false;
for (int i = 0, n = dirVec.size(); i < n; ++i)
{
const DirDetails& details = dirVec[i];
for (int i = 0, n = dirVec.size(); i < n; ++i)
{
const DirDetails& details = dirVec[i];
if (details.type == DIR_TYPE_DIR)
{
FileTree *ft = FileTree::create(details,remote) ;
if (details.type == DIR_TYPE_DIR)
{
for(uint32_t j=0;j<details.children.size();++j)
{
const DirStub& dirStub = details.children[j];
std::cerr << "Created collection file tree:" << std::endl;
ft->print();
DirDetails details;
FileSearchFlags flags = remote?RS_FILE_HINTS_REMOTE:RS_FILE_HINTS_LOCAL ;
QString dir_name = QDir(QString::fromUtf8(details.name.c_str())).dirName();
// do not recursive copy sub dirs.
if (!rsFiles->RequestDirDetails(dirStub.ref, details, flags) || details.type != DIR_TYPE_FILE)
continue;
RetroShareLink link = RetroShareLink::createCollection(dir_name,ft->mTotalSize,ft->mTotalFiles,QString::fromStdString(ft->toRadix64())) ;
if(details.hash.isNull())
{
has_unhashed_files = true;
continue;
}
if(link.valid())
urls.push_back(link) ;
RetroShareLink link = RetroShareLink::createFile(QString::fromUtf8(details.name.c_str()), details.count, details.hash.toStdString().c_str());
if (link.valid()) {
urls.push_back(link) ;
}
}
}
else
{
if(details.hash.isNull())
delete ft ;
}
else
{
if(details.hash.isNull())
{
has_unhashed_files = true;
continue;
}
RetroShareLink link = RetroShareLink::createFile(QString::fromUtf8(details.name.c_str()), details.count, details.hash.toStdString().c_str());
if (link.valid()) {
urls.push_back(link) ;
}
}
}
RetroShareLink link = RetroShareLink::createFile(QString::fromUtf8(details.name.c_str()), details.count, details.hash.toStdString().c_str());
if (link.valid()) {
urls.push_back(link) ;
}
}
}
}
void SharedFilesDialog::copyLink (const QModelIndexList& lst, bool remote)
{
QList<RetroShareLink> urls ;
bool has_unhashed_files = false;
copyLinks(lst,remote,urls,has_unhashed_files) ;
RSLinkClipboard::copyLinks(urls) ;
if(has_unhashed_files)
QMessageBox::warning(NULL,tr("Some files have been omitted"),tr("Some files have been omitted because their hash is not available yet.")) ;
QMessageBox::warning(NULL,tr("Some files have been omitted"),tr("Some files have been omitted because they have not been indexed yet.")) ;
}
void SharedFilesDialog::copyLink()
@ -692,11 +677,11 @@ void SharedFilesDialog::collModif()
QFileInfo qinfo;
qinfo.setFile(QString::fromUtf8(path.c_str()));
if (qinfo.exists()) {
if (qinfo.absoluteFilePath().endsWith(RsCollectionFile::ExtensionString)) {
RsCollectionFile collection;
if (qinfo.absoluteFilePath().endsWith(RsCollection::ExtensionString)) {
RsCollection collection;
collection.openColl(qinfo.absoluteFilePath());
}//if (qinfo.absoluteFilePath().endsWith(RsCollectionFile::ExtensionString))
}//if (qinfo.exists())
}
}
}
void SharedFilesDialog::collView()
@ -722,11 +707,11 @@ void SharedFilesDialog::collView()
QFileInfo qinfo;
qinfo.setFile(QString::fromUtf8(path.c_str()));
if (qinfo.exists()) {
if (qinfo.absoluteFilePath().endsWith(RsCollectionFile::ExtensionString)) {
RsCollectionFile collection;
if (qinfo.absoluteFilePath().endsWith(RsCollection::ExtensionString)) {
RsCollection collection;
collection.openColl(qinfo.absoluteFilePath(), true);
}//if (qinfo.absoluteFilePath().endsWith(RsCollectionFile::ExtensionString))
}//if (qinfo.exists())
}
}
}
void SharedFilesDialog::collOpen()
@ -752,8 +737,8 @@ void SharedFilesDialog::collOpen()
QFileInfo qinfo;
qinfo.setFile(QString::fromUtf8(path.c_str()));
if (qinfo.exists()) {
if (qinfo.absoluteFilePath().endsWith(RsCollectionFile::ExtensionString)) {
RsCollectionFile collection;
if (qinfo.absoluteFilePath().endsWith(RsCollection::ExtensionString)) {
RsCollection collection;
if (collection.load(qinfo.absoluteFilePath())) {
collection.downloadFiles();
return;
@ -763,10 +748,10 @@ void SharedFilesDialog::collOpen()
}
}
RsCollectionFile collection;
RsCollection collection;
if (collection.load(this)) {
collection.downloadFiles();
}//if (collection.load(this))
}
}
void LocalSharedFilesDialog::playselectedfiles()
@ -995,7 +980,7 @@ void LocalSharedFilesDialog::spawnCustomPopupMenu( QPoint point )
QMenu contextMnu(this) ;
bool bIsRsColl = currentFile.endsWith(RsCollectionFile::ExtensionString);
bool bIsRsColl = currentFile.endsWith(RsCollection::ExtensionString);
collCreateAct->setEnabled(true);
collModifAct->setEnabled(bIsRsColl);
collViewAct->setEnabled(bIsRsColl);
@ -1011,6 +996,7 @@ void LocalSharedFilesDialog::spawnCustomPopupMenu( QPoint point )
switch (type) {
case DIR_TYPE_DIR :
contextMnu.addAction(openfolderAct) ;
contextMnu.addAction(copylinkAct) ;
contextMnu.addSeparator() ;//------------------------------------
contextMnu.addMenu(&collectionMenu) ;
break ;
@ -1023,14 +1009,51 @@ void LocalSharedFilesDialog::spawnCustomPopupMenu( QPoint point )
contextMnu.addSeparator() ;//------------------------------------
contextMnu.addMenu(&collectionMenu) ;
contextMnu.addSeparator() ;//------------------------------------
contextMnu.addAction(QIcon(IMAGE_MSG), tr("Recommend in a message to"), this, SLOT(recommendFilesToMsg())) ;
contextMnu.addAction(QIcon(IMAGE_MSG), tr("Recommend in a message to..."), this, SLOT(recommendFilesToMsg())) ;
break ;
default :
return ;
}//switch (type)
}
contextMnu.exec(QCursor::pos()) ;
GxsChannelDialog *channelDialog = dynamic_cast<GxsChannelDialog*>(MainWindow::getPage(MainWindow::Channels));
if(channelDialog != NULL)
{
QMenu shareChannelMenu(tr("Share on channel...")) ;
shareChannelMenu.setIcon(QIcon(IMAGE_CHANNEL));
std::list<RsGroupMetaData> grp_metas ;
channelDialog->getGroupList(grp_metas) ;
for(auto it(grp_metas.begin());it!=grp_metas.end();++it)
if(IS_GROUP_PUBLISHER((*it).mSubscribeFlags))
shareChannelMenu.addAction(QString::fromUtf8((*it).mGroupName.c_str()), this, SLOT(shareOnChannel()))->setData(QString::fromStdString((*it).mGroupId.toStdString())) ;
contextMnu.addMenu(&shareChannelMenu) ;
contextMnu.exec(QCursor::pos()) ; // added here because the shareChannelMenu QMenu object is deleted afterwards
}
else
contextMnu.exec(QCursor::pos()) ;
}
void LocalSharedFilesDialog::shareOnChannel()
{
RsGxsGroupId groupId(qobject_cast<QAction*>(sender())->data().toString().toStdString());
GxsChannelDialog *channelDialog = dynamic_cast<GxsChannelDialog*>(MainWindow::getPage(MainWindow::Channels));
if(channelDialog == NULL)
return ;
std::list<DirDetails> files_info ;
QList<RetroShareLink> file_links_list ;
bool has_unhashed_files ;
copyLinks(getSelected(),false,file_links_list,has_unhashed_files) ;
channelDialog->shareOnChannel(groupId,file_links_list) ;
}
//============================================================================

View File

@ -24,6 +24,7 @@
#include <set>
#include "RsAutoUpdatePage.h"
#include "gui/RetroShareLink.h"
#include "ui_SharedFilesDialog.h"
class RetroshareDirModel;
@ -68,10 +69,6 @@ private slots:
void collView();
void collOpen();
//== void showFrame(bool show);
//== void showFrameRemote(bool show);
//== void showFrameSplitted(bool show);
void recommendFilesToMsg();
void indicatorChanged(int index);
@ -103,6 +100,7 @@ protected:
//QMenu* contextMnu2;
void copyLinks(const QModelIndexList& lst, bool remote, QList<RetroShareLink>& urls, bool& has_unhashed_files);
void copyLink (const QModelIndexList& lst, bool remote);
void FilterItems();
@ -161,6 +159,7 @@ class LocalSharedFilesDialog : public SharedFilesDialog
void runCommandForFile();
void tryToAddNewAssotiation();
void forceCheck();
void shareOnChannel();
QAction* fileAssotiationAction(const QString fileName);

View File

@ -31,7 +31,7 @@
#include <QStandardItemModel>
#include <gui/common/FilesDefs.h>
#include <gui/common/RsCollectionFile.h>
#include <gui/common/RsCollection.h>
#include <gui/common/RsUrlHandler.h>
#include <gui/common/RSTreeView.h>
@ -50,7 +50,7 @@
#include "xprogressbar.h"
#include <gui/settings/rsharesettings.h>
#include "util/misc.h"
#include <gui/common/RsCollectionFile.h>
#include <gui/common/RsCollection.h>
#include "TransferUserNotify.h"
#include "util/QtVersion.h"
#include "util/RsFile.h"
@ -652,7 +652,8 @@ void TransfersDialog::downloadListCustomPopupMenu( QPoint /*point*/ )
QMenu contextMnu( this );
if(!RSLinkClipboard::empty(RetroShareLink::TYPE_FILE)) add_PasteLink=true;
if(!RSLinkClipboard::empty(RetroShareLink::TYPE_FILE)) add_PasteLink=true;
if(!RSLinkClipboard::empty(RetroShareLink::TYPE_FILE_TREE)) add_PasteLink=true;
if(!items.empty())
{
@ -666,8 +667,7 @@ void TransfersDialog::downloadListCustomPopupMenu( QPoint /*point*/ )
//Look only for first column == File List
//Get Info for current item
if (rsFiles->FileDetails(fileHash
, RS_FILE_HINTS_DOWNLOAD, info)) {
if (rsFiles->FileDetails(fileHash, RS_FILE_HINTS_DOWNLOAD, info)) {
/*const uint32_t FT_STATE_FAILED = 0x0000;
*const uint32_t FT_STATE_OKAY = 0x0001;
*const uint32_t FT_STATE_WAITING = 0x0002;
@ -677,22 +677,21 @@ void TransfersDialog::downloadListCustomPopupMenu( QPoint /*point*/ )
*const uint32_t FT_STATE_PAUSED = 0x0006;
*const uint32_t FT_STATE_CHECKING_HASH = 0x0007;
*/
if (info.downloadStatus == FT_STATE_WAITING) {
if (info.downloadStatus == FT_STATE_WAITING)
atLeastOne_Waiting = true ;
}//if (info.downloadStatus == FT_STATE_WAITING)
if (info.downloadStatus == FT_STATE_DOWNLOADING) {
if (info.downloadStatus == FT_STATE_DOWNLOADING)
atLeastOne_Downloading=true ;
}//if (info.downloadStatus == FT_STATE_DOWNLOADING)
if (info.downloadStatus == FT_STATE_COMPLETE) {
atLeastOne_Complete = true ;
add_OpenFileOption = single ;
}//if (info.downloadStatus == FT_STATE_COMPLETE)
if (info.downloadStatus == FT_STATE_QUEUED) {
}
if (info.downloadStatus == FT_STATE_QUEUED)
atLeastOne_Queued = true ;
}//if(info.downloadStatus == FT_STATE_QUEUED)
if (info.downloadStatus == FT_STATE_PAUSED) {
if (info.downloadStatus == FT_STATE_PAUSED)
atLeastOne_Paused = true ;
}//if (info.downloadStatus == FT_STATE_PAUSED)
size_t pos = info.fname.find_last_of('.') ;
if (pos != std::string::npos) {
@ -700,23 +699,23 @@ void TransfersDialog::downloadListCustomPopupMenu( QPoint /*point*/ )
if (misc::isPreviewable(info.fname.substr(pos + 1).c_str())) {
add_PreviewOption = (info.downloadStatus != FT_STATE_COMPLETE) ;
add_PlayOption = !add_PreviewOption ;
}// if (misc::isPreviewable(info.fname.substr(pos + 1).c_str()))
}
// Check if the file is a collection
if (RsCollectionFile::ExtensionString == info.fname.substr(pos + 1).c_str()) {
if (RsCollection::ExtensionString == info.fname.substr(pos + 1).c_str()) {
add_CollActions = (info.downloadStatus == FT_STATE_COMPLETE);
}//if (RsCollectionFile::ExtensionString == info
}// if(pos != std::string::npos)
}
}
}// if FileDetails
}// for items iterate
}// if (!items.empty())
}
}
}
if (atLeastOne_Waiting || atLeastOne_Downloading || atLeastOne_Queued || atLeastOne_Paused) {
contextMnu.addMenu( &prioritySpeedMenu) ;
}
if (atLeastOne_Queued) {
contextMnu.addMenu( &priorityQueueMenu) ;
}//if (atLeastOne_Queued)
}
if ( (!items.empty())
&& (atLeastOne_Downloading || atLeastOne_Queued || atLeastOne_Waiting || atLeastOne_Paused)) {
@ -724,7 +723,7 @@ void TransfersDialog::downloadListCustomPopupMenu( QPoint /*point*/ )
if (single) {
contextMnu.addAction( renameFileAct) ;
}//if (single)
}
QMenu *directoryMenu = contextMnu.addMenu(QIcon(IMAGE_OPENFOLDER), tr("Set destination directory")) ;
directoryMenu->addAction(specifyDestinationDirectoryAct) ;
@ -745,27 +744,24 @@ void TransfersDialog::downloadListCustomPopupMenu( QPoint /*point*/ )
act->setData(QString::fromUtf8( (*it).filename.c_str() ) ) ;
connect(act, SIGNAL(triggered()), this, SLOT(setDestinationDirectory())) ;
directoryMenu->addAction( act) ;
}//for (std::list<SharedDirInfo>::const_iterator it
}//if ( (!items.empty()) &&
}
}
if (atLeastOne_Paused) {
if (atLeastOne_Paused)
contextMnu.addAction(resumeAct) ;
}//if (atLeastOne_Paused)
if (atLeastOne_Downloading || atLeastOne_Queued || atLeastOne_Waiting) {
if (atLeastOne_Downloading || atLeastOne_Queued || atLeastOne_Waiting)
contextMnu.addAction(pauseAct) ;
}//if (atLeastOne_Downloading || atLeastOne_Queued || atLeastOne_Waiting)
if (!atLeastOne_Complete && !items.empty()) {
contextMnu.addAction(forceCheckAct) ;
contextMnu.addAction(cancelAct) ;
}//if (!atLeastOne_Complete && !items.empty())
if (add_PlayOption) {
}
if (add_PlayOption)
contextMnu.addAction(playAct) ;
}//if (add_PlayOption)
if (atLeastOne_Paused || atLeastOne_Downloading || atLeastOne_Complete || add_PlayOption) {
contextMnu.addSeparator() ;//------------------------------------------------
}//if (atLeastOne_Paused ||
if (atLeastOne_Paused || atLeastOne_Downloading || atLeastOne_Complete || add_PlayOption)
contextMnu.addSeparator() ;
if (single) {
if (add_OpenFileOption) contextMnu.addAction( openFileAct) ;
@ -773,20 +769,20 @@ void TransfersDialog::downloadListCustomPopupMenu( QPoint /*point*/ )
contextMnu.addAction( openFolderAct) ;
contextMnu.addAction( detailsFileAct) ;
contextMnu.addSeparator() ;//--------------------------------------------
}//if (single)
}
contextMnu.addAction( clearCompletedAct) ;
contextMnu.addSeparator() ;//------------------------------------------------
contextMnu.addSeparator() ;
if (add_CopyLink) {
contextMnu.addAction( copyLinkAct) ;
}//if (add_CopyLink)
}
if (add_PasteLink) {
contextMnu.addAction( pasteLinkAct) ;
}//if (add_PasteLink)
}
if (add_CopyLink || add_PasteLink) {
contextMnu.addSeparator() ;//--------------------------------------------
}//if (add_CopyLink || add_PasteLink)
contextMnu.addSeparator() ;
}
if (DLLFilterModel->rowCount()>0 ) {
contextMnu.addAction( expandAllDLAct ) ;
@ -1644,7 +1640,27 @@ void TransfersDialog::updateDetailsDialog()
void TransfersDialog::pasteLink()
{
RSLinkClipboard::process(RetroShareLink::TYPE_FILE);
QList<RetroShareLink> links ;
// We want to capture and process all links at once here, because we're possibly pasting a large collection of files. So we first
// merge all links into a single RsCollection and then process it.
RsCollection col ;
RSLinkClipboard::pasteLinks(links,RetroShareLink::TYPE_FILE_TREE);
for(QList<RetroShareLink>::const_iterator it(links.begin());it!=links.end();++it)
{
FileTree *ft = FileTree::create((*it).radix().toStdString()) ;
col.merge_in(*ft) ;
}
links.clear();
RSLinkClipboard::pasteLinks(links,RetroShareLink::TYPE_FILE);
for(QList<RetroShareLink>::const_iterator it(links.begin());it!=links.end();++it)
col.merge_in((*it).name(),(*it).size(),RsFileHash((*it).hash().toStdString())) ;
col.downloadFiles();
}
void TransfersDialog::getDLSelectedItems(std::set<RsFileHash> *ids, std::set<int> *rows)
@ -2155,7 +2171,7 @@ void TransfersDialog::collCreate()
dirVec.push_back(details);
}//for (it = items.begin();
RsCollectionFile(dirVec).openNewColl(this);
RsCollection(dirVec).openNewColl(this);
}
void TransfersDialog::collModif()
@ -2180,12 +2196,12 @@ void TransfersDialog::collModif()
QFileInfo qinfo;
qinfo.setFile(QString::fromUtf8(path.c_str()));
if (qinfo.exists()) {
if (qinfo.absoluteFilePath().endsWith(RsCollectionFile::ExtensionString)) {
RsCollectionFile collection;
if (qinfo.absoluteFilePath().endsWith(RsCollection::ExtensionString)) {
RsCollection collection;
collection.openColl(qinfo.absoluteFilePath());
}//if (qinfo.absoluteFilePath().endsWith(RsCollectionFile::ExtensionString))
}//if (qinfo.exists())
}//if (info.downloadStatus == FT_STATE_COMPLETE)
}
}
}
}
void TransfersDialog::collView()
@ -2210,12 +2226,12 @@ void TransfersDialog::collView()
QFileInfo qinfo;
qinfo.setFile(QString::fromUtf8(path.c_str()));
if (qinfo.exists()) {
if (qinfo.absoluteFilePath().endsWith(RsCollectionFile::ExtensionString)) {
RsCollectionFile collection;
if (qinfo.absoluteFilePath().endsWith(RsCollection::ExtensionString)) {
RsCollection collection;
collection.openColl(qinfo.absoluteFilePath(), true);
}//if (qinfo.absoluteFilePath().endsWith(RsCollectionFile::ExtensionString))
}//if (qinfo.exists())
}//if (info.downloadStatus == FT_STATE_COMPLETE)
}
}
}
}
void TransfersDialog::collOpen()
@ -2240,8 +2256,8 @@ void TransfersDialog::collOpen()
QFileInfo qinfo;
qinfo.setFile(QString::fromUtf8(path.c_str()));
if (qinfo.exists()) {
if (qinfo.absoluteFilePath().endsWith(RsCollectionFile::ExtensionString)) {
RsCollectionFile collection;
if (qinfo.absoluteFilePath().endsWith(RsCollection::ExtensionString)) {
RsCollection collection;
if (collection.load(qinfo.absoluteFilePath())) {
collection.downloadFiles();
return;
@ -2252,95 +2268,24 @@ void TransfersDialog::collOpen()
}
}
RsCollectionFile collection;
RsCollection collection;
if (collection.load(this)) {
collection.downloadFiles();
}//if (collection.load(this))
}
}
void TransfersDialog::setShowDLSizeColumn(bool show)
{
if ( (!ui.downloadList->isColumnHidden(COLUMN_SIZE)) != show) {
ui.downloadList->setColumnHidden(COLUMN_SIZE, !show);
}
}
void TransfersDialog::setShowDLCompleteColumn(bool show)
{
if ( (!ui.downloadList->isColumnHidden(COLUMN_COMPLETED)) != show) {
ui.downloadList->setColumnHidden(COLUMN_COMPLETED, !show);
}
}
void TransfersDialog::setShowDLDLSpeedColumn(bool show)
{
if ( (!ui.downloadList->isColumnHidden(COLUMN_DLSPEED)) != show) {
ui.downloadList->setColumnHidden(COLUMN_DLSPEED, !show);
}
}
void TransfersDialog::setShowDLProgressColumn(bool show)
{
if ( (!ui.downloadList->isColumnHidden(COLUMN_PROGRESS)) != show) {
ui.downloadList->setColumnHidden(COLUMN_PROGRESS, !show);
}
}
void TransfersDialog::setShowDLSourcesColumn(bool show)
{
if ( (!ui.downloadList->isColumnHidden(COLUMN_SOURCES)) != show) {
ui.downloadList->setColumnHidden(COLUMN_SOURCES, !show);
}
}
void TransfersDialog::setShowDLStatusColumn(bool show)
{
if ( (!ui.downloadList->isColumnHidden(COLUMN_STATUS)) != show) {
ui.downloadList->setColumnHidden(COLUMN_STATUS, !show);
}
}
void TransfersDialog::setShowDLPriorityColumn(bool show)
{
if ( (!ui.downloadList->isColumnHidden(COLUMN_PRIORITY)) != show) {
ui.downloadList->setColumnHidden(COLUMN_PRIORITY, !show);
}
}
void TransfersDialog::setShowDLRemainingColumn(bool show)
{
if ( (!ui.downloadList->isColumnHidden(COLUMN_REMAINING)) != show) {
ui.downloadList->setColumnHidden(COLUMN_REMAINING, !show);
}
}
void TransfersDialog::setShowDLDownloadTimeColumn(bool show)
{
if ( (!ui.downloadList->isColumnHidden(COLUMN_DOWNLOADTIME)) != show) {
ui.downloadList->setColumnHidden(COLUMN_DOWNLOADTIME, !show);
}
}
void TransfersDialog::setShowDLIDColumn(bool show)
{
if ( (!ui.downloadList->isColumnHidden(COLUMN_ID)) != show) {
ui.downloadList->setColumnHidden(COLUMN_ID, !show);
}
}
void TransfersDialog::setShowDLLastDLColumn(bool show)
{
if ( (!ui.downloadList->isColumnHidden(COLUMN_LASTDL)) != show) {
ui.downloadList->setColumnHidden(COLUMN_LASTDL, !show);
}
}
void TransfersDialog::setShowDLPath(bool show)
{
if ( (!ui.downloadList->isColumnHidden(COLUMN_PATH)) != show) {
ui.downloadList->setColumnHidden(COLUMN_PATH, !show);
}
}
void TransfersDialog::setShowDLSizeColumn (bool show) { ui.downloadList->setColumnHidden(COLUMN_SIZE, !show); }
void TransfersDialog::setShowDLCompleteColumn (bool show) { ui.downloadList->setColumnHidden(COLUMN_COMPLETED, !show); }
void TransfersDialog::setShowDLDLSpeedColumn (bool show) { ui.downloadList->setColumnHidden(COLUMN_DLSPEED, !show); }
void TransfersDialog::setShowDLProgressColumn (bool show) { ui.downloadList->setColumnHidden(COLUMN_PROGRESS, !show); }
void TransfersDialog::setShowDLSourcesColumn (bool show) { ui.downloadList->setColumnHidden(COLUMN_SOURCES, !show); }
void TransfersDialog::setShowDLStatusColumn (bool show) { ui.downloadList->setColumnHidden(COLUMN_STATUS, !show); }
void TransfersDialog::setShowDLPriorityColumn (bool show) { ui.downloadList->setColumnHidden(COLUMN_PRIORITY, !show); }
void TransfersDialog::setShowDLRemainingColumn (bool show) { ui.downloadList->setColumnHidden(COLUMN_REMAINING, !show); }
void TransfersDialog::setShowDLDownloadTimeColumn(bool show) { ui.downloadList->setColumnHidden(COLUMN_DOWNLOADTIME, !show); }
void TransfersDialog::setShowDLIDColumn (bool show) { ui.downloadList->setColumnHidden(COLUMN_ID, !show); }
void TransfersDialog::setShowDLLastDLColumn (bool show) { ui.downloadList->setColumnHidden(COLUMN_LASTDL, !show); }
void TransfersDialog::setShowDLPath (bool show) { ui.downloadList->setColumnHidden(COLUMN_PATH, !show); }
void TransfersDialog::expandAllDL()
{

View File

@ -103,7 +103,7 @@
#include "gui/statistics/StatisticsWindow.h"
#include "gui/connect/ConnectFriendWizard.h"
#include "gui/common/RsCollectionFile.h"
#include "gui/common/RsCollection.h"
#include "settings/rsettingswin.h"
#include "settings/rsharesettings.h"
#include "settings/WebuiPage.h"
@ -141,6 +141,7 @@
#define IMAGE_BLOGS ":/images/kblogger.png"
#define IMAGE_DHT ":/images/dht16.png"
/*static*/ bool MainWindow::hiddenmode = false;
/*static*/ MainWindow *MainWindow::_instance = NULL;
@ -182,6 +183,8 @@ MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags)
RsPeerDetails pd;
if (rsPeers->getPeerDetails(rsPeers->getOwnId(), pd)) {
nameAndLocation = QString("%1 (%2)").arg(QString::fromUtf8(pd.name.c_str())).arg(QString::fromUtf8(pd.location.c_str()));
if(pd.netMode == RS_NETMODE_HIDDEN)
hiddenmode = true;
}
setWindowTitle(tr("RetroShare %1 a secure decentralized communication platform").arg(Rshare::retroshareVersion(true)) + " - " + nameAndLocation);
@ -207,8 +210,9 @@ MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags)
connect(ui->listWidget, SIGNAL(currentRowChanged(int)), this, SLOT(setNewPage(int)));
connect(ui->stackPages, SIGNAL(currentChanged(int)), this, SLOT(setNewPage(int)));
//ui->stackPages->setCurrentIndex(Settings->getLastPageInMainWindow());
setNewPage(Settings->getLastPageInMainWindow());
int lastpageindex = Settings->getLastPageInMainWindow();
if(lastpageindex < ui->stackPages->count()) //Do not crash when a page was removed after last run
setNewPage(lastpageindex);
ui->splitter->setStretchFactor(0, 0);
ui->splitter->setStretchFactor(1, 1);
@ -241,13 +245,17 @@ MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags)
statusBar()->addWidget(peerstatus);
natstatus = new NATStatus();
natstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowNAT", QVariant(true)).toBool());
if(hiddenmode) natstatus->setVisible(false);
else natstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowNAT", QVariant(true)).toBool());
statusBar()->addWidget(natstatus);
natstatus->getNATStatus();
dhtstatus = new DHTStatus();
dhtstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowDHT", QVariant(true)).toBool());
if(hiddenmode) dhtstatus->setVisible(false);
else dhtstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowDHT", QVariant(true)).toBool());
statusBar()->addWidget(dhtstatus);
dhtstatus->getDHTStatus();
hashingstatus = new HashingStatus();
hashingstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowHashing", QVariant(true)).toBool());
statusBar()->addPermanentWidget(hashingstatus, 1);
@ -702,11 +710,14 @@ void MainWindow::updateStatus()
if (ratesstatus)
ratesstatus->getRatesStatus(downKb, upKb);
if(!hiddenmode)
{
if (natstatus)
natstatus->getNATStatus();
if (dhtstatus)
dhtstatus->getDHTStatus();
}
if (discstatus) {
discstatus->update();
@ -1020,7 +1031,7 @@ void MainWindow::newRsCollection()
{
std::vector <DirDetails> dirVec;
RsCollectionFile(dirVec).openNewColl(this);
RsCollection(dirVec).openNewColl(this);
}
/** Shows Share Manager */
@ -1448,8 +1459,8 @@ void MainWindow::openRsCollection(const QString &filename)
{
QFileInfo qinfo(filename);
if (qinfo.exists()) {
if (qinfo.absoluteFilePath().endsWith(RsCollectionFile::ExtensionString)) {
RsCollectionFile collection;
if (qinfo.absoluteFilePath().endsWith(RsCollection::ExtensionString)) {
RsCollection collection;
collection.openColl(qinfo.absoluteFilePath());
}
}
@ -1576,10 +1587,13 @@ void MainWindow::setCompactStatusMode(bool compact)
//statusComboBox: TODO Show only icon
peerstatus->setCompactMode(compact);
updateFriends();
if(!hiddenmode)
{
natstatus->setCompactMode(compact);
natstatus->getNATStatus();
dhtstatus->setCompactMode(compact);
dhtstatus->getDHTStatus();
}
hashingstatus->setCompactMode(compact);
ratesstatus->setCompactMode(compact);
//opModeStatus: TODO Show only ???

View File

@ -184,6 +184,8 @@ public:
ToasterDisable *toasterDisableInstance();
SysTrayStatus *sysTrayStatusInstance();
static bool hiddenmode;
public slots:
void receiveNewArgs(QStringList args);
void displayErrorMessage(int,int,const QString&) ;

View File

@ -1116,7 +1116,7 @@ static bool addFeedItemIfUniqueCallback(FeedItem *feedItem, void *data)
if (findData->mSecurityIpItem) {
SecurityIpItem *securityIpItem = dynamic_cast<SecurityIpItem*>(feedItem);
if (securityIpItem && securityIpItem->isSame(findData->mId1, findData->mId2, findData->mType)) {
if (securityIpItem && securityIpItem->isSame(RsPeerId(findData->mId1), findData->mId2, findData->mId3, findData->mType)) {
return true;
}
return false;

View File

@ -27,6 +27,8 @@
#include "util/TokenQueue.h"
#include "gui/settings/rsharesettings.h"
#include <iostream>
PostedCreatePostDialog::PostedCreatePostDialog(TokenQueue* tokenQ, RsPosted *posted, const RsGxsGroupId& grpId, QWidget *parent):
@ -35,7 +37,7 @@ PostedCreatePostDialog::PostedCreatePostDialog(TokenQueue* tokenQ, RsPosted *pos
ui(new Ui::PostedCreatePostDialog)
{
ui->setupUi(this);
Settings->loadWidgetInformation(this);
connect(ui->submitButton, SIGNAL(clicked()), this, SLOT(createPost()));
connect(ui->buttonBox, SIGNAL(rejected()), this, SLOT(close()));
@ -50,6 +52,7 @@ PostedCreatePostDialog::PostedCreatePostDialog(TokenQueue* tokenQ, RsPosted *pos
PostedCreatePostDialog::~PostedCreatePostDialog()
{
Settings->saveWidgetInformation(this);
delete ui;
}

View File

@ -104,8 +104,6 @@ void PostedItem::setup()
ui->clearButton->hide();
ui->readAndClearButton->hide();
ui->frame_notes->hide();
}
bool PostedItem::setGroup(const RsPostedGroup &group, bool doFill)
@ -278,11 +276,12 @@ void PostedItem::fill()
// FIX THIS UP LATER.
ui->notes->setText(QString::fromUtf8(mPost.mNotes.c_str()));
if(ui->notes->text().isEmpty())
ui->frame_notes->hide();
// differences between Feed or Top of Comment.
if (mFeedHolder)
{
// feed.
ui->frame_notes->hide();
//frame_comment->show();
ui->commentButton->show();
@ -303,14 +302,6 @@ void PostedItem::fill()
else
{
// no feed.
if(ui->notes->text().isEmpty())
{
ui->frame_notes->hide();
}
else
{
ui->frame_notes->show();
}
//frame_comment->hide();
ui->commentButton->hide();

View File

@ -60,7 +60,7 @@
</property>
</widget>
</item>
<item>
<item>
<layout class="QHBoxLayout" name="newCommHLayout">
<property name="topMargin">
<number>0</number>
@ -327,30 +327,29 @@
<item>
<widget class="QFrame" name="frame_notes">
<property name="frameShape">
<enum>QFrame::Box</enum>
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<widget class="QLabel" name="notes">
<property name="geometry">
<rect>
<x>2</x>
<y>2</y>
<width>16</width>
<height>17</height>
</rect>
<layout class="QGridLayout" name="gridLayout">
<property name="margin">
<number>1</number>
</property>
<property name="styleSheet">
<string notr="true"/>
<property name="spacing">
<number>1</number>
</property>
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
<item row="0" column="0">
<widget class="QLabel" name="notes">
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>

View File

@ -26,7 +26,7 @@
#include <QTimer>
#include <retroshare-gui/RsAutoUpdatePage.h>
#include <gui/common/RsCollectionFile.h>
#include <gui/common/RsCollection.h>
#include <gui/common/RsUrlHandler.h>
#include <gui/common/FilesDefs.h>
#include <gui/common/GroupDefs.h>
@ -1065,7 +1065,7 @@ void RetroshareDirModel::createCollectionFile(QWidget *parent, const QModelIndex
std::vector <DirDetails> dirVec;
getDirDetailsFromSelect(list, dirVec);
RsCollectionFile(dirVec).openNewColl(parent);
RsCollection(dirVec).openNewColl(parent);
}
void RetroshareDirModel::downloadSelected(const QModelIndexList &list)

View File

@ -43,7 +43,7 @@
#include "msgs/MessageComposer.h"
#include "util/misc.h"
#include "common/PeerDefs.h"
#include "common/RsCollectionFile.h"
#include "common/RsCollection.h"
#include <gui/common/RsUrlHandler.h>
#include "gui/connect/ConnectFriendWizard.h"
#include "gui/connect/ConfCertDialog.h"
@ -58,6 +58,7 @@
//#define DEBUG_RSLINK 1
#define HOST_FILE "file"
#define HOST_COLLECTION "collection"
#define HOST_EXTRAFILE "extra"
#define HOST_PERSON "person"
#define HOST_FORUM "forum"
@ -68,13 +69,18 @@
#define HOST_CERTIFICATE "certificate"
#define HOST_PUBLIC_MSG "public_msg"
#define HOST_IDENTITY "identity"
#define HOST_REGEXP "file|extra|person|forum|channel|posted|search|message|certificate|private_chat|public_msg|identity"
#define HOST_REGEXP "file|collection|extra|person|forum|channel|posted|search|message|certificate|private_chat|public_msg|identity"
#define FILE_NAME "name"
#define FILE_SIZE "size"
#define FILE_HASH "hash"
#define FILE_SOURCE "src"
#define COLLECTION_NAME "name"
#define COLLECTION_SIZE "size"
#define COLLECTION_DATA "radix"
#define COLLECTION_COUNT "files"
#define PERSON_NAME "name"
#define PERSON_HASH "hash"
@ -328,6 +334,20 @@ void RetroShareLink::fromUrl(const QUrl& url)
return;
}
if (url.host() == HOST_COLLECTION) {
bool ok;
_type = TYPE_FILE_TREE;
_radix = decodedQueryItemValue(urlQuery, COLLECTION_DATA);
_name = decodedQueryItemValue(urlQuery, COLLECTION_NAME);
_size = urlQuery.queryItemValue(COLLECTION_SIZE).toULongLong(&ok);
_count = urlQuery.queryItemValue(COLLECTION_COUNT).toULongLong(&ok);
#ifdef DEBUG_RSLINK
std::cerr << "Got a certificate link!!" << std::endl;
#endif
check() ;
return;
}
if (url.host() == HOST_CERTIFICATE) {
_type = TYPE_CERTIFICATE;
_radix = decodedQueryItemValue(urlQuery, CERTIFICATE_RADIX);
@ -400,6 +420,21 @@ RetroShareLink RetroShareLink::createFile(const QString& name, uint64_t size, co
return link;
}
RetroShareLink RetroShareLink::createCollection(const QString& name, uint64_t size, uint32_t count, const QString& radix_data)
{
RetroShareLink link;
link.clear();
link._name = name;
link._count = count;
link._size = size;
link._radix = radix_data ;
link._type = TYPE_FILE_TREE;
link.check();
return link;
}
RetroShareLink RetroShareLink::createPublicMsgInvite(time_t time_stamp,const QString& issuer_pgp_id,const QString& hash)
{
RetroShareLink link;
@ -608,6 +643,8 @@ void RetroShareLink::check()
if(!checkSSLId(_SSLid))
_valid = false; // no break! We also test file stuff below.
/* fallthrough */
case TYPE_FILE_TREE:
case TYPE_FILE:
if(_size > (((uint64_t)1)<<40)) // 1TB. Who has such large files?
_valid = false;
@ -615,7 +652,7 @@ void RetroShareLink::check()
if(!checkName(_name))
_valid = false;
if(!checkHash(_hash))
if(!checkRadix64(_radix))
_valid = false;
break;
@ -717,6 +754,8 @@ QString RetroShareLink::title() const
rsPeers->getGPGDetails(RsPgpId(_GPGid.toStdString()), detail) ;
return QObject::tr("Click to send a private message to %1 (%2).").arg(QString::fromUtf8(detail.name.c_str())).arg(_GPGid) ;
}
case TYPE_FILE_TREE:
return QObject::tr("Click to browse/download this file collection");
case TYPE_EXTRAFILE:
return QObject::tr("%1 (%2, Extra - Source included)").arg(hash()).arg(misc::friendlyUnit(size()));
case TYPE_FILE:
@ -860,6 +899,15 @@ QString RetroShareLink::toString() const
break;
case TYPE_FILE_TREE:
url.setScheme(RSLINK_SCHEME);
url.setHost(HOST_COLLECTION) ;
urlQuery.addQueryItem(COLLECTION_NAME, encodeItem(_name));
urlQuery.addQueryItem(COLLECTION_SIZE, QString::number(_size));
urlQuery.addQueryItem(COLLECTION_DATA, encodeItem(_radix));
urlQuery.addQueryItem(COLLECTION_COUNT, QString::number(_count));
break;
case TYPE_CERTIFICATE:
url.setScheme(RSLINK_SCHEME);
url.setHost(HOST_CERTIFICATE) ;
@ -882,9 +930,15 @@ QString RetroShareLink::niceName() const
if (type() == TYPE_PERSON)
return PeerDefs::rsid(name().toUtf8().constData(), RsPgpId(hash().toStdString()));
if(type() == TYPE_FILE_TREE)
return QObject::tr("%1 (%2 files, %3)").arg(_name).arg(_count).arg(misc::friendlyUnit(_size));
if(type() == TYPE_IDENTITY)
return QObject::tr("Identity link (name=%1, ID=%2)").arg(_name).arg(_hash) ;
if(type() == TYPE_FILE_TREE)
return QObject::tr("File directory (Total %s) Click to browse/download this file collection").arg(misc::friendlyUnit(_size));
if(type() == TYPE_PUBLIC_MSG) {
RsPeerDetails detail;
rsPeers->getGPGDetails(RsPgpId(_GPGid.toStdString()), detail) ;
@ -926,10 +980,10 @@ QString RetroShareLink::toHtmlSize() const
{
QString size = QString("(%1)").arg(misc::friendlyUnit(_size));
if (type() == TYPE_FILE && RsCollectionFile::isCollectionFile(name())) {
if (type() == TYPE_FILE && RsCollection::isCollectionFile(name())) {
FileInfo finfo;
if (rsFiles->FileDetails(RsFileHash(hash().toStdString()), RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_LOCAL, finfo)) {
RsCollectionFile collection;
RsCollection collection;
if (collection.load(QString::fromUtf8(finfo.path.c_str()), false)) {
size += QString(" [%1]").arg(misc::friendlyUnit(collection.size()));
}
@ -1095,6 +1149,7 @@ static void processList(const QStringList &list, const QString &textSingular, co
case TYPE_SEARCH:
case TYPE_MESSAGE:
case TYPE_IDENTITY:
case TYPE_FILE_TREE:
case TYPE_CERTIFICATE:
case TYPE_PUBLIC_MSG:
case TYPE_PRIVATE_CHAT:
@ -1336,6 +1391,16 @@ static void processList(const QStringList &list, const QString &textSingular, co
}
break;
case TYPE_FILE_TREE:
{
FileTree *ft = FileTree::create(link.radix().toStdString()) ;
RsCollection(*ft).downloadFiles() ;
delete ft;
}
break;
case TYPE_PERSON:
{
#ifdef DEBUG_RSLINK
@ -1347,34 +1412,6 @@ static void processList(const QStringList &list, const QString &textSingular, co
PGPKeyDialog::showIt(detail.gpg_id,PGPKeyDialog::PageDetails) ;
else
personNotFound.append(PeerDefs::rsid(link.name().toUtf8().constData(), RsPgpId(link.hash().toStdString())));
// needNotifySuccess = true;
// RsPeerDetails detail;
// if (rsPeers->getGPGDetails(RsPgpId(link.hash().toStdString()), detail))
// {
// if (RsPgpId(detail.gpg_id) == rsPeers->getGPGOwnId()) {
// // it's me, do nothing
// break;
// }
//
// if (detail.accept_connection) {
// // peer connection is already accepted
// personExist.append(PeerDefs::rsid(detail));
// break;
// }
//
// if (rsPeers->addFriend(RsPeerId(), RsPgpId(link.hash().toStdString()))) {
// ConfCertDialog::loadAll();
// personAdded.append(PeerDefs::rsid(detail));
// break;
// }
//
// personFailed.append(PeerDefs::rsid(link.name().toUtf8().constData(), RsPgpId(link.hash().toStdString())));
// break;
// }
//
// personNotFound.append(PeerDefs::rsid(link.name().toUtf8().constData(), RsPgpId(link.hash().toStdString())));
}
break;
@ -1679,17 +1716,17 @@ void RSLinkClipboard::copyLinks(const QList<RetroShareLink>& links)
QApplication::clipboard()->setText(res) ;
}
void RSLinkClipboard::pasteLinks(QList<RetroShareLink> &links)
void RSLinkClipboard::pasteLinks(QList<RetroShareLink> &links,RetroShareLink::enumType type)
{
return parseClipboard(links);
return parseClipboard(links,type);
}
void RSLinkClipboard::parseClipboard(QList<RetroShareLink> &links)
void RSLinkClipboard::parseClipboard(QList<RetroShareLink> &links,RetroShareLink::enumType type)
{
// parse clipboard for links.
//
QString text = QApplication::clipboard()->text() ;
parseText(text, links);
parseText(text, links,type);
}
QString RSLinkClipboard::toString()
@ -1734,26 +1771,18 @@ bool RSLinkClipboard::empty(RetroShareLink::enumType type /* = RetroShareLink::T
return true;
}
/*static*/ int RSLinkClipboard::process(RetroShareLink::enumType type /* = RetroShareLink::TYPE_UNKNOWN*/, uint flag /* = RSLINK_PROCESS_NOTIFY_ALL*/)
int RSLinkClipboard::process(RetroShareLink::enumType type /* = RetroShareLink::TYPE_UNKNOWN*/, uint flag /* = RSLINK_PROCESS_NOTIFY_ALL*/)
{
QList<RetroShareLink> links;
pasteLinks(links);
pasteLinks(links,type);
QList<RetroShareLink> linksToProcess;
for (int i = 0; i < links.size(); ++i) {
if (links[i].valid() && (type == RetroShareLink::TYPE_UNKNOWN || links[i].type() == type)) {
linksToProcess.append(links[i]);
}
}
if (linksToProcess.isEmpty()) {
if (links.isEmpty())
return 0;
}
return RetroShareLink::process(linksToProcess, flag);
return RetroShareLink::process(links, flag);
}
void RSLinkClipboard::parseText(QString text, QList<RetroShareLink> &links)
void RSLinkClipboard::parseText(QString text, QList<RetroShareLink> &links,RetroShareLink::enumType type )
{
links.clear();
@ -1768,7 +1797,7 @@ void RSLinkClipboard::parseText(QString text, QList<RetroShareLink> &links)
QString url(text.mid(pos, rx.matchedLength()));
RetroShareLink link(url);
if(link.valid())
if(link.valid() && (type == RetroShareLink::TYPE_UNKNOWN || type == link.type()))
{
// check that the link is not already in the list:
bool already = false ;

View File

@ -69,7 +69,8 @@ class RetroShareLink
TYPE_PRIVATE_CHAT = 0x09,
TYPE_PUBLIC_MSG = 0x0a,
TYPE_POSTED = 0x0b,
TYPE_IDENTITY = 0x0c
TYPE_IDENTITY = 0x0c,
TYPE_FILE_TREE = 0x0d
};
public:
@ -80,6 +81,7 @@ class RetroShareLink
static RetroShareLink createIdentity(const RsGxsId& gxs_id,const QString& name,const QString& radix_data) ;
static RetroShareLink createExtraFile(const QString& name, uint64_t size, const QString& hash, const QString& ssl_id);
static RetroShareLink createFile(const QString& name, uint64_t size, const QString& hash);
static RetroShareLink createCollection(const QString& name, uint64_t size,uint32_t count,const QString& radix_data);
static RetroShareLink createPublicMsgInvite(time_t time_stamp,const QString& pgp_id,const QString& hash) ;
static RetroShareLink createPerson(const RsPgpId &id);
static RetroShareLink createCertificate(const RsPeerId &ssl_id) ;
@ -167,6 +169,7 @@ class RetroShareLink
QString _encrypted_chat_info ; // encrypted data string for the recipient of a chat invite
time_t _time_stamp ; // time stamp at which the link will expire.
QString _radix_group_data;
uint32_t _count ;
unsigned int _subType; // for general use as sub type for _type (RSLINK_SUBTYPE_...)
};
@ -189,7 +192,7 @@ class RSLinkClipboard
// Get the liste of pasted links, either from the internal RS links, or by default
// from the clipboard.
//
static void pasteLinks(QList<RetroShareLink> &links) ;
static void pasteLinks(QList<RetroShareLink> &links,RetroShareLink::enumType type = RetroShareLink::TYPE_UNKNOWN) ;
// Produces a list of links with no html structure.
static QString toString() ;
@ -212,10 +215,10 @@ class RSLinkClipboard
//
static int process(RetroShareLink::enumType type = RetroShareLink::TYPE_UNKNOWN, uint flag = RSLINK_PROCESS_NOTIFY_ALL);
static void parseText(QString text, QList<RetroShareLink> &links) ;
static void parseText(QString text, QList<RetroShareLink> &links, RetroShareLink::enumType type = RetroShareLink::TYPE_UNKNOWN) ;
private:
static void parseClipboard(QList<RetroShareLink> &links) ;
static void parseClipboard(QList<RetroShareLink> &links, RetroShareLink::enumType type = RetroShareLink::TYPE_UNKNOWN) ;
};
#endif

View File

@ -111,7 +111,7 @@ ChatWidget::ChatWidget(QWidget *parent) :
ui->searchButton->setFixedSize(buttonSize);
ui->searchButton->setIconSize(iconSize);
ui->sendButton->setFixedHeight(iconHeight);
ui->sendButton->setIconSize(iconSize);
ui->sendButton->setIconSize(iconSize);
//Initialize search
iCharToStartSearch=Settings->getChatSearchCharToStartSearch();
@ -295,6 +295,7 @@ void ChatWidget::init(const ChatId &chat_id, const QString &title)
this->title = title;
ui->titleLabel->setText(RsHtml::plainText(title));
ui->chatTextEdit->setMaxBytes(this->maxMessageSize() - 200);
RsPeerId ownId = rsPeers->getOwnId();
setName(QString::fromUtf8(rsPeers->getPeerName(ownId).c_str()));
@ -452,6 +453,25 @@ void ChatWidget::processSettings(bool load)
Settings->endGroup();
}
uint32_t ChatWidget::maxMessageSize()
{
uint32_t maxMessageSize = 0;
switch (chatType()) {
case CHATTYPE_UNKNOWN:
break;
case CHATTYPE_PRIVATE:
maxMessageSize = rsMsgs->getMaxMessageSecuritySize(RS_CHAT_TYPE_PRIVATE);
break;
case CHATTYPE_LOBBY:
maxMessageSize = rsMsgs->getMaxMessageSecuritySize(RS_CHAT_TYPE_LOBBY);
break;
case CHATTYPE_DISTANT:
maxMessageSize = rsMsgs->getMaxMessageSecuritySize(RS_CHAT_TYPE_DISTANT);
break;
}
return maxMessageSize;
}
bool ChatWidget::eventFilter(QObject *obj, QEvent *event)
{
if (obj == ui->textBrowser || obj == ui->textBrowser->viewport()
@ -1169,20 +1189,7 @@ void ChatWidget::updateLenOfChatTextEdit()
RsHtml::optimizeHtml(chatWidget, text);
std::wstring msg = text.toStdWString();
uint32_t maxMessageSize = 0;
switch (chatType()) {
case CHATTYPE_UNKNOWN:
break;
case CHATTYPE_PRIVATE:
maxMessageSize = rsMsgs->getMaxMessageSecuritySize(RS_CHAT_TYPE_PRIVATE);
break;
case CHATTYPE_LOBBY:
maxMessageSize = rsMsgs->getMaxMessageSecuritySize(RS_CHAT_TYPE_LOBBY);
break;
case CHATTYPE_DISTANT:
maxMessageSize = rsMsgs->getMaxMessageSecuritySize(RS_CHAT_TYPE_DISTANT);
break;
}
uint32_t maxMessageSize = this->maxMessageSize();
int charRemains = 0;
if (maxMessageSize > 0) {
@ -1561,7 +1568,8 @@ void ChatWidget::addExtraPicture()
QString file;
if (misc::getOpenFileName(window(), RshareSettings::LASTDIR_IMAGES, tr("Load Picture File"), "Pictures (*.png *.xpm *.jpg *.jpeg)", file)) {
QString encodedImage;
if (RsHtml::makeEmbeddedImage(file, encodedImage, 640*480)) {
uint32_t maxMessageSize = this->maxMessageSize();
if (RsHtml::makeEmbeddedImage(file, encodedImage, 640*480, maxMessageSize - 200)) { //-200 for the html stuff
QTextDocumentFragment fragment = QTextDocumentFragment::fromHtml(encodedImage);
ui->chatTextEdit->textCursor().insertFragment(fragment);
}

View File

@ -198,6 +198,8 @@ private:
void setColorAndFont(bool both);
void processSettings(bool load);
uint32_t maxMessageSize();
void completeNickname(bool reverse);
QAbstractItemModel *modelFromPeers();

View File

@ -11,21 +11,12 @@
</rect>
</property>
<layout class="QGridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="verticalSpacing">
<number>2</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item row="1" column="0">
<layout class="QHBoxLayout" name="textChatHLayout">
<property name="spacing">
@ -46,16 +37,7 @@
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="chatTextFrameVLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>0</number>
</property>
<item>
@ -131,16 +113,7 @@
<enum>QFrame::Box</enum>
</property>
<layout class="QHBoxLayout" name="infoFrameHLayout">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>6</number>
</property>
<item>
@ -308,7 +281,7 @@ border-image: url(:/images/closepressed.png)
<height>30</height>
</size>
</property>
<property name="placeholderText">
<property name="placeholderText" stdset="0">
<string>Type a message here</string>
</property>
</widget>
@ -326,16 +299,7 @@ border-image: url(:/images/closepressed.png)
<enum>QFrame::Sunken</enum>
</property>
<layout class="QHBoxLayout" name="toolBarFrameHLayout">
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>2</number>
</property>
<item>
@ -436,6 +400,41 @@ border-image: url(:/images/closepressed.png)
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="searchButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/search.png</normaloff>:/icons/png/search.png</iconset>
</property>
<property name="iconSize">
<size>
<width>28</width>
<height>28</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="LineEditClear" name="leSearch"/>
</item>
<item>
<widget class="QToolButton" name="markButton">
<property name="sizePolicy">
@ -465,9 +464,6 @@ border-image: url(:/images/closepressed.png)
</property>
</widget>
</item>
<item>
<widget class="LineEditClear" name="leSearch"/>
</item>
<item>
<widget class="QToolButton" name="searchBefore">
<property name="minimumSize">
@ -520,38 +516,6 @@ border-image: url(:/images/closepressed.png)
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="searchButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/search.png</normaloff>:/icons/png/search.png</iconset>
</property>
<property name="iconSize">
<size>
<width>28</width>
<height>28</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="notifyButton">
<property name="focusPolicy">
@ -581,16 +545,7 @@ border-image: url(:/images/closepressed.png)
<enum>QFrame::Plain</enum>
</property>
<layout class="QHBoxLayout" name="pluginButtonFrameHLayout">
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>2</number>
</property>
</layout>
@ -688,16 +643,7 @@ border-image: url(:/images/closepressed.png)
<enum>QFrame::Sunken</enum>
</property>
<layout class="QHBoxLayout" name="titleBarFrameHLayout">
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>2</number>
</property>
<item>
@ -778,16 +724,7 @@ border-image: url(:/images/closepressed.png)
<enum>QFrame::Plain</enum>
</property>
<layout class="QHBoxLayout" name="pluginTitleFrameHLayout">
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>2</number>
</property>
</layout>

View File

@ -23,7 +23,7 @@
#include <QFileInfo>
#include "FilesDefs.h"
#include "RsCollectionFile.h"
#include "RsCollection.h"
static QString getInfoFromFilename(const QString& filename, bool anyForUnknown, bool image)
{
@ -54,7 +54,7 @@ static QString getInfoFromFilename(const QString& filename, bool anyForUnknown,
return image ? ":/images/FileTypeDocument.png" : QApplication::translate("FilesDefs", "Document");
} else if (ext == "pdf") {
return image ? ":/images/mimetypes/pdf.png" : QApplication::translate("FilesDefs", "Document");
} else if (ext == RsCollectionFile::ExtensionString) {
} else if (ext == RsCollection::ExtensionString) {
return image ? ":/images/mimetypes/rscollection-16.png" : QApplication::translate("FilesDefs", "RetroShare collection file");
} else if (ext == "sub" || ext == "srt") {
return image ? ":/images/FileTypeAny.png" : QApplication::translate("FilesDefs", "Subtitles");

View File

@ -69,7 +69,7 @@ void MimeTextEdit::insertFromMimeData(const QMimeData* source)
QImage image = qvariant_cast<QImage>(source->imageData());
if (image.isNull() == false) {
QString encodedImage;
if (RsHtml::makeEmbeddedImage(image, encodedImage, 640*480)) {
if (RsHtml::makeEmbeddedImage(image, encodedImage, 640*480, mMaxBytes)) {
QTextDocumentFragment fragment = QTextDocumentFragment::fromHtml(encodedImage);
textCursor().insertFragment(fragment);
return;

View File

@ -50,6 +50,8 @@ public:
QColor textColorQuote() const { return highliter->textColorQuote();}
bool onlyPlainText() const {return mOnlyPlainText;}
void setMaxBytes(int limit) {mMaxBytes = limit;}
public slots:
void setTextColorQuote(QColor textColorQuote) { highliter->setTextColorQuote(textColorQuote);}
void setOnlyPlainText(bool bOnlyPlainText) {mOnlyPlainText = bOnlyPlainText;}
@ -83,6 +85,7 @@ private:
QList<QAction*> mContextMenuActions;
RsSyntaxHighlighter *highliter;
bool mOnlyPlainText;
int mMaxBytes = -1; //limit content size, for pasting images
};
#endif // MIMETEXTEDIT_H

View File

@ -24,7 +24,7 @@
#include <stdexcept>
#include <retroshare/rsfiles.h>
#include "RsCollectionFile.h"
#include "RsCollection.h"
#include "RsCollectionDialog.h"
#include "util/misc.h"
@ -36,28 +36,41 @@
#include <QMessageBox>
#include <QIcon>
const QString RsCollectionFile::ExtensionString = QString("rscollection") ;
// #define COLLECTION_DEBUG 1
RsCollectionFile::RsCollectionFile(QObject *parent)
const QString RsCollection::ExtensionString = QString("rscollection") ;
RsCollection::RsCollection(QObject *parent)
: QObject(parent), _xml_doc("RsCollection")
{
_root = _xml_doc.createElement("RsCollection");
_xml_doc.appendChild(_root);
}
RsCollectionFile::RsCollectionFile(const std::vector<DirDetails>& file_infos, QObject *parent)
RsCollection::RsCollection(const FileTree& fr)
: _xml_doc("RsCollection")
{
_root = _xml_doc.createElement("RsCollection");
_xml_doc.appendChild(_root);
recursAddElements(_xml_doc,fr,0,_root) ;
}
RsCollection::RsCollection(const std::vector<DirDetails>& file_infos, QObject *parent)
: QObject(parent), _xml_doc("RsCollection")
{
QDomElement root = _xml_doc.createElement("RsCollection");
_xml_doc.appendChild(root);
_root = _xml_doc.createElement("RsCollection");
_xml_doc.appendChild(_root);
for(uint32_t i = 0;i<file_infos.size();++i)
recursAddElements(_xml_doc,file_infos[i],root) ;
recursAddElements(_xml_doc,file_infos[i],_root) ;
}
RsCollectionFile::~RsCollectionFile()
RsCollection::~RsCollection()
{
}
void RsCollectionFile::downloadFiles() const
void RsCollection::downloadFiles() const
{
// print out the element names of all elements that are direct children
// of the outermost element.
@ -87,17 +100,35 @@ static QString purifyFileName(const QString& input,bool& bad)
return output ;
}
void RsCollectionFile::recursCollectColFileInfos(const QDomElement& e,std::vector<ColFileInfo>& colFileInfos,const QString& current_path, bool bad_chars_in_parent) const
void RsCollection::merge_in(const QString& fname,uint64_t size,const RsFileHash& hash)
{
ColFileInfo info ;
info.type = DIR_TYPE_FILE ;
info.name = fname ;
info.size = size ;
info.hash = QString::fromStdString(hash.toStdString()) ;
recursAddElements(_xml_doc,info,_root) ;
}
void RsCollection::merge_in(const FileTree& tree)
{
recursAddElements(_xml_doc,tree,0,_root) ;
}
void RsCollection::recursCollectColFileInfos(const QDomElement& e,std::vector<ColFileInfo>& colFileInfos,const QString& current_path, bool bad_chars_in_parent) const
{
QDomNode n = e.firstChild() ;
#ifdef COLLECTION_DEBUG
std::cerr << "Parsing element " << e.tagName().toStdString() << std::endl;
#endif
while(!n.isNull())
{
QDomElement ee = n.toElement(); // try to convert the node to an element.
#ifdef COLLECTION_DEBUG
std::cerr << " Seeing child " << ee.tagName().toStdString() << std::endl;
#endif
if(ee.tagName() == QString("File"))
{
@ -139,7 +170,7 @@ void RsCollectionFile::recursCollectColFileInfos(const QDomElement& e,std::vecto
}
void RsCollectionFile::recursAddElements(QDomDocument& doc,const DirDetails& details,QDomElement& e) const
void RsCollection::recursAddElements(QDomDocument& doc,const DirDetails& details,QDomElement& e) const
{
if (details.type == DIR_TYPE_FILE)
{
@ -175,7 +206,7 @@ void RsCollectionFile::recursAddElements(QDomDocument& doc,const DirDetails& det
}
}
void RsCollectionFile::recursAddElements(QDomDocument& doc,const ColFileInfo& colFileInfo,QDomElement& e) const
void RsCollection::recursAddElements(QDomDocument& doc,const ColFileInfo& colFileInfo,QDomElement& e) const
{
if (colFileInfo.type == DIR_TYPE_FILE)
{
@ -186,7 +217,7 @@ void RsCollectionFile::recursAddElements(QDomDocument& doc,const ColFileInfo& co
f.setAttribute(QString("size"),QString::number(colFileInfo.size)) ;
e.appendChild(f) ;
}
}
else if (colFileInfo.type == DIR_TYPE_DIR)
{
QDomElement d = doc.createElement("Directory") ;
@ -194,21 +225,47 @@ void RsCollectionFile::recursAddElements(QDomDocument& doc,const ColFileInfo& co
d.setAttribute(QString("name"),colFileInfo.name) ;
for (std::vector<ColFileInfo>::const_iterator it = colFileInfo.children.begin(); it != colFileInfo.children.end(); ++it)
{
recursAddElements(doc,(*it),d) ;
}
e.appendChild(d) ;
}
}
void RsCollection::recursAddElements(QDomDocument& doc,const FileTree& ft,uint32_t index,QDomElement& e) const
{
std::vector<uint32_t> subdirs ;
std::vector<FileTree::FileData> subfiles ;
std::string name;
if(!ft.getDirectoryContent(index,name,subdirs,subfiles))
return ;
QDomElement d = doc.createElement("Directory") ;
d.setAttribute(QString("name"),QString::fromUtf8(name.c_str())) ;
e.appendChild(d) ;
for (uint32_t i=0;i<subdirs.size();++i)
recursAddElements(doc,ft,subdirs[i],d) ;
for(uint32_t i=0;i<subfiles.size();++i)
{
QDomElement f = doc.createElement("File") ;
f.setAttribute(QString("name"),QString::fromUtf8(subfiles[i].name.c_str())) ;
f.setAttribute(QString("sha1"),QString::fromStdString(subfiles[i].hash.toStdString())) ;
f.setAttribute(QString("size"),QString::number(subfiles[i].size)) ;
d.appendChild(f) ;
}
}
static void showErrorBox(const QString& fileName, const QString& error)
{
QMessageBox mb(QMessageBox::Warning, QObject::tr("Failed to process collection file"), QObject::tr("The collection file %1 could not be opened.\nReported error is: \n\n%2").arg(fileName).arg(error), QMessageBox::Ok);
mb.exec();
}
bool RsCollectionFile::load(const QString& fileName, bool showError /* = true*/)
bool RsCollection::load(const QString& fileName, bool showError /* = true*/)
{
if (!checkFile(fileName,showError)) return false;
@ -235,10 +292,10 @@ bool RsCollectionFile::load(const QString& fileName, bool showError /* = true*/)
}
return ok;
}
}
// check that the file is a valid rscollection file, and not a lol bomb or some shit like this
bool RsCollectionFile::checkFile(const QString& fileName, bool showError)
bool RsCollection::checkFile(const QString& fileName, bool showError)
{
QFile file(fileName);
@ -305,11 +362,10 @@ bool RsCollectionFile::checkFile(const QString& fileName, bool showError)
}
return false;
}
bool RsCollectionFile::load(QWidget *parent)
bool RsCollection::load(QWidget *parent)
{
QString fileName;
if (!misc::getOpenFileName(parent, RshareSettings::LASTDIR_EXTRAFILE, QApplication::translate("RsCollectionFile", "Open collection file"), QApplication::translate("RsCollectionFile", "Collection files") + " (*." + RsCollectionFile::ExtensionString + ")", fileName))
if (!misc::getOpenFileName(parent, RshareSettings::LASTDIR_EXTRAFILE, QApplication::translate("RsCollectionFile", "Open collection file"), QApplication::translate("RsCollectionFile", "Collection files") + " (*." + RsCollection::ExtensionString + ")", fileName))
return false;
std::cerr << "Got file name: " << fileName.toStdString() << std::endl;
@ -317,7 +373,7 @@ bool RsCollectionFile::load(QWidget *parent)
return load(fileName, true);
}
bool RsCollectionFile::save(const QString& fileName) const
bool RsCollection::save(const QString& fileName) const
{
QFile file(fileName);
@ -337,14 +393,14 @@ bool RsCollectionFile::save(const QString& fileName) const
return true;
}
bool RsCollectionFile::save(QWidget *parent) const
bool RsCollection::save(QWidget *parent) const
{
QString fileName;
if(!misc::getSaveFileName(parent, RshareSettings::LASTDIR_EXTRAFILE, QApplication::translate("RsCollectionFile", "Create collection file"), QApplication::translate("RsCollectionFile", "Collection files") + " (*." + RsCollectionFile::ExtensionString + ")", fileName))
if(!misc::getSaveFileName(parent, RshareSettings::LASTDIR_EXTRAFILE, QApplication::translate("RsCollectionFile", "Create collection file"), QApplication::translate("RsCollectionFile", "Collection files") + " (*." + RsCollection::ExtensionString + ")", fileName))
return false;
if (!fileName.endsWith("." + RsCollectionFile::ExtensionString))
fileName += "." + RsCollectionFile::ExtensionString ;
if (!fileName.endsWith("." + RsCollection::ExtensionString))
fileName += "." + RsCollection::ExtensionString ;
std::cerr << "Got file name: " << fileName.toStdString() << std::endl;
@ -352,17 +408,17 @@ bool RsCollectionFile::save(QWidget *parent) const
}
bool RsCollectionFile::openNewColl(QWidget *parent)
bool RsCollection::openNewColl(QWidget *parent)
{
QString fileName;
if(!misc::getSaveFileName(parent, RshareSettings::LASTDIR_EXTRAFILE
, QApplication::translate("RsCollectionFile", "Create collection file")
, QApplication::translate("RsCollectionFile", "Collection files") + " (*." + RsCollectionFile::ExtensionString + ")"
, QApplication::translate("RsCollectionFile", "Collection files") + " (*." + RsCollection::ExtensionString + ")"
, fileName,0, QFileDialog::DontConfirmOverwrite))
return false;
if (!fileName.endsWith("." + RsCollectionFile::ExtensionString))
fileName += "." + RsCollectionFile::ExtensionString ;
if (!fileName.endsWith("." + RsCollection::ExtensionString))
fileName += "." + RsCollection::ExtensionString ;
std::cerr << "Got file name: " << fileName.toStdString() << std::endl;
@ -419,7 +475,7 @@ bool RsCollectionFile::openNewColl(QWidget *parent)
return _saved;
}
bool RsCollectionFile::openColl(const QString& fileName, bool readOnly /* = false */, bool showError /* = true*/)
bool RsCollection::openColl(const QString& fileName, bool readOnly /* = false */, bool showError /* = true*/)
{
if (load(fileName, showError)) {
std::vector<ColFileInfo> colFileInfos ;
@ -433,11 +489,11 @@ bool RsCollectionFile::openColl(const QString& fileName, bool readOnly /* = fals
delete rcd;
return _saved;
}//if (load(fileName, showError))
}
return false;
}
qulonglong RsCollectionFile::size()
qulonglong RsCollection::size()
{
QDomElement docElem = _xml_doc.documentElement();
@ -453,14 +509,14 @@ qulonglong RsCollectionFile::size()
return size;
}
bool RsCollectionFile::isCollectionFile(const QString &fileName)
bool RsCollection::isCollectionFile(const QString &fileName)
{
QString ext = QFileInfo(fileName).suffix().toLower();
return (ext == RsCollectionFile::ExtensionString);
return (ext == RsCollection::ExtensionString);
}
void RsCollectionFile::saveColl(std::vector<ColFileInfo> colFileInfos, const QString &fileName)
void RsCollection::saveColl(std::vector<ColFileInfo> colFileInfos, const QString &fileName)
{
QDomElement root = _xml_doc.elementsByTagName("RsCollection").at(0).toElement();

View File

@ -56,27 +56,29 @@ public:
};
Q_DECLARE_METATYPE(ColFileInfo)
class RsCollectionFile : public QObject
class RsCollection : public QObject
{
Q_OBJECT
public:
RsCollectionFile(QObject *parent = 0) ;
// create from list of files and directories
RsCollectionFile(const std::vector<DirDetails>& file_entries, QObject *parent = 0) ;
virtual ~RsCollectionFile() ;
RsCollection(QObject *parent = 0) ;
// create from list of files and directories
RsCollection(const std::vector<DirDetails>& file_entries, QObject *parent = 0) ;
RsCollection(const FileTree& fr);
virtual ~RsCollection() ;
void merge_in(const QString& fname,uint64_t size,const RsFileHash& hash) ;
void merge_in(const FileTree& tree) ;
static const QString ExtensionString ;
// Loads file from disk.
bool load(QWidget *parent);
// Loads file from disk.
bool load(QWidget *parent);
bool load(const QString& fileName, bool showError = true);
// Save to disk
bool save(QWidget *parent) const ;
// Save to disk
bool save(QWidget *parent) const ;
bool save(const QString& fileName) const ;
// Open new collection
@ -84,28 +86,31 @@ public:
// Open existing collection
bool openColl(const QString& fileName, bool readOnly = false, bool showError = true);
// Download the content.
void downloadFiles() const ;
// Download the content.
void downloadFiles() const ;
qulonglong size();
qulonglong size();
static bool isCollectionFile(const QString& fileName);
private slots:
void saveColl(std::vector<ColFileInfo> colFileInfos, const QString& fileName);
private:
private:
void recursAddElements(QDomDocument&,const DirDetails&,QDomElement&) const ;
void recursAddElements(QDomDocument&,const DirDetails&,QDomElement&) const ;
void recursAddElements(QDomDocument&,const ColFileInfo&,QDomElement&) const;
void recursAddElements(QDomDocument& doc,const FileTree& ft,uint32_t index,QDomElement& e) const;
void recursCollectColFileInfos(const QDomElement&,std::vector<ColFileInfo>& colFileInfos,const QString& current_dir,bool bad_chars_in_parent) const ;
// check that the file is a valid rscollection file, and not a lol bomb or some shit like this
static bool checkFile(const QString &fileName, bool showError);
QDomDocument _xml_doc ;
QDomDocument _xml_doc ;
QString _fileName ;
bool _saved;
QDomElement _root ;
friend class RsCollectionDialog ;
friend class RsCollectionDialog ;
};

View File

@ -23,13 +23,14 @@
#include <QCheckBox>
#include <QMessageBox>
#include <QMenu>
#include <QTextEdit>
#include <QDir>
#include <QKeyEvent>
#include <QDateTime>
#include <QInputDialog>
#include "RsCollectionDialog.h"
#include "RsCollectionFile.h"
#include "RsCollection.h"
#include "util/misc.h"
#define COLUMN_FILE 0
#define COLUMN_FILEPATH 1
@ -50,6 +51,7 @@
#define MAX_FILE_ADDED_BEFORE_ASK 500 //Number of file added in Recursive mode before asking to continue
#define IMAGE_SEARCH ":/icons/svg/magnifying-glass.svg"
/**
* @brief The FSMSortFilterProxyModel class sort directory before file.
@ -138,7 +140,23 @@ RsCollectionDialog::RsCollectionDialog(const QString& collectionFileName
ui.headerFrame->setHeaderImage(QPixmap(":/images/library64.png"));
ui.headerFrame->setHeaderText(tr("Collection Editor"));
if(creation)
{
ui.headerFrame->setHeaderText(tr("Collection Editor"));
ui.downloadFolder_LE->hide();
ui.downloadFolder_LB->hide();
}
else
{
ui.headerFrame->setHeaderText(tr("Download files"));
ui.downloadFolder_LE->show();
ui.downloadFolder_LB->show();
ui.downloadFolder_LE->setText(QString::fromUtf8(rsFiles->getDownloadDirectory().c_str())) ;
QObject::connect(ui.downloadFolder_LE,SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(openDestinationDirectoryMenu(QPoint)));
}
// 1 - add all elements to the list.
@ -209,6 +227,46 @@ RsCollectionDialog::RsCollectionDialog(const QString& collectionFileName
QMessageBox::warning(NULL,tr("Bad filenames have been cleaned"),tr("Some filenames or directory names contained forbidden characters.\nCharacters <b>\",|,/,\\,&lt;,&gt;,*,?</b> will be replaced by '_'.\n Concerned files are listed in red.")) ;
}
void RsCollectionDialog::openDestinationDirectoryMenu(QPoint)
{
QMenu contextMnu( this );
// pop a menu with existing entries and also a custom entry
// Now get the list of existing directories.
std::list< SharedDirInfo> dirs ;
rsFiles->getSharedDirectories( dirs) ;
for (std::list<SharedDirInfo>::const_iterator it(dirs.begin());it!=dirs.end();++it){
// Check for existence of directory name
QFile directory( QString::fromUtf8((*it).filename.c_str())) ;
if (!directory.exists()) continue ;
if (!(directory.permissions() & QFile::WriteOwner)) continue ;
contextMnu.addAction(QString::fromUtf8((*it).filename.c_str()), this, SLOT(setDestinationDirectory()))->setData(QString::fromUtf8( (*it).filename.c_str() ) ) ;
}
contextMnu.addAction( QIcon(IMAGE_SEARCH),tr("Specify..."),this,SLOT(chooseDestinationDirectory()));
contextMnu.exec(QCursor::pos()) ;
}
void RsCollectionDialog::setDestinationDirectory()
{
QString dest_dir(qobject_cast<QAction*>(sender())->data().toString()) ;
ui.downloadFolder_LE->setText(dest_dir) ;
}
void RsCollectionDialog::chooseDestinationDirectory()
{
QString dest_dir = QFileDialog::getExistingDirectory(this,tr("Choose directory")) ;
if(dest_dir.isNull())
return ;
ui.downloadFolder_LE->setText(dest_dir) ;
}
/**
* @brief RsCollectionDialog::~RsCollectionDialog
*/
@ -243,26 +301,26 @@ bool RsCollectionDialog::eventFilter(QObject *obj, QEvent *event)
for (it = selectedItems.begin(); it != selectedItems.end(); ++it) {
if ((*it)->checkState(COLUMN_FILE) != checkState)
(*it)->setCheckState(COLUMN_FILE, checkState);
}//for (it
}//if (item)
}
}
return true; // eat event
}//if (keyEvent && keyEvent->key() == Qt::Key_Space)
}
if (keyEvent && (keyEvent->key() == Qt::Key_Delete)) {
// Delete pressed
remove();
return true; // eat event
}//if (keyEvent && keyEvent->key() == Qt::Key_Delete)
}
if (keyEvent && (keyEvent->key() == Qt::Key_Plus)) {
// Plus pressed
makeDir();
return true; // eat event
}//if (keyEvent && keyEvent->key() == Qt::Key_Plus)
}
}//if (event->type() == QEvent::KeyPress)
}//if (obj == ui._fileEntriesTW)
}
}
if (obj == ui._systemFileTW) {
if (event->type() == QEvent::KeyPress) {
@ -277,9 +335,9 @@ bool RsCollectionDialog::eventFilter(QObject *obj, QEvent *event)
}
return true; // eat event
}//if (keyEvent && keyEvent->key() == Qt::Key_Enter...
}//if (event->type() == QEvent::KeyPress)
}//if (obj == ui._systemFileTW)
}
}
}
// pass the event on to the parent class
return QDialog::eventFilter(obj, event);
@ -452,7 +510,7 @@ bool RsCollectionDialog::addChild(QTreeWidgetItem* parent, const std::vector<Col
item->setToolTip(COLUMN_FILEC, tr("Real File Count=%1").arg(1));
item->setData(COLUMN_FILEC, ROLE_FILEC, 1);
item->setData(COLUMN_FILEC, ROLE_SELFILEC, 1);
}//if (colFileInfo.type==DIR_TYPE_DIR
}
item->setFont(COLUMN_FILE, font);
if (colFileInfo.filename_has_wrong_characters)
@ -487,12 +545,12 @@ bool RsCollectionDialog::addChild(QTreeWidgetItem* parent, const std::vector<Col
itemParent->setText(COLUMN_FILEC, QString("%1").arg(parentSelFileCount));
itemParent = itemParent->parent();
}//while (itemParent)
}//if (itemParent)
}//if (colFileInfo.type==DIR_TYPE_FILE)
}
}
}
founds.push_back(item);
}//(founds.empty())
}
if (!founds.empty()) {
@ -591,12 +649,12 @@ void RsCollectionDialog::changeFileName()
QString fileName;
if(!misc::getSaveFileName(this, RshareSettings::LASTDIR_EXTRAFILE
, QApplication::translate("RsCollectionFile", "Create collection file")
, QApplication::translate("RsCollectionFile", "Collection files") + " (*." + RsCollectionFile::ExtensionString + ")"
, QApplication::translate("RsCollectionFile", "Collection files") + " (*." + RsCollection::ExtensionString + ")"
, fileName,0, QFileDialog::DontConfirmOverwrite))
return;
if (!fileName.endsWith("." + RsCollectionFile::ExtensionString))
fileName += "." + RsCollectionFile::ExtensionString ;
if (!fileName.endsWith("." + RsCollection::ExtensionString))
fileName += "." + RsCollection::ExtensionString ;
std::cerr << "Got file name: " << fileName.toStdString() << std::endl;
@ -604,7 +662,7 @@ void RsCollectionDialog::changeFileName()
if(file.exists())
{
RsCollectionFile collFile;
RsCollection collFile;
if (!collFile.checkFile(fileName,true)) return;
QMessageBox mb;
@ -624,7 +682,7 @@ void RsCollectionDialog::changeFileName()
if (qddOldFile.setContent(&file)) {
QDomElement docOldElem = qddOldFile.elementsByTagName("RsCollection").at(0).toElement();
collFile.recursCollectColFileInfos(docOldElem,_newColFileInfos,QString(),false);
}//(qddOldFile.setContent(&file))
}
} else if (mb.clickedButton()==btnCancel) {
return;
@ -636,7 +694,7 @@ void RsCollectionDialog::changeFileName()
//create a new empty file to check if name if good.
if (!file.open(QFile::WriteOnly)) return;
file.remove();
}//if(file.exists())
}
_fileName = fileName;
@ -686,7 +744,7 @@ void RsCollectionDialog::addRecursive(bool recursive)
} else {
continue;
}
}//if (fileInfo.isDir())
}
if (fileInfo.isFile()){
fileToHash.append(fileInfo.absoluteFilePath());
++count;
@ -694,9 +752,9 @@ void RsCollectionDialog::addRecursive(bool recursive)
_listOfFilesAddedInDir.insert(fileInfo.absoluteFilePath(),fileInfo.absolutePath());
else
_listOfFilesAddedInDir.insert(fileInfo.absoluteFilePath(),"");
}//if (fileInfo.isFile())
}//if (index.column()==0)
}//foreach (QModelIndex index, milSelectionList)
}
}
}
// Process Dirs
QTreeWidgetItem *item = NULL;
@ -705,8 +763,8 @@ void RsCollectionDialog::addRecursive(bool recursive)
if (item) {
while (item->data(COLUMN_HASH, ROLE_TYPE).toUInt() != DIR_TYPE_DIR) {
item = item->parent();//Only Dir as Parent
}//while
}//if (item)
}
}
int index = 0;
while (index < dirToAdd.count())
@ -722,7 +780,7 @@ void RsCollectionDialog::addRecursive(bool recursive)
//QMap is ordered, so we get parent before child
//Iterator is moved inside this function
processItem(dirToAdd, index, root);
}//while (index < dirToAdd.count())
}
//Update liste before attach files to be sure when file is hashed, parent directory exists.
updateList();
@ -736,9 +794,9 @@ void RsCollectionDialog::addRecursive(bool recursive)
} else if(item) {
if (item->data(COLUMN_HASH, ROLE_NAME) != "") {
it.value() = item->text(COLUMN_FILEPATH);
}//if (item->data(COLUMN_HASH, ROLE_NAME) != "")
}//if (dirToAdd.contains(path))
}//for (QHash<QString,QString>::Iterator it
}
}
}
// Process Files once all done
ui._hashBox->addAttachments(fileToHash,RS_FILE_REQ_ANONYMOUS_ROUTING /*, 0*/);
@ -781,13 +839,13 @@ bool RsCollectionDialog::addAllChild(QFileInfo &fileInfoParent
default:
// should never be reached
break;
}//switch (ret)
}
}
if (fileInfo.isDir()) {
dirToAdd.insert(fileInfo.absoluteFilePath(),fileInfo.absolutePath());
++count;
if (!addAllChild(fileInfo, dirToAdd, fileToHash, count)) return false;
}//if (fileInfo.isDir())
}
if (fileInfo.isFile()){
fileToHash.append(fileInfo.absoluteFilePath());
++count;
@ -795,8 +853,8 @@ bool RsCollectionDialog::addAllChild(QFileInfo &fileInfoParent
_listOfFilesAddedInDir.insert(fileInfo.absoluteFilePath(),fileInfo.absolutePath());
else
_listOfFilesAddedInDir.insert(fileInfo.absoluteFilePath(),"");
}//if (fileInfo.isFile())
}//foreach (QFileInfo fileInfo, dirParent.entryInfoList())
}
}
return true;
}
@ -821,10 +879,10 @@ void RsCollectionDialog::remove()
item->setSelected(false);
} else {
listDir += item->data(COLUMN_HASH, ROLE_NAME).toString() +"<br>";
}//if (listDir.contains(item->data(COLUMN_HASH, ROLE_PATH).toString()))
}//if (item->data(COLUMN_HASH, ROLE_TYPE).toUInt() == DIR_TYPE_DIR)
}//if (item != getRootItem())
}//for (int curs = 0; curs < count; ++curs)
}
}
}
}
//If directories, ask to remove them or not
if (!listDir.isEmpty()){
@ -870,14 +928,14 @@ void RsCollectionDialog::remove()
case QMessageBox::Cancel: {
delete msgBox;
return;
}//case QMessageBox::Cancel:
}
break;
default:
// should never be reached
break;
}//switch (ret)
}
delete msgBox;
}//if (!listDir.isEmpty())
}
//Remove wanted items
int leftItem = 0;
@ -966,7 +1024,7 @@ void RsCollectionDialog::processItem(QMap<QString, QString> &dirToAdd
} else {
_newColFileInfos.push_back(newChild);
}
}//(index < count)
}
}
/**
@ -1006,13 +1064,13 @@ void RsCollectionDialog::makeDir()
default:
// should never be reached
break;
}//switch (ret)
}//if (badChar)
}
}
} else {//if (ok && !childName.isEmpty())
return;
}//if (ok && !childName.isEmpty())
}
}//while (!nameOK)
}
// Process all selected items
int count = ui._fileEntriesTW->selectedItems().count();
@ -1040,8 +1098,8 @@ void RsCollectionDialog::makeDir()
if (item == getRootItem()) newChild.path = "";
_newColFileInfos.push_back(newChild);
}//if (item)
}//for (; curs < count; ++curs)
}
}
updateList();
@ -1074,7 +1132,7 @@ void RsCollectionDialog::fileHashingFinished(QList<HashedFile> hashedFiles)
//File Added in directory, find its parent
colFileInfo.path = _listOfFilesAddedInDir.value(hashedFile.filepath,"");
_listOfFilesAddedInDir.remove(hashedFile.filepath);
}//if (_listOfFilesAddedInDir.value(hashedFile.filepath,"")!="")
}
_newColFileInfos.push_back(colFileInfo);
@ -1112,7 +1170,7 @@ void RsCollectionDialog::itemChanged(QTreeWidgetItem *item, int col)
itemParent->setText(COLUMN_FILEC, QString("%1").arg(parentFileCount));
itemParent = itemParent->parent();
}//while (itemParent)
}
updateSizes() ;
@ -1222,7 +1280,7 @@ void RsCollectionDialog::download()
{
std::cerr << "Downloading!" << std::endl;
QString dldir = QString::fromUtf8(rsFiles->getDownloadDirectory().c_str()) ;
QString dldir = ui.downloadFolder_LE->text();
std::cerr << "downloading all these files:" << std::endl;
@ -1258,8 +1316,8 @@ void RsCollectionDialog::download()
std::list<RsPeerId>());
} else {//if (item->checkState(COLUMN_FILE) == Qt::Checked)
std::cerr<<"Skipping file : " << item->data(COLUMN_HASH,ROLE_NAME).toString().toStdString() << std::endl;
}//if (item->checkState(COLUMN_FILE) == Qt::Checked)
}//while ((item = *itemIterator) != NULL)
}
}
close();
}

View File

@ -22,7 +22,7 @@
****************************************************************/
#include "ui_RsCollectionDialog.h"
#include "RsCollectionFile.h"
#include "RsCollection.h"
#include <QFileSystemModel>
#include <QSortFilterProxyModel>
@ -49,6 +49,9 @@ private slots:
void add() ;
void addRecursive() ;
void remove() ;
void chooseDestinationDirectory();
void setDestinationDirectory();
void openDestinationDirectoryMenu(QPoint pt);
void processItem(QMap<QString, QString> &dirToAdd
, int &index
, ColFileInfo &parent

View File

@ -6,10 +6,13 @@
<rect>
<x>0</x>
<y>0</y>
<width>693</width>
<height>525</height>
<width>969</width>
<height>778</height>
</rect>
</property>
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="windowTitle">
<string>Collection</string>
</property>
@ -67,19 +70,7 @@
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QVBoxLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QFrame" name="_frameInfo">
<property name="sizePolicy">
@ -403,7 +394,7 @@
</widget>
</item>
<item>
<layout class="QHBoxLayout">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="_removeDuplicate_CB">
<property name="text">
@ -424,6 +415,26 @@
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="downloadFolder_LB">
<property name="text">
<string>Destination:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="downloadFolder_LE">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="toolTip">
<string>Right click to change download directory</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="_cancel_PB">
<property name="text">

View File

@ -22,14 +22,14 @@
#include <stdexcept>
#include <QDesktopServices>
#include <QUrl>
#include "RsCollectionFile.h"
#include "RsCollection.h"
#include "RsUrlHandler.h"
bool RsUrlHandler::openUrl(const QUrl& url)
{
if(url.scheme() == QString("file") && url.toLocalFile().endsWith("."+RsCollectionFile::ExtensionString))
if(url.scheme() == QString("file") && url.toLocalFile().endsWith("."+RsCollection::ExtensionString))
{
RsCollectionFile collection ;
RsCollection collection ;
if(collection.load(url.toLocalFile()))
{
collection.downloadFiles() ;

View File

@ -83,7 +83,7 @@ ConfCertDialog::ConfCertDialog(const RsPeerId& id, const RsPgpId &pgp_id, QWidge
{
/* Invoke Qt Designer generated QObject setup routine */
ui.setupUi(this);
Settings->loadWidgetInformation(this);
ui.headerFrame->setHeaderImage(QPixmap(":/images/user/identityinfo64.png"));
//ui.headerFrame->setHeaderText(tr("Friend node details"));
@ -105,6 +105,7 @@ ConfCertDialog::ConfCertDialog(const RsPeerId& id, const RsPgpId &pgp_id, QWidge
ConfCertDialog::~ConfCertDialog()
{
Settings->saveWidgetInformation(this);
QMap<RsPeerId, ConfCertDialog*>::iterator it = instances_ssl.find(peerId);
if (it != instances_ssl.end())
instances_ssl.erase(it);

View File

@ -475,33 +475,17 @@ void ConnectFriendWizard::initializePage(int id)
else
ui->addKeyToKeyring_CB->setToolTip(tr("Check this to add the key to your keyring\nThis might be useful for sending\ndistant messages to this peer\neven if you don't make friends.")) ;
//set the radio button to sign the GPG key
if (peerDetails.accept_connection && !peerDetails.ownsign) {
//gpg key connection is already accepted, don't propose to accept it again
ui->signGPGCheckBox->setChecked(false);
ui->acceptNoSignGPGCheckBox->hide();
ui->acceptNoSignGPGCheckBox->setChecked(false);
}
if (!peerDetails.accept_connection && peerDetails.ownsign) {
//gpg key is already signed, don't propose to sign it again
if(tmp_det.accept_connection) {
ui->acceptNoSignGPGCheckBox->setChecked(true);
ui->signGPGCheckBox->hide();
ui->signGPGCheckBox->setChecked(false);
ui->acceptNoSignGPGCheckBox->setEnabled(false);
ui->acceptNoSignGPGCheckBox->setToolTip(tr("This key is already on your trusted list"));
}
if (!peerDetails.accept_connection && !peerDetails.ownsign) {
ui->acceptNoSignGPGCheckBox->setChecked(true);
ui->signGPGCheckBox->show();
ui->signGPGCheckBox->setChecked(false);
ui->acceptNoSignGPGCheckBox->show();
}
if (peerDetails.accept_connection && peerDetails.ownsign) {
ui->acceptNoSignGPGCheckBox->setChecked(false);
ui->acceptNoSignGPGCheckBox->hide();
ui->signGPGCheckBox->setChecked(false);
ui->signGPGCheckBox->hide();
ui->alreadyRegisteredLabel->show();
} else {
else
ui->alreadyRegisteredLabel->hide();
if(tmp_det.ownsign) {
ui->signGPGCheckBox->setChecked(true);
ui->signGPGCheckBox->setEnabled(false);
ui->signGPGCheckBox->setToolTip(tr("You have already signed this key"));
}
QString trustString;

View File

@ -65,7 +65,7 @@ PGPKeyDialog::PGPKeyDialog(const RsPeerId& id, const RsPgpId &pgp_id, QWidget *p
{
/* Invoke Qt Designer generated QObject setup routine */
ui.setupUi(this);
Settings->loadWidgetInformation(this);
// if(id.isNull())
// ui._useOldFormat_CB->setChecked(true) ;
// else
@ -100,6 +100,7 @@ PGPKeyDialog::PGPKeyDialog(const RsPeerId& id, const RsPgpId &pgp_id, QWidget *p
PGPKeyDialog::~PGPKeyDialog()
{
Settings->saveWidgetInformation(this);
QMap<RsPgpId, PGPKeyDialog*>::iterator it = instances_pgp.find(pgpId);
if (it != instances_pgp.end())
instances_pgp.erase(it);

View File

@ -79,9 +79,9 @@ void SecurityIpItem::setup()
updateItem();
}
bool SecurityIpItem::isSame(const std::string& ipAddr, const std::string& ipAddrReported, uint32_t type)
bool SecurityIpItem::isSame(const RsPeerId &sslId, const std::string& ipAddr, const std::string& ipAddrReported, uint32_t type)
{
if (mType == type && mIpAddr == ipAddr && mIpAddrReported == ipAddrReported) {
if (mType == type && mSslId==sslId && mIpAddr == ipAddr && mIpAddrReported == ipAddrReported) {
return true;
}

View File

@ -44,7 +44,7 @@ public:
void updateItemStatic();
bool isSame(const std::string& ipAddr, const std::string& ipAddrReported, uint32_t type);
bool isSame(const RsPeerId &sslId, const std::string& ipAddr, const std::string& ipAddrReported, uint32_t type);
protected:
/* FeedItem */

View File

@ -34,6 +34,8 @@
#include <retroshare/rspeers.h>
#include <retroshare/rsgxscircles.h>
#include <gui/settings/rsharesettings.h>
#include <iostream>
// Control of Publish Signatures.
@ -66,7 +68,7 @@ GxsGroupDialog::GxsGroupDialog(TokenQueue *tokenExternalQueue, uint32_t enableFl
{
/* Invoke the Qt Designer generated object setup routine */
ui.setupUi(this);
mInternalTokenQueue = NULL;
init();
@ -87,6 +89,7 @@ GxsGroupDialog::GxsGroupDialog(TokenQueue *tokenExternalQueue, RsTokenService *t
GxsGroupDialog::~GxsGroupDialog()
{
Settings->saveWidgetInformation(this);
if (mInternalTokenQueue) {
delete(mInternalTokenQueue);
}
@ -134,6 +137,7 @@ void GxsGroupDialog::init()
ui.personal_required->setChecked(true) ; // this is always true
initMode();
Settings->loadWidgetInformation(this);
}
QIcon GxsGroupDialog::serviceWindowIcon()

View File

@ -121,6 +121,13 @@ GxsGroupFrameDialog::~GxsGroupFrameDialog()
delete(ui);
}
void GxsGroupFrameDialog::getGroupList(std::list<RsGroupMetaData>& group_list)
{
group_list = mCachedGroupMetas ;
if(group_list.empty())
requestGroupSummary();
}
void GxsGroupFrameDialog::initUi()
{
registerHelpButton(ui->helpButton, getHelpString(),pageName()) ;
@ -927,6 +934,8 @@ void GxsGroupFrameDialog::loadGroupSummary(const uint32_t &token)
RsUserdata *userdata = NULL;
loadGroupSummaryToken(token, groupInfo, userdata);
mCachedGroupMetas = groupInfo ;
insertGroupsData(groupInfo, userdata);
mStateHelper->setLoading(TOKEN_TYPE_GROUP_SUMMARY, false);

View File

@ -81,6 +81,8 @@ public:
virtual QString getHelpString() const =0;
virtual void getGroupList(std::list<RsGroupMetaData>& groups) ;
protected:
virtual void showEvent(QShowEvent *event);
virtual void updateDisplay(bool complete);
@ -197,6 +199,8 @@ private:
/** Qt Designer generated object */
Ui::GxsGroupFrameDialog *ui;
std::list<RsGroupMetaData> mCachedGroupMetas;
};
#endif

View File

@ -50,7 +50,7 @@ CreateGxsChannelMsg::CreateGxsChannelMsg(const RsGxsGroupId &cId, RsGxsMessageId
{
/* Invoke the Qt Designer generated object setup routine */
setupUi(this);
Settings->loadWidgetInformation(this);
mChannelQueue = new TokenQueue(rsGxsChannels->getTokenService(), this);
headerFrame->setHeaderImage(QPixmap(":/images/channels.png"));
@ -95,6 +95,7 @@ CreateGxsChannelMsg::CreateGxsChannelMsg(const RsGxsGroupId &cId, RsGxsMessageId
CreateGxsChannelMsg::~CreateGxsChannelMsg()
{
Settings->saveWidgetInformation(this);
#ifdef CHANNELS_FRAME_CATCHER
delete fCatcher;
#endif
@ -411,6 +412,11 @@ void CreateGxsChannelMsg::addExtraFile()
}
}
void CreateGxsChannelMsg::addHtmlText(const QString& text)
{
msgEdit->setHtml(text) ;
}
void CreateGxsChannelMsg::addAttachment(const std::string &path)
{
/* add a SubFileItem to the attachment section */

View File

@ -43,6 +43,7 @@ public:
/** Default Destructor */
~CreateGxsChannelMsg();
void addHtmlText(const QString& text) ;
void addAttachment(const std::string &path);
void addAttachment(const RsFileHash &hash, const std::string &fname, uint64_t size, bool local, const RsPeerId &srcId,bool assume_file_ready = false);

View File

@ -60,7 +60,7 @@
<bool>false</bool>
</property>
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="channelPostTab">
<attribute name="title">

View File

@ -27,6 +27,7 @@
#include "GxsChannelDialog.h"
#include "GxsChannelGroupDialog.h"
#include "GxsChannelPostsWidget.h"
#include "CreateGxsChannelMsg.h"
#include "GxsChannelUserNotify.h"
#include "gui/gxs/GxsGroupShareKey.h"
#include "gui/feeds/GxsChannelPostItem.h"
@ -76,6 +77,20 @@ UserNotify *GxsChannelDialog::getUserNotify(QObject *parent)
return new GxsChannelUserNotify(rsGxsChannels, parent);
}
void GxsChannelDialog::shareOnChannel(const RsGxsGroupId& channel_id,const QList<RetroShareLink>& file_links)
{
std::cerr << "Sharing file link on channel " << channel_id << ": Not yet implemented!" << std::endl;
CreateGxsChannelMsg *msgDialog = new CreateGxsChannelMsg(channel_id) ;
QString txt ;
for(QList<RetroShareLink>::const_iterator it(file_links.begin());it!=file_links.end();++it)
txt += (*it).toHtml() + "\n" ;
msgDialog->addHtmlText(txt);
msgDialog->show();
}
QString GxsChannelDialog::text(TextType type)
{
switch (type) {

View File

@ -42,6 +42,8 @@ public:
virtual UserNotify *getUserNotify(QObject *parent);
void shareOnChannel(const RsGxsGroupId& channel_id, const QList<RetroShareLink>& file_link) ;
protected:
/* GxsGroupFrameDialog */
virtual RetroShareLink::enumType getLinkType() { return RetroShareLink::TYPE_CHANNEL; }

View File

@ -75,6 +75,8 @@ GxsChannelPostsWidget::GxsChannelPostsWidget(const RsGxsGroupId &channelId, QWid
connect(ui->subscribeToolButton, SIGNAL(subscribe(bool)), this, SLOT(subscribeGroup(bool)));
connect(NotifyQt::getInstance(), SIGNAL(settingsChanged()), this, SLOT(settingsChanged()));
ui->postButton->setText(tr("Add new post"));
/* add filter actions */
ui->filterLineEdit->addFilter(QIcon(), tr("Title"), FILTER_TITLE, tr("Search Title"));
ui->filterLineEdit->addFilter(QIcon(), tr("Message"), FILTER_MSG, tr("Search Message"));

View File

@ -169,6 +169,9 @@
<property name="toolTip">
<string>Post to Channel</string>
</property>
<property name="text">
<string>Add new post</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/mail_send.png</normaloff>:/images/mail_send.png</iconset>
@ -179,6 +182,9 @@
<height>16</height>
</size>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>

View File

@ -210,6 +210,9 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget
connect(ui->newmessageButton, SIGNAL(clicked()), this, SLOT(replytoforummessage()));
connect(ui->newthreadButton, SIGNAL(clicked()), this, SLOT(createthread()));
ui->newmessageButton->setText(tr("Reply"));
ui->newthreadButton->setText(tr("New thread"));
connect(ui->threadTreeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(changedThread()));
connect(ui->threadTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(clickedThread(QTreeWidgetItem*,int)));
connect(ui->viewBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changedViewBox()));
@ -228,6 +231,7 @@ GxsForumThreadWidget::GxsForumThreadWidget(const RsGxsGroupId &forumId, QWidget
/* Set own item delegate */
RSElidedItemDelegate *itemDelegate = new RSElidedItemDelegate(this);
itemDelegate->setSpacing(QSize(0, 2));
itemDelegate->setOnlyPlainText(true);
ui->threadTreeWidget->setItemDelegate(itemDelegate);
/* Set header resize modes and initial section sizes */

View File

@ -84,6 +84,9 @@
<property name="toolTip">
<string>Start new Thread for Selected Forum</string>
</property>
<property name="text">
<string>New Thread</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/mail_new.png</normaloff>:/images/mail_new.png</iconset>
@ -94,6 +97,9 @@
<height>16</height>
</size>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
@ -306,8 +312,8 @@
<widget class="QToolButton" name="newmessageButton">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="focusPolicy">
@ -316,10 +322,16 @@
<property name="toolTip">
<string>Reply Message</string>
</property>
<property name="text">
<string>Reply</string>
</property>
<property name="icon">
<iconset resource="../images.qrc">
<normaloff>:/images/mail_reply.png</normaloff>:/images/mail_reply.png</iconset>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
@ -358,7 +370,7 @@
</property>
</widget>
</item>
<item row="0" column="8">
<item row="0" column="9">
<widget class="Line" name="lineRight">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -471,7 +483,7 @@
</property>
</widget>
</item>
<item row="0" column="9">
<item row="0" column="8">
<widget class="QComboBox" name="versions_CB"/>
</item>
<item row="0" column="7">

View File

@ -301,8 +301,15 @@ void AppearancePage::load()
whileBlocking(ui.checkBoxDisableSysTrayToolTip)->setChecked(Settings->valueFromGroup("StatusBar", "DisableSysTrayToolTip", QVariant(false)).toBool());
whileBlocking(ui.checkBoxShowStatusStatus)-> setChecked(Settings->valueFromGroup("StatusBar", "ShowStatus", QVariant(true)).toBool());
whileBlocking(ui.checkBoxShowPeerStatus)-> setChecked(Settings->valueFromGroup("StatusBar", "ShowPeer", QVariant(true)).toBool());
whileBlocking(ui.checkBoxShowNATStatus)-> setChecked(Settings->valueFromGroup("StatusBar", "ShowNAT", QVariant(true)).toBool());
whileBlocking(ui.checkBoxShowDHTStatus)-> setChecked(Settings->valueFromGroup("StatusBar", "ShowDHT", QVariant(true)).toBool());
if(MainWindow::hiddenmode) {
whileBlocking(ui.checkBoxShowNATStatus)-> setChecked(0);
whileBlocking(ui.checkBoxShowDHTStatus)-> setChecked(0);
ui.checkBoxShowNATStatus->setVisible(false);
ui.checkBoxShowDHTStatus->setVisible(false);
} else {
whileBlocking(ui.checkBoxShowNATStatus)-> setChecked(Settings->valueFromGroup("StatusBar", "ShowNAT", QVariant(true)).toBool());
whileBlocking(ui.checkBoxShowDHTStatus)-> setChecked(Settings->valueFromGroup("StatusBar", "ShowDHT", QVariant(true)).toBool());
}
whileBlocking(ui.checkBoxShowHashingStatus)-> setChecked(Settings->valueFromGroup("StatusBar", "ShowHashing", QVariant(true)).toBool());
whileBlocking(ui.checkBoxShowDiscStatus)-> setChecked(Settings->valueFromGroup("StatusBar", "ShowDisc", QVariant(true)).toBool());
whileBlocking(ui.checkBoxShowRateStatus)-> setChecked(Settings->valueFromGroup("StatusBar", "ShowRate", QVariant(true)).toBool());

View File

@ -152,7 +152,6 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags)
connect( ui.allowIpDeterminationCB, SIGNAL( toggled( bool ) ), this, SLOT( toggleIpDetermination(bool) ) );
connect( ui.cleanKnownIPs_PB, SIGNAL( clicked( ) ), this, SLOT( clearKnownAddressList() ) );
connect( ui.testIncoming_PB, SIGNAL( clicked( ) ), this, SLOT( saveAndTestInProxy() ) );
connect( ui.showDiscStatusBar,SIGNAL(toggled(bool)),this,SLOT(updateShowDiscStatusBar())) ;
#ifdef SERVER_DEBUG
std::cerr << "ServerPage::ServerPage() called";
@ -160,7 +159,6 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags)
#endif
connect(ui.netModeComboBox,SIGNAL(currentIndexChanged(int)),this,SLOT(saveAddresses()));
connect(ui.discComboBox, SIGNAL(currentIndexChanged(int)),this,SLOT(saveAddresses()));
connect(ui.localAddress, SIGNAL(textChanged(QString)),this,SLOT(saveAddresses()));
connect(ui.extAddress, SIGNAL(textChanged(QString)),this,SLOT(saveAddresses()));
connect(ui.dynDNS, SIGNAL(textChanged(QString)),this,SLOT(saveAddresses()));
@ -277,8 +275,6 @@ void ServerPage::toggleTunnelConnection(bool b)
//rsPeers->allowTunnelConnection(b) ;
}
void ServerPage::updateShowDiscStatusBar() { Settings->setStatusBarFlag(STATUSBAR_DISC, ui.showDiscStatusBar->isChecked()); }
/** Loads the settings for this page */
void ServerPage::load()
{
@ -303,7 +299,8 @@ void ServerPage::load()
if (mIsHiddenNode)
{
mHiddenType = detail.hiddenType;
ui.tabWidget->setTabEnabled(1,false) ;
ui.tabWidget->setTabEnabled(1,false) ; // ip filter
ui.tabWidget->setTabEnabled(3,false) ; // relay
loadHiddenNode();
return;
}
@ -380,7 +377,6 @@ void ServerPage::load()
/* set DynDNS */
whileBlocking(ui.dynDNS) -> setText(QString::fromStdString(detail.dyndns));
whileBlocking(ui.showDiscStatusBar)->setChecked(Settings->getStatusBarFlags() & STATUSBAR_DISC);
whileBlocking(ui.ipAddressList)->clear();
for(std::list<std::string>::const_iterator it(detail.ipAddressList.begin());it!=detail.ipAddressList.end();++it)
@ -1004,10 +1000,24 @@ void ServerPage::loadHiddenNode()
ui.iconlabel_upnp->hide();
ui.label_nat->hide();
ui.label_warningBandwidth->hide();
ui.iconlabel_netLimited->hide();
ui.textlabel_netLimited->hide();
ui.iconlabel_ext->hide();
ui.textlabel_ext->hide();
ui.extPortLabel->hide();
ui.ipAddressLabel->hide();
ui.cleanKnownIPs_PB->hide();
ui.ipAddressList->hide();
ui.allowIpDeterminationCB->hide();
ui.IPServersLV->hide();
ui.textlabel_hiddenMode->show();
ui.iconlabel_hiddenMode->show() ;
ui.iconlabel_hiddenMode->setPixmap(QPixmap(":/images/ledon1.png"));
// CHANGE OPTIONS ON
whileBlocking(ui.discComboBox)->removeItem(3);
whileBlocking(ui.discComboBox)->removeItem(2);
@ -1048,9 +1058,6 @@ void ServerPage::loadHiddenNode()
whileBlocking(ui.extAddress)->setText(tr("Hidden - See Config"));
whileBlocking(ui.showDiscStatusBar)->setChecked(Settings->getStatusBarFlags() & STATUSBAR_DISC);
ui.showDiscStatusBar->hide() ; // hidden because not functional at the moment.
//ui._turtle_enabled_CB->setChecked(rsTurtle->enabled()) ;
// show what we have in ipAddresses. (should be nothing!)

View File

@ -87,7 +87,6 @@ private slots:
// server
void saveAddresses();
void saveRates();
void updateShowDiscStatusBar() ;
void toggleUPnP();
void toggleIpDetermination(bool) ;
void toggleTunnelConnection(bool) ;

View File

@ -482,13 +482,6 @@ These values don't take into account the Relays.</string>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="showDiscStatusBar">
<property name="text">
<string>Show Discovery information in statusbar</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="allowIpDeterminationCB">
<property name="toolTip">
<string>If you uncheck this, RetroShare can only determine your IP
@ -504,7 +497,7 @@ behind a firewall or a VPN.</string>
</property>
</widget>
</item>
<item row="5" column="0">
<item row="4" column="0">
<widget class="QListWidget" name="IPServersLV">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
@ -517,7 +510,7 @@ behind a firewall or a VPN.</string>
</property>
</widget>
</item>
<item row="6" column="0">
<item row="5" column="0">
<spacer name="tabNetConfVSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -531,7 +524,6 @@ behind a firewall or a VPN.</string>
</spacer>
</item>
</layout>
<zorder>showDiscStatusBar</zorder>
<zorder>allowIpDeterminationCB</zorder>
<zorder>IPServersLV</zorder>
<zorder>ipAddressList</zorder>
@ -831,7 +823,7 @@ behind a firewall or a VPN.</string>
<item>
<widget class="QLabel" name="hiddenpage_outHeader">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Outgoing Connctions&lt;/p&gt;&lt;p&gt;Configure your Tor and I2P SOCKS proxy here. &lt;br/&gt;If you prefer to use BOB to automatically manage I2P check the other tab.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Configure your Tor and I2P SOCKS proxy here. &lt;br/&gt;If you prefer to use BOB to automatically manage I2P check the other tab.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
@ -1475,7 +1467,7 @@ You can connect to Hidden Nodes, even if you are running a standard Node, so why
<item>
<widget class="QLabel" name="hiddenpage_inHeader">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Incoming Connection&lt;/p&gt;&lt;p&gt;Setup your hidden address (and port if needed)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Setup your hidden address (and port if needed)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
@ -2097,7 +2089,6 @@ If you have issues connecting over Tor check the Tor logs too.</string>
<tabstop>extAddress</tabstop>
<tabstop>extPort</tabstop>
<tabstop>dynDNS</tabstop>
<tabstop>showDiscStatusBar</tabstop>
</tabstops>
<resources>
<include location="../images.qrc"/>

View File

@ -95,10 +95,11 @@ StatisticsWindow::StatisticsWindow(QWidget *parent) :
{
ui->setupUi(this);
Settings->loadWidgetInformation(this);
initStackedPage();
connect(ui->stackPages, SIGNAL(currentChanged(int)), this, SLOT(setNewPage(int)));
ui->stackPages->setCurrentIndex(0);
int toolSize = Settings->getToolButtonSize();
ui->toolBar->setToolButtonStyle(Settings->getToolButtonStyle());
ui->toolBar->setIconSize(QSize(toolSize,toolSize));
@ -110,6 +111,11 @@ StatisticsWindow::~StatisticsWindow()
mInstance = NULL;
}
void StatisticsWindow::closeEvent (QCloseEvent * /*event*/)
{
Settings->saveWidgetInformation(this);
}
void StatisticsWindow::changeEvent(QEvent *e)
{
QMainWindow::changeEvent(e);
@ -147,9 +153,19 @@ void StatisticsWindow::initStackedPage()
ui->stackPages->add(rttdlg = new RttStatistics(ui->stackPages),
action = createPageAction(QIcon(IMAGE_RTT), tr("RTT Statistics"), grp));
ui->stackPages->add(dhtw = new DhtWindow(ui->stackPages),
bool showdht = true;
RsPeerDetails detail;
if (rsPeers->getPeerDetails(rsPeers->getOwnId(), detail))
{
if(detail.netMode == RS_NETMODE_HIDDEN)
showdht = false;
}
if(showdht)
{
ui->stackPages->add(dhtw = new DhtWindow(ui->stackPages),
action = createPageAction(QIcon(IMAGE_DHT), tr("DHT"), grp));
}
/*std::cerr << "Looking for interfaces in existing plugins:" << std::endl;
for(int i = 0;i<rsPlugins->nbPlugins();++i)
{

View File

@ -65,7 +65,8 @@ public slots:
protected:
void changeEvent(QEvent *e);
void closeEvent (QCloseEvent * event);
private:
void initStackedPage();

View File

@ -476,7 +476,6 @@ HEADERS += rshare.h \
gui/common/ElidedLabel.h \
gui/common/vmessagebox.h \
gui/common/RsUrlHandler.h \
gui/common/RsCollectionFile.h \
gui/common/RsCollectionDialog.h \
gui/common/rwindow.h \
gui/common/html.h \
@ -568,7 +567,7 @@ HEADERS += rshare.h \
util/imageutil.h \
gui/NetworkDialog/pgpid_item_model.h \
gui/NetworkDialog/pgpid_item_proxy.h
gui/common/RsCollection.h
# gui/ForumsDialog.h \
# gui/forums/ForumDetails.h \
# gui/forums/EditForumDetails.h \
@ -793,7 +792,6 @@ SOURCES += main.cpp \
gui/common/RSGraphWidget.cpp \
gui/common/ElidedLabel.cpp \
gui/common/vmessagebox.cpp \
gui/common/RsCollectionFile.cpp \
gui/common/RsCollectionDialog.cpp \
gui/common/RsUrlHandler.cpp \
gui/common/rwindow.cpp \
@ -930,7 +928,7 @@ SOURCES += main.cpp \
util/imageutil.cpp \
gui/NetworkDialog/pgpid_item_model.cpp \
gui/NetworkDialog/pgpid_item_proxy.cpp
gui/common/RsCollection.cpp
# gui/ForumsDialog.cpp \
# gui/forums/ForumDetails.cpp \
# gui/forums/EditForumDetails.cpp \

View File

@ -35,6 +35,8 @@
#include "HandleRichText.h"
#include "gui/RetroShareLink.h"
#include "util/ObjectPainter.h"
#include "util/imageutil.h"
#include "util/rsscopetimer.h"
#include <iostream>
@ -227,6 +229,7 @@ bool RsHtml::canReplaceAnchor(QDomDocument &/*doc*/, QDomElement &/*element*/, c
switch (link.type()) {
case RetroShareLink::TYPE_UNKNOWN:
case RetroShareLink::TYPE_FILE:
case RetroShareLink::TYPE_FILE_TREE:
case RetroShareLink::TYPE_PERSON:
case RetroShareLink::TYPE_FORUM:
case RetroShareLink::TYPE_CHANNEL:
@ -257,6 +260,7 @@ void RsHtml::anchorStylesheetForImg(QDomDocument &/*doc*/, QDomElement &/*elemen
switch (link.type()) {
case RetroShareLink::TYPE_UNKNOWN:
case RetroShareLink::TYPE_FILE:
case RetroShareLink::TYPE_FILE_TREE:
case RetroShareLink::TYPE_PERSON:
case RetroShareLink::TYPE_FORUM:
case RetroShareLink::TYPE_CHANNEL:
@ -1105,7 +1109,7 @@ QString RsHtml::toHtml(QString text, bool realHtml)
}
/** Loads image and converts image to embedded image HTML fragment **/
bool RsHtml::makeEmbeddedImage(const QString &fileName, QString &embeddedImage, const int maxPixels)
bool RsHtml::makeEmbeddedImage(const QString &fileName, QString &embeddedImage, const int maxPixels, const int maxBytes)
{
QImage image;
@ -1113,54 +1117,15 @@ bool RsHtml::makeEmbeddedImage(const QString &fileName, QString &embeddedImage,
fprintf (stderr, "RsHtml::makeEmbeddedImage() - image \"%s\" can't be load\n", fileName.toLatin1().constData());
return false;
}
return RsHtml::makeEmbeddedImage(image, embeddedImage, maxPixels);
return RsHtml::makeEmbeddedImage(image, embeddedImage, maxPixels, maxBytes);
}
/** Converts image to embedded image HTML fragment **/
bool RsHtml::makeEmbeddedImage(const QImage &originalImage, QString &embeddedImage, const int maxPixels)
bool RsHtml::makeEmbeddedImage(const QImage &originalImage, QString &embeddedImage, const int maxPixels, const int maxBytes)
{
QByteArray bytearray;
QBuffer buffer(&bytearray);
QImage resizedImage;
const QImage *image = &originalImage;
if (maxPixels > 0) {
QSize imgSize = originalImage.size();
if ((imgSize.height() * imgSize.width()) > maxPixels) {
// image is too large - resize keeping aspect ratio
QSize newSize;
newSize.setWidth(int(qSqrt((maxPixels * imgSize.width()) / imgSize.height())));
newSize.setHeight(int((imgSize.height() * newSize.width()) / imgSize.width()));
// ask user
QMessageBox msgBox;
msgBox.setText(QString(QApplication::translate("RsHtml", "Image is oversized for transmission.\nReducing image to %1x%2 pixels?")).arg(newSize.width()).arg(newSize.height()));
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Ok);
if (msgBox.exec() != QMessageBox::Ok) {
return false;
}
resizedImage = originalImage.scaled(newSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
image = &resizedImage;
}
}
if (buffer.open(QIODevice::WriteOnly)) {
if (image->save(&buffer, "PNG")) {
QByteArray encodedByteArray = bytearray.toBase64();
embeddedImage = "<img src=\"data:image/png;base64,";
embeddedImage.append(encodedByteArray);
embeddedImage.append("\">");
} else {
//fprintf (stderr, "RsHtml::makeEmbeddedImage() - image can't be saved to buffer\n");
return false;
}
} else {
fprintf (stderr, "RsHtml::makeEmbeddedImage() - buffer can't be opened\n");
return false;
}
return true;
RsScopeTimer s("Embed image");
QImage opt;
return ImageUtil::optimizeSize(embeddedImage, originalImage, opt, maxPixels, maxBytes);
}
QString RsHtml::plainText(const QString &text)

View File

@ -69,8 +69,8 @@ public:
static void optimizeHtml(QString &text, unsigned int flag = 0, const QColor &backgroundColor = Qt::white, qreal desiredContrast = 1.0, int desiredMinimumFontSize = 10);
static QString toHtml(QString text, bool realHtml = true);
static bool makeEmbeddedImage(const QString &fileName, QString &embeddedImage, const int maxPixels);
static bool makeEmbeddedImage(const QImage &originalImage, QString &embeddedImage, const int maxPixels);
static bool makeEmbeddedImage(const QString &fileName, QString &embeddedImage, const int maxPixels, const int maxBytes = -1);
static bool makeEmbeddedImage(const QImage &originalImage, QString &embeddedImage, const int maxPixels, const int maxBytes = -1);
static QString plainText(const QString &text);
static QString plainText(const std::string &text);

View File

@ -1,5 +1,6 @@
#include "imageutil.h"
#include "util/misc.h"
#include "util/rsscopetimer.h"
#include <QApplication>
#include <QByteArray>
@ -8,6 +9,11 @@
#include <QString>
#include <QTextCursor>
#include <QTextDocumentFragment>
#include <QBuffer>
#include <QtGlobal>
#include <QSet>
#include <cmath>
#include <iostream>
ImageUtil::ImageUtil() {}
@ -42,3 +48,211 @@ void ImageUtil::extractImage(QWidget *window, QTextCursor cursor)
}
}
bool ImageUtil::optimizeSize(QString &html, 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)) {
if(checkSize(html, optimized, maxBytes) <= maxBytes) {
return true;
}
}
QVector<QRgb> ct;
quantization(original, ct);
//Downscale the image to fit into maxPixels
double whratio = (qreal)original.width() / (qreal)original.height();
int maxwidth;
if(maxPixels > 0)
maxwidth = (int)sqrt((double)(maxPixels) * whratio);
else
maxwidth = original.width();
int minwidth = (int)sqrt(100.0 * whratio);
//if maxBytes not defined, do not reduce color space, just downscale
if(maxBytes <= 0) {
checkSize(html, optimized = original.scaledToWidth(maxwidth, Qt::SmoothTransformation), maxBytes);
return true;
}
//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), maxBytes);
if(maxsize <= maxBytes) return true; //success
double minsize = (double)checkSize(html, optimized = original.scaledToWidth(minwidth, Qt::SmoothTransformation).convertToFormat(QImage::Format_Indexed8, ct), maxBytes);
if(minsize > maxBytes) return false; //impossible
// std::cout << "maxS: " << maxsize << " minS: " << minsize << std::endl;
// std::cout << "maxW: " << maxwidth << " minW: " << minwidth << std::endl;
int region = 500;
bool success = false;
do {
double m = (maxsize - minsize) / ((double)maxwidth * (double)maxwidth / whratio - (double)minwidth * (double)minwidth / whratio);
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);
double nextsize = (double)checkSize(html, optimized = original.scaledToWidth(nextwidth, Qt::SmoothTransformation).convertToFormat(QImage::Format_Indexed8, ct), maxBytes);
if(nextsize <= maxBytes) {
minsize = nextsize;
minwidth = nextwidth;
if(nextsize >= (maxBytes - region)) //the file size is close anough to the limit
success = true;
} else {
maxsize = nextsize;
maxwidth = nextwidth;
}
// std::cout << "maxS: " << maxsize << " minS: " << minsize << std::endl;
// std::cout << "maxW: " << maxwidth << " minW: " << minwidth << std::endl;
} while(!success);
return true;
//html = html.arg(original.width());
//std::cout << html.toStdString() << std::endl;
}
int ImageUtil::checkSize(QString &embeddedImage, const QImage &img, int maxBytes)
{
RsScopeTimer st("Check size");
QByteArray bytearray;
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 = "<img width=\"%1\" src=\"data:image/png;base64,";
embeddedImage = "<img src=\"data:image/png;base64,";
embeddedImage.append(encodedByteArray);
embeddedImage.append("\">");
}
} 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;
}
return size;
}
bool redLessThan(const QRgb &c1, const QRgb &c2)
{
return qRed(c1) < qRed(c2);
}
bool greenLessThan(const QRgb &c1, const QRgb &c2)
{
return qGreen(c1) < qGreen(c2);
}
bool blueLessThan(const QRgb &c1, const QRgb &c2)
{
return qBlue(c1) < qBlue(c2);
}
//median cut algoritmh
void ImageUtil::quantization(const QImage &img, QVector<QRgb> &palette)
{
int bits = 4; // bits/pixel
int samplesize = 100000; //only take this many color samples
RsScopeTimer st("Quantization");
QSet<QRgb> colors;
//collect color information
int imgsize = img.width()*img.height();
int width = img.width();
samplesize = qMin(samplesize, imgsize);
double sampledist = (double)imgsize / (double)samplesize;
for (double i = 0; i < imgsize; i += sampledist) {
QRgb pixel = img.pixel((int)i % width, (int)i / width);
colors.insert(pixel);
}
QList<QRgb> colorlist = colors.toList();
//don't do the algoritmh if we have less than 16 different colors
if(colorlist.size() <= (1 << bits)) {
for(int i = 0; i < colors.count(); ++i)
palette.append(colorlist[i]);
} else {
quantization(colorlist.begin(), colorlist.end(), bits, palette);
}
}
void ImageUtil::quantization(QList<QRgb>::iterator begin, QList<QRgb>::iterator end, int depth, QVector<QRgb> &palette)
{
//the buckets are ready
if(depth == 0) {
avgbucket(begin, end, palette);
return;
}
//nothing to do
int count = end - begin;
if(count == 1) {
palette.append(*begin);
return;
}
//widest color channel
int rl = 255;
int gl = 255;
int bl = 255;
int rh = 0;
int gh = 0;
int bh = 0;
for(QList<QRgb>::iterator it = begin; it < end; ++it) {
rl = qMin(rl, qRed(*it));
gl = qMin(gl, qGreen(*it));
bl = qMin(bl, qBlue(*it));
rh = qMax(rh, qRed(*it));
gh = qMax(gh, qGreen(*it));
bh = qMax(bh, qBlue(*it));
}
int red = rh - rl;
int green = gh - gl;
int blue = bh - bl;
//order by the widest channel
if(red > green)
if(red > blue)
qSort(begin, end, redLessThan);
else
qSort(begin, end, blueLessThan);
else
if(green > blue)
qSort(begin, end, greenLessThan);
else
qSort(begin, end, blueLessThan);
//split into two buckets
QList<QRgb>::iterator split = begin + count / 2;
quantization(begin, split, depth - 1, palette);
quantization(split, end, depth - 1, palette);
}
void ImageUtil::avgbucket(QList<QRgb>::iterator begin, QList<QRgb>::iterator end, QVector<QRgb> &palette)
{
int red = 0;
int green = 0;
int blue = 0;
int count = end - begin;
for(QList<QRgb>::iterator it = begin; it < end; ++it) {
red += qRed(*it);
green += qGreen(*it);
blue += qBlue(*it);
}
QRgb color = qRgb(red/count, green/count, blue/count);
palette.append(color);
}

View File

@ -3,6 +3,7 @@
#include <QTextCursor>
#include <QWidget>
#include <qiterator.h>
class ImageUtil
{
@ -10,6 +11,13 @@ public:
ImageUtil();
static void extractImage(QWidget *window, QTextCursor cursor);
static bool optimizeSize(QString &html, const QImage& original, QImage &optimized, int maxPixels = -1, int maxBytes = -1);
private:
static int checkSize(QString& embeddedImage, const QImage& img, int maxBytes = -1);
static void quantization(const QImage& img, QVector<QRgb>& palette);
static void quantization(QList<QRgb>::iterator begin, QList<QRgb>::iterator end, int depth, QVector<QRgb>& palette);
static void avgbucket(QList<QRgb>::iterator begin, QList<QRgb>::iterator end, QVector<QRgb>& palette);
};
#endif // IMAGEUTIL_H

View File

@ -28,7 +28,7 @@ Item
{
id: chatView
property string chatId
property var gxsInfo: ""
property var gxsInfo: ({})
property int token: 0
property string objectName:"chatView"
@ -64,7 +64,7 @@ Item
function changeState ()
{
toolBar.state = "CHATVIEW"
gxsInfo= ChatCache.lastMessageCache.getGxsFromChatId(chatView.chatId)
gxsInfo = ChatCache.lastMessageCache.getGxsFromChatId(chatView.chatId)
toolBar.gxsSource = gxsInfo.gxs
toolBar.titleText = gxsInfo.name
}
@ -100,7 +100,7 @@ Item
anchors.fill: parent
anchors.topMargin: parent.height / 2
anchors.bottomMargin: categorySelectorHeight
anchors.bottomMargin: if(!androidMode) categorySelectorHeight
property int categorySelectorHeight: 50
@ -114,6 +114,7 @@ Item
name: "EMOJI_HIDDEN"
PropertyChanges { target: emojiPicker; anchors.topMargin: parent.height }
PropertyChanges { target: emojiPicker; anchors.bottomMargin: -1 }
PropertyChanges { target: emojiPicker; height: 0 }
},
State {
name: "EMOJI_SHOWN"
@ -132,7 +133,7 @@ Item
id: inferiorPanel
height: ( msgComposer.height > styles.height)? msgComposer.height: styles.height
width: parent.width
anchors.bottom: parent.bottom
anchors.bottom: emojiPicker.androidMode ? emojiPicker.top : parent.bottom
Rectangle
{

View File

@ -50,7 +50,14 @@ Item
console.log("GxsIntentityDelegate onclicked:", model.name,
model.gxs_id)
contactsView.searching = false
if(model.own) contactsView.own_gxs_id = model.gxs_id
if(model.own)
{
contactsView.own_gxs_id = model.gxs_id
stackView.push(
"qrc:/ContactDetails.qml",
{md: ChatCache.contactsCache.getContactFromGxsId(model.gxs_id)})
}
else
{
startDistantChat()

View File

@ -28,6 +28,13 @@ QtObject
property var tokens: ({})
function registerToken(token, callback)
{
if(!maybeToken(token))
{
console.error("TokensManager attempt to register a non int token")
console.trace()
return
}
if (Array.isArray(tokens[token]))
{
if(QT_DEBUG)
@ -72,6 +79,7 @@ QtObject
delete tokens[token]
}
function isTokenValid(token) { return Array.isArray(tokens[token]) }
function maybeToken(value) { return Number(value) === parseInt(value) }
property alias refreshInterval: refreshTokensTimer.interval
@ -81,16 +89,22 @@ QtObject
onResponseReceived:
{
/* TODO: This is vital enough and if some fails appens can create
* difficult to debug unexpected behaviours in any place of the app.
* We should do some more checking on the data received here
*/
var jsonData = JSON.parse(msg).data
// console.log("refreshTokensApi got expired tokens:", msg)
var arrayLength = jsonData.length
for (var i = 0; i < arrayLength; i++)
{
for (var i = 0; i < arrayLength; ++i)
tokensManager.tokenExpire(jsonData[i])
}
}
Component.onCompleted:
{
/* Disable debugging only for this instance of LibresapiLocalClient
* as it is particularly noisy and repetitive, and not useful in
* most of the cases */
if(QT_DEBUG) debug = false
openConnection(apiSocketPath)
@ -99,8 +113,13 @@ QtObject
function refreshTokens()
{
request("/statetokenservice/*",
'['+Object.keys(tokensManager.tokens)+']')
var tokensArr = Object.keys(tokensManager.tokens)
// Filter to avoid "undefined" being sent toghether with tokens
var tokensStr = '['+ tokensArr.filter(maybeToken) +']'
// console.log("refreshTokensApi checking tokens:", tokensStr)
request("/statetokenservice/*", tokensStr)
}
}

View File

@ -6,4 +6,4 @@
androidBuildToolsVersion=24.0.1
androidCompileSdkVersion=23
buildDir=.build
qt5AndroidDir=/opt/Qt5.8.0/5.8/android_armv7/src/android/java
qt5AndroidDir=/opt/Qt/5.9.2/android_armv7/src/android/java

View File

@ -9,6 +9,8 @@
#include <QImageReader>
#include <QBuffer>
#include "qpainter.h"
#ifdef __ANDROID__
# include <QtAndroid>
@ -41,14 +43,44 @@ public slots:
QString localPath = url.toLocalFile();
qDebug() << "imageToBase64() local path:" << localPath ;
// Read the image
QImageReader reader;
reader.setFileName(localPath);
QImage image = reader.read();
QImage image= getImage (localPath);
image = image.scaled(96,96,Qt::KeepAspectRatio,Qt::SmoothTransformation);
qDebug() << "imageToBase64() encoding" ;
return imageToB64(image);
}
static QString b64AvatarGen (QVariantList onloads, int size)
{
qDebug() << "b64AvatarGen(): Generating face Avatar from";
QImage result(size, size, QImage::Format_ARGB32_Premultiplied);
QPainter painter(&result);
int counter = 0;
for (QVariantList::iterator j = onloads.begin(); j != onloads.end(); j++)
{
QImage image = getImage (":/"+(*j).toString());
painter.drawImage(0, 0, image); // xi, yi is the position for imagei
counter++;
}
painter.end();
return imageToB64(result);
}
static QImage getImage (QString const& path)
{
QImageReader reader;
reader.setFileName(path);
return reader.read();
}
static QString imageToB64 (QImage image)
{
// Transform image into PNG format
QByteArray ba;
QBuffer buffer( &ba );
@ -56,11 +88,8 @@ public slots:
image.save( &buffer, "png" );
// Get Based 64 image string
QString encoded = QString(ba.toBase64());
qDebug() << "imageToBase64() encoded" ;
return encoded;
return QString(ba.toBase64());
}
};

View File

@ -4,64 +4,22 @@ import "../" // Needed by ChatCache (where stores generated faces)
Item
{
id: faces
property string hash
property var facesCache: ChatCache.facesCache
Image
{
id: imageAvatar
width: height
height: iconSize
visible: true
}
Canvas
{
id: canvasAvatar
width: height
height: canvasSizes
visible: false
renderStrategy: Canvas.Threaded;
renderTarget: Canvas.Image;
property var images
property var callback
onPaint:
{
var ctx = getContext("2d");
if (images)
{
for (y = 0 ; y< nPieces ; y++)
{
ctx.drawImage(images[y], 0, 0, iconSize, iconSize )
}
}
}
onPainted:
{
if (callback)
{
var data = toDataURL('image/png')
callback(data)
}
}
}
Component.onCompleted:
{
createFromHex(hash)
}
Component.onCompleted: createFromHex(hash)
/* TODO: Is there a reason why we are using var and not proper type for the
* following properties? */
property var facesPath: "/icons/faces/"
@ -134,11 +92,9 @@ Item
{
var url = src(gender, i, data[i+1])
onloads.push(url)
canvasAvatar.loadImage(url)
}
canvasAvatar.images = onloads
canvasAvatar.callback = callback
canvasAvatar.requestPaint()
var base64Image = androidImagePicker.b64AvatarGen(onloads, canvasSizes)
callback("data:image/png;base64,"+base64Image)
}
// Create the identicon
@ -146,32 +102,11 @@ Item
{
var iconId = [dataHex, iconSize];
var update = function(data)
{
// This conditions are for solve a bug on an Lg S3.
// On this device the toDataURL() is incompleted.
// So for see the complete avatar at least at first execution we'll show the canvas,
// instead of the image component.
// See issue: https://gitlab.com/angesoc/RetroShare/issues/37
if (facesCache.iconCache[iconId])
{
imageAvatar.source = data
imageAvatar.visible = true
canvasAvatar.visible = false
canvasAvatar.height = 0
imageAvatar.height = iconSize
}
else
{
canvasAvatar.visible = true
imageAvatar.visible = false
canvasAvatar.height = iconSize
imageAvatar.height = 0
}
facesCache.iconCache[iconId] = data;
}
{
imageAvatar.source = data
imageAvatar.height = iconSize
facesCache.iconCache[iconId] = data;
}
if (facesCache.iconCache.hasOwnProperty(iconId))
{
@ -184,13 +119,13 @@ Item
else
{
var onImageGenerated = function(data)
{
{
facesCache.callbackCache[iconId].forEach(function(callback)
{
callback(data);
})
}
facesCache.callbackCache[iconId].forEach(function(callback)
{
callback(data);
})
}
facesCache.callbackCache[iconId] = [update];
if (dataHex)

View File

@ -1,12 +1,14 @@
import QtQuick 2.7
import QtQuick.Controls.Styles 1.2
Rectangle {
Rectangle
{
id: emojiButton
property var fontName
Text {
Text
{
id: emojiText
color: "gray"
text: qsTr(eCatText)
@ -17,17 +19,22 @@ Rectangle {
state: "RELEASED"
states: [
State {
states:
[
State
{
name: "PRESSED"
PropertyChanges {
PropertyChanges
{
target: emojiText
font.pixelSize: emojiButton.width - 10
}
},
State {
State
{
name: "RELEASED"
PropertyChanges {
PropertyChanges
{
target: emojiText
font.pixelSize: emojiButton.width - 8
}
@ -35,20 +42,25 @@ Rectangle {
]
MouseArea {
MouseArea
{
anchors.fill: parent
hoverEnabled: true
onEntered: {
onEntered:
{
emojiText.color = "black"
}
onExited: {
onExited:
{
emojiText.color = "gray"
}
onPressedChanged: {
onPressedChanged:
{
emojiButton.state = emojiButton.state == "PRESSED" ? "RELEASED" : "PRESSED"
}
onClicked: {
onClicked:
{
Qt.emojiClickedHandler(emojiText.text)
}
}

View File

@ -1,30 +1,37 @@
import QtQuick 2.7
import QtQuick.Controls.Styles 1.2
Rectangle {
Rectangle
{
id: emojiCategoryButton
property string categoryName
property var fontName
function completedHandler() {
function completedHandler()
{
categoryName = eCatName
//initialize
if (parent.currSelEmojiButton === undefined) {
if (parent.currSelEmojiButton === undefined)
{
clickedHandler()
}
}
function pressedHandler() {
if (state != "SELECTED") {
function pressedHandler()
{
if (state != "SELECTED")
{
state = state == "PRESSED" ? "RELEASED" : "PRESSED"
}
}
function clickedHandler() {
if (parent.currSelEmojiButton !== undefined) {
function clickedHandler()
{
if (parent.currSelEmojiButton !== undefined)
{
parent.currSelEmojiButton.state = "RELEASED"
}
@ -34,7 +41,8 @@ Rectangle {
}
Text {
Text
{
id: emojiText
color: "gray"
text: qsTr(eCatText)
@ -45,31 +53,39 @@ Rectangle {
state: "RELEASED"
states: [
State {
states:
[
State
{
name: "PRESSED"
PropertyChanges {
PropertyChanges
{
target: emojiText
font.pixelSize: emojiCategoryButton.width - 10
}
},
State {
State
{
name: "RELEASED"
PropertyChanges {
PropertyChanges
{
target: emojiText
font.pixelSize: emojiCategoryButton.width - 8
}
},
State {
State
{
name: "SELECTED"
PropertyChanges {
PropertyChanges
{
target: emojiCategoryButton
color: "#ADD6FF"
}
}
]
MouseArea {
MouseArea
{
anchors.fill: parent
hoverEnabled: true
onEntered: emojiText.color = "black"

View File

@ -2,33 +2,41 @@ import QtQuick 2.7
import QtQuick.Controls 2.0
import "emoji.js" as EmojiJSON
Rectangle {
Rectangle
{
id: emojiPicker
property EmojiCategoryButton currSelEmojiButton
property variant emojiParsedJson
property int buttonWidth: 40
property TextArea textArea
property bool androidMode: Qt.platform.os === "android" // On Desktop appears on top of text field, instead appears in place of virtual keyboard (under text field)
property var rootFontName: theme.emojiFontName
//displays all Emoji of one categroy by modifying the ListModel of emojiGrid
function categoryChangedHandler (newCategoryName){
function categoryChangedHandler (newCategoryName)
{
emojiByCategory.clear()
for (var i = 0; i < emojiParsedJson.emoji_by_category[newCategoryName].length; i++) {
for (var i = 0; i < emojiParsedJson.emoji_by_category[newCategoryName].length; i++)
{
var elem = emojiParsedJson.emoji_by_category[newCategoryName][i]
emojiByCategory.append({eCatName: newCategoryName, eCatText: elem})
}
}
//adds the clicked Emoji (and one ' ' if the previous character isn't an Emoji) to textArea
function emojiClickedHandler(selectedEmoji) {
function emojiClickedHandler(selectedEmoji)
{
var strAppnd = ""
var plainText = textArea.getText(0, textArea.length)
if (plainText.length > 0) {
var lastChar = plainText[plainText.length-1]
if ((lastChar !== ' ') && (lastChar.charCodeAt(0) < 255)) {
if ((lastChar !== ' ') && (lastChar.charCodeAt(0) < 255))
{
strAppnd = " "
}
}
@ -38,10 +46,12 @@ Rectangle {
}
//parses JSON, publishes button handlers and inits textArea
function completedHandler() {
function completedHandler()
{
// emojiParsedJson = JSON.parse(EmojiJSON.emoji_json)
emojiParsedJson = EmojiJSON.emoji_json
for (var i = 0; i < emojiParsedJson.emoji_categories.length; i++) {
for (var i = 0; i < emojiParsedJson.emoji_categories.length; i++)
{
var elem = emojiParsedJson.emoji_categories[i]
emojiCategoryButtons.append({eCatName: elem.name, eCatText: elem.emoji_unified})
}
@ -56,29 +66,39 @@ Rectangle {
//checks if the previous character is an Emoji and adds a ' ' if that's the case
//this is necessary, because Emoji use a bigger font-size, and that font-size is kept using without a ' '
function keyPressedHandler(event) {
function keyPressedHandler(event)
{
var testStr = textArea.getText(textArea.length-2, textArea.length)
var ptrn = new RegExp("[\uD800-\uDBFF][\uDC00-\uDFFF]")
if ((event.key !== Qt.Key_Backspace) && (ptrn.test(testStr))) {
if ((event.key !== Qt.Key_Backspace) && (ptrn.test(testStr)))
{
textArea.text += " "
textArea.cursorPosition = textArea.length
}
}
//all emoji of one category
ListModel {
ListModel
{
id: emojiByCategory
}
GridView {
GridView
{
id: emojiGrid
width: parent.width
anchors.fill: parent
anchors.bottomMargin: buttonWidth
cellWidth: buttonWidth; cellHeight: buttonWidth
anchors.fill: parent
anchors
{
bottomMargin: if (!androidMode) buttonWidth
topMargin: if (androidMode) buttonWidth
}
cellWidth: buttonWidth; cellHeight: buttonWidth
model: emojiByCategory
delegate: EmojiButton {
delegate: EmojiButton
{
width: buttonWidth
height: buttonWidth
color: emojiPicker.color
@ -88,37 +108,52 @@ Rectangle {
//seperator
Rectangle {
color: emojiPicker.color
anchors.bottom: parent.bottom
Rectangle
{
color: "gray"
anchors
{
bottom: if (!androidMode) parent.bottom
top: if (androidMode) parent.top
bottomMargin: if (!androidMode) buttonWidth
topMargin: if (androidMode) buttonWidth
}
width: parent.width
height: 1
}
Rectangle
{
color: emojiPicker.color
width: parent.width
height: buttonWidth
}
Rectangle {
color: "black"
anchors.bottom: parent.bottom
anchors.bottomMargin: buttonWidth
width: parent.width
height: 1
anchors
{
bottom: if (!androidMode) parent.bottom
top: if (androidMode) parent.top
}
//emoji category selector
ListView
{
width: parent.width
orientation: ListView.Horizontal
anchors.fill: parent
model: emojiCategoryButtons
delegate: EmojiCategoryButton
{
width: buttonWidth
height: buttonWidth
color: emojiPicker.color
fontName: rootFontName
}
}
}
//emoji category selector
ListView {
width: parent.width
anchors.bottom: parent.bottom
anchors.bottomMargin: buttonWidth
orientation: ListView.Horizontal
model: emojiCategoryButtons
delegate: EmojiCategoryButton {
width: buttonWidth
height: buttonWidth
color: emojiPicker.color
fontName: rootFontName
}
}
ListModel {
ListModel
{
id: emojiCategoryButtons
}

View File

@ -133,7 +133,7 @@ android-g++ {
# message(ANDROID_EXTRA_LIBS: $$ANDROID_EXTRA_LIBS)
# message(ANDROID_PLATFORM: $$ANDROID_PLATFORM)
# message(ANDROID_PLATFORM_ROOT_PATH: $$ANDROID_PLATFORM_ROOT_PATH)
# message(NDK_TOOLCHAIN_PATH: $$NDK_TOOLCHAIN_PATH)
# message(NATIVE_LIBS_TOOLCHAIN_PATH: $$NATIVE_LIBS_TOOLCHAIN_PATH)
}
win32 {