From 406eb2f2407ce4cd32ae3314467ae80eb9e06cae Mon Sep 17 00:00:00 2001 From: Chozabu Date: Sat, 25 Jul 2015 11:24:15 +0100 Subject: [PATCH 001/165] add travis file --- .travis.yml | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..49288fa9b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,50 @@ +language: cpp + +compiler: + - gcc + +before_install: + - echo $LANG + - echo $LC_ALL + - sudo apt-get update + - sudo apt-get install build-essential checkinstall cmake g++ git libavcodec-dev libavformat-dev libbz2-dev libcurl4-openssl-dev libdc1394-22-dev libglib2.0-dev libcv-dev libopencv-highgui-dev libhighgui-dev + - sudo apt-get install libgnome-keyring-dev libgstreamer-plugins-base0.10-dev libgstreamer0.10-dev libjasper-dev libjpeg-dev libmicrohttpd-dev libopencv-dev libprotobuf-dev libqt4-dev + - sudo apt-get install libspeex-dev libspeexdsp-dev libsqlite3-dev libssl-dev libswscale-dev + - sudo apt-get install libtbb-dev libtiff4-dev libupnp-dev libv4l-dev libxine-dev libxslt1-dev libxss-dev make pkg-config protobuf-compiler python-dev python-numpy subversion git yasm qtmobility-dev +# - if [ $TRAVIS_OS_NAME == linux ]; then sudo apt-get update && sudo apt-get install -y llvm-3.4 llvm-3.4-dev; fi +# - rvm use $RVM --install --binary --fuzzy +# - gem update --system +# - gem --version + +before_script: + - qmake + +script: make + +#after_success: +# - if [ $TRAVIS_BRANCH == $TRAVIS_TAG ]; then rake deploy; fi + +#branches: +# only: +# - master +# - travis + +notifications: + email: false + irc: + channels: + - "chat.freenode.net#retroshare" + template: + - "%{repository}/%{branch} (%{commit} - %{author}): %{build_url}: %{message}" +# webhooks: +# urls: +# - https://webhooks.gitter.im/e/9502afd22ca6c8e85fb3 +# on_success: change +# on_failure: always +# on_start: always + +#env: +# - RVM=2.0.0 LANG="en_US.UTF-8" + +os: + - linux \ No newline at end of file From 69d23a4982ae4fdaf3f357b994e1455d7353e8d2 Mon Sep 17 00:00:00 2001 From: Chozabu Date: Sat, 25 Jul 2015 14:25:57 +0100 Subject: [PATCH 002/165] add button to copy version info in first level about box --- retroshare-gui/src/gui/AboutDialog.cpp | 81 ++++++++++++++++++++++++++ retroshare-gui/src/gui/AboutDialog.h | 2 + retroshare-gui/src/gui/AboutDialog.ui | 26 ++++++++- 3 files changed, 107 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/AboutDialog.cpp b/retroshare-gui/src/gui/AboutDialog.cpp index 26170558d..003253443 100644 --- a/retroshare-gui/src/gui/AboutDialog.cpp +++ b/retroshare-gui/src/gui/AboutDialog.cpp @@ -24,10 +24,15 @@ #include "HelpDialog.h" #include "rshare.h" +#include +#include #include #include #include "settings/rsharesettings.h" +#include +#include +#include #include #include #include @@ -721,3 +726,79 @@ NextPieceLabel::NextPieceLabel( QWidget* parent /* = 0*/ ) : QLabel(parent) setAlignment(Qt::AlignCenter); setAutoFillBackground(true); } + +static QString addLibraries(const std::string &name, const std::list &libraries) +{ + QString mTextEdit; + mTextEdit+=QString::fromUtf8(name.c_str()); + mTextEdit+="\n"; + + std::list::const_iterator libraryIt; + for (libraryIt = libraries.begin(); libraryIt != libraries.end(); ++libraryIt) { + + mTextEdit+=" - "; + mTextEdit+=QString::fromUtf8(libraryIt->mName.c_str()); + mTextEdit+=": "; + mTextEdit+=QString::fromUtf8(libraryIt->mVersion.c_str()); + mTextEdit+="\n"; + } + mTextEdit+="\n"; + return mTextEdit; +} + + +void AboutDialog::on_copy_button_clicked() +{ + QString verInfo; + QString rsVerString = "RetroShare Version: "; + rsVerString+=Rshare::retroshareVersion(true); + verInfo+=rsVerString; + verInfo+="\n"; + + +#if QT_VERSION >= QT_VERSION_CHECK (5, 0, 0) + #if QT_VERSION >= QT_VERSION_CHECK (5, 4, 0) + verInfo+=QSysInfo::prettyProductName(); + #endif +#else + #ifdef Q_WS_X11 + verInfo+="Linux"; + #endif + #ifdef Q_WS_WIN + verInfo+="Windows"; + #endif + #ifdef Q_WS_MACX + verInfo+="Mac"; + #endif +#endif + verInfo+=" "; + QString qtver = QString("QT ")+QT_VERSION_STR; + verInfo+=qtver; + verInfo+="\n\n"; + + /* Add version numbers of libretroshare */ + std::list libraries; + RsControl::instance()->getLibraries(libraries); + verInfo+=addLibraries("libretroshare", libraries); + + /* Add version numbers of RetroShare */ + // Add versions here. Find a better place. + libraries.clear(); + libraries.push_back(RsLibraryInfo("Libmicrohttpd", MHD_get_version())); + verInfo+=addLibraries("RetroShare", libraries); + + /* Add version numbers of plugins */ + if (rsPlugins) { + for (int i = 0; i < rsPlugins->nbPlugins(); ++i) { + RsPlugin *plugin = rsPlugins->plugin(i); + if (plugin) { + libraries.clear(); + plugin->getLibraries(libraries); + verInfo+=addLibraries(plugin->getPluginName(), libraries); + } + } + } + + + QApplication::clipboard()->setText(verInfo); +} diff --git a/retroshare-gui/src/gui/AboutDialog.h b/retroshare-gui/src/gui/AboutDialog.h index d179d5959..c0095699b 100644 --- a/retroshare-gui/src/gui/AboutDialog.h +++ b/retroshare-gui/src/gui/AboutDialog.h @@ -50,6 +50,8 @@ private slots: void sl_levelChanged(int); void on_help_button_clicked(); + void on_copy_button_clicked(); + signals: void si_scoreChanged(QString); void si_maxScoreChanged(QString); diff --git a/retroshare-gui/src/gui/AboutDialog.ui b/retroshare-gui/src/gui/AboutDialog.ui index d43e9c110..d279f801c 100644 --- a/retroshare-gui/src/gui/AboutDialog.ui +++ b/retroshare-gui/src/gui/AboutDialog.ui @@ -23,7 +23,16 @@ true - + + 9 + + + 9 + + + 9 + + 9 @@ -52,6 +61,17 @@ + + + + Copy Info + + + + :/images/copy.png:/images/copy.png + + + @@ -76,7 +96,9 @@ - + + + close_button From 453415fd3e551c5228cdcefd4edaa4fe528fa66e Mon Sep 17 00:00:00 2001 From: Chozabu Date: Wed, 29 Jul 2015 01:05:05 +0100 Subject: [PATCH 003/165] minor tweak to list friends in order they are shown on graph --- .../gui/statistics/GlobalRouterStatistics.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/retroshare-gui/src/gui/statistics/GlobalRouterStatistics.cpp b/retroshare-gui/src/gui/statistics/GlobalRouterStatistics.cpp index 21bebe336..9aabeeeaf 100644 --- a/retroshare-gui/src/gui/statistics/GlobalRouterStatistics.cpp +++ b/retroshare-gui/src/gui/statistics/GlobalRouterStatistics.cpp @@ -294,6 +294,22 @@ void GlobalRouterStatisticsWidget::updateContent() oy += celly ; oy += celly ; + //print friends in the same order their prob is shown + QString FO = tr("Friend Order ("); + RsPeerDetails peer_ssl_details; + for(uint32_t i=0;igetPeerDetails(matrix_info.friend_ids[i], peer_ssl_details); + QString fn = QString::fromUtf8(peer_ssl_details.name.c_str()); + FO+=fn; + FO+=" "; + + } + FO+=")"; + + painter.drawText(ox+0*cellx,oy+fm_times.height(),FO) ; + oy += celly ; + oy += celly ; + static const int MaxKeySize = 20*fact ; painter.setFont(monospace_f) ; From 9aa8a515e2d0fd18ba2ab4134f06b230d00dc0e9 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 1 Aug 2015 23:13:44 +0200 Subject: [PATCH 004/165] updated packaging script for ubuntu/debian to work with github --- .../Debian+Ubuntu/makeSourcePackage.sh | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh index 5998c3ac9..fb2c1d49d 100755 --- a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh +++ b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh @@ -2,12 +2,12 @@ ###################### PARAMETERS #################### version="0.6.0" -svnpath="svn://csoler@svn.code.sf.net/p/retroshare/code/" +gitpath="https://github.com/RetroShare/RetroShare.git" workdir=retroshare06-${version} #bubba3="Y" # comment out to compile for bubba3 ###################################################### -echo This script is going to build the debian source package for RetroShare, from the SVN repository. +echo This script is going to build the debian source package for RetroShare, from the Git repository. if test -d "${workdir}" ; then echo Removing the ${workdir} directory... @@ -15,14 +15,15 @@ if test -d "${workdir}" ; then fi # Parse options -svnrev="" +rev="" dist="" # This is the key for "Cyril Soler " -gpgkey="C737CA98" +gpgkey="0932399B" + while [ ${#} -gt 0 ]; do case ${1} in "-rev") shift - svnrev=${1} + rev=${1} shift ;; "-distribution") shift @@ -49,46 +50,47 @@ if test "${dist}" = "" ; then dist="precise trusty utopic vivid" fi +echo Attempting to get revision number... +ccount=`git rev-list --count --all` +ccount=`expr $ccount + 8613 - 8267` + +date=`git log --pretty=format:"%ai" | head -1 | cut -d\ -f1` +hhsh=`git log --pretty=format:"%h" | head -1` + +rev=${ccount}.${hhsh} + echo " "Using PGP key id : ${gpgkey} echo " "Using distributions: ${dist} -echo " "Using svn : ${rev} - -echo Updating SVN... -svn update - -if test "${svnrev}" = "" ; then - echo Attempting to get SVN revision number... - svnrev=`svn info|awk '/^Revision:/ {print $NF}'` -else - echo SVN number has been provided. Forcing update. -fi +echo " "Commit count : ${ccount} +echo " "Date : ${date} +echo " "Hash : ${hhsh} +echo " "Using revision : ${rev} echo Done. -version="${version}"."${svnrev}" +version="${version}"."${rev}" echo Got version number ${version}. echo Please check that the changelog is up to date. echo Hit ENTER if this is correct. Otherwise hit Ctrl+C read tmp -packages="." - -echo SVN number is ${svnrev} -echo Version is ${version} - echo Extracting base archive... mkdir -p ${workdir}/src +echo Checking out latest snapshot... +cd ${workdir}/src +git clone https://github.com/RetroShare/RetroShare.git . +cd - + cp -r data ${workdir}/src/ cp -r debian ${workdir}/debian -echo Checking out latest snapshot... -cd ${workdir}/src -svn co -r${svnrev} ${svnpath}/trunk/ . -cd - +#svn co -r${rev} ${svnpath}/trunk/ . # VOIP tweak cp ${workdir}/src/retroshare-gui/src/gui/chat/PopupChatDialog.ui ${workdir}/src/plugins/VOIP/gui/PopupChatDialog.ui +echo waiting... +read tmp # # handling of libssh # LIBSSH_VERSION=0.6.4 # LIBSSH_LOCATION=https://git.libssh.org/projects/libssh.git/snapshot/libssh-${LIBSSH_VERSION}.tar.gz @@ -107,7 +109,7 @@ cd ${workdir} echo Setting version numbers... # setup version numbers -sed -e "s%RS_REVISION_NUMBER.*%RS_REVISION_NUMBER ${svnrev}%" src/libretroshare/src/retroshare/rsversion.in > src/libretroshare/src/retroshare/rsversion.h +sed -e "s%RS_REVISION_NUMBER.*%RS_REVISION_NUMBER ${rev}%" src/libretroshare/src/retroshare/rsversion.in > src/libretroshare/src/retroshare/rsversion.h # Various cleaning echo Cleaning... @@ -116,7 +118,7 @@ find . -depth -name ".svn" -a -type d -exec rm -rf {} \; # remove all svn rep echo Calling debuild... for i in ${dist}; do echo copying changelog for ${i} - sed -e s/XXXXXX/"${svnrev}"/g -e s/YYYYYY/"${i}"/g ../changelog > debian/changelog + 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 From 1248cdc7d9d85bdbbe854f05be92dec375f5061c Mon Sep 17 00:00:00 2001 From: thunder2 Date: Sun, 2 Aug 2015 01:27:17 +0200 Subject: [PATCH 005/165] Added .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..ee312b765 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/RetroShare.pro.user \ No newline at end of file From ee887e7f604a38a38b32ed548a1fa502b851ace0 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 2 Aug 2015 16:45:26 +0200 Subject: [PATCH 006/165] updated ubuntu changelog --- build_scripts/Debian+Ubuntu/changelog | 82 ++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/build_scripts/Debian+Ubuntu/changelog b/build_scripts/Debian+Ubuntu/changelog index 601c16e6f..6c74c0948 100644 --- a/build_scripts/Debian+Ubuntu/changelog +++ b/build_scripts/Debian+Ubuntu/changelog @@ -1,4 +1,84 @@ -retroshare06 (0.6.0-0.XXXXXX~YYYYYY) YYYYYY; urgency=low +retroshare06 (0.6.0-1.XXXXXX~YYYYYY) YYYYYY; urgency=low + + GUI + - improved filtering method against lol bombs. Thx to ConcernedCitizen for pointing this out + - fix #21 typo "defaut" instead of "default" in switch statement in RSGraphWidget (patch from Chozabu) + - moved all bw graph files in statistics. Removed outqueue info widget. Created new cpp files to host the bw graph code. + Started minimal UI to display bw information. The goal is t + - fixed position of scaled/highlighted nodes in node graph (patch from Chozabu) + - fixed a few bugs in statistics GUI. Still misses names and proper curve display + - Enabled Messenger Window in system tray icon. + - Fixed overlay icon (star) for tray icon. + - fixed up various places in the GUI for high DPI screens (new icons and icon qrc file generation script, font-size based widgets, etc) + - disable update of group messages for IdService since it is unused and takes some bandwidth + - fixed typo in server page "127.0.01" + - Added stylesheet to plugins. + - Moved fix font from GenCertDialog to qss (Modified patch from Henry). Added defaults to ui without style sheet + - Fixed typo in string (Patch from Henry). + - Added customize of columns to RSTreeWidget. + - added back functionality to choose DL directory for each channel + - Removed generate of channel messages. + - FriendList: - Added customize of columns with RSTreeWidget. - Reduced display menu. + - Optimized fill of forums when modifying the read state. + - Fixed compile with Qt 5 + - Added disable/enable of GxsIdDetails process. Disabled GxsIdDetails process when filling gxs id's in forums. + - Optimized load of forums by moving the avatar handling for the tooltip to the tooltip creation. + + + added correct image file for finished transfers + + - added correct image file for finished transfers + + Backend / Coverity bug fixes + - removed old function entry to collect outqueue stats. + - removed unused method for OutQueue statistics; improved BW curve display; fixed a few display bugs + - Added missing initialization in - pqissl - pqissludp - PeerConnectStateBox - RsTlvBanListEntry - RsServer + TcpStream - PGPCertificateInfo - peerConnectAddress - AudioInputConfig + - Fixed usage of member _thread_id in RsMutex + - Removed unused member from ProfileManager. + - Added missing restore of ostream format (std::dec) in rschatitems.cc. + - Added missing restore of ostream format (std::dec) in CreateLobbyDialog::createLobby. + - Fixed crash in ChatMsgItem::removeItem when "mParent == NULL". + - Added missing restore of ostream format (std::dec) in p3ServiceServer::sendItem. + - Fixed crash in ChatLobbyUserNotify::subMenuClicked when using "Remove All" of the chat lobby notifier. + - Fixed possible crash in DetailsDialog::setFileHash by checking return value of dynamic_cast. + - Fixed possible crash in ftServer::receiveTurtleData by checking return value of dynamic_cast. + - Fixed possible crash in ftServer::handleIncoming by checking return value of dynamic_cast. + - Fixed possible crash in ServiceControlSerialiser by checking return value of dynamic_cast. + - Fixed possible crash in RsFileTransferSerialiser by checking return value of dynamic_cast. + - Fixed possible crash in ChatLobbyDialog::init by checking return value of dynamic_cast. + - Fixed possible crash in RsGRouterSerialiser by checking return value of dynamic_cast. + - added basic functions to collect bandwidth info in pqistreamer both ways; added a sorting method in BWGraphSource + to create curves from extracted BW info. Still not yet functiona + - Fixed possible crash in RsGxsIdSerialiser by checking return value of dynamic_cast. + - Fixed possible crash in p3GRouter by checking return value of dynamic_cast. + - Removed dead code from ImHistoryBrowser::fillItem. + - Removed potentially unintentional integer overflow in NxsBandwidthRecorder::recordEvent. + - Added initialize of RsGxsChannelPost members. + - fixed potential integer problem in image de-serialization (reported by HM) + - Added initialize of RsVOIPPingItem members + - fixed potential integer problems in de-serialization of different TLV items (patch from Henry) + + Plugins + - fix #20 crash on shutdown with plugins enabled. Settings window did leak plugin config pages (patch from hunbernd) + + WebUI + - allow only whitelisted link protocols to prevent javascript in links + - improved error message in webui: show full path of file if read failed + - make link detection work if the message ends with + - added chat + - fix serialisation of floating point numbers in SuperEasyJSON for german locale. JSON expects decimal points, but german locale used comma. + + GXS IDs + - added additional key checking for IDs received during distant chat DH handshake + - added methods to check public/private keys for consistent fingerprint and content. Should be later used to check GXS keys when they arrive from neighbor nodes. + + Distant chat + - Added check of function parameter to DistantChatService::handleRecvDHPublicKey. + + -- Cyril Soler Sun, 02 Aug 2015 16:00:00 +0100 + +retroshare06 (0.6.0-0.8551~precise) precise; urgency=low GUI From 1e23b972445b8a1476ada716b3f85575d672cedf Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 2 Aug 2015 17:07:05 +0200 Subject: [PATCH 007/165] updated packaging script --- build_scripts/Debian+Ubuntu/makeSourcePackage.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh index fb2c1d49d..fac3c5fb9 100755 --- a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh +++ b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh @@ -54,15 +54,17 @@ echo Attempting to get revision number... ccount=`git rev-list --count --all` ccount=`expr $ccount + 8613 - 8267` -date=`git log --pretty=format:"%ai" | head -1 | cut -d\ -f1` +date=`git log --pretty=format:"%ai" | head -1 | cut -d\ -f1 | sed -e s/-//g` +time=`git log --pretty=format:"%aD" | head -1 | cut -d\ -f5 | sed -e s/://g` hhsh=`git log --pretty=format:"%h" | head -1` -rev=${ccount}.${hhsh} +rev=${date}.${hhsh} echo " "Using PGP key id : ${gpgkey} echo " "Using distributions: ${dist} echo " "Commit count : ${ccount} echo " "Date : ${date} +echo " "Time : ${time} echo " "Hash : ${hhsh} echo " "Using revision : ${rev} @@ -109,7 +111,7 @@ cd ${workdir} echo Setting version numbers... # setup version numbers -sed -e "s%RS_REVISION_NUMBER.*%RS_REVISION_NUMBER ${rev}%" src/libretroshare/src/retroshare/rsversion.in > src/libretroshare/src/retroshare/rsversion.h +sed -e "s%RS_REVISION_NUMBER.*%RS_REVISION_NUMBER 0x0${hssh}%" > src/libretroshare/src/retroshare/rsversion.h # Various cleaning echo Cleaning... From 721b4675d8fe051f423c54f59e5b19ffd6555959 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 2 Aug 2015 17:12:48 +0200 Subject: [PATCH 008/165] updated packaging scripts --- build_scripts/Debian+Ubuntu/makeSourcePackage.sh | 2 +- libretroshare/src/retroshare/rsversion.h | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh index fac3c5fb9..ee44c0e10 100755 --- a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh +++ b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh @@ -56,7 +56,7 @@ ccount=`expr $ccount + 8613 - 8267` date=`git log --pretty=format:"%ai" | head -1 | cut -d\ -f1 | sed -e s/-//g` time=`git log --pretty=format:"%aD" | head -1 | cut -d\ -f5 | sed -e s/://g` -hhsh=`git log --pretty=format:"%h" | head -1` +hhsh=`git log --pretty=format:"%H" | head -1 | cut -c1-8` rev=${date}.${hhsh} diff --git a/libretroshare/src/retroshare/rsversion.h b/libretroshare/src/retroshare/rsversion.h index f0707c1e9..3685a569f 100644 --- a/libretroshare/src/retroshare/rsversion.h +++ b/libretroshare/src/retroshare/rsversion.h @@ -2,4 +2,10 @@ #define RS_MINOR_VERSION 6 #define RS_BUILD_NUMBER 0 #define RS_BUILD_NUMBER_ADD "x" // <-- do we need this? -#define RS_REVISION_NUMBER 0001 + +// The revision number should be the 4 first bytes of the git revision hash, which is obtained using: +// git log --pretty="%H" | head -1 | cut -c1-8 +// +// Do not forget the 0x, since the RS_REVISION_NUMBER should be an integer. +// +#define RS_REVISION_NUMBER 0x01234567 From 2b8eafa1dbfd252b6391640bd04f2e3e92ec4bc1 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 2 Aug 2015 18:35:27 +0200 Subject: [PATCH 009/165] removed default debug flag in .pro files. Fixed up version.h in packaging script. --- build_scripts/Debian+Ubuntu/makeSourcePackage.sh | 13 +++++++++---- libretroshare/src/libretroshare.pro | 3 +-- openpgpsdk/src/openpgpsdk.pro | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh index ee44c0e10..f7fbcfd97 100755 --- a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh +++ b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh @@ -83,6 +83,11 @@ cd ${workdir}/src git clone https://github.com/RetroShare/RetroShare.git . cd - +if ! test -d ${workdir}/src/libretroshare/; then + echo Git clone failed. + exit +fi + cp -r data ${workdir}/src/ cp -r debian ${workdir}/debian @@ -91,8 +96,6 @@ cp -r debian ${workdir}/debian # VOIP tweak cp ${workdir}/src/retroshare-gui/src/gui/chat/PopupChatDialog.ui ${workdir}/src/plugins/VOIP/gui/PopupChatDialog.ui -echo waiting... -read tmp # # handling of libssh # LIBSSH_VERSION=0.6.4 # LIBSSH_LOCATION=https://git.libssh.org/projects/libssh.git/snapshot/libssh-${LIBSSH_VERSION}.tar.gz @@ -111,11 +114,13 @@ cd ${workdir} echo Setting version numbers... # setup version numbers -sed -e "s%RS_REVISION_NUMBER.*%RS_REVISION_NUMBER 0x0${hssh}%" > src/libretroshare/src/retroshare/rsversion.h +sed -e "s%RS_REVISION_NUMBER.*%RS_REVISION_NUMBER 0x${hhsh}%" src/libretroshare/src/retroshare/rsversion.in > src/libretroshare/src/retroshare/rsversion.h # Various cleaning echo Cleaning... -find . -depth -name ".svn" -a -type d -exec rm -rf {} \; # remove all svn repositories + +\rm -rf src/.git +#find . -depth -name ".svn" -a -type d -exec rm -rf {} \; # remove all svn repositories echo Calling debuild... for i in ${dist}; do diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index a103392eb..14833d4cd 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -6,7 +6,7 @@ TARGET = retroshare #GXS Stuff. # This should be disabled for releases until further notice. -CONFIG += gxs debug +CONFIG += gxs #CONFIG += dsdv @@ -19,7 +19,6 @@ profiling { #QMAKE_CFLAGS += -Werror #QMAKE_CXXFLAGS += -Werror -CONFIG += debug debug { # DEFINES *= DEBUG # DEFINES *= OPENDHT_DEBUG DHT_DEBUG CONN_DEBUG DEBUG_UDP_SORTER P3DISC_DEBUG DEBUG_UDP_LAYER FT_DEBUG EXTADDRSEARCH_DEBUG diff --git a/openpgpsdk/src/openpgpsdk.pro b/openpgpsdk/src/openpgpsdk.pro index dced8d172..c0f741857 100644 --- a/openpgpsdk/src/openpgpsdk.pro +++ b/openpgpsdk/src/openpgpsdk.pro @@ -2,7 +2,7 @@ TEMPLATE = lib win32 { CONFIG += staticlib } else { - CONFIG = staticlib debug + CONFIG = staticlib } DEFINES *= OPENSSL_NO_IDEA From 9e978e1442df9a227b2e9961e1c431cce9a3b375 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 2 Aug 2015 19:10:59 +0200 Subject: [PATCH 010/165] updated version info to new hexa format --- libretroshare/src/util/rsversioninfo.cc | 2 +- libretroshare/src/version_detail.sh | 24 ++++++++++++------------ retroshare-gui/src/rshare.cpp | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/libretroshare/src/util/rsversioninfo.cc b/libretroshare/src/util/rsversioninfo.cc index 96520af62..04f03322f 100644 --- a/libretroshare/src/util/rsversioninfo.cc +++ b/libretroshare/src/util/rsversioninfo.cc @@ -12,7 +12,7 @@ std::string RsUtil::retroshareVersion() { std::string version; - rs_sprintf(version, "%d.%d.%d%s Revision %d", RS_MAJOR_VERSION, RS_MINOR_VERSION, RS_BUILD_NUMBER, RS_BUILD_NUMBER_ADD, RS_REVISION_NUMBER); + rs_sprintf(version, "%d.%d.%d%s Revision %08x", RS_MAJOR_VERSION, RS_MINOR_VERSION, RS_BUILD_NUMBER, RS_BUILD_NUMBER_ADD, RS_REVISION_NUMBER); return version; } diff --git a/libretroshare/src/version_detail.sh b/libretroshare/src/version_detail.sh index b9fbead07..d13a30978 100755 --- a/libretroshare/src/version_detail.sh +++ b/libretroshare/src/version_detail.sh @@ -5,24 +5,24 @@ set +e if ( git log -n 1 &> /dev/null); then #retrieve git information - version="git : $(git status | grep branch | cut -c 13-) $(git log -n 1 | grep commit | cut -c 8-)" + version="$(git log --pretty=format:"%H" | head -1 | cut -c1-8)" fi -if ( git log -n 1 | grep svn &> /dev/null); then - #retrieve git svn information - version="${version} svn : $(git log -n 1 | awk '/svn/ {print $2}' | head -1 | sed 's/.*@//')" -elif ( git log -n 10 | grep svn &> /dev/null); then - #retrieve git svn information - version="${version} svn closest version : $(git log -n 10 | awk '/svn/ {print $2}' | head -1 | sed 's/.*@//')" -fi +# if ( git log -n 1 | grep svn &> /dev/null); then +# #retrieve git svn information +# version="${version} svn : $(git log -n 1 | awk '/svn/ {print $2}' | head -1 | sed 's/.*@//')" +# elif ( git log -n 10 | grep svn &> /dev/null); then +# #retrieve git svn information +# version="${version} svn closest version : $(git log -n 10 | awk '/svn/ {print $2}' | head -1 | sed 's/.*@//')" +# fi -if ( svn info &> /dev/null); then - version=$(svn info | awk '/^Revision:/ {print $NF}') -fi +# if ( svn info &> /dev/null); then +# version=$(svn info | awk '/^Revision:/ {print $NF}') +# fi if [[ ${version} != '' ]]; then echo "Writing version to retroshare/rsversion.h : ${version}" - sed -e "s%RS_REVISION_NUMBER.*%RS_REVISION_NUMBER ${version}%" retroshare/rsversion.in >retroshare/rsversion.h + sed -e "s%RS_REVISION_NUMBER.*%RS_REVISION_NUMBER 0x${version}%" retroshare/rsversion.in >retroshare/rsversion.h fi echo "script version_detail.sh finished normally" exit 0 diff --git a/retroshare-gui/src/rshare.cpp b/retroshare-gui/src/rshare.cpp index 46dbc8c3f..8c049b3c5 100644 --- a/retroshare-gui/src/rshare.cpp +++ b/retroshare-gui/src/rshare.cpp @@ -178,7 +178,7 @@ QString Rshare::retroshareVersion(bool withRevision) { QString version = QString("%1.%2.%3%4").arg(RS_MAJOR_VERSION).arg(RS_MINOR_VERSION).arg(RS_BUILD_NUMBER).arg(RS_BUILD_NUMBER_ADD); if (withRevision) { - version += QString(" %1 %2").arg(tr("Revision")).arg(RS_REVISION_NUMBER); + version += QString(" %1 %2").arg(tr("Revision")).arg(QString::number(RS_REVISION_NUMBER,16)); } return version; From 34ec6dfd6cede8211cc522f050fde2cc39a0f0f8 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 2 Aug 2015 19:11:31 +0200 Subject: [PATCH 011/165] fixed cleaning script --- build_scripts/Debian+Ubuntu/clean.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build_scripts/Debian+Ubuntu/clean.sh b/build_scripts/Debian+Ubuntu/clean.sh index 8eeaf34f4..6e68064f9 100755 --- a/build_scripts/Debian+Ubuntu/clean.sh +++ b/build_scripts/Debian+Ubuntu/clean.sh @@ -1,11 +1,11 @@ #!/bin/sh rm -f ./libssh-0.5.4.tar.gz.* -rm -f ./retroshare06_0.6.0-0.*_source.build -rm -f ./retroshare06_0.6.0-0.*_source.changes -rm -f ./retroshare06_0.6.0-0.*.tar.gz -rm -f ./retroshare06_0.6.0-0.*.diff.gz -rm -f ./retroshare06_0.6.0-0.*.dsc +rm -f ./retroshare06_0.6.0-1.*_source.build +rm -f ./retroshare06_0.6.0-1.*_source.changes +rm -f ./retroshare06_0.6.0-1.*.tar.gz +rm -f ./retroshare06_0.6.0-1.*.diff.gz +rm -f ./retroshare06_0.6.0-1.*.dsc rm -f *.upload rm -f *~ From 1412dc6466efe31754b67ce695723d20b945cb29 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 3 Aug 2015 00:06:31 +0200 Subject: [PATCH 012/165] packaging: Removed utopic, added new ppa name --- build_scripts/Debian+Ubuntu/makeSourcePackage.sh | 2 +- build_scripts/Debian+Ubuntu/ppa_upload.sh | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh index f7fbcfd97..da096fb7f 100755 --- a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh +++ b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh @@ -47,7 +47,7 @@ while [ ${#} -gt 0 ]; do done if test "${dist}" = "" ; then - dist="precise trusty utopic vivid" + dist="precise trusty vivid" fi echo Attempting to get revision number... diff --git a/build_scripts/Debian+Ubuntu/ppa_upload.sh b/build_scripts/Debian+Ubuntu/ppa_upload.sh index 617a611d5..e6897618a 100644 --- a/build_scripts/Debian+Ubuntu/ppa_upload.sh +++ b/build_scripts/Debian+Ubuntu/ppa_upload.sh @@ -1,3 +1,2 @@ #!/bin/sh -Apply dput ppa:csoler-users/retroshare-snapshots retroshare_0.5.5#.changes -Apply dput ppa:csoler-users/retroshare-unstable retroshare06_0.6.0-0.#.changes +Apply dput ppa:retroshare/unstable retroshare06_0.6.0-1.#.changes From 789df68582e7e1189526604c070671e4bed897a5 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Tue, 4 Aug 2015 14:07:52 +0200 Subject: [PATCH 013/165] - Added update of version information for Windows build - Added template file version.html.in - Removed RS_BUILD_NUMBER from Windows executable FileVersion --- libretroshare/src/libretroshare.pro | 13 +++- libretroshare/src/retroshare/rsversion.h | 1 + libretroshare/src/retroshare/rsversion.in | 9 ++- libretroshare/src/svn_revision.bat | 2 - libretroshare/src/version_detail.bat | 48 +++++++++++++++ retroshare-gui/src/gui/help/version.html.in | 4 ++ .../src/gui/images/retroshare_win.rc | 10 ++-- retroshare-gui/src/retroshare-gui.pro | 15 +++-- retroshare-gui/src/svn_revision.bat | 2 - retroshare-gui/src/version_detail.bat | 59 +++++++++++++++++++ 10 files changed, 146 insertions(+), 17 deletions(-) delete mode 100644 libretroshare/src/svn_revision.bat create mode 100644 libretroshare/src/version_detail.bat create mode 100644 retroshare-gui/src/gui/help/version.html.in delete mode 100644 retroshare-gui/src/svn_revision.bat create mode 100644 retroshare-gui/src/version_detail.bat diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 14833d4cd..af6f27fc7 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -189,9 +189,16 @@ linux-g++-64 { } version_detail_bash_script { - QMAKE_EXTRA_TARGETS += write_version_detail - PRE_TARGETDEPS = write_version_detail - write_version_detail.commands = ./version_detail.sh + linux-* { + QMAKE_EXTRA_TARGETS += write_version_detail + PRE_TARGETDEPS = write_version_detail + write_version_detail.commands = ./version_detail.sh + } + win32 { + QMAKE_EXTRA_TARGETS += write_version_detail + PRE_TARGETDEPS = write_version_detail + write_version_detail.commands = $$PWD/version_detail.bat + } } #################### Cross compilation for windows under Linux #################### diff --git a/libretroshare/src/retroshare/rsversion.h b/libretroshare/src/retroshare/rsversion.h index 3685a569f..26cf284a6 100644 --- a/libretroshare/src/retroshare/rsversion.h +++ b/libretroshare/src/retroshare/rsversion.h @@ -8,4 +8,5 @@ // // Do not forget the 0x, since the RS_REVISION_NUMBER should be an integer. // +#define RS_REVISION_STRING "01234567" #define RS_REVISION_NUMBER 0x01234567 diff --git a/libretroshare/src/retroshare/rsversion.in b/libretroshare/src/retroshare/rsversion.in index d405810f7..cf3521ed2 100644 --- a/libretroshare/src/retroshare/rsversion.in +++ b/libretroshare/src/retroshare/rsversion.in @@ -2,4 +2,11 @@ #define RS_MINOR_VERSION 6 #define RS_BUILD_NUMBER 0 #define RS_BUILD_NUMBER_ADD "x" // <-- do we need this? -#define RS_REVISION_NUMBER $WCREV$ + +// The revision number should be the 4 first bytes of the git revision hash, which is obtained using: +// git log --pretty="%H" | head -1 | cut -c1-8 +// +// Do not forget the 0x, since the RS_REVISION_NUMBER should be an integer. +// +#define RS_REVISION_STRING "$REV$" +#define RS_REVISION_NUMBER 0x$REV$ diff --git a/libretroshare/src/svn_revision.bat b/libretroshare/src/svn_revision.bat deleted file mode 100644 index d828ece90..000000000 --- a/libretroshare/src/svn_revision.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -"D:\Programme\TortoiseSVN\bin\SubWCRev" . util\rsversion.in util\rsversion.h \ No newline at end of file diff --git a/libretroshare/src/version_detail.bat b/libretroshare/src/version_detail.bat new file mode 100644 index 000000000..ffb523a96 --- /dev/null +++ b/libretroshare/src/version_detail.bat @@ -0,0 +1,48 @@ +@echo off + +setlocal enabledelayedexpansion + +:: Search git in PATH +set GitPath= +for %%P in ("%PATH:;=" "%") do ( + if exist "%%~P.\git.exe" ( + set GitPath=%%~P + goto found_git + ) +) + +:found_git +if "%GitPath%"=="" ( + echo git not found in PATH. Version update cancelled. + endlocal + exit /B 0 +) + +echo Update version + +:: Retrieve git information +set RsHash= + +pushd "%~dp0" +for /f "tokens=1*" %%A in ('"git log --pretty=format:"%%H" --max-count=1"') do set RsHash=%%A +popd + +if "%RsHash%"=="" ( + echo Git hash not found. + endlocal + exit /B 1 +) + +:: Create file +set InFile=%~dp0retroshare\rsversion.in +set OutFile=%~dp0retroshare\rsversion.h +if exist "%OutFile%" del /Q "%OutFile%" + +for /f "tokens=* delims= " %%a in (%InFile%) do ( + set line=%%a + set line=!line:$REV$=%RsHash:~0,8%! + echo !line!>>"%OutFile%" +) + +endlocal +exit /B 0 diff --git a/retroshare-gui/src/gui/help/version.html.in b/retroshare-gui/src/gui/help/version.html.in new file mode 100644 index 000000000..189d71df2 --- /dev/null +++ b/retroshare-gui/src/gui/help/version.html.in @@ -0,0 +1,4 @@ +Retroshare Gui version : +Git version : $Branch$ +$Hash$ +$Date$ \ No newline at end of file diff --git a/retroshare-gui/src/gui/images/retroshare_win.rc b/retroshare-gui/src/gui/images/retroshare_win.rc index 404d6ecd2..76840ad79 100644 --- a/retroshare-gui/src/gui/images/retroshare_win.rc +++ b/retroshare-gui/src/gui/images/retroshare_win.rc @@ -5,11 +5,11 @@ IDI_ICON1 ICON "logo/logo_64.ico" #define STRINGIZER(version) #version -#define VERSION_STRING(major,minor,build,buildadd,revision) STRINGIZER(major) "." STRINGIZER(minor) "." STRINGIZER(build) buildadd "." STRINGIZER(revision) +#define VERSION_STRING(major,minor,build,buildadd,revision) STRINGIZER(major) "." STRINGIZER(minor) "." STRINGIZER(build) buildadd "." revision VS_VERSION_INFO VERSIONINFO -FILEVERSION RS_MAJOR_VERSION,RS_MINOR_VERSION,RS_BUILD_NUMBER,RS_REVISION_NUMBER -PRODUCTVERSION RS_MAJOR_VERSION,RS_MINOR_VERSION,RS_BUILD_NUMBER,RS_REVISION_NUMBER +FILEVERSION RS_MAJOR_VERSION,RS_MINOR_VERSION,RS_BUILD_NUMBER,0 +PRODUCTVERSION RS_MAJOR_VERSION,RS_MINOR_VERSION,RS_BUILD_NUMBER,0 FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS 0 FILEOS VOS_NT_WINDOWS32 @@ -22,11 +22,11 @@ BEGIN BEGIN VALUE "CompanyName", "" VALUE "FileDescription", "RetroShare" - VALUE "FileVersion", VERSION_STRING(RS_MAJOR_VERSION, RS_MINOR_VERSION, RS_BUILD_NUMBER, RS_BUILD_NUMBER_ADD, RS_REVISION_NUMBER) + VALUE "FileVersion", VERSION_STRING(RS_MAJOR_VERSION, RS_MINOR_VERSION, RS_BUILD_NUMBER, RS_BUILD_NUMBER_ADD, RS_REVISION_STRING) VALUE "InternalName", "RetroShare" VALUE "OriginalFilename", "RetroShare.exe" VALUE "ProductName", "RetroShare" - VALUE "ProductVersion", VERSION_STRING(RS_MAJOR_VERSION, RS_MINOR_VERSION, RS_BUILD_NUMBER, RS_BUILD_NUMBER_ADD, RS_REVISION_NUMBER) + VALUE "ProductVersion", VERSION_STRING(RS_MAJOR_VERSION, RS_MINOR_VERSION, RS_BUILD_NUMBER, RS_BUILD_NUMBER_ADD, RS_REVISION_STRING) VALUE "LegalCopyright", "" END END diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index ec9517108..79988dce8 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -118,10 +118,17 @@ linux-g++-64 { } version_detail_bash_script { - DEFINES += ADD_LIBRETROSHARE_VERSION_INFO - QMAKE_EXTRA_TARGETS += write_version_detail - PRE_TARGETDEPS = write_version_detail - write_version_detail.commands = ./version_detail.sh + linux-* { + DEFINES += ADD_LIBRETROSHARE_VERSION_INFO + QMAKE_EXTRA_TARGETS += write_version_detail + PRE_TARGETDEPS = write_version_detail + write_version_detail.commands = ./version_detail.sh + } + win32 { + QMAKE_EXTRA_TARGETS += write_version_detail + PRE_TARGETDEPS = write_version_detail + write_version_detail.commands = $$PWD/version_detail.bat + } } install_rs { diff --git a/retroshare-gui/src/svn_revision.bat b/retroshare-gui/src/svn_revision.bat deleted file mode 100644 index c32e950fc..000000000 --- a/retroshare-gui/src/svn_revision.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -"D:\Programme\TortoiseSVN\bin\SubWCRev" . util\rsguiversion.in util\rsguiversion.cpp \ No newline at end of file diff --git a/retroshare-gui/src/version_detail.bat b/retroshare-gui/src/version_detail.bat new file mode 100644 index 000000000..e413fc70e --- /dev/null +++ b/retroshare-gui/src/version_detail.bat @@ -0,0 +1,59 @@ +@echo off + +setlocal enabledelayedexpansion + +:: Search git in PATH +set GitPath= +for %%P in ("%PATH:;=" "%") do ( + if exist "%%~P.\git.exe" ( + set GitPath=%%~P + goto found_git + ) +) + +:found_git +if "%GitPath%"=="" ( + echo git not found in PATH. Version update cancelled. + endlocal + exit /B 0 +) + +echo Update version + +:: Retrieve git information +set RsBranch= +set RsHash= + +pushd "%~dp0" +for /f "tokens=1*" %%A in ('"git log --pretty=format:"%%H" --max-count=1"') do set RsHash=%%A +for /f "tokens=*" %%A in ('git rev-parse --abbrev-ref HEAD') do set RsBranch=%%A +popd + +if "%RsBranch%"=="" ( + echo Git branch not found. + endlocal + exit /B 1 +) +if "%RsHash%"=="" ( + echo Git hash not found. + endlocal + exit /B 1 +) + +set RsDate=%date% %TIME% + +:: Create file +set InFile=%~dp0gui\help\version.html.in +set OutFile=%~dp0gui\help\version.html +if exist "%OutFile%" del /Q "%OutFile%" + +for /f "tokens=* delims= " %%a in (%InFile%) do ( + set line=%%a + set line=!line:$Hash$=%RsHash%! + set line=!line:$Branch$=%RsBranch%! + set line=!line:$Date$=%RsDate%! + echo !line!>>"%OutFile%" +) + +endlocal +exit /B 0 From 43db562c2a171e2b735886fa8a33b0cd9e7aef4b Mon Sep 17 00:00:00 2001 From: thunder2 Date: Tue, 4 Aug 2015 19:02:13 +0200 Subject: [PATCH 014/165] Fixed build script for Windows installer --- build_scripts/Windows/GetRsVersion.bat | 43 ++++++++++++++++++++++++ build_scripts/Windows/make_installer.bat | 25 ++++++-------- build_scripts/Windows/retroshare.nsi | 7 ++-- 3 files changed, 58 insertions(+), 17 deletions(-) create mode 100644 build_scripts/Windows/GetRsVersion.bat diff --git a/build_scripts/Windows/GetRsVersion.bat b/build_scripts/Windows/GetRsVersion.bat new file mode 100644 index 000000000..153b5969d --- /dev/null +++ b/build_scripts/Windows/GetRsVersion.bat @@ -0,0 +1,43 @@ +@:: Usage: +@:: call GetRsVersion.bat Define Variable + +@setlocal +@echo off + +set Define=%~1 +if "%Define%"=="" ( + echo. + echo Parameter error + endlocal + exit /B1 +) + +set Variable=%~2 +if "%Variable%"=="" ( + echo. + echo Parameter error + endlocal + exit /B1 +) + +set Result= +set VersionFile="%~dp0..\..\libretroshare\src\retroshare\rsversion.h" + +if not exist "%VersionFile%" ( + echo. + echo Version file doesn't exist. + echo %VersionFile% + endlocal + exit /B1 +) + +for /F "usebackq tokens=1,2,3" %%A in (%VersionFile%) do ( + if "%%A"=="#define" ( + if "%%B"=="%Define%" ( + set Result=%%~C + ) + ) +) + +endlocal & set %Variable%=%Result% +exit /B 0 \ No newline at end of file diff --git a/build_scripts/Windows/make_installer.bat b/build_scripts/Windows/make_installer.bat index e2f8cfc14..42b3776e9 100644 --- a/build_scripts/Windows/make_installer.bat +++ b/build_scripts/Windows/make_installer.bat @@ -24,32 +24,27 @@ if "%MinGWDir%" NEQ "" set NSIS_PARAM=%NSIS_PARAM% /DMINGWDIR="%MinGWDir%" if "%OutDir%" NEQ "" set NSIS_PARAM=%NSIS_PARAM% /DOUTDIR="%OutDir%" :: Scan version from source +set Revision= set BuildAdd= -set VersionFile="%SourceDir%\libretroshare\src\retroshare\rsversion.h" +call "%~dp0GetRsVersion.bat" RS_REVISION_STRING Revision +if errorlevel 1 goto exit +call "%~dp0GetRsVersion.bat" RS_BUILD_NUMBER_ADD BuildAdd +if errorlevel 1 goto exit -if not exist "%VersionFile%" ( +if "%Revision%"=="" ( echo. - echo Version file doesn't exist. + echo Version not found in echo %VersionFile% - goto :exit + goto exit ) - -for /F "usebackq tokens=1,2,3" %%A in (%VersionFile%) do ( - if "%%A"=="#define" ( - if "%%B"=="RS_BUILD_NUMBER_ADD" ( - set BuildAdd=%%~C - ) - ) -) - if "%BuildAdd%"=="" ( echo. echo Version not found in echo %VersionFile% - goto :exit + goto exit ) -set NSIS_PARAM=%NSIS_PARAM% /DBUILDADD=%BuildAdd% +set NSIS_PARAM=%NSIS_PARAM% /DREVISION=%Revision% /DBUILDADD=%BuildAdd% :: Create installer "%NSIS_EXE%" %NSIS_PARAM% "%~dp0retroshare.nsi" diff --git a/build_scripts/Windows/retroshare.nsi b/build_scripts/Windows/retroshare.nsi index d6f6f9f9c..01b381657 100644 --- a/build_scripts/Windows/retroshare.nsi +++ b/build_scripts/Windows/retroshare.nsi @@ -42,7 +42,7 @@ !GetDllVersion "${RELEASEDIR}\retroshare-gui\src\release\RetroShare.exe" VERSION_ !define VERSION ${VERSION_1}.${VERSION_2}.${VERSION_3}${BUILDADD} -!define REVISION ${VERSION_4} +;!define REVISION ${VERSION_4} # Check version !ifndef REVISION @@ -53,6 +53,9 @@ !error "REVISION is not defined" !endif +# Date +!define /date Date "%Y%m%d" + # Application name and version !define APPNAME "RetroShare" !define APPNAMEANDVERSION "${APPNAME} ${VERSION}" @@ -68,7 +71,7 @@ # Main Install settings Name "${APPNAMEANDVERSION}" InstallDirRegKey HKLM "Software\${APPNAME}" "" -OutFile "${OUTDIR_}RetroShare_${VERSION}_${REVISION}_setup.exe" +OutFile "${OUTDIR_}RetroShare-${VERSION}-${Date}-${REVISION}-setup.exe" BrandingText "${APPNAMEANDVERSION}" RequestExecutionlevel highest # Use compression From 8e9f068da905fbc83406cb7da4761101d0d6703d Mon Sep 17 00:00:00 2001 From: cave beat Date: Tue, 4 Aug 2015 22:29:56 +0200 Subject: [PATCH 015/165] coverity integration to travis --- .travis.yml | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 49288fa9b..e697b0d01 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,10 +16,28 @@ before_install: # - gem update --system # - gem --version +env: + global: + # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created + # via the "travis encrypt" command using the project repo's public key + - secure: "iQ4oroMsE1Olp2ClnAXw45zzTlGcgQBuu/s2k7GGGLibXcuQkkwMpyIQaWQzrs/lPgNOu7o2vT2OzyAkW6xKvpuGW2s3cJ2+kMetVuEaB8thrBhfz44g5uHB8ep1+eDCSW3c1TyWpI5c6R0FTwwRcloJdwLsFm8wvR0bHDQ9B9CdixiX1/RtWw4U9/QqtmuSWbQFz3skNo4MurbjKh3u/DmuddFSWJoS/B69vkSrUtfHDBP8x2dVqXOXMfQZ6vZI+RhQPp7LN17g5VbyMzPlNihGY7muBuxn1i56d1Q3hz82d1bfSAywK1aiGOL/fZwkd5cpvUIF9mltYs9l5Xj/1mkcBLUhVuMbi7FfrbKgXwInG4p9zduEADGsg44kQ7W6fp9qcEpaInrDsXk55KqP2IF6/MkoG5zqRHgqgjnGy8qW7PTXHyZeagvXOdQHyCeR+XC4P973n7elTF4a/VM2VAvjm6+AGhNUjPaHz8fmLdgNs+WZZxRMqDKvUo0qk3KH4N6rrNkVOp/gkSDQrpN+jaK7QASyCeEo9DYjNstabzsYYu0dEjj7ZrRN5cUGYt6hBk2HTU2suUiSi5zVocXEJRDDHWGD0reXKDsnWTtjqtj+ef7tk9uo3UhKwNvC/WAktzrgMQfj5MGZ0rz3P7A96dKeWmCmmjR9X5Xne0iqW1M=" + +addons: + coverity_scan: + project: + name: "cavebeat/RetroShare" + description: "Build submitted via Travis CI" + notification_email: cave@cavebeat.org + build_command_prepend: "qmake; make clean" + build_command: "make -j 4" + branch_pattern: coverity_scan + before_script: - qmake -script: make +#script: make +script: if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then make ; fi + #after_success: # - if [ $TRAVIS_BRANCH == $TRAVIS_TAG ]; then rake deploy; fi @@ -47,4 +65,4 @@ notifications: # - RVM=2.0.0 LANG="en_US.UTF-8" os: - - linux \ No newline at end of file + - linux From 51ab1fcf673fd7c8b11cbeb78020266cab39f769 Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 5 Aug 2015 12:25:13 +0200 Subject: [PATCH 016/165] updated readme file --- README.txt | 99 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/README.txt b/README.txt index 07a43335a..4862c5cc0 100644 --- a/README.txt +++ b/README.txt @@ -1,67 +1,70 @@ -To compile: +Compilation on Ubuntu/Debian +============================ + +1 - install package dependencies: -- install the package dependencies. On ubuntu: # sudo apt-get install libglib2.0-dev libupnp-dev qt4-dev-tools \ - libqt4-dev libssl-dev libxss-dev libgnome-keyring-dev libbz2-dev \ + qt4-dev-tools libqt4-dev libssl-dev libxss-dev libgnome-keyring-dev libbz2-dev \ libqt4-opengl-dev libqtmultimediakit1 qtmobility-dev \ - libspeex-dev libspeexdsp-dev libxslt1-dev libprotobuf-dev \ - protobuf-compiler cmake libcurl4-openssl-dev + libspeex-dev libspeexdsp-dev libxslt1-dev libcurl4-openssl-dev + +2 - checkout the source code -- create project directory (e.g. ~/retroshare) and check out the source code # mkdir ~/retroshare - # cd ~/retroshare && svn co svn://svn.code.sf.net/p/retroshare/code/trunk trunk + # cd ~/retroshare + # git clone https://github.com/RetroShare/RetroShare.git trunk -- create a new directory named lib - # mkdir lib +3 - compile -- get source code for libssh-0.5.4, unzip it, and create build directory (if needed) - - # cd lib - # wget http://git.libssh.org/projects/libssh.git/snapshot/libssh-libssh-0.6.4.zip - # tar zxvf libssh-0.6.4.tar.gz - # cd libssh-0.6.4 - # mkdir build - # cd build - # cmake -DWITH_STATIC_LIB=ON -DWITH_GSSAPI=OFF .. - # make - # cd ../../.. - -- get source code for sqlcipher, and build it (only needed for GXS) - - # cd lib - # git clone git://github.com/sqlcipher/sqlcipher.git - # cd sqlcipher - # ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \ - LDFLAGS="-lcrypto" - # make - # cd .. - -- go to your svn base directory # cd trunk - # qmake CONFIG=release - # make -j 4 + # qmake CONFIG=debug + # make + + => the executables produced will be - => the executable produced will be trunk/retroshare-gui/src/Retroshare trunk/retroshare-nogui/src/retroshare-nogui -- to use the SSH RS server (nogui): +If libsqlcipher is not available as a package: +============================================= - # ssh-keygen -t rsa -f rs_ssh_host_rsa_key # this makes a RSA - # ./retroshare-nogui -G # generates a login+passwd hash for the RSA key used. - # ./retroshare-nogui -S 7022 -U[SSLid] -P [Passwd hash] + You need to place sqlcipher so that the hierarchy is: -- to connect from a remote place to the server by SSH: + retroshare + | + +--- trunk + | + +--- lib + | + +---- sqlcipher - # ssh -T -p 7022 [user]@[host] + # mkdir lib + # cd lib + # git clone git://github.com/sqlcipher/sqlcipher.git + # cd sqlcipher + # ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" LDFLAGS="-lcrypto" + # make + # cd .. - and use the command line interface to control your RS instance. +Using retroshare-nogui & webUI +============================== -List of non backward compatible changes for V0.6: -================================================ + The webUI needs to be enabled as a parameter option in retroshare-nogui: + + ./retroshare-nogui --webinterface 9090 --docroot /usr/share/RetroShare06/webui/ + + The webUI is only accessible on localhost:9090 (unless you canged that + option in the GUI). It is advised to keep it that way so that your RS + cannot be controlled using an untrusted connection. + + To access your web UI from a distance, just open a SSH tunnel on it: + + distant_machine:~/ > ssh rs_host -L 9090:localhost:9090 -N + + "rs_host" is the machine running retroshare-nogui. Then on the distant machine, access your webUI on + + http://localhost:9090 + + That also works with a retroshare GUI of course. -- in rscertificate.cc, enable V_06_USE_CHECKSUM -- in p3charservice, remove all usage of _deprecated items -- turn file transfer into a service. Will break item IDs, but cleanup and - simplify lots of code. From a87adb87ccaf71ded4e179a7a4005cff5cf2a61f Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 5 Aug 2015 15:52:47 +0200 Subject: [PATCH 017/165] improved README file --- README.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.txt b/README.txt index 4862c5cc0..02475b120 100644 --- a/README.txt +++ b/README.txt @@ -6,7 +6,8 @@ Compilation on Ubuntu/Debian # sudo apt-get install libglib2.0-dev libupnp-dev qt4-dev-tools \ qt4-dev-tools libqt4-dev libssl-dev libxss-dev libgnome-keyring-dev libbz2-dev \ libqt4-opengl-dev libqtmultimediakit1 qtmobility-dev \ - libspeex-dev libspeexdsp-dev libxslt1-dev libcurl4-openssl-dev + libspeex-dev libspeexdsp-dev libxslt1-dev libcurl4-openssl-dev \ + libopencv-dev, tcl8.5, libmicrohttpd-dev 2 - checkout the source code From 168eb45539c92b286e0fb00b77aadc0a569783e1 Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 5 Aug 2015 20:51:34 +0200 Subject: [PATCH 018/165] removed debug info about missing keys; added debug info about deserialization checking of string --- libretroshare/src/serialiser/rstlvbase.cc | 5 +++++ libretroshare/src/services/p3idservice.cc | 2 ++ 2 files changed, 7 insertions(+) diff --git a/libretroshare/src/serialiser/rstlvbase.cc b/libretroshare/src/serialiser/rstlvbase.cc index 21b99e96a..5bd704fe4 100644 --- a/libretroshare/src/serialiser/rstlvbase.cc +++ b/libretroshare/src/serialiser/rstlvbase.cc @@ -602,6 +602,11 @@ bool GetTlvString(void *data, uint32_t size, uint32_t *offset, in = std::string(strdata, strsize); } +#ifdef TLV_BASE_DEBUG + if(type == TLV_TYPE_STR_MSG) + std::cerr << "Checking string \"" << in << "\"" << std::endl; +#endif + // Check for string content. We want to avoid possible lol bombs as soon as possible. static const int number_of_suspiscious_strings = 4 ; diff --git a/libretroshare/src/services/p3idservice.cc b/libretroshare/src/services/p3idservice.cc index 6e8105770..8eaa08928 100644 --- a/libretroshare/src/services/p3idservice.cc +++ b/libretroshare/src/services/p3idservice.cc @@ -718,7 +718,9 @@ bool p3IdService::validateData(const uint8_t *data,uint32_t data_size,const RsTl if(signature_key.keyData.bin_data == NULL) { +#ifdef DEBUG_IDS std::cerr << "(EE) Cannot validate signature for unknown key " << signature.keyId << std::endl; +#endif signing_error = RS_GIXS_ERROR_KEY_NOT_AVAILABLE ; return false; } From fabc3a398536565efe77fb1b1ef37bd484dc7d4a Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 5 Aug 2015 20:53:18 +0200 Subject: [PATCH 019/165] added some rules to .gitignore --- .gitignore | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ee312b765..0a7937db7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,8 @@ -/RetroShare.pro.user \ No newline at end of file +/RetroShare.pro.user +*.o +moc_*.cpp +qrc_*.cpp +ui_*.h +Makefile.* +*~ + From 48bb8b48c9b93122ae5ccd011456903c371c1240 Mon Sep 17 00:00:00 2001 From: sehraf Date: Wed, 5 Aug 2015 23:41:04 +0200 Subject: [PATCH 020/165] sequel to 6b2ed2fb2d84d7e48b15fa917aa4eb8015922d15 --- retroshare-gui/src/gui/MainWindow.cpp | 10 +++++----- retroshare-gui/src/gui/settings/PluginsPage.cpp | 10 ++++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index 4e5f6fa63..05aaade2d 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -391,17 +391,17 @@ void MainWindow::initStackedPage() std::cerr << "Looking for interfaces in existing plugins:" << std::endl; for(int i = 0;inbPlugins();++i) { - QIcon icon ; + MainPage *pluginPage = NULL; + QIcon icon, *pIcon = NULL; - if(rsPlugins->plugin(i) != NULL && rsPlugins->plugin(i)->qt_page() != NULL) + if(rsPlugins->plugin(i) != NULL && (pluginPage = rsPlugins->plugin(i)->qt_page()) != NULL) { - if(rsPlugins->plugin(i)->qt_icon() != NULL) - icon = *rsPlugins->plugin(i)->qt_icon() ; + if((pIcon = rsPlugins->plugin(i)->qt_icon()) != NULL) + icon = *pIcon ; else icon = QIcon(":images/extension_48.png") ; std::cerr << " Addign widget page for plugin " << rsPlugins->plugin(i)->getPluginName() << std::endl; - MainPage *pluginPage = rsPlugins->plugin(i)->qt_page(); pluginPage->setIconPixmap(icon); pluginPage->setPageName(QString::fromUtf8(rsPlugins->plugin(i)->getPluginName().c_str())); addPage(pluginPage, grp, ¬ify); diff --git a/retroshare-gui/src/gui/settings/PluginsPage.cpp b/retroshare-gui/src/gui/settings/PluginsPage.cpp index 23b4bb5a6..33b7bd1ac 100644 --- a/retroshare-gui/src/gui/settings/PluginsPage.cpp +++ b/retroshare-gui/src/gui/settings/PluginsPage.cpp @@ -90,8 +90,9 @@ PluginsPage::PluginsPage(QWidget * parent, Qt::WindowFlags flags) if(plugin!=NULL) { - if(plugin->qt_icon() != NULL) - plugin_icon = *plugin->qt_icon() ; + QIcon *icon = plugin->qt_icon(); + if(icon != NULL) + plugin_icon = *icon ; pluginTitle = QString::fromUtf8(plugin->getPluginName().c_str()) ; pluginDescription = QString::fromUtf8(plugin->getShortPluginDescription().c_str()) ; @@ -169,8 +170,9 @@ void PluginsPage::aboutPlugin(int i) { std::cerr << "Launching about window for plugin " << i << std::endl; - if(rsPlugins->plugin(i) != NULL && rsPlugins->plugin(i)->qt_about_page() != NULL) - rsPlugins->plugin(i)->qt_about_page()->exec() ; + QDialog *dialog = NULL; + if(rsPlugins->plugin(i) != NULL && (dialog = rsPlugins->plugin(i)->qt_about_page()) != NULL) + dialog->exec() ; } void PluginsPage::configurePlugin(int i) { From c168765bb257a07f0d778f15c00ccea030ae851b Mon Sep 17 00:00:00 2001 From: defnax Date: Fri, 7 Aug 2015 15:14:47 +0200 Subject: [PATCH 021/165] Added tab for the DHT TreeWidgets for better view Added a search Filter for DHT IP addresses --- .../src/gui/statistics/DhtWindow.cpp | 47 +- retroshare-gui/src/gui/statistics/DhtWindow.h | 6 + .../src/gui/statistics/DhtWindow.ui | 1156 +++++++++-------- 3 files changed, 655 insertions(+), 554 deletions(-) diff --git a/retroshare-gui/src/gui/statistics/DhtWindow.cpp b/retroshare-gui/src/gui/statistics/DhtWindow.cpp index 083c5ea58..7827f296e 100644 --- a/retroshare-gui/src/gui/statistics/DhtWindow.cpp +++ b/retroshare-gui/src/gui/statistics/DhtWindow.cpp @@ -40,7 +40,9 @@ DhtWindow::DhtWindow(QWidget *parent) : RsAutoUpdatePage(1000,parent) { ui.setupUi(this); - + + connect( ui.filterLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(filterItems(QString))); + connect( ui.filterLineEdit, SIGNAL(filterChanged(int)), this, SLOT(filterColumnChanged(int))); } DhtWindow::~DhtWindow() @@ -700,3 +702,46 @@ void DhtWindow::getDHTStatus() // } // } } + +void DhtWindow::filterColumnChanged(int) +{ + filterItems(ui.filterLineEdit->text()); +} + +void DhtWindow::filterItems(const QString &text) +{ + int filterColumn = ui.filterLineEdit->currentFilter(); + + int count = ui.dhtTreeWidget->topLevelItemCount (); + for (int index = 0; index < count; ++index) { + filterItem(ui.dhtTreeWidget->topLevelItem(index), text, filterColumn); + } +} + +bool DhtWindow::filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn) +{ + bool visible = true; + + if (text.isEmpty() == false) { + if (item->text(filterColumn).contains(text, Qt::CaseInsensitive) == false) { + visible = false; + } + } + + int visibleChildCount = 0; + int count = item->childCount(); + for (int index = 0; index < count; ++index) { + if (filterItem(item->child(index), text, filterColumn)) { + ++visibleChildCount; + } + } + + if (visible || visibleChildCount) { + item->setHidden(false); + } else { + item->setHidden(true); + } + + return (visible || visibleChildCount); +} + diff --git a/retroshare-gui/src/gui/statistics/DhtWindow.h b/retroshare-gui/src/gui/statistics/DhtWindow.h index d95d50cb1..83d550336 100644 --- a/retroshare-gui/src/gui/statistics/DhtWindow.h +++ b/retroshare-gui/src/gui/statistics/DhtWindow.h @@ -42,11 +42,17 @@ public: public slots: virtual void updateDisplay() ; + void filterColumnChanged(int); + void filterItems(const QString &text); + + protected: //void changeEvent(QEvent *e); private: + bool filterItem(QTreeWidgetItem *item, const QString &text, int filterColumn); + /** Qt Designer generated object */ Ui::DhtWindow ui; diff --git a/retroshare-gui/src/gui/statistics/DhtWindow.ui b/retroshare-gui/src/gui/statistics/DhtWindow.ui index 1a8425812..dac79743d 100644 --- a/retroshare-gui/src/gui/statistics/DhtWindow.ui +++ b/retroshare-gui/src/gui/statistics/DhtWindow.ui @@ -23,577 +23,622 @@ DHT - - - - - Qt::Vertical - - - + + + + + - + - - - - - - 75 - true - - - - Net Status: - - - - - - - Qt::LeftToRight - - - Net Status - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - - - 75 - true - - - - Network Mode: - - - - - - - Network Mode - - - - - - - - - - - - 75 - true - - - - Nat Type: - - - - - - - Nat Type - - - - - - - - - - - - 75 - true - - - - Nat Hole: - - - - - - - Nat Hole - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - - 75 - true - - - - Connect Mode: - - - - - - - - 0 - 0 - - - - Qt::LeftToRight - - - Connect Options - - - - - - - - - - - - 75 - true - - - - Peer Address: - - - - - - - - 0 - 0 - - - - Peer Address - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - - - - - 75 - true - - - - Unreach: - - - - - - - - - - - - - - - - - - - 75 - true - - - - Online: - - - - - - - - - - - - - - - - - - - 75 - true - - - - Offline: - - - - - - - - - - - - - - - - - - - 75 - true - - - - DHT Peers: - - - - - - - - - - - - - - - - - - - Qt::Vertical + + + + 75 + true + + + + Net Status: - - + + + Qt::LeftToRight + + + Net Status + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + + + 75 + true + + + + Network Mode: + + + + + + + Network Mode + + + + + + + + + + + + 75 + true + + + + Nat Type: + + + + + + + Nat Type + + + + + + + + + + + + 75 + true + + + + Nat Hole: + + + + + + + Nat Hole + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + + 75 + true + + + + Connect Mode: + + + + + + + + 0 + 0 + + + + Qt::LeftToRight + + + Connect Options + + + + + + + + + + + + 75 + true + + + + Peer Address: + + + + + + + + 0 + 0 + + + + Peer Address + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + - - - - - - 75 - true - - - - Disconnected: - - - - - - - - - - - - - - - - - - - 75 - true - - - - Direct: - - - - - - - - - - - - - - - - - - - 75 - true - - - - Proxy: - - - - - - - - - - - - - - - - - - - 75 - true - - - - Relay: - - - - - - - - - - - - - - - - Qt::Horizontal + + + + 75 + true + - - - 40 - 20 - + + Unreach: - + + + + + + + + + + + + + + + + 75 + true + + + + Online: + + + + + + + + + + + + + + + + + + + 75 + true + + + + Offline: + + + + + + + + + + + + + + + + + + + 75 + true + + + + DHT Peers: + + + + + + + + + + + + + + + + + + + Qt::Vertical + + + + + + + + + + + + + 75 + true + + + + Disconnected: + + + + + + + + + + + + + + + + + + + 75 + true + + + + Direct: + + + + + + + + + + + + + + + + + + + 75 + true + + + + Proxy: + + + + + + + + + + + + + + + + + + + 75 + true + + + + Relay: + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 0 + + + + DHT + + + + + + true + + + + Bucket + + + + + IP:Port + + + + + Key + + + + + Status Flags + + + + + Found + + + + + Last Sent + + + + + Last Recv + + + + + + + + + + Filter: + + + + + + + Search Network + - - - true - - - - Name - - - - - PeerId - - - - - DHT Status - - - - - ConnectLogic - - - - - Connect Status - - - - - Connect Mode - - - - - Request Status - - - - - Cb Status - - - - - RsId - - + + + Peers + + + + + + true + + + + Name + + + + + PeerId + + + + + DHT Status + + + + + ConnectLogic + + + + + Connect Status + + + + + Connect Mode + + + + + Request Status + + + + + Cb Status + + + + + RsId + + + + + - - - true - - - - Bucket - - - - - IP:Port - - - - - Key - - - - - Status Flags - - - - - Found - - - - - Last Sent - - - - - Last Recv - - - - - - true - - - - Relay Mode - - - - - Source - - - - - Proxy - - - - - Destination - - - - - Class - - - - - Age - - - - - Last Sent - - - - - Bandwidth - - + + + Relay + + + + + + true + + + + Relay Mode + + + + + Source + + + + + Proxy + + + + + Destination + + + + + Class + + + + + Age + + + + + Last Sent + + + + + Bandwidth + + + + + @@ -636,6 +681,11 @@
gui/statistics/dhtgraph.h
1 + + LineEditClear + QLineEdit +
gui/common/LineEditClear.h
+
From d5c33f5631e813ee1646300074133643380ab6bc Mon Sep 17 00:00:00 2001 From: defnax Date: Fri, 7 Aug 2015 16:50:35 +0200 Subject: [PATCH 022/165] fixed windows build script --- build-all-mingw32make.bat | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/build-all-mingw32make.bat b/build-all-mingw32make.bat index 67aa98694..56d2fe787 100644 --- a/build-all-mingw32make.bat +++ b/build-all-mingw32make.bat @@ -3,9 +3,6 @@ set MINGW=C:\MinGW set PATH=%QTDIR%\bin;%MINGW%\bin;%PATH% -"C:\Program Files\TortoiseSVN\bin\SubWCRev" . libretroshare\src\retroshare\rsversion.in libretroshare\src\retroshare\rsversion.h -"C:\Program Files\TortoiseSVN\bin\SubWCRev" . retroshare-gui\src\retroshare.in retroshare-gui\src\retroshare.nsi - @echo off rem emptying used variables in case the script was aborted and tempfile @@ -65,6 +62,13 @@ qmake openpgpsdk.pro mingw32-make +cd ..\..\libresapi\src + +if not %clean%x==x mingw32-make clean + +qmake libresapi.pro + +mingw32-make %%a cd ..\..\libretroshare\src From 45e1e81d9cf8f18d94307ed22bf3a0cba6274e07 Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 7 Aug 2015 16:33:22 +0200 Subject: [PATCH 023/165] Store chat lobby history on disk --- libretroshare/src/pqi/p3historymgr.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libretroshare/src/pqi/p3historymgr.cc b/libretroshare/src/pqi/p3historymgr.cc index 69bfe6402..ee720160a 100644 --- a/libretroshare/src/pqi/p3historymgr.cc +++ b/libretroshare/src/pqi/p3historymgr.cc @@ -115,11 +115,6 @@ void p3HistoryMgr::addMessage(const ChatMessage& cm) item->sendTime = cm.sendTime; item->recvTime = cm.recvTime; - if (cm.chat_id.isLobbyId()) { - // disable save to disc for chat lobbies until they are saved - item->saveToDisc = false; - } - item->message = cm.msg ; //librs::util::ConvertUtf16ToUtf8(chatItem->message, item->message); From ef5fca5e5ee98bc1a24007fa733418ebb4d6cf8b Mon Sep 17 00:00:00 2001 From: AsamK Date: Fri, 7 Aug 2015 19:08:10 +0200 Subject: [PATCH 024/165] Resolve nicks from gxsId in lobby chat history --- retroshare-gui/src/gui/chat/ChatWidget.cpp | 17 +++++++++++++++-- .../src/gui/im_history/ImHistoryBrowser.cpp | 15 ++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/chat/ChatWidget.cpp b/retroshare-gui/src/gui/chat/ChatWidget.cpp index 5e8067577..81baa6f7e 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.cpp +++ b/retroshare-gui/src/gui/chat/ChatWidget.cpp @@ -321,8 +321,21 @@ void ChatWidget::init(const ChatId &chat_id, const QString &title) // it can happen that a message is first added to the message history // and later the gui receives the message through notify // avoid this by not adding history entries if their age is < 2secs - if((time(NULL)-2) > historyIt->recvTime) - addChatMsg(historyIt->incoming, QString::fromUtf8(historyIt->peerName.c_str()), QDateTime::fromTime_t(historyIt->sendTime), QDateTime::fromTime_t(historyIt->recvTime), QString::fromUtf8(historyIt->message.c_str()), MSGTYPE_HISTORY); + if ((time(NULL)-2) <= historyIt->recvTime) + continue; + + QString name; + if (chatId.isLobbyId()) { + RsIdentityDetails details; + if (rsIdentity->getIdDetails(RsGxsId(historyIt->peerName), details)) + name = QString::fromUtf8(details.mNickname.c_str()); + else + name = QString::fromUtf8(historyIt->peerName.c_str()); + } else { + name = QString::fromUtf8(historyIt->peerName.c_str()); + } + + addChatMsg(historyIt->incoming, name, QDateTime::fromTime_t(historyIt->sendTime), QDateTime::fromTime_t(historyIt->recvTime), QString::fromUtf8(historyIt->message.c_str()), MSGTYPE_HISTORY); } } } diff --git a/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp b/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp index 6e49396ef..a59f71656 100644 --- a/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp +++ b/retroshare-gui/src/gui/im_history/ImHistoryBrowser.cpp @@ -36,6 +36,7 @@ #include "rshare.h" #include +#include #include "gui/settings/rsharesettings.h" #include "gui/notifyqt.h" @@ -272,7 +273,19 @@ void ImHistoryBrowser::fillItem(QListWidgetItem *itemWidget, HistoryMsg& msg) } QString messageText = RsHtml().formatText(NULL, QString::fromUtf8(msg.message.c_str()), formatTextFlag); - QString formatMsg = style.formatMessage(type, QString::fromUtf8(msg.peerName.c_str()), QDateTime::fromTime_t(msg.sendTime), messageText); + + QString name; + if (m_chatId.isLobbyId()) { + RsIdentityDetails details; + if (rsIdentity->getIdDetails(RsGxsId(msg.peerName), details)) + name = QString::fromUtf8(details.mNickname.c_str()); + else + name = QString::fromUtf8(msg.peerName.c_str()); + } else { + name = QString::fromUtf8(msg.peerName.c_str()); + } + + QString formatMsg = style.formatMessage(type, name, QDateTime::fromTime_t(msg.sendTime), messageText); itemWidget->setData(Qt::DisplayRole, qVariantFromValue(IMHistoryItemPainter(formatMsg))); itemWidget->setData(ROLE_MSGID, msg.msgId); From ec67ee0e00f4becf37072cb922d68bb6ed1f23db Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 7 Aug 2015 21:40:48 -0400 Subject: [PATCH 025/165] added graph display of instantly required bandwidth for VOIP, in preparation to chosing new video codec. GUI layout needs to be sorted. --- plugins/VOIP/gui/AudioInputConfig.cpp | 66 ++++++++++++++++++++++- plugins/VOIP/gui/AudioInputConfig.h | 20 ++++++- plugins/VOIP/gui/AudioInputConfig.ui | 76 +++++++++++++++++---------- plugins/VOIP/gui/QVideoDevice.cpp | 5 +- plugins/VOIP/interface/rsVOIP.h | 2 + plugins/VOIP/services/p3VOIP.cc | 8 +++ 6 files changed, 147 insertions(+), 30 deletions(-) diff --git a/plugins/VOIP/gui/AudioInputConfig.cpp b/plugins/VOIP/gui/AudioInputConfig.cpp index 5c7553ee8..e23083200 100644 --- a/plugins/VOIP/gui/AudioInputConfig.cpp +++ b/plugins/VOIP/gui/AudioInputConfig.cpp @@ -39,6 +39,7 @@ //#include "NetworkConfig.h" #include "audiodevicehelper.h" #include "AudioWizard.h" +#include "gui/common/RSGraphWidget.h" #include #define iroundf(x) ( static_cast(x) ) @@ -51,6 +52,59 @@ void AudioInputDialog::showEvent(QShowEvent *) { qtTick->start(20); }*/ +class voipGraphSource: public RSGraphSource +{ +public: + voipGraphSource() {} + + void setVideoInput(QVideoInputDevice *vid) { video_input = vid ; } + + virtual QString displayName(int) const { return tr("Required bandwidth") ;} + + virtual QString displayValue(float v) const + { + if(v < 1000) + return QString::number(v,10,2) + " B/s" ; + else if(v < 1000*1024) + return QString::number(v/1024,10,2) + " KB/s" ; + else + return QString::number(v/(1024*1024),10,2) + " MB/s" ; + } + + virtual void getValues(std::map& vals) const + { + RsVOIPDataChunk chunk ; + uint32_t total_size = 0 ; + vals.clear() ; + + while(video_input && video_input->getNextEncodedPacket(chunk)) + { + total_size += chunk.size ; + chunk.clear() ; + } + + vals[std::string("bw")] = (float)total_size ; + } + +private: + QVideoInputDevice *video_input ; +}; + +void voipGraph::setVoipSource(voipGraphSource *gs) +{ +_src = gs ; +RSGraphWidget::setSource(gs) ; +} + +voipGraph::voipGraph(QWidget *parent) + : RSGraphWidget(parent) +{ + setFlags(RSGraphWidget::RSGRAPH_FLAGS_SHOW_LEGEND) ; + setFlags(RSGraphWidget::RSGRAPH_FLAGS_PAINT_STYLE_PLAIN) ; + + _src = NULL ; +} + /** Constructor */ AudioInputConfig::AudioInputConfig(QWidget * parent, Qt::WindowFlags flags) : ConfigPage(parent, flags) @@ -71,11 +125,21 @@ AudioInputConfig::AudioInputConfig(QWidget * parent, Qt::WindowFlags flags) // videoInput = new QVideoInputDevice(this) ; videoInput->setEchoVideoTarget(ui.videoDisplay) ; - videoInput->setVideoEncoder(NULL) ; + videoInput->setVideoEncoder(new JPEGVideoEncoder()) ; + + graph_source = new voipGraphSource ; + ui.voipBwGraph->setSource(graph_source); + + graph_source->setVideoInput(videoInput) ; + graph_source->setCollectionTimeLimit(1000*300) ; + graph_source->start() ; } AudioInputConfig::~AudioInputConfig() { + graph_source->stop() ; + graph_source->setVideoInput(NULL) ; + std::cerr << "Deleting audioInputConfig object" << std::endl; if(videoInput != NULL) { diff --git a/plugins/VOIP/gui/AudioInputConfig.h b/plugins/VOIP/gui/AudioInputConfig.h index 1b64085a3..cc0fd15c3 100644 --- a/plugins/VOIP/gui/AudioInputConfig.h +++ b/plugins/VOIP/gui/AudioInputConfig.h @@ -35,10 +35,27 @@ #include "retroshare-gui/configpage.h" -#include "ui_AudioInputConfig.h" #include "SpeexProcessor.h" #include "VideoProcessor.h" #include "AudioStats.h" +#include "gui/common/RSGraphWidget.h" + +class voipGraphSource ; + +class voipGraph: public RSGraphWidget +{ +public: + voipGraph(QWidget *parent) ; + + voipGraphSource *voipSource() const { return _src ; } + + void setVoipSource(voipGraphSource *gs) ; + +private: + voipGraphSource *_src ; +}; + +#include "ui_AudioInputConfig.h" class AudioInputConfig : public ConfigPage { @@ -54,6 +71,7 @@ class AudioInputConfig : public ConfigPage QVideoInputDevice *videoInput ; bool loaded; + voipGraphSource *graph_source ; protected: QTimer *qtTick; diff --git a/plugins/VOIP/gui/AudioInputConfig.ui b/plugins/VOIP/gui/AudioInputConfig.ui index 6aa071b4a..8037dea93 100644 --- a/plugins/VOIP/gui/AudioInputConfig.ui +++ b/plugins/VOIP/gui/AudioInputConfig.ui @@ -6,8 +6,8 @@ 0 0 - 501 - 406 + 1155 + 713 @@ -348,33 +348,49 @@ - - - - Video Processing - - - - - - - 170 - 128 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - + + + + Video Processing + + + + + + + 170 + 128 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + @@ -397,6 +413,12 @@
gui/QVideoDevice.h
1 + + voipGraph + QFrame +
gui/AudioInputConfig.h
+ 1 +
qcbTransmit diff --git a/plugins/VOIP/gui/QVideoDevice.cpp b/plugins/VOIP/gui/QVideoDevice.cpp index eed14b58b..eaec96f71 100644 --- a/plugins/VOIP/gui/QVideoDevice.cpp +++ b/plugins/VOIP/gui/QVideoDevice.cpp @@ -88,7 +88,10 @@ void QVideoInputDevice::grabFrame() bool QVideoInputDevice::getNextEncodedPacket(RsVOIPDataChunk& chunk) { - return _video_encoder->nextPacket(chunk) ; + if(_video_encoder) + return _video_encoder->nextPacket(chunk) ; + else + return false ; } QVideoInputDevice::~QVideoInputDevice() diff --git a/plugins/VOIP/interface/rsVOIP.h b/plugins/VOIP/interface/rsVOIP.h index 18f258769..7269610b4 100644 --- a/plugins/VOIP/interface/rsVOIP.h +++ b/plugins/VOIP/interface/rsVOIP.h @@ -56,6 +56,8 @@ struct RsVOIPDataChunk void *data ; // create/delete using malloc/free. uint32_t size ; RsVOIPDataType type ; // video or audio + + void clear() ; }; class RsVOIP diff --git a/plugins/VOIP/services/p3VOIP.cc b/plugins/VOIP/services/p3VOIP.cc index d7377077c..fb164bd7c 100644 --- a/plugins/VOIP/services/p3VOIP.cc +++ b/plugins/VOIP/services/p3VOIP.cc @@ -147,6 +147,14 @@ RsServiceInfo p3VOIP::getServiceInfo() TURTLE_MIN_MINOR_VERSION); } +void RsVOIPDataChunk::clear() +{ + + if(data) + free(data) ; + data=NULL; + size=0 ; +} int p3VOIP::tick() { #ifdef DEBUG_VOIP From 87f2e6da37fc3309029d68fbd56977cbe21e7c96 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Sat, 8 Aug 2015 20:27:19 +0200 Subject: [PATCH 026/165] FriendList: - Removed avatar column - Removed state column - Added combined avatar and status icon - Added status icons in 64px - Renamed "Hide state" to "Show state" - Added sort by name and state RSTreeWidget: - Added version for load/save state - Added method setColumnCustomizable --- retroshare-gui/src/gui/FriendsDialog.cpp | 2 - retroshare-gui/src/gui/MessengerWindow.cpp | 3 - retroshare-gui/src/gui/common/FriendList.cpp | 1055 ++++++++--------- retroshare-gui/src/gui/common/FriendList.h | 28 +- retroshare-gui/src/gui/common/FriendList.ui | 52 +- .../src/gui/common/RSTreeWidget.cpp | 43 +- retroshare-gui/src/gui/common/RSTreeWidget.h | 8 +- retroshare-gui/src/gui/common/StatusDefs.cpp | 10 +- retroshare-gui/src/gui/icons.qrc | 5 + .../src/gui/icons/user-away-extended_64.png | Bin 0 -> 22117 bytes retroshare-gui/src/gui/icons/user-away_64.png | Bin 0 -> 18514 bytes retroshare-gui/src/gui/icons/user-busy_64.png | Bin 0 -> 18316 bytes .../src/gui/icons/user-offline_64.png | Bin 0 -> 12673 bytes .../src/gui/icons/user-online_64.png | Bin 0 -> 19510 bytes retroshare-gui/src/gui/images.qrc | 9 - .../src/gui/images/connect_established.png | Bin 818 -> 0 bytes .../gui/images/connect_established_low.png | Bin 856 -> 0 bytes retroshare-gui/src/gui/images/connect_no.png | Bin 757 -> 0 bytes retroshare-gui/src/gui/images/reload24.png | Bin 1387 -> 0 bytes .../gui/images/status/user-away-extended.png | Bin 1658 -> 0 bytes .../src/gui/images/status/user-away.png | Bin 1482 -> 0 bytes .../src/gui/images/status/user-busy.png | Bin 1218 -> 0 bytes .../src/gui/images/status/user-offline.png | Bin 1272 -> 0 bytes .../src/gui/images/status/user-online.png | Bin 1308 -> 0 bytes 24 files changed, 619 insertions(+), 596 deletions(-) create mode 100644 retroshare-gui/src/gui/icons/user-away-extended_64.png create mode 100644 retroshare-gui/src/gui/icons/user-away_64.png create mode 100644 retroshare-gui/src/gui/icons/user-busy_64.png create mode 100644 retroshare-gui/src/gui/icons/user-offline_64.png create mode 100644 retroshare-gui/src/gui/icons/user-online_64.png delete mode 100644 retroshare-gui/src/gui/images/connect_established.png delete mode 100644 retroshare-gui/src/gui/images/connect_established_low.png delete mode 100644 retroshare-gui/src/gui/images/connect_no.png delete mode 100644 retroshare-gui/src/gui/images/reload24.png delete mode 100644 retroshare-gui/src/gui/images/status/user-away-extended.png delete mode 100644 retroshare-gui/src/gui/images/status/user-away.png delete mode 100644 retroshare-gui/src/gui/images/status/user-busy.png delete mode 100644 retroshare-gui/src/gui/images/status/user-offline.png delete mode 100644 retroshare-gui/src/gui/images/status/user-online.png diff --git a/retroshare-gui/src/gui/FriendsDialog.cpp b/retroshare-gui/src/gui/FriendsDialog.cpp index b7dfe466c..9a5d3a3f0 100644 --- a/retroshare-gui/src/gui/FriendsDialog.cpp +++ b/retroshare-gui/src/gui/FriendsDialog.cpp @@ -142,9 +142,7 @@ QList sizes; // load settings RsAutoUpdatePage::lockAllEvents(); - ui.friendList->setColumnVisible(FriendList::COLUMN_STATE, false); ui.friendList->setColumnVisible(FriendList::COLUMN_LAST_CONTACT, false); - ui.friendList->setColumnVisible(FriendList::COLUMN_AVATAR, true); ui.friendList->setColumnVisible(FriendList::COLUMN_IP, false); ui.friendList->setShowGroups(true); processSettings(true); diff --git a/retroshare-gui/src/gui/MessengerWindow.cpp b/retroshare-gui/src/gui/MessengerWindow.cpp index d8bb1364e..097089b85 100644 --- a/retroshare-gui/src/gui/MessengerWindow.cpp +++ b/retroshare-gui/src/gui/MessengerWindow.cpp @@ -142,13 +142,10 @@ MessengerWindow::MessengerWindow(QWidget* parent, Qt::WindowFlags flags) // load settings RsAutoUpdatePage::lockAllEvents(); - ui.friendList->setColumnVisible(FriendList::COLUMN_STATE, false); ui.friendList->setColumnVisible(FriendList::COLUMN_LAST_CONTACT, false); - ui.friendList->setColumnVisible(FriendList::COLUMN_AVATAR, true); ui.friendList->setColumnVisible(FriendList::COLUMN_IP, false); ui.friendList->setShowGroups(false); processSettings(true); - ui.friendList->setBigName(true); RsAutoUpdatePage::unlockAllEvents(); // add self nick diff --git a/retroshare-gui/src/gui/common/FriendList.cpp b/retroshare-gui/src/gui/common/FriendList.cpp index 7e8db11d8..ab23f3b84 100644 --- a/retroshare-gui/src/gui/common/FriendList.cpp +++ b/retroshare-gui/src/gui/common/FriendList.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "retroshare/rspeers.h" @@ -73,20 +74,18 @@ #define IMAGE_COLLAPSE ":/images/edit_remove24.png" /* Images for Status icons */ #define IMAGE_AVAILABLE ":/images/user/identityavaiblecyan24.png" -#define IMAGE_CONNECT2 ":/images/reload24.png" #define IMAGE_PASTELINK ":/images/pasterslink.png" #define IMAGE_GROUP24 ":/images/user/group24.png" #define COLUMN_DATA 0 // column for storing the userdata id +#define COLUMN_SORT COLUMN_NAME // column for sorting -#define COLUMN_AVATAR_WIDTH 42 - -#define ROLE_SORT Qt::UserRole -#define ROLE_ID Qt::UserRole + 1 -#define ROLE_STANDARD Qt::UserRole + 2 -// to store the best ssl id for pgp items -// the best id decides which avatar image we want to display at the pgpg item -#define ROLE_BEST_SSL Qt::UserRole + 3 +#define ROLE_ID Qt::UserRole +#define ROLE_STANDARD Qt::UserRole + 1 +#define ROLE_SORT_GROUP Qt::UserRole + 2 +#define ROLE_SORT_STANDARD_GROUP Qt::UserRole + 3 +#define ROLE_SORT_NAME Qt::UserRole + 4 +#define ROLE_SORT_STATE Qt::UserRole + 5 #define TYPE_GPG 0 #define TYPE_SSL 1 @@ -101,9 +100,6 @@ #define PEER_STATE_INACTIVE 5 #define PEER_STATE_OFFLINE 6 -#define BuildStateSortString(bEnabled,sName,nState) bEnabled ? (QString ("%1").arg(nState) + " " + sName) : sName - - /****** * #define FRIENDS_DEBUG 1 *****/ @@ -111,10 +107,9 @@ FriendList::FriendList(QWidget *parent) : RsAutoUpdatePage(1500, parent), ui(new Ui::FriendList), - m_compareRole(new RSTreeWidgetItemCompareRole), - mBigName(false), + mCompareRole(new RSTreeWidgetItemCompareRole), mShowGroups(true), - mHideState(true), + mShowState(false), mHideUnconnected(false), groupsHasChanged(false), openGroups(NULL), @@ -122,37 +117,26 @@ FriendList::FriendList(QWidget *parent) : { ui->setupUi(this); - m_compareRole->setRole(COLUMN_NAME, ROLE_SORT); - m_compareRole->setRole(COLUMN_STATE, ROLE_SORT); - m_compareRole->setRole(COLUMN_LAST_CONTACT, ROLE_SORT); - m_compareRole->setRole(COLUMN_IP, ROLE_SORT); - m_compareRole->setRole(COLUMN_AVATAR, ROLE_STANDARD); - connect(ui->peerTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(peerTreeWidgetCustomPopupMenu())); connect(ui->peerTreeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(chatfriend(QTreeWidgetItem *))); connect(NotifyQt::getInstance(), SIGNAL(groupsChanged(int)), this, SLOT(groupsChanged())); connect(NotifyQt::getInstance(), SIGNAL(friendsChanged()), this, SLOT(insertPeers())); - connect(NotifyQt::getInstance(), SIGNAL(peerHasNewAvatar(const QString&)), this, SLOT(updateAvatar(const QString&))); connect(ui->actionHideOfflineFriends, SIGNAL(triggered(bool)), this, SLOT(setHideUnconnected(bool))); - connect(ui->actionHideState, SIGNAL(triggered(bool)), this, SLOT(setHideState(bool))); + connect(ui->actionShowState, SIGNAL(triggered(bool)), this, SLOT(setShowState(bool))); connect(ui->actionShowGroups, SIGNAL(triggered(bool)), this, SLOT(setShowGroups(bool))); + connect(ui->actionSortByName, SIGNAL(triggered()), this, SLOT(setSortByName())); + connect(ui->actionSortByState, SIGNAL(triggered()), this, SLOT(setSortByState())); + connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterItems(QString))); ui->filterLineEdit->setPlaceholderText(tr("Search")) ; ui->filterLineEdit->showFilterIcon(); - initializeHeader(false); - - ui->peerTreeWidget->sortItems(COLUMN_NAME, Qt::AscendingOrder); - - // set header text aligment - QTreeWidgetItem *headerItem = ui->peerTreeWidget->headerItem(); - headerItem->setTextAlignment(COLUMN_NAME, Qt::AlignHCenter | Qt::AlignVCenter); - headerItem->setTextAlignment(COLUMN_STATE, Qt::AlignLeft | Qt::AlignVCenter); - headerItem->setTextAlignment(COLUMN_AVATAR, Qt::AlignLeft | Qt::AlignVCenter); + /* Set sort */ + setSortMode(SORT_MODE_NAME); // workaround for Qt bug, should be solved in next Qt release 4.7.0 // http://bugreports.qt.nokia.com/browse/QTBUG-8270 @@ -160,9 +144,16 @@ FriendList::FriendList(QWidget *parent) : connect(Shortcut, SIGNAL(activated()), this, SLOT(removefriend())); /* Initialize tree */ - ui->peerTreeWidget->setColumnCustomizable(true); + ui->peerTreeWidget->enableColumnCustomize(true); + ui->peerTreeWidget->setColumnCustomizable(COLUMN_NAME, false); connect(ui->peerTreeWidget, SIGNAL(columnVisibleChanged(int,bool)), this, SLOT(peerTreeColumnVisibleChanged(int,bool))); + /* Set initial column width */ + int fontWidth = QFontMetricsF(ui->peerTreeWidget->font()).width("W"); + ui->peerTreeWidget->setColumnWidth(COLUMN_NAME, 22 * fontWidth); + ui->peerTreeWidget->setColumnWidth(COLUMN_LAST_CONTACT, 12 * fontWidth); + ui->peerTreeWidget->setColumnWidth(COLUMN_IP, 15 * fontWidth); + /* Initialize display menu */ createDisplayMenu(); } @@ -170,7 +161,7 @@ FriendList::FriendList(QWidget *parent) : FriendList::~FriendList() { delete ui; - delete(m_compareRole); + delete(mCompareRole); } void FriendList::addToolButton(QToolButton *toolButton) @@ -190,6 +181,7 @@ void FriendList::addToolButton(QToolButton *toolButton) void FriendList::processSettings(bool load) { // state of peer tree + ui->peerTreeWidget->setSettingsVersion(1); ui->peerTreeWidget->processSettings(load); if (load) { @@ -200,9 +192,12 @@ void FriendList::processSettings(bool load) // states setHideUnconnected(Settings->value("hideUnconnected", mHideUnconnected).toBool()); - setHideState(Settings->value("hideState", mHideState).toBool()); + setShowState(Settings->value("showState", mShowState).toBool()); setShowGroups(Settings->value("showGroups", mShowGroups).toBool()); + // sort + setSortMode((SortMode) Settings->value("sortMode", SORT_MODE_NAME).toInt()); + // open groups int arrayIndex = Settings->beginReadArray("Groups"); for (int index = 0; index < arrayIndex; ++index) { @@ -210,18 +205,17 @@ void FriendList::processSettings(bool load) addGroupToExpand(Settings->value("open").toString().toStdString()); } Settings->endArray(); - - initializeHeader(true); - peerTreeColumnVisibleChanged(COLUMN_STATE, !ui->peerTreeWidget->isColumnHidden(COLUMN_STATE)); } else { // save settings // states Settings->setValue("hideUnconnected", mHideUnconnected); - Settings->setValue("hideState", mHideState); - Settings->setValue("rootIsDecorated", ui->peerTreeWidget->rootIsDecorated()); + Settings->setValue("showState", mShowState); Settings->setValue("showGroups", mShowGroups); + // sort + Settings->setValue("sortMode", sortMode()); + // open groups Settings->beginWriteArray("Groups"); int arrayIndex = 0; @@ -248,22 +242,6 @@ void FriendList::changeEvent(QEvent *e) } } -void FriendList::initializeHeader(bool /*afterLoadSettings*/) -{ - // set column size - QHeaderView *header = ui->peerTreeWidget->header(); - QHeaderView_setSectionsMovable(header, true); - //QHeaderView_setSectionResizeModeColumn(header, COLUMN_NAME, QHeaderView::Stretch); - QHeaderView_setSectionResizeModeColumn(header, COLUMN_NAME, QHeaderView::Interactive); - QHeaderView_setSectionResizeModeColumn(header, COLUMN_STATE, QHeaderView::Interactive); - QHeaderView_setSectionResizeModeColumn(header, COLUMN_LAST_CONTACT, QHeaderView::Interactive); - QHeaderView_setSectionResizeModeColumn(header, COLUMN_IP, QHeaderView::Interactive); - QHeaderView_setSectionResizeModeColumn(header, COLUMN_AVATAR, QHeaderView::Fixed); - header->setStretchLastSection(false); - - header->resizeSection(COLUMN_AVATAR, COLUMN_AVATAR_WIDTH); -} - /* Utility Fns */ inline std::string getRsId(QTreeWidgetItem *item) { @@ -476,31 +454,21 @@ void FriendList::groupsChanged() insertPeers(); } -void FriendList::updateAvatar(const QString& id) +static QIcon createAvatar(const QPixmap &avatar, const QPixmap &overlay) { - if (ui->peerTreeWidget->isColumnHidden(COLUMN_AVATAR)) - return; + QPixmap pixmap(avatar); - QTreeWidgetItemIterator it(ui->peerTreeWidget); - while (*it) { - // case ssl item - if ((*it)->type() == TYPE_SSL && id == (*it)->data(COLUMN_DATA, ROLE_ID).toString()) { - if ((*it)->parent() != NULL && (*it)->parent()->type() == TYPE_GPG) { - QPixmap avatar; - AvatarDefs::getAvatarFromSslId(RsPeerId(id.toStdString()), avatar); - QIcon avatar_icon(avatar); - (*it)->setIcon(COLUMN_AVATAR, avatar_icon); - } - } - // case pgp item - if ((*it)->type() == TYPE_GPG && id == (*it)->data(COLUMN_DATA, ROLE_BEST_SSL).toString()) { - QPixmap avatar; - AvatarDefs::getAvatarFromSslId(RsPeerId(id.toStdString()), avatar); - QIcon avatar_icon(avatar); - (*it)->setIcon(COLUMN_AVATAR, avatar_icon); - } - ++it; - } + int x = avatar.width() / 2; + int y = avatar.height() / 2; + int w = avatar.width() / 2; + int h = avatar.height() / 2; + + QPainter painter(&pixmap); + painter.drawPixmap(x, y, w, h, overlay); + + QIcon icon; + icon.addPixmap(pixmap); + return icon; } /** @@ -509,7 +477,7 @@ void FriendList::updateAvatar(const QString& id) * If enabled, peers are sorted in their associated groups. * Groups are only updated, when groupsHasChanged is true. */ -void FriendList::insertPeers() +void FriendList::insertPeers() { if (RsAutoUpdatePage::eventsLocked()) return; @@ -518,8 +486,6 @@ void FriendList::insertPeers() std::cerr << "FriendList::insertPeers() called." << std::endl; #endif - bool isStatusColumnHidden = ui->peerTreeWidget->isColumnHidden(COLUMN_STATE); - bool isAvatarColumnHidden = ui->peerTreeWidget->isColumnHidden(COLUMN_AVATAR); int columnCount = ui->peerTreeWidget->columnCount(); std::list statusInfo; @@ -562,72 +528,72 @@ void FriendList::insertPeers() ++itemIterator; switch (item->type()) { case TYPE_GPG: - { - QTreeWidgetItem *parent = item->parent(); - RsPgpId gpg_widget_id ( getRsId(item)); + { + QTreeWidgetItem *parent = item->parent(); + RsPgpId gpg_widget_id ( getRsId(item)); - // remove items that are not friends anymore - if (std::find(gpgFriends.begin(), gpgFriends.end(), gpg_widget_id) == gpgFriends.end()) { - if (parent) { - delete(parent->takeChild(parent->indexOfChild(item))); - } else { - delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); + // remove items that are not friends anymore + if (std::find(gpgFriends.begin(), gpgFriends.end(), gpg_widget_id) == gpgFriends.end()) { + if (parent) { + delete(parent->takeChild(parent->indexOfChild(item))); + } else { + delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); + } + break; } - break; - } - if (mShowGroups && groupsHasChanged) { - if (parent) { - if (parent->type() == TYPE_GROUP) { - std::string groupId = getRsId(parent); + if (mShowGroups && groupsHasChanged) { + if (parent) { + if (parent->type() == TYPE_GROUP) { + std::string groupId = getRsId(parent); - // the parent is a group, check if the gpg id is assigned to the group - for (groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); ++groupIt) { - if (groupIt->id == groupId) { - if (std::find(groupIt->peerIds.begin(), groupIt->peerIds.end(), gpg_widget_id) == groupIt->peerIds.end()) { - delete(parent->takeChild(parent->indexOfChild(item))); + // the parent is a group, check if the gpg id is assigned to the group + for (groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); ++groupIt) { + if (groupIt->id == groupId) { + if (std::find(groupIt->peerIds.begin(), groupIt->peerIds.end(), gpg_widget_id) == groupIt->peerIds.end()) { + delete(parent->takeChild(parent->indexOfChild(item))); + } + break; } + } + } + } else { + // gpg item without group, check if the gpg id is assigned to a group + for (groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); ++groupIt) { + if (std::find(groupIt->peerIds.begin(), groupIt->peerIds.end(), gpg_widget_id) != groupIt->peerIds.end()) { + delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); break; } } } - } else { - // gpg item without group, check if the gpg id is assigned to a group - for (groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); ++groupIt) { - if (std::find(groupIt->peerIds.begin(), groupIt->peerIds.end(), gpg_widget_id) != groupIt->peerIds.end()) { - delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); - break; - } - } } } - } break; case TYPE_GROUP: - { - if (!mShowGroups) { - if (item->parent()) { - delete(item->parent()->takeChild(item->parent()->indexOfChild(item))); - } else { - delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); - } - } else if (groupsHasChanged) { - // remove deleted groups - std::string groupId = getRsId(item); - for (groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); ++groupIt) { - if (groupIt->id == groupId) { - break; - } - } - if (groupIt == groupInfoList.end() || groupIt->peerIds.empty()) { + { + if (!mShowGroups) { if (item->parent()) { delete(item->parent()->takeChild(item->parent()->indexOfChild(item))); } else { delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); } + } else if (groupsHasChanged) { + // remove deleted groups + std::string groupId = getRsId(item); + for (groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); ++groupIt) { + if (groupIt->id == groupId) { + break; + } + } + if (groupIt == groupInfoList.end() || groupIt->peerIds.empty()) { + if (item->parent()) { + delete(item->parent()->takeChild(item->parent()->indexOfChild(item))); + } else { + delete(peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(item))); + } + } } } - } break; } } @@ -662,13 +628,12 @@ void FriendList::insertPeers() if (groupItem == NULL) { // add group item - groupItem = new RSTreeWidgetItem(m_compareRole, TYPE_GROUP); + groupItem = new RSTreeWidgetItem(mCompareRole, TYPE_GROUP); /* Add item to the list. Add here, because for setHidden the item must be added */ peerTreeWidget->addTopLevelItem(groupItem); groupItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless); - groupItem->setSizeHint(COLUMN_NAME, QSize(26, 26)); groupItem->setTextAlignment(COLUMN_NAME, Qt::AlignLeft | Qt::AlignVCenter); groupItem->setIcon(COLUMN_NAME, QIcon(IMAGE_GROUP24)); groupItem->setForeground(COLUMN_NAME, QBrush(textColorGroup())); @@ -677,6 +642,10 @@ void FriendList::insertPeers() groupItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(groupInfo->id)); groupItem->setData(COLUMN_DATA, ROLE_STANDARD, (groupInfo->flag & RS_GROUP_FLAG_STANDARD) ? true : false); + /* Sort data */ + groupItem->setData(COLUMN_SORT, ROLE_SORT_GROUP, 1); + groupItem->setData(COLUMN_SORT, ROLE_SORT_STANDARD_GROUP, (groupInfo->flag & RS_GROUP_FLAG_STANDARD) ? 0 : 1); + groupItem->setData(COLUMN_SORT, ROLE_SORT_STATE, 0); } else { // remove all gpg items that are not more assigned int childCount = groupItem->childCount(); @@ -703,404 +672,411 @@ void FriendList::insertPeers() // iterate through gpg friends for (gpgIt = gpgFriends.begin(); gpgIt != gpgFriends.end(); ++gpgIt) - { - RsPgpId gpgId = *gpgIt; + { + RsPgpId gpgId = *gpgIt; - if (mShowGroups) { - if (groupInfo) { - // we fill a group, check if gpg id is assigned - if (std::find(groupInfo->peerIds.begin(), groupInfo->peerIds.end(), gpgId) == groupInfo->peerIds.end()) { - continue; - } - } else { - // we fill the not assigned gpg ids - if (std::find(fillGpgIds.begin(), fillGpgIds.end(), gpgId) != fillGpgIds.end()) { - continue; + if (mShowGroups) { + if (groupInfo) { + // we fill a group, check if gpg id is assigned + if (std::find(groupInfo->peerIds.begin(), groupInfo->peerIds.end(), gpgId) == groupInfo->peerIds.end()) { + continue; + } + } else { + // we fill the not assigned gpg ids + if (std::find(fillGpgIds.begin(), fillGpgIds.end(), gpgId) != fillGpgIds.end()) { + continue; + } } + + // add equal too, its no problem + fillGpgIds.push_back(gpgId); } - // add equal too, its no problem - fillGpgIds.push_back(gpgId); - } - - //add the gpg friends + //add the gpg friends #ifdef FRIENDS_DEBUG - std::cerr << "FriendList::insertPeers() inserting gpg_id : " << gpgId << std::endl; + std::cerr << "FriendList::insertPeers() inserting gpg_id : " << gpgId << std::endl; #endif - /* make a widget per friend */ - QTreeWidgetItem *gpgItem = NULL; - QTreeWidgetItem *gpgItemLoop = NULL; + /* make a widget per friend */ + QTreeWidgetItem *gpgItem = NULL; + QTreeWidgetItem *gpgItemLoop = NULL; - // search existing gpg item - int itemCount = groupItem ? groupItem->childCount() : peerTreeWidget->topLevelItemCount(); - for (int index = 0; index < itemCount; ++index) { - gpgItemLoop = groupItem ? groupItem->child(index) : peerTreeWidget->topLevelItem(index); - if (gpgItemLoop->type() == TYPE_GPG && getRsId(gpgItemLoop) == gpgId.toStdString()) { - gpgItem = gpgItemLoop; - break; - } - } - - RsPeerDetails detail; - if ((!rsPeers->getGPGDetails(gpgId, detail) || !detail.accept_connection) && detail.gpg_id != ownId) { - // don't accept anymore connection, remove from the view - if (gpgItem) { - if (groupItem) { - delete(groupItem->takeChild(groupItem->indexOfChild(gpgItem))); - } else { - delete (peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(gpgItem))); - } - } - continue; - } - - if (gpgItem == NULL) { - // create gpg item and add it to tree - gpgItem = new RSTreeWidgetItem(m_compareRole, TYPE_GPG); //set type to 0 for custom popup menu - - /* Add gpg item to the list. Add here, because for setHidden the item must be added */ - if (groupItem) { - groupItem->addChild(gpgItem); - } else { - peerTreeWidget->addTopLevelItem(gpgItem); - } - - gpgItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless); - gpgItem->setTextAlignment(COLUMN_NAME, Qt::AlignLeft | Qt::AlignVCenter); - - /* not displayed, used to find back the item */ - gpgItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(detail.gpg_id.toStdString())); - } - - if (mBigName && !mHideState && isStatusColumnHidden) { - gpgItem->setSizeHint(COLUMN_NAME, QSize(40, 40)); - } else { - gpgItem->setSizeHint(COLUMN_NAME, QSize(26, 26)); - } - - ++availableCount; - - QString gpgItemText = QString::fromUtf8(detail.name.c_str()); - - // remove items that are not friends anymore - int childCount = gpgItem->childCount(); - int childIndex = 0; - while (childIndex < childCount) { - std::string ssl_id = getRsId(gpgItem->child(childIndex)); - if (!rsPeers->isFriend(RsPeerId(ssl_id))) { - delete (gpgItem->takeChild(childIndex)); - // count again - childCount = gpgItem->childCount(); - } else { - ++childIndex; - } - } - - // update the childs (ssl certs) - bool gpg_connected = false; - bool gpg_online = false; - bool gpg_hasPrivateChat = false; - int bestPeerState = 0; // for gpg item - unsigned int bestRSState = 0; // for gpg item - RsPeerId bestSslId; // for gpg item - QString bestCustomStateString;// for gpg item - std::list sslContacts; - QDateTime lastContact; - QString itemIP; - - rsPeers->getAssociatedSSLIds(detail.gpg_id, sslContacts); - for (std::list::iterator sslIt = sslContacts.begin(); sslIt != sslContacts.end(); ++sslIt) { - QTreeWidgetItem *sslItem = NULL; - RsPeerId sslId = *sslIt; - - //find the corresponding sslItem child item of the gpg item - bool newChild = true; - childCount = gpgItem->childCount(); - for (int childIndex = 0; childIndex < childCount; ++childIndex) { - // we assume, that only ssl items are child of the gpg item, so we don't need to test the type - if (getRsId(gpgItem->child(childIndex)) == sslId.toStdString()) { - sslItem = gpgItem->child(childIndex); - newChild = false; + // search existing gpg item + int itemCount = groupItem ? groupItem->childCount() : peerTreeWidget->topLevelItemCount(); + for (int index = 0; index < itemCount; ++index) { + gpgItemLoop = groupItem ? groupItem->child(index) : peerTreeWidget->topLevelItem(index); + if (gpgItemLoop->type() == TYPE_GPG && getRsId(gpgItemLoop) == gpgId.toStdString()) { + gpgItem = gpgItemLoop; break; } } - RsPeerDetails sslDetail; - if (!rsPeers->getPeerDetails(sslId, sslDetail) || !rsPeers->isFriend(sslId)) { -#ifdef FRIENDS_DEBUG - std::cerr << "Removing widget from the view : id : " << sslId << std::endl; -#endif - //child has disappeared, remove it from the gpg_item - if (sslItem) { - gpgItem->removeChild(sslItem); + RsPeerDetails detail; + if ((!rsPeers->getGPGDetails(gpgId, detail) || !detail.accept_connection) && detail.gpg_id != ownId) { + // don't accept anymore connection, remove from the view + if (gpgItem) { + if (groupItem) { + delete(groupItem->takeChild(groupItem->indexOfChild(gpgItem))); + } else { + delete (peerTreeWidget->takeTopLevelItem(peerTreeWidget->indexOfTopLevelItem(gpgItem))); + } } continue; } - if (newChild) { - sslItem = new RSTreeWidgetItem(m_compareRole, TYPE_SSL); //set type to 1 for custom popup menu + if (gpgItem == NULL) { + // create gpg item and add it to tree + gpgItem = new RSTreeWidgetItem(mCompareRole, TYPE_GPG); //set type to 0 for custom popup menu -#ifdef FRIENDS_DEBUG - std::cerr << "FriendList::insertPeers() inserting sslItem." << std::endl; -#endif + /* Add gpg item to the list. Add here, because for setHidden the item must be added */ + if (groupItem) { + groupItem->addChild(gpgItem); + } else { + peerTreeWidget->addTopLevelItem(gpgItem); + } - /* Add ssl child to the list. Add here, because for setHidden the item must be added */ - gpgItem->addChild(sslItem); + gpgItem->setChildIndicatorPolicy(QTreeWidgetItem::DontShowIndicatorWhenChildless); + gpgItem->setTextAlignment(COLUMN_NAME, Qt::AlignLeft | Qt::AlignVCenter); + + /* not displayed, used to find back the item */ + gpgItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(detail.gpg_id.toStdString())); + + /* Sort data */ + gpgItem->setData(COLUMN_SORT, ROLE_SORT_GROUP, 2); + // show first the standard groups, than the user groups + gpgItem->setData(COLUMN_SORT, ROLE_SORT_STANDARD_GROUP, 1); } - /* not displayed, used to find back the item */ - sslItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(sslDetail.id.toStdString())); + ++availableCount; - if (!isAvatarColumnHidden) - updateAvatar(QString::fromStdString(sslDetail.id.toStdString())); + QString gpgName = QString::fromUtf8(detail.name.c_str()); + QString gpgItemText = gpgName; - QString sText; - QString customStateString; - if (sslDetail.state & RS_PEER_STATE_CONNECTED) { - customStateString = QString::fromUtf8(rsMsgs->getCustomStateString(sslDetail.id).c_str()); - } - sText = QString::fromUtf8(sslDetail.location.c_str()); - if (customStateString.isEmpty() == false) { - sText += " - " + customStateString; + // remove items that are not friends anymore + int childCount = gpgItem->childCount(); + int childIndex = 0; + while (childIndex < childCount) { + std::string ssl_id = getRsId(gpgItem->child(childIndex)); + if (!rsPeers->isFriend(RsPeerId(ssl_id))) { + delete (gpgItem->takeChild(childIndex)); + // count again + childCount = gpgItem->childCount(); + } else { + ++childIndex; + } } - QString connectStateString = StatusDefs::connectStateWithoutTransportTypeString(sslDetail); - if (!isStatusColumnHidden) { - sslItem->setText(COLUMN_STATE, connectStateString); - } else if (!mHideState && connectStateString.isEmpty() == false) { - sText += " [" + connectStateString + "]"; - } - sslItem->setText( COLUMN_NAME, sText); + // update the childs (ssl certs) + bool gpg_connected = false; + bool gpg_online = false; + bool gpg_hasPrivateChat = false; + int bestPeerState = 0; // for gpg item + unsigned int bestRSState = 0; // for gpg item + QString bestCustomStateString;// for gpg item + std::list sslContacts; + QDateTime bestLastContact; + QString bestIP; + QPixmap bestAvatar; - if (isStatusColumnHidden == true && mHideState == true) { - /* Show the state as tooltip */ - sslItem->setToolTip(COLUMN_NAME, connectStateString); - } else { - sslItem->setToolTip(COLUMN_NAME, ""); - } + rsPeers->getAssociatedSSLIds(detail.gpg_id, sslContacts); + for (std::list::iterator sslIt = sslContacts.begin(); sslIt != sslContacts.end(); ++sslIt) { + QTreeWidgetItem *sslItem = NULL; + RsPeerId sslId = *sslIt; - // sort node - sslItem->setData(COLUMN_STATE, ROLE_SORT, sText); - - /* last contact */ - QDateTime sslLastContact = QDateTime::fromTime_t(sslDetail.lastConnect); - sslItem->setData(COLUMN_LAST_CONTACT, Qt::DisplayRole, QVariant(sslLastContact)); - sslItem->setData(COLUMN_LAST_CONTACT, ROLE_SORT, sslLastContact); - if (sslLastContact > lastContact) { - lastContact = sslLastContact; - } - - /* IP */ - - QString sslItemIP = (sslDetail.state & RS_PEER_STATE_CONNECTED) ? StatusDefs::connectStateIpString(sslDetail) : QString("---"); - - sslItem->setData(COLUMN_IP, Qt::DisplayRole, QVariant(sslItemIP)); - sslItem->setData(COLUMN_IP, ROLE_SORT, sslItemIP); - if (sslItemIP != itemIP) { - itemIP = sslItemIP; - } - - /* change color and icon */ - QIcon sslIcon; - QFont sslFont; - QColor sslColor; - if (sslDetail.state & RS_PEER_STATE_CONNECTED) { - // get the status info for this ssl id - int peerState = 0; - int rsState = 0; - std::list::iterator it; - for(it = statusInfo.begin(); it != statusInfo.end(); ++it) { - if(it->id == sslId){ - rsState = it->status; - switch (rsState) { - case RS_STATUS_INACTIVE: - peerState = PEER_STATE_INACTIVE; - break; - - case RS_STATUS_ONLINE: - peerState = PEER_STATE_ONLINE; - break; - - case RS_STATUS_AWAY: - peerState = PEER_STATE_AWAY; - break; - - case RS_STATUS_BUSY: - peerState = PEER_STATE_BUSY; - break; - } - - /* find the best ssl contact for the gpg item */ - if (bestPeerState == 0 || peerState < bestPeerState) { - /* first ssl contact or higher state */ - bestPeerState = peerState; - bestSslId = sslId; - bestRSState = rsState; - bestCustomStateString = customStateString; - } else if (peerState == bestPeerState) { - /* equal state */ - if (mBigName && bestCustomStateString.isEmpty() && !customStateString.isEmpty()) { - /* when customStateString is shown in name item, use sslId with customStateString. - second with a custom state string ... use second */ - bestPeerState = peerState; - bestSslId = sslId; - bestRSState = rsState; - bestCustomStateString = customStateString; - } - } + // find the corresponding sslItem child item of the gpg item + bool newChild = true; + childCount = gpgItem->childCount(); + for (int childIndex = 0; childIndex < childCount; ++childIndex) { + // we assume, that only ssl items are child of the gpg item, so we don't need to test the type + if (getRsId(gpgItem->child(childIndex)) == sslId.toStdString()) { + sslItem = gpgItem->child(childIndex); + newChild = false; break; } } - sslItem->setHidden(false); - gpg_connected = true; + RsPeerDetails sslDetail; + if (!rsPeers->getPeerDetails(sslId, sslDetail) || !rsPeers->isFriend(sslId)) { +#ifdef FRIENDS_DEBUG + std::cerr << "Removing widget from the view : id : " << sslId << std::endl; +#endif + // child has disappeared, remove it from the gpg_item + if (sslItem) { + gpgItem->removeChild(sslItem); + delete(sslItem); + } + continue; + } - sslIcon = QIcon(":/images/connect_established.png"); + if (newChild) { + sslItem = new RSTreeWidgetItem(mCompareRole, TYPE_SSL); //set type to 1 for custom popup menu + +#ifdef FRIENDS_DEBUG + std::cerr << "FriendList::insertPeers() inserting sslItem." << std::endl; +#endif + + /* Add ssl child to the list. Add here, because for setHidden the item must be added */ + gpgItem->addChild(sslItem); + + /* Sort data */ + sslItem->setData(COLUMN_SORT, ROLE_SORT_GROUP, 2); + sslItem->setData(COLUMN_SORT, ROLE_SORT_STANDARD_GROUP, 1); + } + + /* not displayed, used to find back the item */ + sslItem->setData(COLUMN_DATA, ROLE_ID, QString::fromStdString(sslDetail.id.toStdString())); + + /* Custom state string */ + QString customStateString; + if (sslDetail.state & RS_PEER_STATE_CONNECTED) { + customStateString = QString::fromUtf8(rsMsgs->getCustomStateString(sslDetail.id).c_str()); + } + + QPixmap sslAvatar; + AvatarDefs::getAvatarFromSslId(RsPeerId(sslDetail.id.toStdString()), sslAvatar); + + /* last contact */ + QDateTime sslLastContact = QDateTime::fromTime_t(sslDetail.lastConnect); + sslItem->setData(COLUMN_LAST_CONTACT, Qt::DisplayRole, QVariant(sslLastContact)); + if (sslLastContact > bestLastContact) { + bestLastContact = sslLastContact; + } + + /* IP */ + QString sslIP = (sslDetail.state & RS_PEER_STATE_CONNECTED) ? StatusDefs::connectStateIpString(sslDetail) : QString("---"); + sslItem->setText(COLUMN_IP, sslIP); + + /* change color and icon */ + QPixmap sslOverlayIcon; + QFont sslFont; + QColor sslColor; + int peerState = 0; + QString connectStateString; + if (sslDetail.state & RS_PEER_STATE_CONNECTED) { + // get the status info for this ssl id + int rsState = 0; + std::list::iterator it; + for (it = statusInfo.begin(); it != statusInfo.end(); ++it) { + if (it->id == sslId) { + rsState = it->status; + switch (rsState) { + case RS_STATUS_INACTIVE: + peerState = PEER_STATE_INACTIVE; + break; + + case RS_STATUS_ONLINE: + peerState = PEER_STATE_ONLINE; + break; + + case RS_STATUS_AWAY: + peerState = PEER_STATE_AWAY; + break; + + case RS_STATUS_BUSY: + peerState = PEER_STATE_BUSY; + break; + } + + /* find the best ssl contact for the gpg item */ + if (bestPeerState == 0 || peerState < bestPeerState) { + /* first ssl contact or higher state */ + bestPeerState = peerState; + bestRSState = rsState; + bestCustomStateString = customStateString; + bestIP = sslIP; + if (!sslAvatar.isNull()) { + bestAvatar = sslAvatar; + } + } else if (peerState == bestPeerState) { + /* equal state */ + if (bestCustomStateString.isEmpty() && !customStateString.isEmpty()) { + /* when customStateString is shown in name item, use sslId with customStateString. + second with a custom state string ... use second */ + bestPeerState = peerState; + bestRSState = rsState; + bestCustomStateString = customStateString; + } + if (bestAvatar.isNull() && !sslAvatar.isNull()) { + /* Use available avatar */ + bestAvatar = sslAvatar; + } + } + break; + } + } + + sslItem->setHidden(false); + gpg_connected = true; + + sslOverlayIcon = QPixmap(StatusDefs::imageStatus(bestRSState)); + + connectStateString = StatusDefs::name(rsState); + + if (rsState == 0) { + sslFont.setBold(true); + sslColor = mTextColorStatus[RS_STATUS_ONLINE]; + } else { + sslFont = StatusDefs::font(rsState); + sslColor = mTextColorStatus[rsState]; + } + } else if (sslDetail.state & RS_PEER_STATE_ONLINE) { + sslItem->setHidden(mHideUnconnected); + gpg_online = true; + peerState = PEER_STATE_AVAILABLE; + + if (sslDetail.connectState) { + sslOverlayIcon = QPixmap(":/images/connect_creating.png"); + } else { + sslOverlayIcon = QPixmap(StatusDefs::imageStatus(RS_STATUS_ONLINE)); + } + + connectStateString = StatusDefs::name(RS_STATUS_ONLINE); - if (rsState == 0) { sslFont.setBold(true); sslColor = mTextColorStatus[RS_STATUS_ONLINE]; } else { - sslFont = StatusDefs::font(rsState); - sslColor = mTextColorStatus[rsState]; - } - } else if (sslDetail.state & RS_PEER_STATE_ONLINE) { - sslItem->setHidden(mHideUnconnected); - gpg_online = true; + peerState = PEER_STATE_OFFLINE; + sslItem->setHidden(mHideUnconnected); + if (sslDetail.connectState) { + sslOverlayIcon = QPixmap(":/images/connect_creating.png"); + } else { + sslOverlayIcon = QPixmap(StatusDefs::imageStatus(RS_STATUS_OFFLINE)); + } - if (sslDetail.connectState) { - sslIcon = QIcon(":/images/connect_creating.png"); + connectStateString = StatusDefs::connectStateWithoutTransportTypeString(sslDetail); + + sslFont.setBold(false); + sslColor = mTextColorStatus[RS_STATUS_OFFLINE]; + } + + /* Location */ + QString sName = QString::fromUtf8(sslDetail.location.c_str()); + QString sText = sName; + + if (mShowState) { + if (!connectStateString.isEmpty()) { + sText += "\n" + connectStateString; + if (!customStateString.isEmpty()) { + sText += " [" + customStateString + "]"; + } + } else { + if (!customStateString.isEmpty()) { + sText += "\n" + customStateString; + } + } + + sslItem->setToolTip(COLUMN_NAME, ""); } else { - sslIcon = QIcon(":/images/connect_no.png"); + if (!customStateString.isEmpty()) { + sText += "\n" + customStateString; + } + + /* Show the state as tooltip */ + sslItem->setToolTip(COLUMN_NAME, connectStateString); + } + sslItem->setText(COLUMN_NAME, sText); + + if (std::find(privateChatIds.begin(), privateChatIds.end(), sslDetail.id) != privateChatIds.end()) { + // private chat is available + sslOverlayIcon = QPixmap(":/images/chat.png"); + gpg_hasPrivateChat = true; + } + sslItem->setIcon(COLUMN_NAME, createAvatar(sslAvatar, sslOverlayIcon)); + + /* Sort data */ + sslItem->setData(COLUMN_SORT, ROLE_SORT_NAME, sName); + sslItem->setData(COLUMN_SORT, ROLE_SORT_STATE, peerState); + + for (int i = 0; i < columnCount; ++i) { + sslItem->setTextColor(i, sslColor); + sslItem->setFont(i, sslFont); + } + } + + QPixmap gpgOverlayIcon; + if (gpg_connected) { + gpgItem->setHidden(false); + + ++onlineCount; + + if (bestPeerState == 0) { + // show as online + bestPeerState = PEER_STATE_ONLINE; + bestRSState = RS_STATUS_ONLINE; } - sslFont.setBold(true); - sslColor = mTextColorStatus[RS_STATUS_ONLINE]; - } else { - sslItem->setHidden(mHideUnconnected); - if (sslDetail.connectState) { - sslIcon = QIcon(":/images/connect_creating.png"); - } else { - sslIcon = QIcon(":/images/connect_no.png"); + QColor textColor = mTextColorStatus[bestRSState]; + QFont font = StatusDefs::font(bestRSState); + for(int i = 0; i < columnCount; ++i) { + gpgItem->setTextColor(i, textColor); + gpgItem->setFont(i, font); } - sslFont.setBold(false); - sslColor = mTextColorStatus[RS_STATUS_OFFLINE]; - } + gpgOverlayIcon = QPixmap(StatusDefs::imageStatus(bestRSState)); - if (std::find(privateChatIds.begin(), privateChatIds.end(), sslDetail.id) != privateChatIds.end()) { - // private chat is available - sslIcon = QIcon(":/images/chat.png"); - gpg_hasPrivateChat = true; - } - sslItem -> setIcon(COLUMN_NAME, sslIcon); - - for (int i = 0; i < columnCount; ++i) { - sslItem -> setTextColor(i, sslColor); - sslItem -> setFont(i, sslFont); - } - } - - QIcon gpgIcon; - if (gpg_connected) { - gpgItem->setHidden(false); - - ++onlineCount; - - if (bestPeerState == 0) { - // show as online - bestPeerState = PEER_STATE_ONLINE; - bestRSState = RS_STATUS_ONLINE; - } - - QColor textColor = mTextColorStatus[bestRSState]; - QFont font = StatusDefs::font(bestRSState); - for(int i = 0; i < columnCount; ++i) { - gpgItem->setTextColor(i, textColor); - gpgItem->setFont(i, font); - } - - gpgIcon = QIcon(StatusDefs::imageStatus(bestRSState)); - - if (!isStatusColumnHidden) { - gpgItem->setText(COLUMN_STATE, StatusDefs::name(bestRSState)); - } - - if (isStatusColumnHidden && mBigName && !mHideState) { - if (bestCustomStateString.isEmpty()) { + if (mShowState) { gpgItemText += "\n" + StatusDefs::name(bestRSState); + if (!bestCustomStateString.isEmpty()) { + gpgItemText += " [" + bestCustomStateString + "]"; + } } else { - gpgItemText += "\n" + bestCustomStateString; + if (!bestCustomStateString.isEmpty()) { + gpgItemText += "\n" + bestCustomStateString; + } + } + } else if (gpg_online) { + if (mShowState) { + gpgItemText += "\n" + tr("Available"); + } + + bestPeerState = PEER_STATE_AVAILABLE; + ++onlineCount; + gpgItem->setHidden(mHideUnconnected); + gpgOverlayIcon = QPixmap(IMAGE_AVAILABLE); + + QFont font; + font.setBold(true); + QColor textColor = mTextColorStatus[RS_STATUS_ONLINE]; + for(int i = 0; i < columnCount; ++i) { + gpgItem->setTextColor(i, textColor); + gpgItem->setFont(i,font); + } + } else { + if (mShowState) { + gpgItemText += "\n" + StatusDefs::name(RS_STATUS_OFFLINE); + } + + bestPeerState = PEER_STATE_OFFLINE; + gpgItem->setHidden(mHideUnconnected); + gpgOverlayIcon = QPixmap(StatusDefs::imageStatus(RS_STATUS_OFFLINE)); + + QColor textColor = mTextColorStatus[RS_STATUS_OFFLINE]; + QFont font = StatusDefs::font(RS_STATUS_OFFLINE); + for(int i = 0; i < columnCount; ++i) { + gpgItem->setTextColor(i, textColor); + gpgItem->setFont(i, font); } - } else if (isStatusColumnHidden && !mHideState){ - gpgItemText += " - " + StatusDefs::name(bestRSState); - } - } else if (gpg_online) { - if (!isStatusColumnHidden) { - gpgItem->setText(COLUMN_STATE, tr("Available")); - } else if (!mHideState && !mBigName) { - gpgItemText += " - " + tr("Available") ; } - bestPeerState = PEER_STATE_AVAILABLE; - ++onlineCount; - gpgItem->setHidden(mHideUnconnected); - gpgIcon = QIcon(IMAGE_AVAILABLE); - - QFont font; - font.setBold(true); - QColor textColor = mTextColorStatus[RS_STATUS_ONLINE]; - for(int i = 0; i < columnCount; ++i) { - gpgItem->setTextColor(i, textColor); - gpgItem->setFont(i,font); - } - } else { - if (!isStatusColumnHidden) { - gpgItem->setText(COLUMN_STATE, StatusDefs::name(RS_STATUS_OFFLINE)); - } else if (!mHideState && !mBigName) { - gpgItemText += " - " + StatusDefs::name(RS_STATUS_OFFLINE) ; + if (gpg_hasPrivateChat) { + gpgOverlayIcon = QPixmap(":/images/chat.png"); } - bestPeerState = PEER_STATE_OFFLINE; - gpgItem->setHidden(mHideUnconnected); - gpgIcon = QIcon(StatusDefs::imageStatus(RS_STATUS_OFFLINE)); + gpgItem->setIcon(COLUMN_NAME, createAvatar(bestAvatar.isNull() ? QPixmap(AVATAR_DEFAULT_IMAGE) : bestAvatar, gpgOverlayIcon)); - QColor textColor = mTextColorStatus[RS_STATUS_OFFLINE]; - QFont font = StatusDefs::font(RS_STATUS_OFFLINE); - for(int i = 0; i < columnCount; ++i) { - gpgItem->setTextColor(i, textColor); - gpgItem->setFont(i, font); + gpgItem->setText(COLUMN_NAME, gpgItemText); + gpgItem->setData(COLUMN_LAST_CONTACT, Qt::DisplayRole, QVariant(bestLastContact)); + gpgItem->setText(COLUMN_IP, bestIP); + + /* Sort data */ + gpgItem->setData(COLUMN_SORT, ROLE_SORT_NAME, gpgName); + gpgItem->setData(COLUMN_SORT, ROLE_SORT_STATE, bestPeerState); + + if (openPeers != NULL && openPeers->find(gpgId.toStdString()) != openPeers->end()) { + gpgItem->setExpanded(true); } } - if (gpg_hasPrivateChat) { - gpgIcon = QIcon(":/images/chat.png"); - } - - if (!isAvatarColumnHidden){ - QPixmap avatar; - AvatarDefs::getAvatarFromSslId(bestSslId, avatar); - QIcon avatar_icon(avatar); - gpgItem->setIcon(COLUMN_AVATAR, avatar_icon); - // tell the avatar callback which avatar must be filled in at this place - gpgItem->setData(COLUMN_DATA, ROLE_BEST_SSL, QString::fromStdString(bestSslId.toStdString())); - } - - gpgItem->setText(COLUMN_NAME, gpgItemText); - gpgItem->setData(COLUMN_NAME, ROLE_SORT, "2 " + gpgItemText); - gpgItem->setData(COLUMN_STATE, ROLE_SORT, "2 " + BuildStateSortString(true, gpgItemText, bestPeerState)); - gpgItem->setIcon(COLUMN_NAME, gpgIcon); - gpgItem->setData(COLUMN_LAST_CONTACT, Qt::DisplayRole, QVariant(lastContact)); - gpgItem->setData(COLUMN_LAST_CONTACT, ROLE_SORT, "2 " + lastContact.toString("yyyyMMdd_hhmmss")); - gpgItem->setData(COLUMN_IP, Qt::DisplayRole, QVariant()); - gpgItem->setData(COLUMN_IP, ROLE_SORT, "2 " + itemIP); - - if (openPeers != NULL && openPeers->find(gpgId.toStdString()) != openPeers->end()) { - gpgItem->setExpanded(true); - } - } - if (groupInfo && groupItem) { if ((groupInfo->flag & RS_GROUP_FLAG_STANDARD) && groupItem->childCount() == 0) { // there are some dead id's assigned @@ -1109,8 +1085,9 @@ void FriendList::insertPeers() groupItem->setHidden(false); QString groupName = GroupDefs::name(*groupInfo); groupItem->setText(COLUMN_NAME, QString("%1 (%2/%3)").arg(groupName).arg(onlineCount).arg(availableCount)); - // show first the standard groups, than the user groups - groupItem->setData(COLUMN_NAME, ROLE_SORT, ((groupInfo->flag & RS_GROUP_FLAG_STANDARD) ? "0 " : "1 ") + groupName); + + /* Sort data */ + groupItem->setData(COLUMN_SORT, ROLE_SORT_NAME, groupName); } } @@ -1135,6 +1112,8 @@ void FriendList::insertPeers() delete(openPeers); openPeers = NULL; } + + ui->peerTreeWidget->sortItems(COLUMN_SORT, Qt::AscendingOrder); } /** @@ -1458,7 +1437,6 @@ void FriendList::connectfriend() QTreeWidgetItem *item = c->child(childIndex); if (item->type() == TYPE_SSL) { rsPeers->connectAttempt(RsPeerId(getRsId(item))); - item->setIcon(COLUMN_NAME,(QIcon(IMAGE_CONNECT2))); // Launch ProgressDialog, only if single SSL child. if (childCount == 1) @@ -1470,7 +1448,6 @@ void FriendList::connectfriend() } else { //this is a SSL key rsPeers->connectAttempt(RsPeerId(getRsId(c))); - c->setIcon(COLUMN_NAME,(QIcon(IMAGE_CONNECT2))); // Launch ProgressDialog. ConnectProgressDialog::showProgress(RsPeerId(getRsId(c))); } @@ -1682,37 +1659,66 @@ void FriendList::setColumnVisible(Column column, bool visible) peerTreeColumnVisibleChanged(column, visible); } -void FriendList::sortByColumn(Column column, Qt::SortOrder sortOrder) +void FriendList::peerTreeColumnVisibleChanged(int /*column*/, bool visible) { - ui->peerTreeWidget->sortByColumn(column, sortOrder); -} - -void FriendList::peerTreeColumnVisibleChanged(int column, bool visible) -{ - switch (column) { - case COLUMN_NAME: - case COLUMN_AVATAR: - case COLUMN_LAST_CONTACT: - case COLUMN_IP: - break; - case COLUMN_STATE: - ui->actionHideState->setEnabled(!visible); - break; - } - if (visible) { insertPeers(); } } -void FriendList::setHideState(bool hidden) +void FriendList::setShowState(bool show) { - if (mHideState != hidden) { - mHideState = hidden; + if (mShowState != show) { + mShowState = show; insertPeers(); } } +void FriendList::setSortByName() +{ + setSortMode(SORT_MODE_NAME); +} + +void FriendList::setSortByState() +{ + setSortMode(SORT_MODE_STATE); +} + +void FriendList::setSortMode(SortMode sortMode) +{ + // Add changes also in FriendList::sortMode + mCompareRole->setRole(COLUMN_SORT, ROLE_SORT_GROUP); + mCompareRole->addRole(COLUMN_SORT, ROLE_SORT_STANDARD_GROUP); + + switch (sortMode) { + case SORT_MODE_STATE: + mCompareRole->addRole(COLUMN_SORT, ROLE_SORT_STATE); + mCompareRole->addRole(COLUMN_SORT, ROLE_SORT_NAME); + break; + default: // SORT_MODE_NAME + mCompareRole->addRole(COLUMN_SORT, ROLE_SORT_NAME); + mCompareRole->addRole(COLUMN_SORT, ROLE_SORT_STATE); + } + + ui->peerTreeWidget->sortItems(COLUMN_SORT, Qt::AscendingOrder); +} + +FriendList::SortMode FriendList::sortMode() +{ + QList roles; + mCompareRole->findRoles(COLUMN_SORT, roles); + if (roles.count() == 4) { + switch (roles.at(2)) { + case ROLE_SORT_NAME: + return SORT_MODE_NAME; + case ROLE_SORT_STATE: + return SORT_MODE_STATE; + } + } + + return SORT_MODE_NAME; +} + void FriendList::setShowGroups(bool show) { if (mShowGroups != show) { @@ -1735,35 +1741,6 @@ void FriendList::setShowGroups(bool show) } } -/** - * If set to true, the customStateString will be shwon in all gpg peer items, - * not only in the ssl ids (used in MessengerWindow). - * These items will then be doublespaced. - */ -void FriendList::setBigName(bool bigName) -{ - if (mBigName != bigName) { - mBigName = bigName; - - // Change the size of the already existing items - QSize newSize; - if (mBigName) { - newSize.setHeight(40); - newSize.setWidth(40); - } else { - newSize.setHeight(26); - newSize.setWidth(26); - } - QTreeWidgetItemIterator it(ui->peerTreeWidget); - while (*it) { - if ((*it)->type() == TYPE_GPG) { - (*it)->setSizeHint(COLUMN_NAME, newSize); - } - ++it; - } - } -} - /** * Hides all items that don't contain text in the name column. */ @@ -1802,8 +1779,16 @@ void FriendList::createDisplayMenu() QMenu *displayMenu = new QMenu(this); connect(displayMenu, SIGNAL(aboutToShow()), this, SLOT(updateMenu())); + QActionGroup *actionGroup = new QActionGroup(displayMenu); + + QMenu *menu = displayMenu->addMenu(tr("Sort by")); + menu->addAction(ui->actionSortByName); + ui->actionSortByName->setActionGroup(actionGroup); + menu->addAction(ui->actionSortByState); + ui->actionSortByState->setActionGroup(actionGroup); + displayMenu->addAction(ui->actionHideOfflineFriends); - displayMenu->addAction(ui->actionHideState); + displayMenu->addAction(ui->actionShowState); displayMenu->addAction(ui->actionShowGroups); ui->displayButton->setMenu(displayMenu); @@ -1812,6 +1797,16 @@ void FriendList::createDisplayMenu() void FriendList::updateMenu() { ui->actionHideOfflineFriends->setChecked(mHideUnconnected); - ui->actionHideState->setChecked(mHideState); + ui->actionShowState->setChecked(mShowState); ui->actionShowGroups->setChecked(mShowGroups); + ui->actionSortByName->setChecked(true); + + switch (sortMode()) { + case SORT_MODE_NAME: + ui->actionSortByName->setChecked(true); + break; + case SORT_MODE_STATE: + ui->actionSortByState->setChecked(true); + break; + } } diff --git a/retroshare-gui/src/gui/common/FriendList.h b/retroshare-gui/src/gui/common/FriendList.h index 8a559a99c..aa8965ad2 100644 --- a/retroshare-gui/src/gui/common/FriendList.h +++ b/retroshare-gui/src/gui/common/FriendList.h @@ -52,10 +52,14 @@ public: enum Column { COLUMN_NAME = 0, - COLUMN_AVATAR = 1, - COLUMN_STATE = 2, - COLUMN_LAST_CONTACT = 3, - COLUMN_IP = 4 + COLUMN_LAST_CONTACT = 1, + COLUMN_IP = 2 + }; + + enum SortMode + { + SORT_MODE_NAME = 1, + SORT_MODE_STATE = 2 }; public: @@ -74,7 +78,9 @@ public: virtual void updateDisplay(); void setColumnVisible(Column column, bool visible); - void sortByColumn(Column column, Qt::SortOrder sortOrder); + + void setSortMode(SortMode sortMode); + SortMode sortMode(); QColor textColorGroup() const { return mTextColorGroup; } QColor textColorStatusOffline() const { return mTextColorStatus[RS_STATUS_OFFLINE]; } @@ -92,11 +98,12 @@ public: public slots: void filterItems(const QString &text); + void setSortByName(); + void setSortByState(); - void setBigName(bool bigName); // show customStateString in second line of the name cell void setShowGroups(bool show); void setHideUnconnected(bool hidden); - void setHideState(bool hidden); + void setShowState(bool show); private slots: void peerTreeColumnVisibleChanged(int column, bool visible); @@ -107,12 +114,11 @@ protected: private: Ui::FriendList *ui; - RSTreeWidgetItemCompareRole *m_compareRole; + RSTreeWidgetItemCompareRole *mCompareRole; // Settings for peer list display - bool mBigName; bool mShowGroups; - bool mHideState; + bool mShowState; bool mHideUnconnected; QString mFilterText; @@ -126,14 +132,12 @@ private: QColor mTextColorStatus[RS_STATUS_COUNT]; QTreeWidgetItem *getCurrentPeer() const; - void initializeHeader(bool afterLoadSettings); void getSslIdsFromItem(QTreeWidgetItem *item, std::list &sslIds); private slots: void groupsChanged(); void insertPeers(); void peerTreeWidgetCustomPopupMenu(); - void updateAvatar(const QString &); void updateMenu(); void pastePerson(); diff --git a/retroshare-gui/src/gui/common/FriendList.ui b/retroshare-gui/src/gui/common/FriendList.ui index 0f114a198..d4d62da9d 100644 --- a/retroshare-gui/src/gui/common/FriendList.ui +++ b/retroshare-gui/src/gui/common/FriendList.ui @@ -81,15 +81,6 @@ 38
- - 1 - - - 20 - - - true - true @@ -97,7 +88,7 @@ false - 5 + 3 false @@ -106,15 +97,8 @@ Friend nodes - - - - Avatar - - - - - Status + + AlignHCenter|AlignVCenter|AlignCenter @@ -138,15 +122,37 @@ Hide Offline Friends - + true - - false + + Name + + + Sort by Name + + + + + true - Hide State + State + + + Sort by State + + + + + true + + + Stow State + + + Show State diff --git a/retroshare-gui/src/gui/common/RSTreeWidget.cpp b/retroshare-gui/src/gui/common/RSTreeWidget.cpp index ef8e225ba..dece380df 100644 --- a/retroshare-gui/src/gui/common/RSTreeWidget.cpp +++ b/retroshare-gui/src/gui/common/RSTreeWidget.cpp @@ -29,7 +29,8 @@ RSTreeWidget::RSTreeWidget(QWidget *parent) : QTreeWidget(parent) { - mColumnCustomizable = false; + mEnableColumnCustomize = false; + mSettingsVersion = 0; // disabled } void RSTreeWidget::setPlaceholderText(const QString &text) @@ -117,32 +118,45 @@ bool RSTreeWidget::filterItem(QTreeWidgetItem *item, int filterColumn, const QSt return (itemVisible || visibleChildCount); } +void RSTreeWidget::setSettingsVersion(qint32 version) +{ + mSettingsVersion = version; +} + void RSTreeWidget::processSettings(bool load) { if (load) { - // load settings + // Load settings - // state of tree widget - header()->restoreState(Settings->value(objectName()).toByteArray()); + // State of tree widget + if (mSettingsVersion == 0 || Settings->value(QString("%1Version").arg(objectName())) == mSettingsVersion) { + // Compare version, because Qt can crash in restoreState after column changes + header()->restoreState(Settings->value(objectName()).toByteArray()); + } } else { - // save settings + // Save settings // state of tree widget Settings->setValue(objectName(), header()->saveState()); + + // Save version + if (mSettingsVersion) { + Settings->setValue(QString("%1Version").arg(objectName()), mSettingsVersion); + } } } -void RSTreeWidget::setColumnCustomizable(bool customizable) +void RSTreeWidget::enableColumnCustomize(bool customizable) { - if (customizable == mColumnCustomizable) { + if (customizable == mEnableColumnCustomize) { return; } - mColumnCustomizable = customizable; + mEnableColumnCustomize = customizable; QHeaderView *h = header(); - if (mColumnCustomizable) { + if (mEnableColumnCustomize) { h->setContextMenuPolicy(Qt::CustomContextMenu); connect(h, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(headerContextMenuRequested(QPoint))); } else { @@ -151,9 +165,14 @@ void RSTreeWidget::setColumnCustomizable(bool customizable) } } +void RSTreeWidget::setColumnCustomizable(int column, bool customizable) +{ + mColumnCustomizable[column] = customizable; +} + void RSTreeWidget::headerContextMenuRequested(const QPoint &pos) { - if (!mColumnCustomizable) { + if (!mEnableColumnCustomize) { return; } @@ -162,6 +181,10 @@ void RSTreeWidget::headerContextMenuRequested(const QPoint &pos) QTreeWidgetItem *item = headerItem(); int columnCount = item->columnCount(); for (int column = 0; column < columnCount; ++column) { + QMap::const_iterator it = mColumnCustomizable.find(column); + if (it != mColumnCustomizable.end() && *it == false) { + continue; + } QAction *action = contextMenu.addAction(QIcon(), item->text(column), this, SLOT(columnVisible())); action->setCheckable(true); action->setData(column); diff --git a/retroshare-gui/src/gui/common/RSTreeWidget.h b/retroshare-gui/src/gui/common/RSTreeWidget.h index 12c76ddf7..91b75b810 100644 --- a/retroshare-gui/src/gui/common/RSTreeWidget.h +++ b/retroshare-gui/src/gui/common/RSTreeWidget.h @@ -37,9 +37,11 @@ public: void filterItems(int filterColumn, const QString &text); + void setSettingsVersion(qint32 version); void processSettings(bool load); - void setColumnCustomizable(bool customizable); + void enableColumnCustomize(bool customizable); + void setColumnCustomizable(int column, bool customizable); signals: void signalMouseMiddleButtonClicked(QTreeWidgetItem *item); @@ -58,7 +60,9 @@ protected: private: QString mPlaceholderText; - bool mColumnCustomizable; + bool mEnableColumnCustomize; + quint32 mSettingsVersion; + QMap mColumnCustomizable; }; #endif diff --git a/retroshare-gui/src/gui/common/StatusDefs.cpp b/retroshare-gui/src/gui/common/StatusDefs.cpp index 6ff7315a6..b0756c88f 100644 --- a/retroshare-gui/src/gui/common/StatusDefs.cpp +++ b/retroshare-gui/src/gui/common/StatusDefs.cpp @@ -86,15 +86,15 @@ const char *StatusDefs::imageStatus(unsigned int status) { switch (status) { case RS_STATUS_OFFLINE: - return ":/images/status/user-offline.png"; + return ":/icons/user-offline_64.png"; case RS_STATUS_AWAY: - return ":/images/status/user-away.png"; + return ":/icons/user-away_64.png"; case RS_STATUS_BUSY: - return ":/images/status/user-busy.png"; + return ":/icons/user-busy_64.png"; case RS_STATUS_ONLINE: - return ":/images/status/user-online.png"; + return ":/icons/user-online_64.png"; case RS_STATUS_INACTIVE: - return ":/images/status/user-away-extended.png"; + return ":/icons/user-away-extended_64.png"; } std::cerr << "StatusDefs::imageUser: Unknown status requested " << status; diff --git a/retroshare-gui/src/gui/icons.qrc b/retroshare-gui/src/gui/icons.qrc index 23fe2dbc0..8840c6087 100644 --- a/retroshare-gui/src/gui/icons.qrc +++ b/retroshare-gui/src/gui/icons.qrc @@ -55,5 +55,10 @@ icons/tile_downloaded_48.png icons/tile_downloading_48.png icons/tile_inactive_48.png + icons/user-away_64.png + icons/user-away-extended_64.png + icons/user-busy_64.png + icons/user-offline_64.png + icons/user-online_64.png diff --git a/retroshare-gui/src/gui/icons/user-away-extended_64.png b/retroshare-gui/src/gui/icons/user-away-extended_64.png new file mode 100644 index 0000000000000000000000000000000000000000..e89dfde784b41d85f151beb8a1207b8df7f6abd4 GIT binary patch literal 22117 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�-iV6vYw5A(%l_L=+K} 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 R%3J^d002ovPDHLkV1g^L`=tN? literal 0 HcmV?d00001 diff --git a/retroshare-gui/src/gui/icons/user-busy_64.png b/retroshare-gui/src/gui/icons/user-busy_64.png new file mode 100644 index 0000000000000000000000000000000000000000..fa2f3d0ad8ff1cdd1b68c0b25f6c82d22fa6305f GIT binary patch literal 18316 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 bFG>dhHrNJO5L3!r00000NkvXXu0mjfL0y`) literal 0 HcmV?d00001 diff --git a/retroshare-gui/src/gui/icons/user-offline_64.png b/retroshare-gui/src/gui/icons/user-offline_64.png new file mode 100644 index 0000000000000000000000000000000000000000..577b102d984713f13db27f895556ca147f1e7c24 GIT binary patch literal 12673 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⪼iV&Ix41&Pn2Yr4V;6a}O0q+l( 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/btn_green.png images/btn_green_hover.png images/btn_green_pressed.png - images/connect_established.png - images/connect_established_low.png images/connect_creating.png - images/connect_no.png images/dht16.png images/dht32.png images/edit-clear-history.png @@ -424,7 +421,6 @@ images/replymail-pressed.png images/replymail24.png images/replymailall24-hover.png - images/reload24.png images/reset.png images/resume.png images/security-high-16.png @@ -694,11 +690,6 @@ images/tags/dev-translator.png images/tags/dev-patcher.png images/tags/developer.png - images/status/user-online.png - images/status/user-offline.png - images/status/user-busy.png - images/status/user-away-extended.png - images/status/user-away.png images/circles/circles_32.png images/circles/circles_64.png images/newsfeed/news-feed-32.png diff --git a/retroshare-gui/src/gui/images/connect_established.png b/retroshare-gui/src/gui/images/connect_established.png deleted file mode 100644 index 2c45f9d8669c285976d21bd395467b93def0c2b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 818 zcmV-21I_%2P)I};geLW>p@G}V2+-+6T%GBdPUZ@=^I zf^+VunW>q5_t~eP{MyDYv{DBk%qLt~Uf6h+=K%b_fc5ot^C7^@pdxL}Ko3jN8*jdK zC^nN*BC<$CM*!@bzPfK_x4ri_eJH-UeCgtk{|a#K<>PK;?!f!#&wbdbN(vz$cn@+8 z0HCU1W;C%u(v0U=(snJE1FUv;J;u!7l%QtV9;F#zFqoQ2Vl%U9Mdd(FD+?eIO)-Ku zi@8IY%#1()Gb4^i*{`wyW`<$vW!B695Xh0Ks;LUddEXi^KR>VDdpL4Cx=+(%A_5Vi zu4`%ySY2HWolb>N6d>oeL>_Dhas(LQoI_Q1P?lv@E89hb!QiJmckX6A|3@HZw0G~L zHK%mHHK3|0dTL=|vbea|X+v3FUZ!rZm(67sKtu=o{a(k+FjyM^2AC;S4XO%JfiOcv zAgZXUvP(pdw+1k?4TnRR8Aik5-}+vm(=8$p5vVHax<*Q=eFP~b#HIleVLYyZt#-Ao zYa*otW`>$!G#VqNl#|K>L;u0 zS5CjUzj2RzTo#@}2yoLM4#39H*{lT%s%Gtjr)6+4>%hYX&PyjxJtG`XGV}9h_Nr?05%5dZ)H07*qoM6N<$f`?goivR!s diff --git a/retroshare-gui/src/gui/images/connect_established_low.png b/retroshare-gui/src/gui/images/connect_established_low.png deleted file mode 100644 index 75ad75032d38f8e90697df7f23cdc6f6ae215810..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 856 zcmV-e1E>6nP)2P(bF|u^;LacT@AuA@bqw@a*GYYQyDw=2Sd{tBh-xK5Ei|pSI_F_(f&x=xCZ z#rUV!LILGS*j!cxKx9%|Gqxf{v-CuhR90WsDq2p0H`9S|89)p{cfKWvjDF_~KoLQy z*j_2Mb{1Svo~*qGDpxC)Rsc%AyG{88<{(MJOvlI0hpAbIESl~J&9tV=SR~52oB^op za3zg0j#qWW_0A<}0WsP4nu!IKwR;8?u4_!QRKDp%Y`7QM%m7@*yoc+b*Q>OrV(fRu z3c!*5pgzOnyN)+?5poZr3z)SIu?bqCy@~h-fRLPpMvFV;1<|f@Sud(lBeD|RPAQTN zf-}HzlPm>BYq|$&RmY;ypxeyZ;a(GevHiDR@5$28+|;LMLD}G0;u$#dv?^RROcD1g zrjY}Xdi{Ez{xxgevk6s?HbM`-v{%*e+3)GvqJJCx9u6E7<^!~o3 ib~iv20ewGpwfhY%6qn^8y;jfw0000G0if%vZYSUVbDz4& zI#AJxFo>8E$<&3NJw4qEOPTrkxzFR7m6f^W<>jXn6B8dRT3t)iT3?AL5|>h`6kIot z+*$$Mk&dC*@cto`7l)a_%pf8Z3I+W9@eL43BzGq-1K`!w)m{KswgiZXZH$4N&%+P_ z0E{sZaW^)z0;qx*%mhOWVzxxYu1mW1ftg{7MYygDDg&fMt_O&KiRwVw)-c9^h{P8_ zL?{|l2dIUx2&4>%N_EDVO<9)bS80(yz%aur7U34$jX8#`><_0EmfSVf^o2xT)fXZZVMovzV& z?0T|)c5?V}XT%7;;mgH`uyfIt;OBqT(2iJ)o#wc(*6YK)>57sqN#s9mq^#NJ(>-LrcxbKxQ2M38`#e9~xM zzM0>Q=9?LeG2CqX?593)UF6mP)u1)|29txX{ljm5{pgOTOAiA~e0NlAeX3Ug2xANf_T2XQU3X4A zAi@=q_l3zhhKy_Q9fNCWY=JG%mN6Qo42d*^kxWN#|Kyjpmy27YC?ez7oSUntL+}3a zYnAEv#J?Be0QBX}mmj-(>d;W9i_{U8Be9(n>=Z10Wur!cY(W&F+cE8yqSdHUzw{3p zjg;juWyr!loY{JG;;Uux&at)Qn?Q#hiC|$COSchjLN=e``w6}$5ncy4g)4}PAzDX- zYj|Ouv>D?z4I)sqYKlrj(TA}g2};NA`eM(>*;m$&H~Vo-9kRZpZA#NfvuY>bkq#3M?3OlnQ_m%84{^tV@7w;?Yw{AsIq{LMY;(Zz#n zY7;1U24Nd)8@gR6b$7Eezwm^2IQT{71d4xwzfND2!1iC$)}%*Bk&x zu%#n%%5|si)V+o@0bjN{b3j;Dh3nNVK57u zhm4@AB=f@1de*8xeawAt?`Y7&QgM;B^~?U`g>81OD_`(D7ss(lZ3|_L7~bPmmQ24+ z=ELD+BJSGQ2v99BO~BBx33#v^Co1}u&V28eN$tMQYMs1iaD0bhGw`|IvGRwdt};c@ zg=hIFBu&#~y|0ef+Ay-#Dm24@YPE*012xc&x%yOG2$J$lcmLsYr7e$*1U0MxRK})C zK+-GSLLom8I1N14#}WdGq@_ZdQIkf}q%jauUu;laX&{yXX)q2~fs@PDUfJ7oV65Cj z9F|DyDXEtrO+qzka=E&W%B09lg7Q*Qk)pIDi6n8Dkkm9u9rP-g%V0VUCcXwZbEfg) zH}36Up0mwMg^zS*X(S-Q!~&<3!IK%Zkr*M-LL#jcMM^AEVml#n6Jl4R3I;Wx$%#DC zQu`_Z@Y7SPuRe5_`@qU)cE6Mz@UyC=5Rsr5cdRa?@1HbTZCn185ymnY3`m2M*koHi zZd1p)X^d)W+{AU9$o>5$@cb7F!p)aCc{Y9Z+xKSge?#n=_WJ!S5xjGLcILw$UwYz3 zrTYIu81vs{KK60{?xB5C)7eokJNK8_-!1+8(mgi|T=&bo_}BRKxnIrPuP#Zf*s*VR ta=7LU{xg!L=ydmR>A}(MBl~X!_$NeDvu7={FP)h9Z{NPnzTM5wW)}$%oDfthbVM<&Silsgzf{dg1A*$G?O2LBQpE{Qi$85G zEiKv>TWm+C79^x)Y#pa%N{~_%i)0M8(w14UBoY}m*-f(9zxVe2oZfv&ARUU_nKS3! zbMHOhJLjICNBD?w&$hQ`5}_4D&0;x+f!ea1fI-3j1;zmecfPo;srOPk=>G}t{>kAP zBuSfv!sU+R%C_T@AUMqBZI+2hktG&HvMkv`$?urC{iO$Q`rxtvUwQV;Hu1&VOSTg# z7#4Cxi}Qv>M#)AQqzq72tf>kIH6Q5#A1X8-tBRZh^VfGgbn~uD0<3!G(8I3FTMDL) z;hc%#tbxXuiiHh2uAQbMUg`JFB}Ysg@6X}z`#GE(D4{B(p;GrF=vN>~wBhCTi++3& zz=|IoY;&1+W{Vc3M-2}8nASB<#e&%}4hDn574pQa|h0H-Xf|A zYX}8=ED^2V{m7DC=K;R_gV*aB^j_YyLxZCxrdKNb)Sa_vN~I5yonsDMG1*cczvpq` zdz?!R^QJwg=*)lsbAS72bDwu{`R4r{hV8ZvrsxI8|M?{{ z1s&3yb5@>!U;OzK_m?&f$PUA*~!;JezL+-k;lT z7vC3e%Cq7D`u3OV5h=dP(r`DqMWB!cKXWilb@h#CYiqj*AeBm?tE-C>i3H7?HxJ#V zYxq>MNaD?*NZ3fXeP{1J%axWE92xiC9K$VFtB4G31{ZCV0bB#^U=?Gd{TF}tY z;JL&!O&mFL1U)@HAk)ACBaitHtj8PuHePsh02Q($0Nnkw?5RKXi)oz&m7i{zPSXP? zppSO2YmjGwTV!^`{H5b@WZfW|nwq$xqJoYdJ<9p)C^ecHTwlzvzsMxr(Tc(PYxuEO z&X5llWLO{47oYf}0mZMf62NmSXCP=DgqGb0HsDz>!T0~$#gTN(`+7-|FsI6o8_Xms zi{{uFLA3ZYphZitu0tfWT?E-?iN5goYliF(`enb)KW&{x73N={X7)0hL|i0skv(e; z9xveKcgHgMwi!NJTB{1V2vcL+N@0Q0{CP-=Z{Y_!`^ho0aLj^9pWF0mzpCkVS}?+o zFPlnn{N!tA$tYw{ zD&{_<&wlIo`}|t)R=u)@?^+nA8|rNM&ps&t9PbTSctCJZ(FMTrnkUQIwPeyaK7pRJ z!oPVdNx6|UOe5b#w{G0iuKKm7BUMq%pB2NsH&sDNb%4@upO2ymACGY!n~(2J$d$QG z2;A9*7v37iu~P#W8BU>O8jn%)BOO;Ns+tH#s^w^HjPC#R6wC-4ET8@%xgyboBG3Fu z0As$NB!^nb`r1dS-_o${^>dsa9H2~Q$aWoPwwH;`8+LbSfr{2>ZJe%}8OPd1QTE$s zi4(s7kB(e;%<}*u06Z6oisOqQxZ)dZN2k*ELn)l-O>$~5Nk*}-`@ohJD?Nb4>vz;k zvhrRi9MR+PDY&jNj#W2SiOk5uJ^cqbA9TYl*#GOQk_@HcMrey}hvg4q*U@40oJ=B_ zJcsOPCg-~D+`n#J)px#1e(IqeZK5Ra3`Zgqi^cis`WUrbUxR6tK1L}=ZYlvcGYA$q z6pWI5#Z^oJo%%;Cyz)+(PxKAY;6M_YOol}lT>Zwgt1p!6iLvm3Uq37>$`(=oQC(e4 z(P#}mKC_0es}IriY87G4>j^w+ICN&H#K-!w^!MI0QmHf#4God#5A4{^hQmL*`{IT( zF+O?!iz|irc~w>QGEgX_L)Uc#M7dTJ#XDo$Hj0LUTrP)fHV2^?rBW#;uRQ_q^BiiKOMiZL-hjBSn!ROJf!|u0yu%uw_~0&Ss0}7EK@R-P^x*`KCX4%>U}o zXObkhmIF=D$HdP>biDqj1pB9;10q;E-}%+r-b?BDFV~e>)rMC?sj*4yU8=6f^m zn|TN$$l{$1>4;Dai23Yy0s$mydIacX({DgfOF&iomgltG&IjH~x$wi2qmkpbGKX^& zMdf8hMK(Yo(w2!wM1kjs4di)FW=_5&qO#9c=3TiXz_U9}l(G}=4$F$IUy6V~7@>d^ zK`AVQ2BHCIjzyzD7SVuKvjL(+0~rP04@58SUp1rhwgB@#s9&S1w5>lRLytcMJw6G> zIgBtp!wOj`R&d6ebUSx%2!3hz!^z8jxY!YfIGYHuRufoE0&pCzt5`kr{b2y}-uu2( zB|6{>MzE_-B8!1=dHyJvI^IDRi-o0vA28MOgo>h2AP~Sa%^k3-_8J8ui1ug^Y-R&- zhzky`eW-E};F))8(g^T;ASBy5`$CW!E70br$6``K9LpBcKO!CY*JqY{xbEqpjfXB_ zTdxd>(I#S%_!&8}zj!6TRo^&w>v5MPtHs>`8LUQx?WN#Ps%9%in+3Fq8oOvbKK1r@WwHwIusfx(PBXstL>idQ z=E2R9BvE;JIVLA3LuqO0FaVFo1J%{l)ZE;R6DLlDGvRyak~@g(&OzW{JwEy7(PI&n zo7J!Iuw;e<9-a`dr(~!!H8nv^O$`(k6+uQuhOP^RLU8)@X?>03ILOP(gY4{VsQ=vy zdrx#g6t6G<^*GMi{B1k?Opbt&wiKn}U5tthU@%2m_^PU6MMZ^vA2~TW6crVPjg5^u zi!w7aAvZTy*M-Aj_@g&O8xFUj0V2RdtkJ=MxegxZ;r{7#(N$TYg81V5sg& zPXu<>T&J$i4)l7vWmQqe>jwGj4!T5hRB=M06YoxU!m^nOWD@W{0fc12-Sr;0(BdXf zryHeU|H0aA^GbAs2UqV;<9Ok`Ejq^PbSA;1aZZ?je;gS3TfRrbB+RH;+1LY37v11? zUk6{G*Uw0iUAKLH>!61RR_!lk)I1O!6N3(ilQPpBSTw~BDY1qTBWUl9z~Qr9bfL8a zJ3HLq^?Dg))dfH7SnyZ79+2rTeY%Dhgl(+PhsxyVKTb!EFV=|0#=WfQ5_AM251W2v kqZUZ5I{V48mfQLG6B|31dB=UEkpKVy07*qoM6N<$f}abwL;wH) diff --git a/retroshare-gui/src/gui/images/status/user-busy.png b/retroshare-gui/src/gui/images/status/user-busy.png deleted file mode 100644 index 85453b4e46dd48787591cc60bf3a8c58bf2a82cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1218 zcmV;z1U>tSP)X`vgzMJbp@3dLd;HMP;PNth(_|IGYqA!7Z&vC{Jd~QS==; zq)sZut=6Mz-&2mDT9u{SxADjHwElhf?i#l~`3IOj(|G1tfUCfnbUHox=E;+IZFm?C zof?`L(|E86q8fS7Fht08K>Krc7QbG;4A1jEJq~>N3;=2QFp*4Nf4f+eT|+~fWXQ%k zHb!Ag+YAtf5`l!Fk|udPKaZa$CbV9weMGvxZ2?%$>0oZp@Njm|kt0YtjyewGcO1|* z0U96-UpE1Q05tvuQsesm&6|3EcGl9h-_|60yd@DfVR4{gkPqnP*(l!xatSO=m#0!@4FcC{z5_AbQ&g^RGQE%fD%k#vxzg{ z5HM;wmB@LmrZl0!_dK1Onvy3$P-lJK5Ei!BY0UU;IvN}q5jUTQNu|_rUEv&o3Bj6~ zMD8s`_Hf2d!)jFn-xtpCOC^0UGb4Wycs&fqAZqsJ2tK7eNx4 zj5^FF!L?y+=)BQ%4FJk$AW?HsO+y0ID-{hGb)C-FxPHWa+h~Dpv{*%NWQ{r6NB!wx zv{Y10q|;&=(MMg~YBURAHHeL7yVqtw5UqQjP)YHW>m>$2shEkRBEGo>C>L`t8PmlR zg>KhHipFkkP{Zi0Hf_}+t3BH2Vz7%*rLEFrQ+Wx|^;~akv##d$rpl}Fy!jPshhv4!&bCsF+!2iGW+W>8Twg7vHlaCv##3}l0 g;s0ii?eN+1FOo#Y#I=_;hyVZp07*qoM6N<$f<{VF4*&oF diff --git a/retroshare-gui/src/gui/images/status/user-offline.png b/retroshare-gui/src/gui/images/status/user-offline.png deleted file mode 100644 index d896ddf92f65abcd3f28a986da676c8204dfa596..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1272 zcmVDVT8Bnx%pv@=L2>m*3rDY{X?#)degH|iz^ zf*WyYgy>20A)AR=yO&Jod1$vGMuc-QDlLzP{gvg@rj%Qc_H8Y^($Y1!??? ziwm>2w`bSa*Ujna>1SMj0q8Y={(BPO)vH$~Dk|y+Z0>YAoniU;`GULk^YcUUo~@Se zA$xmsb7NLkR%B*o#^Qd4r0UPk&ffO*_1Q-O>gwu#3Jwl#Eh#CH%*;$d1p+W#y4eMS z*m_4mU8q177Z+uGd|XgnOJ`^29}fUPOO?OB|C_S1GLx2;rdc~24hFRdVhHA40fJfp zvl6+zz13<~S65|pbkts7U;hZY`aJ+mO-;{n`;eQP8~WIVL0|L`FtN?EL(^I)~*~RaKd+tgL$!Ei5e9{{DWYkq@%7 zvrTzj;AI{F(3D_pRt^!E13_V%_0Wcdv465Qh=a4rB* z8u|U%vu9FWT`h-)heENr4h|0fAw}y62?@z`PGn@HA(w%HffgGL#3d~rN4e~(u5vpE zbP2?^NX%SbUQ#=IbabSS`uOqV1_3UUl9K#EkqU<3g6t|XP-;Ec5MR4r{1XgPzsE!W;@iPF73*hPj zMRWoIAdsOBg@uI*z$!=+0qA*Tt^iY0Q{>;mC<;Ia-lNDRatQ%qVqy$}$-8&&EVxt` z!9g}7Bg44IhFb$xu(Y&f;3Rbsv@_nB^jB(tN`y9@n3xc}EH0Z$ zMMZ_Ar>A>n66eqI^0EvM4~xsDf+VE4xR^F&=HjyHFRZ|c7q!vY`V<-g?BL*_;bzVv zmclMapJ)a2IY$Wlfx(fKt*opxOaT1rXz?_f_o(39r%mA?3r83oZZU9@9+}`almP5%I*BxR zyNL9;yO&cJTIrDqkhi!VKQbRX^g)vYRcU{CHyZtpY&n1Q(8q7D+uPfpKJ*^}asued izbyznfWTk;+wwmgI#Ez|FYSc@0000^dOP)tEQE*C?V4EzT23~<=7Ww0}ovbV0^D*3)V zx>DUi{OL+TM#o3>{I&BkQ=0X>7KRCQpm`jl_XLPN&(B@hZ3#Ypc;kbaSD)C8$2UEx zZY(Zx=T0@x@c>$HHst5aKjO2WPU!Df{w(`G-b4i_nqLO@+zsHoj{WIW;>g=O-@=Zq zJ77D2W$_Cux;eUA=N|X@%hmFLk@F+?@bpJ0S8DHipWx_S0HozLH|`7_+;u><1w<;GjA+3aJ&PjiN+WwI?6x?vXA7zzm9|q7I)KmdWctwT$;n1|yknJd;}w zY{_rJ#=b2S1qQ@qg7J%j>hv84&7%+|*#-0sPz;{j1P9lZ@e8;xdKnYffKmb9NqjG^ zclBXSZXGn$BeJ=F8`7z)N*q!rEjRy=dy2gJA%#o2v;iqsinug(PAgL?6aN6yO+VNOY3&q=o*@HOQp1DBKWCT#AHVT=NR{l1F&zIv^eY325^~?8+^a_b%%H^#W+w>{iu~=IO%Ktg z=HnH3)5bP)yIa9buuV z-LsnPP-x3gL>C#W!qkKVF;=Zig&L%KAhf8`o?@&?iv}(tJw{-ix(ODVu+Vg%tyLI+ z>M9CRd&sp3U?k&6a@<&J`ya7MrQ& zxxUoai=zI6sK`9l%xr5V+<<@s2*ChCFkrv|0~6fT3i(ET7U9S&a%7%bW@OF- zQ4`(~4E>nP;l`S9;`0FEaA}ZwdY|k65B(*87QMDeE|g%wYm3F#mgCF6w)_Y7z-5Cp S< Date: Sat, 8 Aug 2015 21:14:02 +0200 Subject: [PATCH 027/165] Updated english translation --- plugins/VOIP/lang/VOIP_en.ts | 28 +- retroshare-gui/src/lang/retroshare_en.ts | 643 ++++++++++++----------- 2 files changed, 343 insertions(+), 328 deletions(-) diff --git a/plugins/VOIP/lang/VOIP_en.ts b/plugins/VOIP/lang/VOIP_en.ts index 6fff12491..05ec2f65f 100644 --- a/plugins/VOIP/lang/VOIP_en.ts +++ b/plugins/VOIP/lang/VOIP_en.ts @@ -1,6 +1,6 @@ - + AudioInput @@ -130,7 +130,7 @@ - + Video Processing @@ -138,7 +138,7 @@ AudioInputConfig - + Continuous @@ -168,7 +168,7 @@ - + VOIP @@ -366,7 +366,7 @@ - + This is the audio tuning wizard for RetroShare. This will help you correctly set the input levels of your sound card, and also set the correct parameters for sound processing in Retroshare. @@ -381,13 +381,13 @@ - + <p >Open your sound control panel and go to the recording settings. Make sure the microphone is selected as active input with maximum recording volume. If there's an option to enable a &quot;Microphone boost&quot; make sure it's checked. </p> <p>Speak loudly, as when you are annoyed or excited. Decrease the volume in the sound control panel until the bar below stays as high as possible in the green and orange but not the red zone while you speak. </p> - + Talk normally, and adjust the slider below so that the bar moves into green when you talk, and doesn't go into the orange zone. @@ -452,7 +452,7 @@ - + Congratulations. You should now be ready to enjoy a richer sound experience with Retroshare. @@ -460,7 +460,7 @@ QObject - + <h3>RetroShare VOIP plugin</h3><br/> * Contributors: Cyril Soler, Josselin Jacquard<br/> @@ -498,7 +498,7 @@ VOIP - + This plugin provides voice communication between friends in RetroShare. @@ -747,4 +747,12 @@ + + voipGraphSource + + + Required bandwidth + + + diff --git a/retroshare-gui/src/lang/retroshare_en.ts b/retroshare-gui/src/lang/retroshare_en.ts index 33cecc3f1..e20f8c5c8 100644 --- a/retroshare-gui/src/lang/retroshare_en.ts +++ b/retroshare-gui/src/lang/retroshare_en.ts @@ -1,6 +1,6 @@ - + AWidget @@ -573,24 +573,36 @@ p, li { white-space: pre-wrap; } - + Icon Size = 8x8 - - + + Icon Size = 16x16 - - + + Icon Size = 24x24 - + + + Icon Size = 64x64 + + + + + + Icon Size = 128x128 + + + + Status Bar @@ -620,8 +632,8 @@ p, li { white-space: pre-wrap; } - - + + Icon Size = 32x32 @@ -733,7 +745,7 @@ p, li { white-space: pre-wrap; } BWGraphSource - + KB/s @@ -749,13 +761,13 @@ p, li { white-space: pre-wrap; } BandwidthGraph - + RetroShare Bandwidth Usage - + Show Settings @@ -810,7 +822,7 @@ p, li { white-space: pre-wrap; } - + Since: @@ -820,6 +832,31 @@ p, li { white-space: pre-wrap; } + + BandwidthStatsWidget + + + + Sum + + + + + + All + + + + + KB/s + + + + + Count + + + BwCtrlWindow @@ -883,7 +920,7 @@ p, li { white-space: pre-wrap; } - + TOTALS @@ -898,6 +935,44 @@ p, li { white-space: pre-wrap; } + + BwStatsWidget + + + Form + + + + + Friend: + + + + + Type: + + + + + Up + + + + + Down + + + + + Service: + + + + + Unit: + + + ChannelPage @@ -947,7 +1022,7 @@ p, li { white-space: pre-wrap; } - + Mute participant @@ -982,7 +1057,7 @@ p, li { white-space: pre-wrap; } - + Lobby chat @@ -1035,12 +1110,12 @@ p, li { white-space: pre-wrap; } - + Start private chat - + Decryption failed. @@ -1157,7 +1232,7 @@ p, li { white-space: pre-wrap; } - + Create chat lobby @@ -1208,7 +1283,7 @@ p, li { white-space: pre-wrap; } - + Search Name @@ -1218,7 +1293,12 @@ p, li { white-space: pre-wrap; } - + + <h1><img width="%1" src=":/icons/help_64.png">&nbsp;&nbsp;Chat Lobbies</h1> <p>Chat lobbies are distributed chat rooms, and work pretty much like IRC. They allow you to talk anonymously with tons of people without the need to make friends.</p> <p>A chat lobby can be public (your friends see it) or private (your friends can't see it, unless you invite them with <img src=":/images/add_24x24.png" width=%2/>). Once you have been invited to a private lobby, you will be able to see it when your friends are using it.</p> <p>The list at left shows chat lobbies your friends are participating in. You can either <ul> <li>Right click to create a new chat lobby</li> <li>Double click a chat lobby to enter, chat, and show it to your friends</li> </ul> Note: For the chat lobbies to work properly, your computer needs be on time. So check your system clock! </p> + + + + Columns @@ -1274,7 +1354,7 @@ Double click lobbies to enter and chat. - + Private Subscribed Lobbies @@ -1283,18 +1363,13 @@ Double click lobbies to enter and chat. Public Subscribed Lobbies - - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;Chat Lobbies</h1> <p>Chat lobbies are distributed chat rooms, and work pretty much like IRC. They allow you to talk anonymously with tons of people without the need to make friends.</p> <p>A chat lobby can be public (your friends see it) or private (your friends can't see it, unless you invite them with <img src=":/images/add_24x24.png" width=12/>). Once you have been invited to a private lobby, you will be able to see it when your friends are using it.</p> <p>The list at left shows chat lobbies your friends are participating in. You can either <ul> <li>Right click to create a new chat lobby</li> <li>Double click a chat lobby to enter, chat, and show it to your friends</li> </ul> Note: For the chat lobbies to work properly, your computer needs be on time. So check your system clock! </p> - - Chat Lobbies - + Leave this lobby @@ -1324,7 +1399,7 @@ Double click lobbies to enter and chat. - + Show @@ -1377,7 +1452,7 @@ Double click lobbies to enter and chat. - + Quick Message @@ -4165,7 +4240,7 @@ Do you want to reject this message? - + DHT Off @@ -4285,7 +4360,7 @@ Do you want to reject this message? DhtWindow - + Net Status @@ -4315,7 +4390,7 @@ Do you want to reject this message? - + Name @@ -4360,7 +4435,7 @@ Do you want to reject this message? - + Bucket @@ -4386,17 +4461,17 @@ Do you want to reject this message? - + Last Sent - + Last Recv - + Relay Mode @@ -4431,7 +4506,7 @@ Do you want to reject this message? - + Unknown NetState @@ -4692,13 +4767,14 @@ Do you want to reject this message? - + + DHT - + Net Status: @@ -4768,7 +4844,27 @@ Do you want to reject this message? - + + Filter: + + + + + Search Network + + + + + Peers + + + + + Relay + + + + DHT Graph @@ -5011,7 +5107,7 @@ you plug it in. FileTransferInfoWidget - + Chunk map @@ -5186,7 +5282,7 @@ you plug it in. FlatStyle_RDM - + Friends Directories @@ -5262,31 +5358,17 @@ you plug it in. FriendList - - - Status - - - - - - + Last Contact - - - Avatar - - - - + Hide Offline Friends - + State @@ -5295,30 +5377,18 @@ you plug it in. Sort by State - - - Hide State - - - - - - Sort Descending Order - - - - - - Sort Ascending Order - - - - - Show Avatar Column - - + Stow State + + + + + Show State + + + + Name @@ -5328,33 +5398,13 @@ you plug it in. - - Sort by last contact - - - - - Show Last Contact Column - - - - - Set root is Decorated - - - - - Set Root Decorated - - - - + Show Groups - + Group @@ -5395,7 +5445,12 @@ you plug it in. - + + Search + + + + Move to group @@ -5425,40 +5480,22 @@ you plug it in. - - + Available - + Do you want to remove this Friend? - - Columns - - - - - - + IP - - Sort by IP - - - - - Show IP Column - - - - + Attempt to connect @@ -5468,7 +5505,7 @@ you plug it in. - + Display @@ -5478,12 +5515,12 @@ you plug it in. - + Sort by - + Node @@ -5493,17 +5530,17 @@ you plug it in. - + Do you want to remove this node? - + Friend nodes - + Send message to whole group @@ -5668,7 +5705,12 @@ you plug it in. - + + <h1><img width="32" src=":/icons/help_64.png">&nbsp;&nbsp;Network</h1> <p>The Network tab shows your friend Retroshare nodes: the neighbor Retroshare nodes that are connected to you. </p> <p>You can group nodes together to allow a finer level of information access, for instance to only allow some nodes to see some of your files.</p> <p>On the right, you will find 3 useful tabs: <ul> <li>Broadcast sends messages to all connected nodes at once</li> <li>Local network graph shows the network around you, based on discovery information</li> <li>Keyring contains node keys you collected, mostly forwarded to you by your friend nodes</li> </ul> </p> + + + + Retroshare broadcast chat: messages are sent to all connected friends. @@ -5684,12 +5726,7 @@ you plug it in. - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;Network</h1> <p>The Network tab shows your friend Retroshare nodes: the neighbor Retroshare nodes that are connected to you. </p> <p>You can group nodes together to allow a finer level of information access, for instance to only allow some nodes to see some of your files.</p> <p>On the right, you will find 3 useful tabs: <ul> <li>Broadcast sends messages to all connected nodes at once</li> <li>Local network graph shows the network around you, based on discovery information</li> <li>Keyring contains node keys you collected, mostly forwarded to you by your friend nodes</li> </ul> </p> - - - - + Set your status message here. @@ -6652,7 +6689,7 @@ p, li { white-space: pre-wrap; } GroupTreeWidget - + Title @@ -6672,7 +6709,7 @@ p, li { white-space: pre-wrap; } - + Sort by Name @@ -6692,7 +6729,7 @@ p, li { white-space: pre-wrap; } - + You have admin rights @@ -6803,7 +6840,7 @@ p, li { white-space: pre-wrap; } GxsChannelDialog - + Channels @@ -6814,17 +6851,22 @@ p, li { white-space: pre-wrap; } - + Enable Auto-Download - + My Channels - + + <h1><img width="32" src=":/icons/help_64.png">&nbsp;&nbsp;Channels</h1> <p>Channels allow you to post data (e.g. movies, music) that will spread in the network</p> <p>You can see the channels your friends are subscribed to, and you automatically forward subscribed channels to your friends. This promotes good channels in the network.</p> <p>Only the channel's creator can post on that channel. Other peers in the network can only read from it, unless the channel is private. You can however share the posting rights or the reading rights with friend Retroshare nodes.</p> <p>Channels can be made anonymous, or attached to a Retroshare identity so that readers can contact you if needed. Enable "Allow Comments" if you want to let users comment on your posts.</p> <p>Channel posts get deleted after %1 months.</p> + + + + Subscribed Channels @@ -6839,13 +6881,29 @@ p, li { white-space: pre-wrap; } - + + Select channel download directory + + + + Disable Auto-Download - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;Channels</h1> <p>Channels allow you to post data (e.g. movies, music) that will spread in the network</p> <p>You can see the channels your friends are subscribed to, and you automatically forward subscribed channels to your friends. This promotes good channels in the network.</p> <p>Only the channel's creator can post on that channel. Other peers in the network can only read from it, unless the channel is private. You can however share the posting rights or the reading rights with friend Retroshare nodes.</p> <p>Channels can be made anonymous, or attached to a Retroshare identity so that readers can contact you if needed. Enable "Allow Comments" if you want to let users comment on your posts.</p> <p>Channel posts get deleted after %1 months.</p> + + Set download directory + + + + + + [Default directory] + + + + + Specify... @@ -7186,7 +7244,7 @@ p, li { white-space: pre-wrap; } - + Disable Auto-Download @@ -7545,13 +7603,13 @@ before you can comment - + Author - + Loading @@ -7611,7 +7669,7 @@ before you can comment - + Reply @@ -7756,12 +7814,12 @@ before you can comment - + <p>Subscribing to the forum will gather available posts from your subscribed friends, and make the forum visible to all other friends.</p><p>Afterwards you can unsubscribe from the context menu of the forum list at left.</p> - + Reply with private message @@ -7777,7 +7835,12 @@ before you can comment GxsForumsDialog - + + <h1><img width="32" src=":/icons/help_64.png">&nbsp;&nbsp;Forums</h1> <p>Retroshare Forums look like internet forums, but they work in a decentralized way</p> <p>You see forums your friends are subscribed to, and you forward subscribed forums to your friends. This automatically promotes interesting forums in the network.</p> <p>Forum messages get deleted after %1 months.</p> + + + + Forums @@ -7807,11 +7870,6 @@ before you can comment Other Forums - - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;Forums</h1> <p>Retroshare Forums look like internet forums, but they work in a decentralized way</p> <p>You see forums your friends are subscribed to, and you forward subscribed forums to your friends. This automatically promotes interesting forums in the network.</p> <p>Forum messages get deleted after %1 months.</p> - - GxsForumsFillThread @@ -8830,12 +8888,7 @@ p, li { white-space: pre-wrap; } - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;Identities</h1> <p>In this tab you can create/edit pseudo-anonymous identities. </p> <p>Identities are used to securely identify your data: sign forum and channel posts, and receive feedback using Retroshare built-in email system, post comments after channel posts, etc.</p> <p> Identities can optionally be signed by your Retroshare node's certificate. Signed identities are easier to trust but are easily linked to your node's IP address. </p> <p> Anonymous identities allow you to anonymously interact with other users. They cannot be spoofed, but noone can prove who really owns a given identity. </p> - - - - + This identity is owned by you @@ -8905,7 +8958,12 @@ p, li { white-space: pre-wrap; } - + + <h1><img width="32" src=":/icons/help_64.png">&nbsp;&nbsp;Identities</h1> <p>In this tab you can create/edit pseudo-anonymous identities. </p> <p>Identities are used to securely identify your data: sign forum and channel posts, and receive feedback using Retroshare built-in email system, post comments after channel posts, etc.</p> <p> Identities can optionally be signed by your Retroshare node's certificate. Signed identities are easier to trust but are easily linked to your node's IP address. </p> <p> Anonymous identities allow you to anonymously interact with other users. They cannot be spoofed, but noone can prove who really owns a given identity. </p> + + + + Linked to a friend Retroshare node @@ -9202,13 +9260,13 @@ p, li { white-space: pre-wrap; } ImHistoryBrowser - + Message History - + Copy @@ -9306,7 +9364,7 @@ p, li { white-space: pre-wrap; } - + Options @@ -9340,12 +9398,12 @@ p, li { white-space: pre-wrap; } - + RetroShare %1 a secure decentralized communication platform - + Unfinished @@ -9379,7 +9437,12 @@ p, li { white-space: pre-wrap; } - + + Open Messenger + + + + Open Messages @@ -10523,7 +10586,7 @@ Do you want to save message ? MessagesDialog - + New Message @@ -10590,7 +10653,7 @@ Do you want to save message ? - + Tags @@ -10598,7 +10661,7 @@ Do you want to save message ? - + Inbox @@ -10695,7 +10758,7 @@ Do you want to save message ? - + Reply to All @@ -10713,12 +10776,12 @@ Do you want to save message ? - + From - + Date @@ -10746,12 +10809,12 @@ Do you want to save message ? - + Click to sort by from - + Click to sort by date @@ -10806,7 +10869,12 @@ Do you want to save message ? - + + <h1><img width="%1" src=":/icons/help_64.png">&nbsp;&nbsp;Messages</h1> <p>Retroshare has its own internal email system. You can send/receive emails to/from connected friend nodes.</p> <p>It is also possible to send messages to other people's Identities using the global routing system. These messages are always encrypted and signed, and are relayed by intermediate nodes until they reach their final destination. </p> <p>Distant messages stay into your Outbox until an acknowledgement of receipt has been received.</p> <p>Generally, you may use messages to recommend files to your friends by pasting file links, or recommend friend nodes to other friend nodes, in order to strenghten your network, or send feedback to a channel's owner.</p> + + + + Starred @@ -10913,12 +10981,12 @@ Do you want to save message ? - + Click to sort by signature - + This message was signed and the signature checks @@ -10932,11 +11000,6 @@ Do you want to save message ? This message comes from a distant person. - - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;Messages</h1> <p>Retroshare has its own internal email system. You can send/receive emails to/from connected friend nodes.</p> <p>It is also possible to send messages to other people's Identities using the global routing system. These messages are always encrypted and are relayed by intermediate nodes until they reach their final destination. </p> <p>It is recommended to cryptographically sign distant messages, as a proof of your identity, using the <img width="16" src=":/images/stock_signature_ok.png"/> button in the message composer window. Distant messages stay into your Outbox until an acknowledgement of receipt has been received.</p> <p>Generally, you may use messages to recommend files to your friends by pasting file links, or recommend friend nodes to other friend nodes, in order to strenghten your network, or send feedback to a channel's owner.</p> - - MessengerWindow @@ -11036,7 +11099,7 @@ Do you want to save message ? - + Network Status Unknown @@ -11080,26 +11143,6 @@ Do you want to save message ? Forwarded Port - - - OK | RetroShare Server - - - - - Internet connection - - - - - No internet connection - - - - - No local network - - NetworkDialog @@ -11271,7 +11314,7 @@ For security, your keyring was previously backed-up to file - + Personal signature @@ -11337,7 +11380,7 @@ Right-click and select 'make friend' to be able to connect. - + Data inconsistency in the keyring. This is most probably a bug. Please contact the developers. @@ -11476,7 +11519,7 @@ Reported error: NewsFeed - + News Feed @@ -11495,18 +11538,13 @@ Reported error: This is a test. - - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;News Feed</h1> <p>The News Feed displays the last events on your network, sorted by the time you received them. This gives you a summary of the activity of your friends. You can configure which events to show by pressing on <b>Options</b>. </p> <p>The various events shown are: <ul> <li>Connection attempts (useful to make friends with new people and control who's trying to reach you)</li> <li>Channel and Forum posts</li> <li>New Channels and Forums you can subscribe to</li> <li>Private messages from your friends</li> </ul> </p> - - News feed - + Newest on top @@ -11515,6 +11553,11 @@ Reported error: Oldest on top + + + <h1><img width="32" src=":/icons/help_64.png">&nbsp;&nbsp;News Feed</h1> <p>The News Feed displays the last events on your network, sorted by the time you received them. This gives you a summary of the activity of your friends. You can configure which events to show by pressing on <b>Options</b>. </p> <p>The various events shown are: <ul> <li>Connection attempts (useful to make friends with new people and control who's trying to reach you)</li> <li>Channel and Forum posts</li> <li>New Channels and Forums you can subscribe to</li> <li>Private messages from your friends</li> </ul> </p> + + NotifyPage @@ -11658,7 +11701,12 @@ Reported error: - + + <h1><img width="24" src=":/icons/help_64.png">&nbsp;&nbsp;Notify</h1> <p>Retroshare will notify you about what happens in your network. Depending on your usage, you may want to enable or disable some of the notifications. This page is designed for that!</p> + + + + Top Left @@ -11682,11 +11730,6 @@ Reported error: Notify - - - <h1><img width="24" src=":/images/64px_help.png">&nbsp;&nbsp;Notify</h1> <p>Retroshare will notify you about what happens in your network. Depending on your usage, you may want to enable or disable some of the notifications. This page is designed for that!</p> - - Disable All Toasters @@ -11846,24 +11889,6 @@ Reported error: - - OutQueueStatisticsWidget - - - Outqueue statistics - - - - - By priority: - - - - - By service : - - - PGPKeyDialog @@ -12683,13 +12708,13 @@ malicious behavior of crafted plugins. - - Plugins + + <h1><img width="24" src=":/icons/help_64.png">&nbsp;&nbsp;Plugins</h1> <p>Plugins are loaded from the directories listed in the bottom list.</p> <p>For security reasons, accepted plugins load automatically until the main Retroshare executable or the plugin library changes. In such a case, the user needs to confirm them again. After the program is started, you can enable a plugin manually by clicking on the "Enable" button and then restart Retroshare.</p> <p>If you want to develop your own plugins, contact the developpers team they will be happy to help you out!</p> - - <h1><img width="24" src=":/images/64px_help.png">&nbsp;&nbsp;Plugins</h1> <p>Plugins are loaded from the directories listed in the bottom list.</p> <p>For security reasons, accepted plugins load automatically until the main Retroshare executable or the plugin library changes. In such a case, the user needs to confirm them again. After the program is started, you can enable a plugin manually by clicking on the "Enable" button and then restart Retroshare.</p> <p>If you want to develop your own plugins, contact the developpers team they will be happy to help you out!</p> + + Plugins @@ -12860,7 +12885,12 @@ malicious behavior of crafted plugins. - + + <h1><img width="32" src=":/icons/help_64.png">&nbsp;&nbsp;Posted</h1> <p>The posted service allows you to share internet links, that spread among Retroshare nodes like forums and channels</p> <p>Links can be commented by subscribed users. A promotion system also gives the opportunity to enlight important links.</p> <p>There is no restriction on which links are shared. Be careful when clicking on them.</p> <p>Posted links get deleted after %1 months.</p> + + + + Create Topic @@ -12884,11 +12914,6 @@ malicious behavior of crafted plugins. Other Topics - - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;Posted</h1> <p>The posted service allows you to share internet links, that spread among Retroshare nodes like forums and channels</p> <p>Links can be commented by subscribed users. A promotion system also gives the opportunity to enlight important links.</p> <p>There is no restriction on which links are shared. Be careful when clicking on them.</p> <p>Posted links get deleted after %1 months.</p> - - PostedGroupDialog @@ -13690,7 +13715,7 @@ Characters <b>",|,/,\,&lt;,&gt;,*,?</b> will be replace - + Deny friend @@ -13854,7 +13879,7 @@ Reported error is: - + enabled @@ -14209,7 +14234,7 @@ p, li { white-space: pre-wrap; } RSGraphWidget - + %1 KB @@ -14245,7 +14270,7 @@ p, li { white-space: pre-wrap; } RSPermissionMatrixWidget - + Allowed by default @@ -14276,7 +14301,7 @@ p, li { white-space: pre-wrap; } - Switched Off + Globally switched Off @@ -14298,7 +14323,7 @@ p, li { white-space: pre-wrap; } RSettingsWin - + Error Saving Configuration on page @@ -14407,7 +14432,7 @@ p, li { white-space: pre-wrap; } - <h1><img width="24" src=":/images/64px_help.png">&nbsp;&nbsp;Relays</h1> <p>By activating relays, you allow your Retroshare node to act as a bridge between Retroshare users who cannot connect directly, e.g. because they're firewalled.</p> <p>You may choose to act as a relay by checking <i>enable relay connections</i>, or simply benefit from other peers acting as relay, by checking <i>use relay servers</i>. For the former, you may specify the bandwidth allocated when acting as a relay for friends of you, for friends of your friends, or anyone in the Retroshare network.</p> <p>In any case, a Retroshare node acting as a relay cannot see the relayed traffic, since it is encrypted and authenticated by the two relayed nodes.</p> + <h1><img width="24" src=":/icons/help_64.png">&nbsp;&nbsp;Relays</h1> <p>By activating relays, you allow your Retroshare node to act as a bridge between Retroshare users who cannot connect directly, e.g. because they're firewalled.</p> <p>You may choose to act as a relay by checking <i>enable relay connections</i>, or simply benefit from other peers acting as relay, by checking <i>use relay servers</i>. For the former, you may specify the bandwidth allocated when acting as a relay for friends of you, for friends of your friends, or anyone in the Retroshare network.</p> <p>In any case, a Retroshare node acting as a relay cannot see the relayed traffic, since it is encrypted and authenticated by the two relayed nodes.</p> @@ -14432,7 +14457,7 @@ p, li { white-space: pre-wrap; } RetroshareDirModel - + NEW @@ -14868,29 +14893,6 @@ Reducing image to %1x%2 pixels? - - SFListDelegate - - - B - - - - - KB - - - - - MB - - - - - GB - - - SearchDialog @@ -15905,13 +15907,13 @@ Check your ports! - - <h1><img width="24" src=":/images/64px_help.png">&nbsp;&nbsp;Permissions</h1> <p>Permissions allow you to control which services are available to which friends</p> <p>Each interruptor shows two lights, indicating whether you or your friend has enabled that service. Both needs to be ON (showing <img height=20 src=":/images/switch11.png"/>) to let information transfer for a specific service/friend combination.</p> <p>For each service, the global switch <img height=20 src=":/images/global_switch_on.png"> / <img height=20 src=":/images/global_switch_off.png"> allow to turn a service ON/OFF for all friends at once.</p> <p>Be very careful: Some services depend on each other. For instance turning turtle OFF will also stop all anonymous transfer, distant chat and distant messaging.</p> + + hide offline - - hide offline + + <h1><img width="24" src=":/icons/help_64.png">&nbsp;&nbsp;Permissions</h1> <p>Permissions allow you to control which services are available to which friends</p> <p>Each interruptor shows two lights, indicating whether you or your friend has enabled that service. Both needs to be ON (showing <img height=20 src=":/images/switch11.png"/>) to let information transfer for a specific service/friend combination.</p> <p>For each service, the global switch <img height=20 src=":/images/global_switch_on.png"> / <img height=20 src=":/images/global_switch_off.png"> allow to turn a service ON/OFF for all friends at once.</p> <p>Be very careful: Some services depend on each other. For instance turning turtle OFF will also stop all anonymous transfer, distant chat and distant messaging.</p> @@ -16881,7 +16883,7 @@ p, li { white-space: pre-wrap; } TBoard - + Pause @@ -17268,25 +17270,25 @@ p, li { white-space: pre-wrap; } - + Slower - - + + Average - - + + Faster - + Random @@ -17311,7 +17313,12 @@ p, li { white-space: pre-wrap; } - + + <h1><img width="%1" src=":/icons/help_64.png">&nbsp;&nbsp;File Transfer</h1> <p>Retroshare brings two ways of transferring files: direct transfers from your friends, and distant anonymous tunnelled transfers. In addition, file transfer is multi-source and allows swarming (you can be a source while downloading)</p> <p>You can share files using the <img src=":/images/directoryadd_24x24_shadow.png" width=%2 /> icon from the left side bar. These files will be listed in the My Files tab. You can decide for each friend group whether they can or not see these files in their Friends Files tab</p> <p>The search tab reports files from your friends' file lists, and distant files that can be reached anonymously using the multi-hop tunnelling system.</p> + + + + Move in Queue... @@ -17471,7 +17478,7 @@ Try to be patient! - + Last Time Seen i.e: Last Time Receiced Data @@ -17577,7 +17584,7 @@ Try to be patient! - + Columns @@ -17587,7 +17594,7 @@ Try to be patient! - + Path i.e: Where file is saved @@ -17603,12 +17610,7 @@ Try to be patient! - - <h1><img width="32" src=":/images/64px_help.png">&nbsp;&nbsp;File Transfer</h1> <p>Retroshare brings two ways of transferring files: direct transfers from your friends, and distant anonymous tunnelled transfers. In addition, file transfer is multi-source and allows swarming (you can be a source while downloading)</p> <p>You can share files using the <img src=":/images/directoryadd_24x24_shadow.png" width=16 /> icon from the left side bar. These files will be listed in the My Files tab. You can decide for each friend group whether they can or not see these files in their Friends Files tab</p> <p>The search tab reports files from your friends' file lists, and distant files that can be reached anonymously using the multi-hop tunnelling system.</p> - - - - + Could not delete preview file @@ -17618,7 +17620,7 @@ Try to be patient! - + Create Collection... @@ -17633,7 +17635,7 @@ Try to be patient! - + Collection @@ -17648,12 +17650,12 @@ Try to be patient! - + Show file list transfers - + version: @@ -17689,7 +17691,7 @@ Try to be patient! - + Friends Directories @@ -18027,10 +18029,20 @@ Try to be patient! - + + <h1><img width="24" src=":/icons/help_64.png">&nbsp;&nbsp;Webinterface</h1> <p>The webinterface allows to control Retroshare from the browser. Multiple devices can share control over one Retroshare instance. So you could start a conversation on a tablet computer and later use a desktop computer to continue it.</p> <p>Warning: don't expose the webinterface to the internet, because there is no access control and no encryption. If you want to use the webinterface over the internet, use a SSH tunnel or a proxy to secure the connection.</p> + + + + Webinterface not enabled + + + The webinterface is not enabled. Enable it in Settings -> Webinterface. + + failed to start Webinterface @@ -18041,11 +18053,6 @@ Try to be patient! Webinterface - - - <h1><img width="24" src=":/images/64px_help.png">&nbsp;&nbsp;Webinterface</h1> <p>The webinterface allows to control Retroshare from the browser. Multiple devices can share control over one Retroshare instance. So you could start a conversation on a tablet computer and later use a desktop computer to continue it.</p> <p>Warning: don't expose the webinterface to the internet, because there is no access control and no encryption. If you want to use the webinterface over the internet, use a SSH tunnel or a proxy to secure the connection.</p> - - WikiAddDialog From d5c95c4b288c08c58a57e7a6de6285a7e6522b9f Mon Sep 17 00:00:00 2001 From: thunder2 Date: Sat, 8 Aug 2015 22:44:30 +0200 Subject: [PATCH 028/165] Fixed layout of the ServicePermissionsPage --- TODO.txt | 2 +- .../gui/settings/ServicePermissionsPage.ui | 56 +++++++++++++------ 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/TODO.txt b/TODO.txt index c33834fb6..ef4d189fb 100644 --- a/TODO.txt +++ b/TODO.txt @@ -63,7 +63,7 @@ GUI 0013 [ ] new design, new icons, minimal UI (from purplehaze420) comment: use webui as base for minimal ui cyril: we cannot change everything now. But purplehaze420 said he would provide a consistent set of icons. That would be great. -0014 [ ] go to Settings -> Permissions: wait for scrollbars to appear go back to any other setting (e.g. Notify): the page now +0014 [X] go to Settings -> Permissions: wait for scrollbars to appear go back to any other setting (e.g. Notify): the page now needs the same space as the permission matrix (happens on windows + linux; can be "fixed" by closing and reopen the setting window) (from sehraf) diff --git a/retroshare-gui/src/gui/settings/ServicePermissionsPage.ui b/retroshare-gui/src/gui/settings/ServicePermissionsPage.ui index e0144f137..488ba9518 100644 --- a/retroshare-gui/src/gui/settings/ServicePermissionsPage.ui +++ b/retroshare-gui/src/gui/settings/ServicePermissionsPage.ui @@ -11,6 +11,46 @@ + + + + QFrame::StyledPanel + + + QFrame::Raised + + + true + + + + + 0 + 0 + 619 + 280 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + @@ -52,22 +92,6 @@ - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - From c9197864c60360700a00835e50583c6cb3dfb864 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Sun, 9 Aug 2015 15:52:26 +0200 Subject: [PATCH 029/165] Fixed typo. Updated english translation. --- retroshare-gui/src/gui/common/FriendList.ui | 2 +- retroshare-gui/src/lang/retroshare_en.ts | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/retroshare-gui/src/gui/common/FriendList.ui b/retroshare-gui/src/gui/common/FriendList.ui index d4d62da9d..70e323ff0 100644 --- a/retroshare-gui/src/gui/common/FriendList.ui +++ b/retroshare-gui/src/gui/common/FriendList.ui @@ -149,7 +149,7 @@ true - Stow State + Show State Show State diff --git a/retroshare-gui/src/lang/retroshare_en.ts b/retroshare-gui/src/lang/retroshare_en.ts index e20f8c5c8..7b60e33c7 100644 --- a/retroshare-gui/src/lang/retroshare_en.ts +++ b/retroshare-gui/src/lang/retroshare_en.ts @@ -5379,10 +5379,6 @@ you plug it in. - Stow State - - - Show State From 9d0b0664f1993780ec7172c0b723e73727533211 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Sun, 9 Aug 2015 22:07:24 +0200 Subject: [PATCH 030/165] Fixed hide offline friends in ServicePermissionsPage --- .../gui/settings/RSPermissionMatrixWidget.cpp | 44 +++++++++++-------- .../gui/settings/RSPermissionMatrixWidget.h | 5 +++ .../gui/settings/ServicePermissionsPage.cpp | 20 ++++----- .../src/gui/settings/ServicePermissionsPage.h | 3 -- 4 files changed, 39 insertions(+), 33 deletions(-) diff --git a/retroshare-gui/src/gui/settings/RSPermissionMatrixWidget.cpp b/retroshare-gui/src/gui/settings/RSPermissionMatrixWidget.cpp index cf9486ae5..cd2ffcf72 100644 --- a/retroshare-gui/src/gui/settings/RSPermissionMatrixWidget.cpp +++ b/retroshare-gui/src/gui/settings/RSPermissionMatrixWidget.cpp @@ -67,6 +67,18 @@ RSPermissionMatrixWidget::RSPermissionMatrixWidget(QWidget *parent) _max_width = 400 ; _max_height = 0 ; + + mHideOffline = false; +} + +void RSPermissionMatrixWidget::setHideOffline(bool hide) +{ + if (mHideOffline == hide) { + return; + } + + mHideOffline = hide; + repaint(); } void RSPermissionMatrixWidget::updateDisplay() @@ -238,25 +250,21 @@ void RSPermissionMatrixWidget::paintEvent(QPaintEvent *) // sort list { - // RSPermissionMatrixWidgets parent is ServicePermissionsPage which holds the checkbox - ServicePermissionsPage *spp = dynamic_cast(parentWidget()); - if(spp != NULL) { - // sort out offline peers - if(spp->isHideOfflineChecked()) { - RsPeerDetails peerDetails; - for(std::list::iterator it = ssllist.begin(); it != ssllist.end();) { - rsPeers->getPeerDetails(*it, peerDetails); + // sort out offline peers + if(mHideOffline) { + RsPeerDetails peerDetails; + for(std::list::iterator it = ssllist.begin(); it != ssllist.end();) { + rsPeers->getPeerDetails(*it, peerDetails); - switch (peerDetails.connectState) { - case RS_PEER_CONNECTSTATE_OFFLINE: - case RS_PEER_CONNECTSTATE_TRYING_TCP: - case RS_PEER_CONNECTSTATE_TRYING_UDP: - it = ssllist.erase(it); - break; - default: - it++; - break; - } + switch (peerDetails.connectState) { + case RS_PEER_CONNECTSTATE_OFFLINE: + case RS_PEER_CONNECTSTATE_TRYING_TCP: + case RS_PEER_CONNECTSTATE_TRYING_UDP: + it = ssllist.erase(it); + break; + default: + it++; + break; } } } diff --git a/retroshare-gui/src/gui/settings/RSPermissionMatrixWidget.h b/retroshare-gui/src/gui/settings/RSPermissionMatrixWidget.h index 356521c78..b56c76a61 100644 --- a/retroshare-gui/src/gui/settings/RSPermissionMatrixWidget.h +++ b/retroshare-gui/src/gui/settings/RSPermissionMatrixWidget.h @@ -60,6 +60,9 @@ public: RSPermissionMatrixWidget(QWidget *parent=NULL); virtual ~RSPermissionMatrixWidget() ; +public slots: + void setHideOffline(bool hide); + protected slots: // Calls the internal source for a new data points; called by the timer. You might want to overload this // if the collection system needs it. Otherwise, the default method will call getValues() @@ -100,6 +103,8 @@ private: /** The current dimensions of the graph. */ QRect _rec; + bool mHideOffline; + static const float fROW_SIZE ; static const float fCOL_SIZE ; static const float fICON_SIZE_X ; diff --git a/retroshare-gui/src/gui/settings/ServicePermissionsPage.cpp b/retroshare-gui/src/gui/settings/ServicePermissionsPage.cpp index e755ec90e..5cf0a59c0 100644 --- a/retroshare-gui/src/gui/settings/ServicePermissionsPage.cpp +++ b/retroshare-gui/src/gui/settings/ServicePermissionsPage.cpp @@ -28,16 +28,19 @@ #include #include -#define PermissionStateUserRole (Qt::UserRole) -#define ServiceIdUserRole (Qt::UserRole + 1) -#define PeerIdUserRole (Qt::UserRole + 2) - -ServicePermissionsPage::ServicePermissionsPage(QWidget * parent, Qt::WindowFlags /*flags*/) +ServicePermissionsPage::ServicePermissionsPage(QWidget * parent, Qt::WindowFlags flags) : + ConfigPage(parent, flags) { /* Invoke the Qt Designer generated object setup routine */ ui.setupUi(this); + connect(ui.cb_hideOffline, SIGNAL(toggled(bool)), ui.frame, SLOT(setHideOffline(bool))); //QObject::connect(ui.tableWidget,SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(tableItemChanged(QTableWidgetItem *))); + + ui.frame->setHideOffline(ui.cb_hideOffline->isChecked()); + + // Not implemented? + ui.pushButton->hide(); } QString ServicePermissionsPage::helpText() const @@ -52,10 +55,3 @@ QString ServicePermissionsPage::helpText() const

Be very careful: Some services depend on each other. For instance turning turtle OFF will also\ stop all anonymous transfer, distant chat and distant messaging.

"); } - -bool ServicePermissionsPage::isHideOfflineChecked() -{ - return ui.cb_hideOffline->checkState() == Qt::Checked; -} - - diff --git a/retroshare-gui/src/gui/settings/ServicePermissionsPage.h b/retroshare-gui/src/gui/settings/ServicePermissionsPage.h index 7566e6d92..1e4f5c973 100644 --- a/retroshare-gui/src/gui/settings/ServicePermissionsPage.h +++ b/retroshare-gui/src/gui/settings/ServicePermissionsPage.h @@ -44,10 +44,7 @@ public: virtual QString pageName() const { return tr("Permissions") ; } virtual QString helpText() const ; - bool isHideOfflineChecked(); - private: - Ui::ServicePermissionsPage ui; }; From 783465bc897a7d1d05982781f8dcbe7239dbf469 Mon Sep 17 00:00:00 2001 From: defnax Date: Mon, 10 Aug 2015 18:27:29 +0200 Subject: [PATCH 031/165] forget to commit this, for the Search Filter DHT IPs --- .../src/gui/statistics/DhtWindow.cpp | 24 ++++++++++++------- .../src/gui/statistics/DhtWindow.ui | 6 +++++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/retroshare-gui/src/gui/statistics/DhtWindow.cpp b/retroshare-gui/src/gui/statistics/DhtWindow.cpp index 7827f296e..5a971c010 100644 --- a/retroshare-gui/src/gui/statistics/DhtWindow.cpp +++ b/retroshare-gui/src/gui/statistics/DhtWindow.cpp @@ -36,6 +36,14 @@ #include "retroshare/rsconfig.h" #include "retroshare/rspeers.h" +#define DTW_COL_BUCKET 0 +#define DTW_COL_IPADDR 1 +#define DTW_COL_PEERID 2 +#define DTW_COL_FLAGS 3 +#define DTW_COL_FOUND 4 +#define DTW_COL_SEND 5 +#define DTW_COL_RECV 6 + DhtWindow::DhtWindow(QWidget *parent) : RsAutoUpdatePage(1000,parent) { @@ -43,6 +51,10 @@ DhtWindow::DhtWindow(QWidget *parent) connect( ui.filterLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(filterItems(QString))); connect( ui.filterLineEdit, SIGNAL(filterChanged(int)), this, SLOT(filterColumnChanged(int))); + + /* add filter actions */ + ui.filterLineEdit->addFilter(QIcon(), tr("IP"), DTW_COL_IPADDR, tr("Search IP")); + ui.filterLineEdit->setCurrentFilter(DTW_COL_IPADDR); } DhtWindow::~DhtWindow() @@ -577,14 +589,6 @@ void DhtWindow::updateRelays() /****************************/ -#define DTW_COL_BUCKET 0 -#define DTW_COL_IPADDR 1 -#define DTW_COL_PEERID 2 -#define DTW_COL_FLAGS 3 -#define DTW_COL_FOUND 4 -#define DTW_COL_SEND 5 -#define DTW_COL_RECV 6 - class DhtTreeWidgetItem : public QTreeWidgetItem { public: @@ -666,6 +670,10 @@ void DhtWindow::updateDhtPeers() dht_item -> setData(DTW_COL_RECV, Qt::DisplayRole, lastrecvstr); ui.dhtTreeWidget->addTopLevelItem(dht_item); + + if (ui.filterLineEdit->text().isEmpty() == false) { + filterItems(ui.filterLineEdit->text()); + } } } diff --git a/retroshare-gui/src/gui/statistics/DhtWindow.ui b/retroshare-gui/src/gui/statistics/DhtWindow.ui index dac79743d..b2dfd8237 100644 --- a/retroshare-gui/src/gui/statistics/DhtWindow.ui +++ b/retroshare-gui/src/gui/statistics/DhtWindow.ui @@ -467,6 +467,12 @@ + + Qt::CopyAction + + + QAbstractItemView::MultiSelection + true From ab538c6d284030223386e9f8f360d07e22b297ff Mon Sep 17 00:00:00 2001 From: thunder2 Date: Mon, 10 Aug 2015 13:27:46 +0200 Subject: [PATCH 032/165] Avoid error messages "table already exists" in RsDataService::initialise by using "IF NOT EXISTS" --- libretroshare/src/gxs/rsdataservice.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libretroshare/src/gxs/rsdataservice.cc b/libretroshare/src/gxs/rsdataservice.cc index 340ecfbe9..719b496c8 100644 --- a/libretroshare/src/gxs/rsdataservice.cc +++ b/libretroshare/src/gxs/rsdataservice.cc @@ -216,7 +216,7 @@ void RsDataService::initialise(){ // create table for msg data - mDb->execSQL("CREATE TABLE " + MSG_TABLE_NAME + "(" + + mDb->execSQL("CREATE TABLE IF NOT EXISTS " + MSG_TABLE_NAME + "(" + KEY_MSG_ID + " TEXT PRIMARY KEY," + KEY_GRP_ID + " TEXT," + KEY_NXS_FLAGS + " INT," + @@ -238,7 +238,7 @@ void RsDataService::initialise(){ KEY_NXS_FILE_LEN + " INT);"); // create table for grp data - mDb->execSQL("CREATE TABLE " + GRP_TABLE_NAME + "(" + + mDb->execSQL("CREATE TABLE IF NOT EXISTS " + GRP_TABLE_NAME + "(" + KEY_GRP_ID + " TEXT PRIMARY KEY," + KEY_TIME_STAMP + " INT," + KEY_NXS_FILE + " TEXT," + @@ -268,7 +268,7 @@ void RsDataService::initialise(){ KEY_GRP_REP_CUTOFF + " INT," + KEY_SIGN_SET + " BLOB);"); - mDb->execSQL("CREATE TRIGGER " + GRP_LAST_POST_UPDATE_TRIGGER + + mDb->execSQL("CREATE TRIGGER IF NOT EXISTS " + GRP_LAST_POST_UPDATE_TRIGGER + " INSERT ON " + MSG_TABLE_NAME + std::string(" BEGIN ") + " UPDATE " + GRP_TABLE_NAME + " SET " + KEY_GRP_LAST_POST + "= new." From b8edb7589585e84be00e61bf10f41e3e986c2b4c Mon Sep 17 00:00:00 2001 From: thunder2 Date: Mon, 10 Aug 2015 15:24:56 +0200 Subject: [PATCH 033/165] Optimized SELECT creation in RetroDb::sqlQuery --- libretroshare/src/util/retrodb.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/libretroshare/src/util/retrodb.cc b/libretroshare/src/util/retrodb.cc index 8438ab831..368c5240e 100644 --- a/libretroshare/src/util/retrodb.cc +++ b/libretroshare/src/util/retrodb.cc @@ -183,12 +183,11 @@ RetroCursor* RetroDb::sqlQuery(const std::string& tableName, const std::list::const_iterator it = columns.begin(); for(; it != columns.end(); ++it){ - columnSelection += *it; - - ++it; - if(it != columns.end()) + if (it != columns.begin()) { columnSelection += ","; - --it; + } + + columnSelection += *it; } // construct query From 442ec2337f7282404216a0d178e6e4c055d479ba Mon Sep 17 00:00:00 2001 From: thunder2 Date: Mon, 10 Aug 2015 13:58:19 +0200 Subject: [PATCH 034/165] Added index in database for column grpId in table MESSAGES. --- libretroshare/src/gxs/rsdataservice.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libretroshare/src/gxs/rsdataservice.cc b/libretroshare/src/gxs/rsdataservice.cc index 719b496c8..d66463c1e 100644 --- a/libretroshare/src/gxs/rsdataservice.cc +++ b/libretroshare/src/gxs/rsdataservice.cc @@ -36,6 +36,7 @@ #define GRP_LAST_POST_UPDATE_TRIGGER std::string("LAST_POST_UPDATE") +#define MSG_INDEX_GRPID std::string("INDEX_MESSAGES_GRPID") // generic #define KEY_NXS_FILE std::string("nxsFile") @@ -274,6 +275,8 @@ void RsDataService::initialise(){ " UPDATE " + GRP_TABLE_NAME + " SET " + KEY_GRP_LAST_POST + "= new." + KEY_RECV_TS + " WHERE " + KEY_GRP_ID + "=new." + KEY_GRP_ID + ";" + std::string("END;")); + + mDb->execSQL("CREATE INDEX IF NOT EXISTS " + MSG_INDEX_GRPID + " ON " + MSG_TABLE_NAME + "(" + KEY_GRP_ID + ");"); } RsGxsGrpMetaData* RsDataService::locked_getGrpMeta(RetroCursor &c) @@ -1286,6 +1289,7 @@ int RsDataService::resetDataStore() delete mit->second; } + mDb->execSQL("DROP INDEX " + MSG_INDEX_GRPID); mDb->execSQL("DROP TABLE " + MSG_TABLE_NAME); mDb->execSQL("DROP TABLE " + GRP_TABLE_NAME); mDb->execSQL("DROP TRIGGER " + GRP_LAST_POST_UPDATE_TRIGGER); From e73e68d8607e215406bd3258ddcb332f980ffe62 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Tue, 11 Aug 2015 13:40:02 +0200 Subject: [PATCH 035/165] Reduced the size of the status icon on the avatar image in FriendList. --- retroshare-gui/src/gui/common/FriendList.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/retroshare-gui/src/gui/common/FriendList.cpp b/retroshare-gui/src/gui/common/FriendList.cpp index ab23f3b84..07bfad25e 100644 --- a/retroshare-gui/src/gui/common/FriendList.cpp +++ b/retroshare-gui/src/gui/common/FriendList.cpp @@ -456,15 +456,18 @@ void FriendList::groupsChanged() static QIcon createAvatar(const QPixmap &avatar, const QPixmap &overlay) { + int avatarWidth = avatar.width(); + int avatarHeight = avatar.height(); + QPixmap pixmap(avatar); - int x = avatar.width() / 2; - int y = avatar.height() / 2; - int w = avatar.width() / 2; - int h = avatar.height() / 2; + int overlayWidth = avatarWidth / 2.5; + int overlayHeight = avatarHeight / 2.5; + int overlayX = avatarWidth - overlayWidth; + int overlayY = avatarHeight - overlayHeight; QPainter painter(&pixmap); - painter.drawPixmap(x, y, w, h, overlay); + painter.drawPixmap(overlayX, overlayY, overlayWidth, overlayHeight, overlay); QIcon icon; icon.addPixmap(pixmap); From a765016240c9a99bf042bca92754c88c942fba8e Mon Sep 17 00:00:00 2001 From: thunder2 Date: Tue, 11 Aug 2015 16:01:43 +0200 Subject: [PATCH 036/165] Moved column show/hide from context menu of the tree to the context menu of the header in IdDialog. --- retroshare-gui/src/gui/Identity/IdDialog.cpp | 118 +++++-------------- retroshare-gui/src/gui/Identity/IdDialog.h | 10 -- retroshare-gui/src/gui/Identity/IdDialog.ui | 14 +-- 3 files changed, 36 insertions(+), 106 deletions(-) diff --git a/retroshare-gui/src/gui/Identity/IdDialog.cpp b/retroshare-gui/src/gui/Identity/IdDialog.cpp index 0409c007e..1189b2d37 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.cpp +++ b/retroshare-gui/src/gui/Identity/IdDialog.cpp @@ -81,9 +81,9 @@ IdDialog::IdDialog(QWidget *parent) : /* Setup UI helper */ mStateHelper = new UIStateHelper(this); -// mStateHelper->addWidget(IDDIALOG_IDLIST, ui->treeWidget_IdList); - mStateHelper->addLoadPlaceholder(IDDIALOG_IDLIST, ui->treeWidget_IdList, false); - mStateHelper->addClear(IDDIALOG_IDLIST, ui->treeWidget_IdList); +// mStateHelper->addWidget(IDDIALOG_IDLIST, ui->idTreeWidget); + mStateHelper->addLoadPlaceholder(IDDIALOG_IDLIST, ui->idTreeWidget, false); + mStateHelper->addClear(IDDIALOG_IDLIST, ui->idTreeWidget); mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->lineEdit_Nickname); mStateHelper->addWidget(IDDIALOG_IDDETAILS, ui->lineEdit_KeyId); @@ -142,8 +142,8 @@ IdDialog::IdDialog(QWidget *parent) : connect(ui->editIdentity, SIGNAL(triggered()), this, SLOT(editIdentity())); connect(ui->chatIdentity, SIGNAL(triggered()), this, SLOT(chatIdentity())); - connect(ui->treeWidget_IdList, SIGNAL(itemSelectionChanged()), this, SLOT(updateSelection())); - connect(ui->treeWidget_IdList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(IdListCustomPopupMenu(QPoint))); + connect(ui->idTreeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(updateSelection())); + connect(ui->idTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(IdListCustomPopupMenu(QPoint))); connect(ui->filterComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterComboBoxChanged())); connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); @@ -172,34 +172,29 @@ IdDialog::IdDialog(QWidget *parent) : ui->filterComboBox->setCurrentIndex(0); /* Add filter actions */ - QTreeWidgetItem *headerItem = ui->treeWidget_IdList->headerItem(); + QTreeWidgetItem *headerItem = ui->idTreeWidget->headerItem(); QString headerText = headerItem->text(RSID_COL_NICKNAME); ui->filterLineEdit->addFilter(QIcon(), headerText, RSID_COL_NICKNAME, QString("%1 %2").arg(tr("Search"), headerText)); headerText = headerItem->text(RSID_COL_KEYID); ui->filterLineEdit->addFilter(QIcon(), headerItem->text(RSID_COL_KEYID), RSID_COL_KEYID, QString("%1 %2").arg(tr("Search"), headerText)); - initializeHeader(true); - /* Setup tree */ - ui->treeWidget_IdList->sortByColumn(RSID_COL_NICKNAME, Qt::AscendingOrder); - ui->treeWidget_IdList->setContextMenuPolicy(Qt::CustomContextMenu) ; - - /** Setup the actions for the header context menu */ - hideIdAct= new QAction(headerItem->text(RSID_COL_KEYID),this); - hideIdAct->setCheckable(true); hideIdAct->setToolTip(tr("Show")+" "+hideIdAct->text()+" "+tr("column")); - connect(hideIdAct,SIGNAL(triggered(bool)),this,SLOT(setHideIdColumn(bool))) ; - - hideTypeAct= new QAction(headerItem->text(RSID_COL_IDTYPE),this); - hideTypeAct->setCheckable(true); hideTypeAct->setToolTip(tr("Show")+" "+hideTypeAct->text()+" "+tr("column")); - connect(hideTypeAct,SIGNAL(triggered(bool)),this,SLOT(setHideIdTypeColumn(bool))) ; - + ui->idTreeWidget->sortByColumn(RSID_COL_NICKNAME, Qt::AscendingOrder); + + ui->idTreeWidget->enableColumnCustomize(true); + ui->idTreeWidget->setColumnCustomizable(RSID_COL_NICKNAME, false); + + /* Set initial column width */ + int fontWidth = QFontMetricsF(ui->idTreeWidget->font()).width("W"); + ui->idTreeWidget->setColumnWidth(RSID_COL_NICKNAME, 18 * fontWidth); + ui->idTreeWidget->setColumnWidth(RSID_COL_KEYID, 25 * fontWidth); + ui->idTreeWidget->setColumnWidth(RSID_COL_IDTYPE, 18 * fontWidth); + mIdQueue = new TokenQueue(rsIdentity->getTokenService(), this); mStateHelper->setActive(IDDIALOG_IDDETAILS, false); mStateHelper->setActive(IDDIALOG_REPLIST, false); - ui->treeWidget_IdList->setColumnHidden(RSID_COL_IDTYPE, true); - // Hiding RepList until that part is finished. //ui->treeWidget_RepList->setVisible(false); ui->toolButton_Reputation->setVisible(false); @@ -243,18 +238,6 @@ IdDialog::~IdDialog() delete(mIdQueue); } -void IdDialog::initializeHeader(bool ) -{ - /* Set header resize modes and initial section sizes ID TreeView*/ - QHeaderView * _idheader = ui->treeWidget_IdList->header () ; - _idheader->resizeSection ( RSID_COL_NICKNAME, 170 ); - _idheader->resizeSection ( RSID_COL_KEYID, 120 ); - _idheader->resizeSection ( RSID_COL_IDTYPE, 170 ); - - - -} - void IdDialog::todo() { QMessageBox::information(this, "Todo", @@ -265,19 +248,17 @@ void IdDialog::todo() void IdDialog::processSettings(bool load) { - QHeaderView *header = ui->treeWidget_IdList->header(); - Settings->beginGroup("IdDialog"); + // state of peer tree + ui->idTreeWidget->processSettings(load); + if (load) { // load settings // filterColumn ui->filterLineEdit->setCurrentFilter(Settings->value("filterColumn", RSID_COL_NICKNAME).toInt()); - // state of thread tree - header->restoreState(Settings->value("IdList").toByteArray()); - // state of splitter ui->splitter->restoreState(Settings->value("splitter").toByteArray()); } else { @@ -286,9 +267,6 @@ void IdDialog::processSettings(bool load) // filterColumn Settings->setValue("filterColumn", ui->filterLineEdit->currentFilter()); - // state of thread tree - Settings->setValue("IdList", header->saveState()); - // state of splitter Settings->setValue("splitter", ui->splitter->saveState()); } @@ -308,7 +286,7 @@ void IdDialog::filterChanged(const QString& /*text*/) void IdDialog::updateSelection() { - QTreeWidgetItem *item = ui->treeWidget_IdList->currentItem(); + QTreeWidgetItem *item = ui->idTreeWidget->currentItem(); RsGxsGroupId id; if (item) { @@ -478,7 +456,7 @@ void IdDialog::insertIdList(uint32_t token) RsPgpId ownPgpId = rsPeers->getGPGOwnId(); /* Update existing and remove not existing items */ - QTreeWidgetItemIterator itemIterator(ui->treeWidget_IdList); + QTreeWidgetItemIterator itemIterator(ui->idTreeWidget); QTreeWidgetItem *item = NULL; while ((item = *itemIterator) != NULL) { ++itemIterator; @@ -510,7 +488,7 @@ void IdDialog::insertIdList(uint32_t token) item = NULL; if (fillIdListItem(*vit, item, ownPgpId, accept)) { - ui->treeWidget_IdList->addTopLevelItem(item); + ui->idTreeWidget->addTopLevelItem(item); } } @@ -853,7 +831,7 @@ void IdDialog::addIdentity() void IdDialog::removeIdentity() { - QTreeWidgetItem *item = ui->treeWidget_IdList->currentItem(); + QTreeWidgetItem *item = ui->idTreeWidget->currentItem(); if (!item) { #ifdef ID_DEBUG @@ -876,7 +854,7 @@ void IdDialog::removeIdentity() void IdDialog::editIdentity() { - QTreeWidgetItem *item = ui->treeWidget_IdList->currentItem(); + QTreeWidgetItem *item = ui->idTreeWidget->currentItem(); if (!item) { #ifdef ID_DEBUG @@ -901,7 +879,7 @@ void IdDialog::filterIds() int filterColumn = ui->filterLineEdit->currentFilter(); QString text = ui->filterLineEdit->text(); - ui->treeWidget_IdList->filterItems(filterColumn, text); + ui->idTreeWidget->filterItems(filterColumn, text); } void IdDialog::requestRepList() @@ -970,7 +948,7 @@ void IdDialog::IdListCustomPopupMenu( QPoint ) std::list own_identities ; rsIdentity->getOwnIds(own_identities) ; - QTreeWidgetItem *item = ui->treeWidget_IdList->currentItem(); + QTreeWidgetItem *item = ui->idTreeWidget->currentItem(); if (item) { uint32_t item_flags = item->data(RSID_COL_KEYID,Qt::UserRole).toUInt() ; @@ -1015,19 +993,12 @@ void IdDialog::IdListCustomPopupMenu( QPoint ) contextMnu.addSeparator(); - hideIdAct->setChecked(!ui->treeWidget_IdList->isColumnHidden(RSID_COL_KEYID)); - hideTypeAct->setChecked(!ui->treeWidget_IdList->isColumnHidden(RSID_COL_IDTYPE)); - - QMenu *menu = contextMnu.addMenu(tr("Columns")); - menu->addAction(hideIdAct); - menu->addAction(hideTypeAct); - contextMnu.exec(QCursor::pos()); } void IdDialog::chatIdentity() { - QTreeWidgetItem *item = ui->treeWidget_IdList->currentItem(); + QTreeWidgetItem *item = ui->idTreeWidget->currentItem(); if (!item) { std::cerr << "IdDialog::editIdentity() Invalid item"; @@ -1050,7 +1021,7 @@ void IdDialog::chatIdentity() void IdDialog::sendMsg() { - QTreeWidgetItem *item = ui->treeWidget_IdList->currentItem(); + QTreeWidgetItem *item = ui->idTreeWidget->currentItem(); if (!item) { return; @@ -1070,34 +1041,3 @@ void IdDialog::sendMsg() /* window will destroy itself! */ } - -void IdDialog::setHideIdColumn(bool show) -{ - if (ui->treeWidget_IdList->isColumnHidden(RSID_COL_KEYID) == show) { - ui->treeWidget_IdList->setColumnHidden(RSID_COL_KEYID, !show); - } - ui->treeWidget_IdList->header()->setVisible(getNumColVisible()>1); - - initializeHeader(true); -} - -void IdDialog::setHideIdTypeColumn(bool show) -{ - if (ui->treeWidget_IdList->isColumnHidden(RSID_COL_IDTYPE) == show) { - ui->treeWidget_IdList->setColumnHidden(RSID_COL_IDTYPE, !show); - } - ui->treeWidget_IdList->header()->setVisible(getNumColVisible()>1); - - initializeHeader(true); -} - -int IdDialog::getNumColVisible() -{ - int iNumColVis=0; - for (int iColumn = 0; iColumn treeWidget_IdList->isColumnHidden(iColumn)) { - ++iNumColVis; - } - } - return iNumColVis; -} diff --git a/retroshare-gui/src/gui/Identity/IdDialog.h b/retroshare-gui/src/gui/Identity/IdDialog.h index 4ab354989..a46a6ce73 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.h +++ b/retroshare-gui/src/gui/Identity/IdDialog.h @@ -74,9 +74,6 @@ private slots: /** Create the context popup menu and it's submenus */ void IdListCustomPopupMenu( QPoint point ); - - void setHideIdColumn(bool hide); - void setHideIdTypeColumn(bool hide); private: void processSettings(bool load); @@ -95,19 +92,12 @@ private: void requestIdEdit(std::string &id); void showIdEdit(uint32_t token); - - void initializeHeader(bool); private: TokenQueue *mIdQueue; UIStateHelper *mStateHelper; RsGxsGroupId mId; - - /** Defines the actions for the header context menu */ - QAction* hideIdAct; - QAction* hideTypeAct; - int getNumColVisible(); /* UI - Designer */ Ui::IdDialog *ui; diff --git a/retroshare-gui/src/gui/Identity/IdDialog.ui b/retroshare-gui/src/gui/Identity/IdDialog.ui index a8914b9fa..4109e6bcb 100644 --- a/retroshare-gui/src/gui/Identity/IdDialog.ui +++ b/retroshare-gui/src/gui/Identity/IdDialog.ui @@ -177,22 +177,22 @@ - + 0 0 - - - 22 - 22 - + + Qt::CustomContextMenu true + + false + Identity name @@ -725,7 +725,7 @@
todoPushButton - treeWidget_IdList + idTreeWidget lineEdit_Nickname lineEdit_KeyId lineEdit_GpgId From 9d291aa6f646b18be8855f0e612ee78ed220f0ac Mon Sep 17 00:00:00 2001 From: defnax Date: Tue, 11 Aug 2015 16:44:59 +0200 Subject: [PATCH 037/165] update windows build scripts changed gxs id icon for linked with profile. --- build-all-mingw32make.bat | 7 ++++--- libretroshare/src/mingw32make.bat | 9 ++++----- retroshare-gui/src/gui/gxs/GxsIdDetails.cpp | 2 +- retroshare-gui/src/mingw32make.bat | 5 +++-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/build-all-mingw32make.bat b/build-all-mingw32make.bat index 56d2fe787..819642b46 100644 --- a/build-all-mingw32make.bat +++ b/build-all-mingw32make.bat @@ -1,7 +1,8 @@ set QTDIR=C:\Qt\4.8.6 set MINGW=C:\MinGW +set GIT=C:\Program Files\Git -set PATH=%QTDIR%\bin;%MINGW%\bin;%PATH% +set PATH=%QTDIR%\bin;%MINGW%\bin;%GIT%\bin;%PATH% @echo off @@ -74,7 +75,7 @@ cd ..\..\libretroshare\src if not %clean%x==x mingw32-make clean -qmake libretroshare.pro +qmake libretroshare.pro "CONFIG+=version_detail_bash_script" mingw32-make %%a @@ -101,7 +102,7 @@ cd ..\..\retroshare-gui\src if not %clean%x==x mingw32-make clean -qmake retroshare-gui.pro +qmake retroshare-gui.pro "CONFIG+=version_detail_bash_script" mingw32-make %%a diff --git a/libretroshare/src/mingw32make.bat b/libretroshare/src/mingw32make.bat index f5b493923..3a58fe173 100644 --- a/libretroshare/src/mingw32make.bat +++ b/libretroshare/src/mingw32make.bat @@ -1,13 +1,12 @@ set QTDIR=C:\Qt\4.8.6 set MINGW=C:\MinGW +set GIT=C:\Program Files\Git -set PATH=%QTDIR%\bin;%MINGW%\bin;%PATH% +set PATH=%QTDIR%\bin;%MINGW%\bin;;%GIT%\bin;%PATH% -"c:\Program Files\TortoiseSVN\bin\SubWCRev" . retroshare\rsversion.in retroshare\rsversion.h +mingw32-make clean -mingw32-make clean - -qmake libretroshare.pro +qmake libretroshare.pro "CONFIG+=version_detail_bash_script" mingw32-make diff --git a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp index cfc7eba1d..aab87ddf7 100644 --- a/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp +++ b/retroshare-gui/src/gui/gxs/GxsIdDetails.cpp @@ -37,7 +37,7 @@ /* Images for tag icons */ #define IMAGE_LOADING ":/images/folder-draft.png" -#define IMAGE_PGPKNOWN ":/images/tags/pgp-known.png" +#define IMAGE_PGPKNOWN ":/images/contact.png" #define IMAGE_PGPUNKNOWN ":/images/tags/pgp-unknown.png" #define IMAGE_ANON ":/images/tags/anon.png" diff --git a/retroshare-gui/src/mingw32make.bat b/retroshare-gui/src/mingw32make.bat index ec970270a..bab087ec7 100644 --- a/retroshare-gui/src/mingw32make.bat +++ b/retroshare-gui/src/mingw32make.bat @@ -1,10 +1,11 @@ set QTDIR=C:\Qt\4.8.6 set MINGW=C:\MinGW +set GIT=C:\Program Files\Git -set PATH=%QTDIR%\bin;%MINGW%\bin;%PATH% +set PATH=%QTDIR%\bin;%MINGW%\bin;%GIT%\bin;%PATH% -qmake retroshare-gui.pro +qmake retroshare-gui.pro "CONFIG+=version_detail_bash_script" mingw32-make From 2a6b6233000cc5f9f53eef9dfd50b72414b1cacb Mon Sep 17 00:00:00 2001 From: thunder2 Date: Tue, 11 Aug 2015 23:19:37 +0200 Subject: [PATCH 038/165] Added extended debug outputs of times in RsDataService. --- libretroshare/src/gxs/rsdataservice.cc | 125 ++++++++++++++++++++++--- libretroshare/src/libretroshare.pro | 2 + libretroshare/src/util/rsscopetimer.cc | 59 ++++++++++++ libretroshare/src/util/rsscopetimer.h | 31 +++--- 4 files changed, 187 insertions(+), 30 deletions(-) create mode 100644 libretroshare/src/util/rsscopetimer.cc diff --git a/libretroshare/src/gxs/rsdataservice.cc b/libretroshare/src/gxs/rsdataservice.cc index d66463c1e..0ed762a01 100644 --- a/libretroshare/src/gxs/rsdataservice.cc +++ b/libretroshare/src/gxs/rsdataservice.cc @@ -24,11 +24,19 @@ * */ +/***** + * #define RS_DATA_SERVICE_DEBUG 1 + * #define RS_DATA_SERVICE_DEBUG_TIME 1 + ****/ #include #include #include +#ifdef RS_DATA_SERVICE_DEBUG_TIME +#include +#endif + #include "rsdataservice.h" #define MSG_TABLE_NAME std::string("MESSAGES") @@ -141,10 +149,6 @@ #define COL_IDENTITY 4 #define COL_HASH 5 -/***** - * #define RS_DATA_SERVICE_DEBUG 1 - ****/ - const std::string RsGeneralDataService::GRP_META_SERV_STRING = KEY_NXS_SERV_STRING; const std::string RsGeneralDataService::GRP_META_STATUS = KEY_GRP_STATUS; const std::string RsGeneralDataService::GRP_META_SUBSCRIBE_FLAG = KEY_GRP_SUBCR_FLAG; @@ -900,7 +904,13 @@ bool RsDataService::validSize(RsNxsGrp* grp) const return false; } -int RsDataService::retrieveNxsGrps(std::map &grp, bool withMeta, bool /* cache */){ +int RsDataService::retrieveNxsGrps(std::map &grp, bool withMeta, bool /* cache */) +{ +#ifdef RS_DATA_SERVICE_DEBUG_TIME + RsScopeTimer timer(""); + int resultCount = 0; + int requestedGroups = grp.size(); +#endif if(grp.empty()){ @@ -914,6 +924,10 @@ int RsDataService::retrieveNxsGrps(std::map &grp, bool locked_retrieveGroups(c, grps); std::vector::iterator vit = grps.begin(); +#ifdef RS_DATA_SERVICE_DEBUG_TIME + resultCount = grps.size(); +#endif + for(; vit != grps.end(); ++vit) { grp[(*vit)->grpId] = *vit; @@ -943,6 +957,10 @@ int RsDataService::retrieveNxsGrps(std::map &grp, bool { RsNxsGrp* ng = grps.front(); grp[ng->grpId] = ng; + +#ifdef RS_DATA_SERVICE_DEBUG_TIME + ++resultCount; +#endif }else{ toRemove.push_back(grpId); } @@ -958,6 +976,10 @@ int RsDataService::retrieveNxsGrps(std::map &grp, bool } } +#ifdef RS_DATA_SERVICE_DEBUG_TIME + std::cerr << "RsDataService::retrieveNxsGrps() Requests: " << requestedGroups << ", Results: " << resultCount << ", Time: " << timer.duration() << std::endl; +#endif + if(withMeta && !grp.empty()) { std::map metaMap; @@ -980,6 +1002,10 @@ int RsDataService::retrieveNxsGrps(std::map &grp, bool std::cerr << std::endl; #endif } + +#ifdef RS_DATA_SERVICE_DEBUG_TIME + std::cerr << "RsDataService::retrieveNxsGrps() Time with meta: " << timer.duration() << std::endl; +#endif } return 1; @@ -1005,6 +1031,10 @@ void RsDataService::locked_retrieveGroups(RetroCursor* c, std::vector int RsDataService::retrieveNxsMsgs(const GxsMsgReq &reqIds, GxsMsgResult &msg, bool /* cache */, bool withMeta) { +#ifdef RS_DATA_SERVICE_DEBUG_TIME + RsScopeTimer timer(""); + int resultCount = 0; +#endif GxsMsgReq::const_iterator mit = reqIds.begin(); @@ -1026,8 +1056,14 @@ int RsDataService::retrieveNxsMsgs(const GxsMsgReq &reqIds, GxsMsgResult &msg, b RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, msgColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", ""); if(c) + { locked_retrieveMessages(c, msgSet); +#ifdef RS_DATA_SERVICE_DEBUG_TIME + resultCount += msgSet.size(); +#endif + } + delete c; }else{ @@ -1043,8 +1079,14 @@ int RsDataService::retrieveNxsMsgs(const GxsMsgReq &reqIds, GxsMsgResult &msg, b + "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", ""); if(c) + { locked_retrieveMessages(c, msgSet); +#ifdef RS_DATA_SERVICE_DEBUG_TIME + resultCount += c->getResultCount(); +#endif + } + delete c; } } @@ -1066,6 +1108,10 @@ int RsDataService::retrieveNxsMsgs(const GxsMsgReq &reqIds, GxsMsgResult &msg, b msgSet.clear(); } +#ifdef RS_DATA_SERVICE_DEBUG_TIME + std::cerr << "RsDataService::retrieveNxsMsgs() Requests: " << reqIds.size() << "Results: " << resultCount << ", Time: " << timer.duration() << std::endl; +#endif + // tres expensive !? if(withMeta) { @@ -1117,6 +1163,10 @@ int RsDataService::retrieveNxsMsgs(const GxsMsgReq &reqIds, GxsMsgResult &msg, b meta_lit = msgMetaV.erase(meta_lit); } } + +#ifdef RS_DATA_SERVICE_DEBUG_TIME + std::cerr << "RsDataService::retrieveNxsMsgs() Time with meta: " << timer.duration() << std::endl; +#endif } return 1; @@ -1129,7 +1179,7 @@ void RsDataService::locked_retrieveMessages(RetroCursor *c, std::vectormoveToNext(); @@ -1139,9 +1189,13 @@ void RsDataService::locked_retrieveMessages(RetroCursor *c, std::vectorsqlQuery(MSG_TABLE_NAME, msgMetaColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", ""); - locked_retrieveMsgMeta(c, metaSet); + if (c) + { + locked_retrieveMsgMeta(c, metaSet); +#ifdef RS_DATA_SERVICE_DEBUG_TIME + resultCount += metaSet.size(); +#endif + } }else{ // request each grp @@ -1168,13 +1228,24 @@ int RsDataService::retrieveGxsMsgMetaData(const GxsMsgReq& reqIds, GxsMsgMetaRes RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, msgMetaColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", ""); - locked_retrieveMsgMeta(c, metaSet); + if (c) + { + locked_retrieveMsgMeta(c, metaSet); + +#ifdef RS_DATA_SERVICE_DEBUG_TIME + resultCount += c->getResultCount(); +#endif + } } } msgMeta[grpId] = metaSet; } +#ifdef RS_DATA_SERVICE_DEBUG_TIME + std::cerr << "RsDataService::retrieveGxsMsgMetaData() Requests: " << reqIds.size() << ", Results: " << resultCount << ", Time: " << timer.duration() << std::endl; +#endif + return 1; } @@ -1205,6 +1276,10 @@ int RsDataService::retrieveGxsGrpMetaData(std::map &grpIds) { RsStackMutex stack(mDbMutex); +#ifdef RS_DATA_SERVICE_DEBUG_TIME + RsScopeTimer timer(""); + int resultCount = 0; +#endif + RetroCursor* c = mDb->sqlQuery(GRP_TABLE_NAME, grpIdColumn, "", ""); if(c) @@ -1462,6 +1545,10 @@ int RsDataService::retrieveGroupIds(std::vector &grpIds) c->getString(0, grpId); grpIds.push_back(RsGxsGroupId(grpId)); valid = c->moveToNext(); + +#ifdef RS_DATA_SERVICE_DEBUG_TIME + ++resultCount; +#endif } delete c; }else @@ -1469,11 +1556,19 @@ int RsDataService::retrieveGroupIds(std::vector &grpIds) return 0; } +#ifdef RS_DATA_SERVICE_DEBUG_TIME + std::cerr << "RsDataService::retrieveGroupIds() Results: " << resultCount << ", Time: " << timer.duration() << std::endl; +#endif + return 1; } -int RsDataService::retrieveMsgIds(const RsGxsGroupId& grpId, - RsGxsMessageId::std_vector& msgIds) { +int RsDataService::retrieveMsgIds(const RsGxsGroupId& grpId, RsGxsMessageId::std_vector& msgIds) +{ +#ifdef RS_DATA_SERVICE_DEBUG_TIME + RsScopeTimer timer(""); + int resultCount = 0; +#endif RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, mMsgIdColumn, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", ""); @@ -1491,6 +1586,10 @@ int RsDataService::retrieveMsgIds(const RsGxsGroupId& grpId, msgIds.push_back(RsGxsMessageId(msgId)); valid = c->moveToNext(); + +#ifdef RS_DATA_SERVICE_DEBUG_TIME + ++resultCount; +#endif } delete c; }else @@ -1498,6 +1597,10 @@ int RsDataService::retrieveMsgIds(const RsGxsGroupId& grpId, return 0; } +#ifdef RS_DATA_SERVICE_DEBUG_TIME + std::cerr << "RsDataService::retrieveNxsGrps() Results: " << resultCount << ", Time: " << timer.duration() << std::endl; +#endif + return 1; } diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index af6f27fc7..2cbe24c3d 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -483,6 +483,7 @@ HEADERS += util/folderiterator.h \ util/rsmemcache.h \ util/rstickevent.h \ util/rsrecogn.h \ + util/rsscopetimer.h SOURCES += dbase/cachestrapper.cc \ dbase/fimonitor.cc \ @@ -632,6 +633,7 @@ SOURCES += util/folderiterator.cc \ util/rsrandom.cc \ util/rstickevent.cc \ util/rsrecogn.cc \ + util/rsscopetimer.cc upnp_miniupnpc { diff --git a/libretroshare/src/util/rsscopetimer.cc b/libretroshare/src/util/rsscopetimer.cc new file mode 100644 index 000000000..b3ce8fbc3 --- /dev/null +++ b/libretroshare/src/util/rsscopetimer.cc @@ -0,0 +1,59 @@ +/* + * libretroshare/src/util: rsscopetimer.cc + * + * 3P/PQI network interface for RetroShare. + * + * Copyright 2013- by Cyril Soler + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + +#include +#include +#include "rsscopetimer.h" + +RsScopeTimer::RsScopeTimer(const std::string& name) +{ + _name = name ; + start(); +} + +RsScopeTimer::~RsScopeTimer() +{ + if (!_name.empty()) + { + std::cerr << "Time for \"" << _name << "\": " << duration() << std::endl; + } +} + +double RsScopeTimer::currentTime() +{ + timeval tv ; + gettimeofday(&tv,NULL) ; + return (tv.tv_sec % 10000) + tv.tv_usec/1000000.0f ; // the %1000 is here to allow double precision to cover the decimals. +} + +void RsScopeTimer::start() +{ + _seconds = currentTime(); +} + +double RsScopeTimer::duration() +{ + return currentTime() - _seconds; +} diff --git a/libretroshare/src/util/rsscopetimer.h b/libretroshare/src/util/rsscopetimer.h index d4b7553d9..b76ae4f96 100644 --- a/libretroshare/src/util/rsscopetimer.h +++ b/libretroshare/src/util/rsscopetimer.h @@ -31,29 +31,22 @@ // callToMeasure() ; // } // -#include + +#include class RsScopeTimer { - public: - RsScopeTimer(const std::string& name) - { - timeval tv ; - gettimeofday(&tv,NULL) ; - _seconds = (tv.tv_sec % 10000) + tv.tv_usec/1000000.0f ; // the %1000 is here to allow double precision to cover the decimals. - _name = name ; - } +public: + RsScopeTimer(const std::string& name); + ~RsScopeTimer(); - ~RsScopeTimer() - { - timeval tv ; - gettimeofday(&tv,NULL) ; - double ss = (tv.tv_sec % 10000) + tv.tv_usec/1000000.0f ; + void start(); + double duration(); - std::cerr << "Time for \"" << _name << "\": " << ss - _seconds << std::endl; - } +private: + double currentTime(); - private: - std::string _name ; - double _seconds ; +private: + std::string _name ; + double _seconds ; }; From 94317d1a390f297d182b09f8cddd70c8f6d5c198 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 7 Aug 2015 21:40:48 -0400 Subject: [PATCH 039/165] added graph display of instantly required bandwidth for VOIP, in preparation to chosing new video codec. GUI layout needs to be sorted. --- plugins/VOIP/gui/AudioInputConfig.cpp | 66 ++++++++++++++++++++++- plugins/VOIP/gui/AudioInputConfig.h | 20 ++++++- plugins/VOIP/gui/AudioInputConfig.ui | 76 +++++++++++++++++---------- plugins/VOIP/gui/QVideoDevice.cpp | 5 +- plugins/VOIP/interface/rsVOIP.h | 2 + plugins/VOIP/services/p3VOIP.cc | 8 +++ 6 files changed, 147 insertions(+), 30 deletions(-) diff --git a/plugins/VOIP/gui/AudioInputConfig.cpp b/plugins/VOIP/gui/AudioInputConfig.cpp index 5c7553ee8..e23083200 100644 --- a/plugins/VOIP/gui/AudioInputConfig.cpp +++ b/plugins/VOIP/gui/AudioInputConfig.cpp @@ -39,6 +39,7 @@ //#include "NetworkConfig.h" #include "audiodevicehelper.h" #include "AudioWizard.h" +#include "gui/common/RSGraphWidget.h" #include #define iroundf(x) ( static_cast(x) ) @@ -51,6 +52,59 @@ void AudioInputDialog::showEvent(QShowEvent *) { qtTick->start(20); }*/ +class voipGraphSource: public RSGraphSource +{ +public: + voipGraphSource() {} + + void setVideoInput(QVideoInputDevice *vid) { video_input = vid ; } + + virtual QString displayName(int) const { return tr("Required bandwidth") ;} + + virtual QString displayValue(float v) const + { + if(v < 1000) + return QString::number(v,10,2) + " B/s" ; + else if(v < 1000*1024) + return QString::number(v/1024,10,2) + " KB/s" ; + else + return QString::number(v/(1024*1024),10,2) + " MB/s" ; + } + + virtual void getValues(std::map& vals) const + { + RsVOIPDataChunk chunk ; + uint32_t total_size = 0 ; + vals.clear() ; + + while(video_input && video_input->getNextEncodedPacket(chunk)) + { + total_size += chunk.size ; + chunk.clear() ; + } + + vals[std::string("bw")] = (float)total_size ; + } + +private: + QVideoInputDevice *video_input ; +}; + +void voipGraph::setVoipSource(voipGraphSource *gs) +{ +_src = gs ; +RSGraphWidget::setSource(gs) ; +} + +voipGraph::voipGraph(QWidget *parent) + : RSGraphWidget(parent) +{ + setFlags(RSGraphWidget::RSGRAPH_FLAGS_SHOW_LEGEND) ; + setFlags(RSGraphWidget::RSGRAPH_FLAGS_PAINT_STYLE_PLAIN) ; + + _src = NULL ; +} + /** Constructor */ AudioInputConfig::AudioInputConfig(QWidget * parent, Qt::WindowFlags flags) : ConfigPage(parent, flags) @@ -71,11 +125,21 @@ AudioInputConfig::AudioInputConfig(QWidget * parent, Qt::WindowFlags flags) // videoInput = new QVideoInputDevice(this) ; videoInput->setEchoVideoTarget(ui.videoDisplay) ; - videoInput->setVideoEncoder(NULL) ; + videoInput->setVideoEncoder(new JPEGVideoEncoder()) ; + + graph_source = new voipGraphSource ; + ui.voipBwGraph->setSource(graph_source); + + graph_source->setVideoInput(videoInput) ; + graph_source->setCollectionTimeLimit(1000*300) ; + graph_source->start() ; } AudioInputConfig::~AudioInputConfig() { + graph_source->stop() ; + graph_source->setVideoInput(NULL) ; + std::cerr << "Deleting audioInputConfig object" << std::endl; if(videoInput != NULL) { diff --git a/plugins/VOIP/gui/AudioInputConfig.h b/plugins/VOIP/gui/AudioInputConfig.h index 1b64085a3..cc0fd15c3 100644 --- a/plugins/VOIP/gui/AudioInputConfig.h +++ b/plugins/VOIP/gui/AudioInputConfig.h @@ -35,10 +35,27 @@ #include "retroshare-gui/configpage.h" -#include "ui_AudioInputConfig.h" #include "SpeexProcessor.h" #include "VideoProcessor.h" #include "AudioStats.h" +#include "gui/common/RSGraphWidget.h" + +class voipGraphSource ; + +class voipGraph: public RSGraphWidget +{ +public: + voipGraph(QWidget *parent) ; + + voipGraphSource *voipSource() const { return _src ; } + + void setVoipSource(voipGraphSource *gs) ; + +private: + voipGraphSource *_src ; +}; + +#include "ui_AudioInputConfig.h" class AudioInputConfig : public ConfigPage { @@ -54,6 +71,7 @@ class AudioInputConfig : public ConfigPage QVideoInputDevice *videoInput ; bool loaded; + voipGraphSource *graph_source ; protected: QTimer *qtTick; diff --git a/plugins/VOIP/gui/AudioInputConfig.ui b/plugins/VOIP/gui/AudioInputConfig.ui index 6aa071b4a..8037dea93 100644 --- a/plugins/VOIP/gui/AudioInputConfig.ui +++ b/plugins/VOIP/gui/AudioInputConfig.ui @@ -6,8 +6,8 @@ 0 0 - 501 - 406 + 1155 + 713 @@ -348,33 +348,49 @@
- - - - Video Processing - - - - - - - 170 - 128 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - + + + + Video Processing + + + + + + + 170 + 128 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + @@ -397,6 +413,12 @@
gui/QVideoDevice.h
1 + + voipGraph + QFrame +
gui/AudioInputConfig.h
+ 1 +
qcbTransmit diff --git a/plugins/VOIP/gui/QVideoDevice.cpp b/plugins/VOIP/gui/QVideoDevice.cpp index eed14b58b..eaec96f71 100644 --- a/plugins/VOIP/gui/QVideoDevice.cpp +++ b/plugins/VOIP/gui/QVideoDevice.cpp @@ -88,7 +88,10 @@ void QVideoInputDevice::grabFrame() bool QVideoInputDevice::getNextEncodedPacket(RsVOIPDataChunk& chunk) { - return _video_encoder->nextPacket(chunk) ; + if(_video_encoder) + return _video_encoder->nextPacket(chunk) ; + else + return false ; } QVideoInputDevice::~QVideoInputDevice() diff --git a/plugins/VOIP/interface/rsVOIP.h b/plugins/VOIP/interface/rsVOIP.h index 18f258769..7269610b4 100644 --- a/plugins/VOIP/interface/rsVOIP.h +++ b/plugins/VOIP/interface/rsVOIP.h @@ -56,6 +56,8 @@ struct RsVOIPDataChunk void *data ; // create/delete using malloc/free. uint32_t size ; RsVOIPDataType type ; // video or audio + + void clear() ; }; class RsVOIP diff --git a/plugins/VOIP/services/p3VOIP.cc b/plugins/VOIP/services/p3VOIP.cc index d7377077c..fb164bd7c 100644 --- a/plugins/VOIP/services/p3VOIP.cc +++ b/plugins/VOIP/services/p3VOIP.cc @@ -147,6 +147,14 @@ RsServiceInfo p3VOIP::getServiceInfo() TURTLE_MIN_MINOR_VERSION); } +void RsVOIPDataChunk::clear() +{ + + if(data) + free(data) ; + data=NULL; + size=0 ; +} int p3VOIP::tick() { #ifdef DEBUG_VOIP From 2107a1c858cca4565435d876056ec5978f6c5999 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 8 Aug 2015 18:46:49 -0400 Subject: [PATCH 040/165] fixed up image display layout in VOIP config tab --- plugins/VOIP/gui/QVideoDevice.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/VOIP/gui/QVideoDevice.cpp b/plugins/VOIP/gui/QVideoDevice.cpp index eaec96f71..67c79ee5b 100644 --- a/plugins/VOIP/gui/QVideoDevice.cpp +++ b/plugins/VOIP/gui/QVideoDevice.cpp @@ -113,6 +113,7 @@ void QVideoOutputDevice::showFrameOff() void QVideoOutputDevice::showFrame(const QImage& img) { - setPixmap(QPixmap::fromImage(img).scaled(minimumSize(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation)) ; + std::cerr << "img.size = " << img.width() << " x " << img.height() << std::endl; + setPixmap(QPixmap::fromImage(img).scaled( QSize(height()*640/480,height()),Qt::IgnoreAspectRatio,Qt::SmoothTransformation)) ; } From c0614e70ac235724fe74085197e602f4978bfa47 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 9 Aug 2015 18:09:17 -0400 Subject: [PATCH 041/165] added preview option to show decoded stream in Audio config --- plugins/VOIP/gui/AudioInputConfig.cpp | 45 ++++++++++++----- plugins/VOIP/gui/AudioInputConfig.h | 2 + plugins/VOIP/gui/AudioInputConfig.ui | 10 ++++ plugins/VOIP/gui/QVideoDevice.cpp | 61 ++++++++++++++-------- plugins/VOIP/gui/QVideoDevice.h | 10 ++++ plugins/VOIP/gui/VideoProcessor.cpp | 73 ++++++++++++++++++++------- plugins/VOIP/gui/VideoProcessor.h | 53 +++++++++++++++---- plugins/VOIP/interface/rsVOIP.h | 4 +- 8 files changed, 195 insertions(+), 63 deletions(-) diff --git a/plugins/VOIP/gui/AudioInputConfig.cpp b/plugins/VOIP/gui/AudioInputConfig.cpp index e23083200..d9931a2af 100644 --- a/plugins/VOIP/gui/AudioInputConfig.cpp +++ b/plugins/VOIP/gui/AudioInputConfig.cpp @@ -55,9 +55,9 @@ void AudioInputDialog::showEvent(QShowEvent *) { class voipGraphSource: public RSGraphSource { public: - voipGraphSource() {} + voipGraphSource() : video_input(NULL) {} - void setVideoInput(QVideoInputDevice *vid) { video_input = vid ; } + void setVideoInput(const QVideoInputDevice *vid) { video_input = vid ; } virtual QString displayName(int) const { return tr("Required bandwidth") ;} @@ -73,21 +73,14 @@ public: virtual void getValues(std::map& vals) const { - RsVOIPDataChunk chunk ; - uint32_t total_size = 0 ; vals.clear() ; - while(video_input && video_input->getNextEncodedPacket(chunk)) - { - total_size += chunk.size ; - chunk.clear() ; - } - - vals[std::string("bw")] = (float)total_size ; + if(video_input) + vals[std::string("bw")] = video_input->currentBandwidth() ; } private: - QVideoInputDevice *video_input ; + const QVideoInputDevice *video_input ; }; void voipGraph::setVoipSource(voipGraphSource *gs) @@ -127,12 +120,31 @@ AudioInputConfig::AudioInputConfig(QWidget * parent, Qt::WindowFlags flags) videoInput->setEchoVideoTarget(ui.videoDisplay) ; videoInput->setVideoEncoder(new JPEGVideoEncoder()) ; + videoDecoder = new JPEGVideoDecoder; + videoDecoder->setDisplayTarget(NULL) ; + graph_source = new voipGraphSource ; ui.voipBwGraph->setSource(graph_source); graph_source->setVideoInput(videoInput) ; graph_source->setCollectionTimeLimit(1000*300) ; graph_source->start() ; + + QObject::connect(ui.showEncoded_CB,SIGNAL(toggled(bool)),this,SLOT(togglePreview(bool))) ; +} + +void AudioInputConfig::togglePreview(bool b) +{ + if(b) + { + videoInput->setEchoVideoTarget(NULL) ; + videoDecoder->setDisplayTarget(ui.videoDisplay) ; + } + else + { + videoInput->setEchoVideoTarget(ui.videoDisplay) ; + videoDecoder->setDisplayTarget(NULL) ; + } } AudioInputConfig::~AudioInputConfig() @@ -352,6 +364,15 @@ void AudioInputConfig::on_Tick_timeout() { abSpeech->iValue = iroundf(inputAudioProcessor->dVoiceAcivityLevel * 32767.0f + 0.5f); abSpeech->update(); + + // also transmit encoded video + RsVOIPDataChunk chunk ; + + while(videoInput->getNextEncodedPacket(chunk)) + { + videoDecoder->receiveEncodedData(static_cast(chunk.data),chunk.size) ; + chunk.clear() ; + } } void AudioInputConfig::emptyBuffer() { diff --git a/plugins/VOIP/gui/AudioInputConfig.h b/plugins/VOIP/gui/AudioInputConfig.h index cc0fd15c3..faaadb63e 100644 --- a/plugins/VOIP/gui/AudioInputConfig.h +++ b/plugins/VOIP/gui/AudioInputConfig.h @@ -69,6 +69,7 @@ class AudioInputConfig : public ConfigPage //VideoDecoder *videoDecoder ; //VideoEncoder *videoEncoder ; QVideoInputDevice *videoInput ; + VideoDecoder *videoDecoder ; bool loaded; voipGraphSource *graph_source ; @@ -96,6 +97,7 @@ class AudioInputConfig : public ConfigPage private slots: void loadSettings(); void emptyBuffer(); + void togglePreview(bool) ; void on_qsTransmitHold_valueChanged(int v); void on_qsAmp_valueChanged(int v); diff --git a/plugins/VOIP/gui/AudioInputConfig.ui b/plugins/VOIP/gui/AudioInputConfig.ui index 8037dea93..7b77fb3a9 100644 --- a/plugins/VOIP/gui/AudioInputConfig.ui +++ b/plugins/VOIP/gui/AudioInputConfig.ui @@ -391,6 +391,16 @@
+ + + + <html><head/><body><p>Display encoded (and then decoded) frame, to check the codec's quality. If not selected, the image above only shows the frame that is grabbed from your camera.</p></body></html> + + + preview + + + diff --git a/plugins/VOIP/gui/QVideoDevice.cpp b/plugins/VOIP/gui/QVideoDevice.cpp index 67c79ee5b..3a7ee029e 100644 --- a/plugins/VOIP/gui/QVideoDevice.cpp +++ b/plugins/VOIP/gui/QVideoDevice.cpp @@ -13,6 +13,9 @@ QVideoInputDevice::QVideoInputDevice(QWidget *parent) _capture_device = NULL ; _video_encoder = NULL ; _echo_output_device = NULL ; + _estimated_bw = 0 ; + _total_encoded_size = 0 ; + _last_bw_estimate_TS = time(NULL) ; } void QVideoInputDevice::stop() @@ -54,36 +57,52 @@ void QVideoInputDevice::start() void QVideoInputDevice::grabFrame() { - IplImage *img=cvQueryFrame(_capture_device); + IplImage *img=cvQueryFrame(_capture_device); - if(img == NULL) - { - std::cerr << "(EE) Cannot capture image from camera. Something's wrong." << std::endl; - return ; - } - // get the image data + if(img == NULL) + { + std::cerr << "(EE) Cannot capture image from camera. Something's wrong." << std::endl; + return ; + } + // get the image data - if(img->nChannels != 3) - { - std::cerr << "(EE) expected 3 channels. Got " << img->nChannels << std::endl; - return ; - } + if(img->nChannels != 3) + { + std::cerr << "(EE) expected 3 channels. Got " << img->nChannels << std::endl; + return ; + } // convert to RGB and copy to new buffer, because cvQueryFrame tells us to not modify the buffer cv::Mat img_rgb; cv::cvtColor(cv::Mat(img), img_rgb, CV_BGR2RGB); - static const int _encoded_width = 128 ; - static const int _encoded_height = 128 ; + QImage image = QImage(img_rgb.data,img_rgb.cols,img_rgb.rows,QImage::Format_RGB888); - QImage image = QImage(img_rgb.data,img_rgb.cols,img_rgb.rows,QImage::Format_RGB888).scaled(QSize(_encoded_width,_encoded_height),Qt::IgnoreAspectRatio,Qt::SmoothTransformation) ; + if(_video_encoder != NULL) + { + uint32_t encoded_size ; - if(_video_encoder != NULL) - { - _video_encoder->addImage(image) ; - emit networkPacketReady() ; - } - if(_echo_output_device != NULL) _echo_output_device->showFrame(image) ; + _video_encoder->addImage(image,0,encoded_size) ; + + std::cerr << "Encoded size = " << encoded_size << std::endl; + _total_encoded_size += encoded_size ; + + time_t now = time(NULL) ; + + if(now > _last_bw_estimate_TS) + { + _estimated_bw = uint32_t(0.75*_estimated_bw + 0.25 * (_total_encoded_size / (float)(now - _last_bw_estimate_TS))) ; + + _total_encoded_size = 0 ; + _last_bw_estimate_TS = now ; + + std::cerr << "new bw estimate: " << _estimated_bw << std::endl; + } + + emit networkPacketReady() ; + } + if(_echo_output_device != NULL) + _echo_output_device->showFrame(image) ; } bool QVideoInputDevice::getNextEncodedPacket(RsVOIPDataChunk& chunk) diff --git a/plugins/VOIP/gui/QVideoDevice.h b/plugins/VOIP/gui/QVideoDevice.h index 7cb62ca0c..513932487 100644 --- a/plugins/VOIP/gui/QVideoDevice.h +++ b/plugins/VOIP/gui/QVideoDevice.h @@ -42,6 +42,12 @@ class QVideoInputDevice: public QObject // bool getNextEncodedPacket(RsVOIPDataChunk&) ; + // gets the estimated current bandwidth required to transmit the encoded data, in B/s + // + uint32_t currentBandwidth() const { return _estimated_bw ; } + + // control + void start() ; void stop() ; @@ -59,5 +65,9 @@ class QVideoInputDevice: public QObject QVideoOutputDevice *_echo_output_device ; std::list _out_queue ; + + uint32_t _estimated_bw ; + time_t _last_bw_estimate_TS; + uint32_t _total_encoded_size ; }; diff --git a/plugins/VOIP/gui/VideoProcessor.cpp b/plugins/VOIP/gui/VideoProcessor.cpp index 27343c412..c9add1b26 100644 --- a/plugins/VOIP/gui/VideoProcessor.cpp +++ b/plugins/VOIP/gui/VideoProcessor.cpp @@ -12,9 +12,15 @@ VideoDecoder::VideoDecoder() _output_device = NULL ; } -bool VideoEncoder::addImage(const QImage& img) +VideoEncoder::VideoEncoder() + :_frame_size(128,128) { - encodeData(img) ; +} + +bool VideoEncoder::addImage(const QImage& img,uint32_t size_hint,uint32_t& encoded_size) +{ + std::cerr << "reducing to " << _frame_size.width() << " x " << _frame_size.height() << std::endl; + encodeData(img.scaled(_frame_size,Qt::IgnoreAspectRatio,Qt::SmoothTransformation),size_hint,encoded_size) ; return true ; } @@ -32,6 +38,7 @@ bool VideoEncoder::nextPacket(RsVOIPDataChunk& chunk) void VideoDecoder::receiveEncodedData(const unsigned char *data,uint32_t size) { + if(_output_device) _output_device->showFrame(decodeData(data,size)) ; } @@ -50,24 +57,54 @@ QImage JPEGVideoDecoder::decodeData(const unsigned char *encoded_image_data,uint void VideoEncoder::setMaximumFrameRate(uint32_t bytes_per_sec) { - std::cerr << "Video Encoder: maximum frame rate is set to " << bytes_per_sec << " Bps" << std::endl; + std::cerr << "Video Encoder: maximum frame rate is set to " << bytes_per_sec << " Bps" << std::endl; } - -void JPEGVideoEncoder::encodeData(const QImage& image) +void VideoEncoder::setInternalFrameSize(QSize s) { - QByteArray qb ; - - QBuffer buffer(&qb) ; - buffer.open(QIODevice::WriteOnly) ; - image.save(&buffer,"JPEG") ; - - RsVOIPDataChunk voip_chunk ; - voip_chunk.data = malloc(qb.size()); - memcpy(voip_chunk.data,qb.data(),qb.size()) ; - voip_chunk.size = qb.size() ; - voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; - - _out_queue.push_back(voip_chunk) ; + _frame_size = s ; +} + +JPEGVideoEncoder::JPEGVideoEncoder() + : _ref_frame_max_distance(10),_ref_frame_count(10) +{ +} + +void JPEGVideoEncoder::encodeData(const QImage& image,uint32_t /* size_hint */,uint32_t& encoded_size) +{ + // check if we make a diff image, or if we use the full frame. + + QImage encoded_frame ; + + if(_ref_frame_count++ < _ref_frame_max_distance && image.size() == _reference_frame.size()) + { + // compute difference with reference frame. + encoded_frame = image ; + + for(uint32_t i=0;i _out_queue ; + + QSize _frame_size ; }; // Now derive various image encoding/decoding algorithms. @@ -75,16 +77,45 @@ class VideoEncoder class JPEGVideoDecoder: public VideoDecoder { - protected: - virtual QImage decodeData(const unsigned char *encoded_image,uint32_t encoded_image_size) ; +protected: + virtual QImage decodeData(const unsigned char *encoded_image,uint32_t encoded_image_size) ; + +private: + QImage _last_reference_frame ; }; class JPEGVideoEncoder: public VideoEncoder { - public: - JPEGVideoEncoder() {} +public: + JPEGVideoEncoder() ; - protected: - virtual void encodeData(const QImage& Image) ; +protected: + virtual void encodeData(const QImage& Image, uint32_t size_hint, uint32_t &encoded_size) ; + +private: + QImage _reference_frame ; + uint32_t _ref_frame_max_distance ; // max distance between two reference frames. + uint32_t _ref_frame_count ; }; +class DifferentialWaveletEncoder: public VideoEncoder +{ +public: + DifferentialWaveletEncoder() {} + +protected: + virtual void encodeData(const QImage& Image, uint32_t size_hint, uint32_t &encoded_size) ; + +}; + +class DifferentialWaveletDecoder: public VideoDecoder +{ +public: + DifferentialWaveletDecoder() {} + +protected: + virtual QImage decodeData(const unsigned char *encoded_image,uint32_t encoded_image_size) ; + +private: + QImage _last_reference_frame ; +}; diff --git a/plugins/VOIP/interface/rsVOIP.h b/plugins/VOIP/interface/rsVOIP.h index 7269610b4..25fd0cfbd 100644 --- a/plugins/VOIP/interface/rsVOIP.h +++ b/plugins/VOIP/interface/rsVOIP.h @@ -51,7 +51,9 @@ class RsVOIPPongResult struct RsVOIPDataChunk { - typedef enum { RS_VOIP_DATA_TYPE_AUDIO, RS_VOIP_DATA_TYPE_VIDEO } RsVOIPDataType ; + typedef enum { RS_VOIP_DATA_TYPE_UNKNOWN = 0x00, + RS_VOIP_DATA_TYPE_AUDIO = 0x01, + RS_VOIP_DATA_TYPE_VIDEO = 0x02 } RsVOIPDataType ; void *data ; // create/delete using malloc/free. uint32_t size ; From 3bda2c2660131e5694d8375527c2262c52db53eb Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 10 Aug 2015 22:13:50 -0400 Subject: [PATCH 042/165] added differential frames encoding/decoding, and bandwidth items --- plugins/VOIP/gui/AudioInputConfig.cpp | 57 +++++++++--------- plugins/VOIP/gui/VideoProcessor.cpp | 83 +++++++++++++++++++++----- plugins/VOIP/gui/VideoProcessor.h | 14 +++-- plugins/VOIP/services/rsVOIPItems.cc | 85 +++++++++++++++++++++++++++ plugins/VOIP/services/rsVOIPItems.h | 29 +++++++-- 5 files changed, 213 insertions(+), 55 deletions(-) diff --git a/plugins/VOIP/gui/AudioInputConfig.cpp b/plugins/VOIP/gui/AudioInputConfig.cpp index d9931a2af..29a27026a 100644 --- a/plugins/VOIP/gui/AudioInputConfig.cpp +++ b/plugins/VOIP/gui/AudioInputConfig.cpp @@ -29,17 +29,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -//#include "AudioInput.h" -//#include "AudioOutput.h" #include "AudioStats.h" #include "AudioInputConfig.h" -//#include "Global.h" -//#include "NetworkConfig.h" #include "audiodevicehelper.h" #include "AudioWizard.h" #include "gui/common/RSGraphWidget.h" +#include "util/RsProtectedTimer.h" + #include #define iroundf(x) ( static_cast(x) ) @@ -104,33 +101,33 @@ AudioInputConfig::AudioInputConfig(QWidget * parent, Qt::WindowFlags flags) { std::cerr << "Creating audioInputConfig object" << std::endl; - /* Invoke the Qt Designer generated object setup routine */ - ui.setupUi(this); + /* Invoke the Qt Designer generated object setup routine */ + ui.setupUi(this); - loaded = false; + loaded = false; - inputAudioProcessor = NULL; - inputAudioDevice = NULL; - abSpeech = NULL; - qtTick = NULL; + inputAudioProcessor = NULL; + inputAudioDevice = NULL; + abSpeech = NULL; + qtTick = NULL; - // Create the video pipeline. - // - videoInput = new QVideoInputDevice(this) ; - videoInput->setEchoVideoTarget(ui.videoDisplay) ; - videoInput->setVideoEncoder(new JPEGVideoEncoder()) ; - - videoDecoder = new JPEGVideoDecoder; - videoDecoder->setDisplayTarget(NULL) ; - - graph_source = new voipGraphSource ; - ui.voipBwGraph->setSource(graph_source); - - graph_source->setVideoInput(videoInput) ; - graph_source->setCollectionTimeLimit(1000*300) ; - graph_source->start() ; - - QObject::connect(ui.showEncoded_CB,SIGNAL(toggled(bool)),this,SLOT(togglePreview(bool))) ; + // Create the video pipeline. + // + videoInput = new QVideoInputDevice(this) ; + videoInput->setEchoVideoTarget(ui.videoDisplay) ; + videoInput->setVideoEncoder(new JPEGVideoEncoder()) ; + + videoDecoder = new JPEGVideoDecoder; + videoDecoder->setDisplayTarget(NULL) ; + + graph_source = new voipGraphSource ; + ui.voipBwGraph->setSource(graph_source); + + graph_source->setVideoInput(videoInput) ; + graph_source->setCollectionTimeLimit(1000*300) ; + graph_source->start() ; + + QObject::connect(ui.showEncoded_CB,SIGNAL(toggled(bool)),this,SLOT(togglePreview(bool))) ; } void AudioInputConfig::togglePreview(bool b) @@ -178,7 +175,7 @@ void AudioInputConfig::load() //connect( ui.allowIpDeterminationCB, SIGNAL( toggled( bool ) ), this, SLOT( toggleIpDetermination(bool) ) ); //connect( ui.allowTunnelConnectionCB, SIGNAL( toggled( bool ) ), this, SLOT( toggleTunnelConnection(bool) ) ); - qtTick = new QTimer(this); + qtTick = new RsProtectedTimer(this); connect( qtTick, SIGNAL( timeout ( ) ), this, SLOT( on_Tick_timeout() ) ); qtTick->start(20); /*if (AudioInputRegistrar::qmNew) { diff --git a/plugins/VOIP/gui/VideoProcessor.cpp b/plugins/VOIP/gui/VideoProcessor.cpp index c9add1b26..b19ee03d0 100644 --- a/plugins/VOIP/gui/VideoProcessor.cpp +++ b/plugins/VOIP/gui/VideoProcessor.cpp @@ -13,14 +13,15 @@ VideoDecoder::VideoDecoder() } VideoEncoder::VideoEncoder() - :_frame_size(128,128) + :_frame_size(256,256) { } bool VideoEncoder::addImage(const QImage& img,uint32_t size_hint,uint32_t& encoded_size) { - std::cerr << "reducing to " << _frame_size.width() << " x " << _frame_size.height() << std::endl; +// std::cerr << "reducing to " << _frame_size.width() << " x " << _frame_size.height() << std::endl; encodeData(img.scaled(_frame_size,Qt::IgnoreAspectRatio,Qt::SmoothTransformation),size_hint,encoded_size) ; + //encodeData(img,size_hint,encoded_size) ; return true ; } @@ -44,15 +45,51 @@ void VideoDecoder::receiveEncodedData(const unsigned char *data,uint32_t size) QImage JPEGVideoDecoder::decodeData(const unsigned char *encoded_image_data,uint32_t size) { - QByteArray qb((char*)encoded_image_data,size) ; - QImage image ; - if(image.loadFromData(qb,"JPEG")) - return image ; - else - { - std::cerr << "image.loadFromData(): returned an error.: " << std::endl; - return QImage() ; - } + static const int HEADER_SIZE = 4 ; + + // read frame type. Use first 4 bytes to give info about content. + + if(size < HEADER_SIZE) + { + std::cerr << "JPEGVideoDecoder::decodeData(): Too small a data packet. size=" << size << std::endl; + return QImage() ; + } + + uint32_t flags = encoded_image_data[0] + (encoded_image_data[1] << 8) ; + + // un-compress image data + + QByteArray qb((char*)&encoded_image_data[HEADER_SIZE],(int)size - HEADER_SIZE) ; + QImage image ; + if(!image.loadFromData(qb,"JPEG")) + { + std::cerr << "image.loadFromData(): returned an error.: " << std::endl; + return QImage() ; + } + + // now see if the frame is a differential frame, or just a reference frame. + + if(flags & JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME) + { + if(_reference_frame.size() != image.size()) + { + std::cerr << "Bad reference frame!" << std::endl; + return image ; + } + + QImage res = _reference_frame ; + + for(uint32_t i=0;i> 8) & 0xff ; + ((unsigned char *)voip_chunk.data)[2] = 0 ; + ((unsigned char *)voip_chunk.data)[3] = 0 ; + + memcpy(voip_chunk.data+HEADER_SIZE,qb.data(),qb.size()) ; + voip_chunk.size = HEADER_SIZE + qb.size() ; voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; _out_queue.push_back(voip_chunk) ; diff --git a/plugins/VOIP/gui/VideoProcessor.h b/plugins/VOIP/gui/VideoProcessor.h index d78b1ad9d..42124b4f4 100644 --- a/plugins/VOIP/gui/VideoProcessor.h +++ b/plugins/VOIP/gui/VideoProcessor.h @@ -80,8 +80,11 @@ class JPEGVideoDecoder: public VideoDecoder protected: virtual QImage decodeData(const unsigned char *encoded_image,uint32_t encoded_image_size) ; + static const uint32_t HEADER_SIZE = 0x04 ; + + static const uint32_t JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME = 0x0001 ; private: - QImage _last_reference_frame ; + QImage _reference_frame ; }; class JPEGVideoEncoder: public VideoEncoder @@ -92,10 +95,13 @@ public: protected: virtual void encodeData(const QImage& Image, uint32_t size_hint, uint32_t &encoded_size) ; + static const uint32_t HEADER_SIZE = 0x04 ; + + static const uint32_t JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME = 0x0001 ; private: - QImage _reference_frame ; - uint32_t _ref_frame_max_distance ; // max distance between two reference frames. - uint32_t _ref_frame_count ; + QImage _reference_frame ; + uint32_t _ref_frame_max_distance ; // max distance between two reference frames. + uint32_t _ref_frame_count ; }; class DifferentialWaveletEncoder: public VideoEncoder diff --git a/plugins/VOIP/services/rsVOIPItems.cc b/plugins/VOIP/services/rsVOIPItems.cc index eb8842468..a75fa4c16 100644 --- a/plugins/VOIP/services/rsVOIPItems.cc +++ b/plugins/VOIP/services/rsVOIPItems.cc @@ -76,6 +76,19 @@ std::ostream& RsVOIPProtocolItem::print(std::ostream &out, uint16_t indent) printRsItemEnd(out, "RsVOIPProtocolItem", indent); return out; } +std::ostream& RsVOIPBandwidthItem::print(std::ostream &out, uint16_t indent) +{ + printRsItemBase(out, "RsVOIPBandwidthItem", indent); + uint16_t int_Indent = indent + 2; + printIndent(out, int_Indent); + out << "flags: " << std::hex << flags << std::dec << std::endl; + + printIndent(out, int_Indent); + out << "speed: " << bytes_per_sec << std::endl; + + printRsItemEnd(out, "RsVOIPBandwidthItem", indent); + return out; +} std::ostream& RsVOIPDataItem::print(std::ostream &out, uint16_t indent) { printRsItemBase(out, "RsVOIPDataItem", indent); @@ -100,6 +113,14 @@ uint32_t RsVOIPDataItem::serial_size() const return s; } +uint32_t RsVOIPBandwidthItem::serial_size() const +{ + uint32_t s = 8; /* header */ + s += 4; /* flags */ + s += 4; /* bandwidth */ + + return s; +} uint32_t RsVOIPProtocolItem::serial_size() const { uint32_t s = 8; /* header */ @@ -150,6 +171,40 @@ bool RsVOIPProtocolItem::serialise(void *data, uint32_t& pktsize) return ok; } +bool RsVOIPBandwidthItem::serialise(void *data, uint32_t& pktsize) +{ + uint32_t tlvsize = serial_size() ; + uint32_t offset = 0; + + if (pktsize < tlvsize) + return false; /* not enough space */ + + pktsize = tlvsize; + + bool ok = true; + + ok &= setRsItemHeader(data, tlvsize, PacketId(), tlvsize); + +#ifdef RSSERIAL_DEBUG + std::cerr << "RsVOIPSerialiser::serialiseVOIPBandwidthItem() Header: " << ok << std::endl; + std::cerr << "RsVOIPSerialiser::serialiseVOIPBandwidthItem() Size: " << tlvsize << std::endl; +#endif + + /* skip the header */ + offset += 8; + + /* add mandatory parts first */ + ok &= setRawUInt32(data, tlvsize, &offset, flags); + ok &= setRawUInt32(data, tlvsize, &offset, bytes_per_sec); + + if (offset != tlvsize) + { + ok = false; + std::cerr << "RsVOIPSerialiser::serialiseVOIPBandwidthItem() Size Error! " << std::endl; + } + + return ok; +} /* serialise the data to the buffer */ bool RsVOIPDataItem::serialise(void *data, uint32_t& pktsize) { @@ -254,6 +309,36 @@ RsVOIPProtocolItem::RsVOIPProtocolItem(void *data, uint32_t pktsize) if (!ok) throw std::runtime_error("Deserialisation error!") ; } +RsVOIPBandwidthItem::RsVOIPBandwidthItem(void *data, uint32_t pktsize) + : RsVOIPItem(RS_PKT_SUBTYPE_VOIP_BANDWIDTH) +{ + /* get the type and size */ + uint32_t rstype = getRsItemId(data); + uint32_t rssize = getRsItemSize(data); + + uint32_t offset = 0; + + if ((RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) || (RS_SERVICE_TYPE_VOIP_PLUGIN != getRsItemService(rstype)) || (RS_PKT_SUBTYPE_VOIP_BANDWIDTH != getRsItemSubType(rstype))) + throw std::runtime_error("Wrong packet type!") ; + + if (pktsize < rssize) /* check size */ + throw std::runtime_error("Not enough size!") ; + + bool ok = true; + + /* skip the header */ + offset += 8; + + /* get mandatory parts first */ + ok &= getRawUInt32(data, rssize, &offset, &flags); + ok &= getRawUInt32(data, rssize, &offset, &bytes_per_sec); + + if (offset != rssize) + throw std::runtime_error("Deserialisation error!") ; + + if (!ok) + throw std::runtime_error("Deserialisation error!") ; +} RsVOIPPingItem::RsVOIPPingItem(void *data, uint32_t pktsize) : RsVOIPItem(RS_PKT_SUBTYPE_VOIP_PING) { diff --git a/plugins/VOIP/services/rsVOIPItems.h b/plugins/VOIP/services/rsVOIPItems.h index fa440ef19..7658ea4cc 100644 --- a/plugins/VOIP/services/rsVOIPItems.h +++ b/plugins/VOIP/services/rsVOIPItems.h @@ -55,11 +55,12 @@ const uint16_t RS_SERVICE_TYPE_VOIP_PLUGIN = 0xa021; -const uint8_t RS_PKT_SUBTYPE_VOIP_PING = 0x01; -const uint8_t RS_PKT_SUBTYPE_VOIP_PONG = 0x02; -const uint8_t RS_PKT_SUBTYPE_VOIP_PROTOCOL = 0x03 ; - // 0x04 is unused because of a change in the protocol -const uint8_t RS_PKT_SUBTYPE_VOIP_DATA = 0x05 ; +const uint8_t RS_PKT_SUBTYPE_VOIP_PING = 0x01; +const uint8_t RS_PKT_SUBTYPE_VOIP_PONG = 0x02; +const uint8_t RS_PKT_SUBTYPE_VOIP_PROTOCOL = 0x03 ; + // 0x04,0x05 is unused because of a change in the protocol +const uint8_t RS_PKT_SUBTYPE_VOIP_BANDWIDTH = 0x06 ; +const uint8_t RS_PKT_SUBTYPE_VOIP_DATA = 0x07 ; const uint8_t QOS_PRIORITY_RS_VOIP = 9 ; @@ -117,9 +118,27 @@ class RsVOIPDataItem: public RsVOIPItem uint32_t flags ; uint32_t data_size ; + void *voip_data ; }; +class RsVOIPBandwidthItem: public RsVOIPItem +{ + public: + RsVOIPBandwidthItem() :RsVOIPItem(RS_PKT_SUBTYPE_VOIP_BANDWIDTH) {} + RsVOIPBandwidthItem(void *data,uint32_t size) ; // de-serialization + + virtual bool serialise(void *data,uint32_t& size) ; + virtual uint32_t serial_size() const ; + + virtual ~RsVOIPBandwidthItem() {} + virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); + + uint32_t flags ; // is that incoming or expected bandwidth? + uint32_t bytes_per_sec ; // bandwidth in bytes per sec. +}; + + class RsVOIPProtocolItem: public RsVOIPItem { public: From caa97cce70733f489867ffa54f7da306d8ecd19d Mon Sep 17 00:00:00 2001 From: thunder2 Date: Thu, 13 Aug 2015 11:03:57 +0200 Subject: [PATCH 043/165] Added database name to the debug output in RsDataService. --- libretroshare/src/gxs/rsdataservice.cc | 20 ++++++++++---------- libretroshare/src/gxs/rsdataservice.h | 4 +++- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/libretroshare/src/gxs/rsdataservice.cc b/libretroshare/src/gxs/rsdataservice.cc index 0ed762a01..18bd745b5 100644 --- a/libretroshare/src/gxs/rsdataservice.cc +++ b/libretroshare/src/gxs/rsdataservice.cc @@ -161,8 +161,8 @@ const uint32_t RsGeneralDataService::GXS_MAX_ITEM_SIZE = 1572864; // 1.5 Mbytes RsDataService::RsDataService(const std::string &serviceDir, const std::string &dbName, uint16_t serviceType, RsGxsSearchModule * /* mod */, const std::string& key) - : RsGeneralDataService(), mDbMutex("RsDataService"), mServiceDir(serviceDir), mDbName(mServiceDir + "/" + dbName), mServType(serviceType), - mDb( new RetroDb(mDbName, RetroDb::OPEN_READWRITE_CREATE, key)) { + : RsGeneralDataService(), mDbMutex("RsDataService"), mServiceDir(serviceDir), mDbName(dbName), mDbPath(mServiceDir + "/" + dbName), mServType(serviceType), + mDb( new RetroDb(mDbPath, RetroDb::OPEN_READWRITE_CREATE, key)) { initialise(); @@ -977,7 +977,7 @@ int RsDataService::retrieveNxsGrps(std::map &grp, bool } #ifdef RS_DATA_SERVICE_DEBUG_TIME - std::cerr << "RsDataService::retrieveNxsGrps() Requests: " << requestedGroups << ", Results: " << resultCount << ", Time: " << timer.duration() << std::endl; + std::cerr << "RsDataService::retrieveNxsGrps() " << mDbName << ", Requests: " << requestedGroups << ", Results: " << resultCount << ", Time: " << timer.duration() << std::endl; #endif if(withMeta && !grp.empty()) @@ -1004,7 +1004,7 @@ int RsDataService::retrieveNxsGrps(std::map &grp, bool } #ifdef RS_DATA_SERVICE_DEBUG_TIME - std::cerr << "RsDataService::retrieveNxsGrps() Time with meta: " << timer.duration() << std::endl; + std::cerr << "RsDataService::retrieveNxsGrps() " << mDbName << ", Time with meta: " << timer.duration() << std::endl; #endif } @@ -1109,7 +1109,7 @@ int RsDataService::retrieveNxsMsgs(const GxsMsgReq &reqIds, GxsMsgResult &msg, b } #ifdef RS_DATA_SERVICE_DEBUG_TIME - std::cerr << "RsDataService::retrieveNxsMsgs() Requests: " << reqIds.size() << "Results: " << resultCount << ", Time: " << timer.duration() << std::endl; + std::cerr << "RsDataService::retrieveNxsMsgs() " << mDbName << ", Requests: " << reqIds.size() << "Results: " << resultCount << ", Time: " << timer.duration() << std::endl; #endif // tres expensive !? @@ -1165,7 +1165,7 @@ int RsDataService::retrieveNxsMsgs(const GxsMsgReq &reqIds, GxsMsgResult &msg, b } #ifdef RS_DATA_SERVICE_DEBUG_TIME - std::cerr << "RsDataService::retrieveNxsMsgs() Time with meta: " << timer.duration() << std::endl; + std::cerr << "RsDataService::retrieveNxsMsgs() " << mDbName << ", Time with meta: " << timer.duration() << std::endl; #endif } @@ -1243,7 +1243,7 @@ int RsDataService::retrieveGxsMsgMetaData(const GxsMsgReq& reqIds, GxsMsgMetaRes } #ifdef RS_DATA_SERVICE_DEBUG_TIME - std::cerr << "RsDataService::retrieveGxsMsgMetaData() Requests: " << reqIds.size() << ", Results: " << resultCount << ", Time: " << timer.duration() << std::endl; + std::cerr << "RsDataService::retrieveGxsMsgMetaData() " << mDbName << ", Requests: " << reqIds.size() << ", Results: " << resultCount << ", Time: " << timer.duration() << std::endl; #endif return 1; @@ -1336,7 +1336,7 @@ int RsDataService::retrieveGxsGrpMetaData(std::map &grpIds) } #ifdef RS_DATA_SERVICE_DEBUG_TIME - std::cerr << "RsDataService::retrieveGroupIds() Results: " << resultCount << ", Time: " << timer.duration() << std::endl; + std::cerr << "RsDataService::retrieveGroupIds() " << mDbName << ", Results: " << resultCount << ", Time: " << timer.duration() << std::endl; #endif return 1; @@ -1598,7 +1598,7 @@ int RsDataService::retrieveMsgIds(const RsGxsGroupId& grpId, RsGxsMessageId::std } #ifdef RS_DATA_SERVICE_DEBUG_TIME - std::cerr << "RsDataService::retrieveNxsGrps() Results: " << resultCount << ", Time: " << timer.duration() << std::endl; + std::cerr << "RsDataService::retrieveNxsGrps() " << mDbName << ", Results: " << resultCount << ", Time: " << timer.duration() << std::endl; #endif return 1; diff --git a/libretroshare/src/gxs/rsdataservice.h b/libretroshare/src/gxs/rsdataservice.h index ea74bc831..aafa2eb45 100644 --- a/libretroshare/src/gxs/rsdataservice.h +++ b/libretroshare/src/gxs/rsdataservice.h @@ -270,7 +270,9 @@ private: std::list grpMetaColumns; std::list grpIdColumn; - std::string mServiceDir, mDbName; + std::string mServiceDir; + std::string mDbName; + std::string mDbPath; uint16_t mServType; RetroDb* mDb; From e66707111bfa2fca995f7ce893504b825ee80e05 Mon Sep 17 00:00:00 2001 From: defnax Date: Thu, 13 Aug 2015 13:48:57 +0200 Subject: [PATCH 044/165] Moved IP Filter Widgets into Tabs --- retroshare-gui/src/gui/settings/ServerPage.ui | 303 +++++++++--------- 1 file changed, 153 insertions(+), 150 deletions(-) diff --git a/retroshare-gui/src/gui/settings/ServerPage.ui b/retroshare-gui/src/gui/settings/ServerPage.ui index 354adb8ee..5a481d8b5 100755 --- a/retroshare-gui/src/gui/settings/ServerPage.ui +++ b/retroshare-gui/src/gui/settings/ServerPage.ui @@ -511,175 +511,178 @@ behind a firewall or a VPN. - - - IP blacklist + + + 0 - - - - - Qt::CustomContextMenu - - - <html><head/><body><p>This list gets automatically filled with information gathered at multiple sources: masquerading peers reported by the DHT, IP ranges entered by you, and IP ranges reported by your friends. Default settings should protect you against large scale traffic relaying.</p><p>Automatically guessing masquerading IPs can put your friends IPs in the blacklist. In this case, use the context menu to whitelist them.</p></body></html> - - - true - - - QAbstractItemView::SingleSelection - - - false - - - true - - - - IP range + + + IP blacklist + + + + + + Qt::CustomContextMenu - - - - Status + + <html><head/><body><p>This list gets automatically filled with information gathered at multiple sources: masquerading peers reported by the DHT, IP ranges entered by you, and IP ranges reported by your friends. Default settings should protect you against large scale traffic relaying.</p><p>Automatically guessing masquerading IPs can put your friends IPs in the blacklist. In this case, use the context menu to whitelist them.</p></body></html> - - - - Origin + + true - - - - Reason + + QAbstractItemView::SingleSelection - - - - Comment + + false - - - - - - - <html><head/><body><p>This is very drastic, be careful. Since masquerading IPs might be actual real IPs, this option might cause disconnection, and will probably force you to add your friends' IPs into the whitelist.</p></body></html> - - - Ban every IP reported by your friends - - - - - - - <html><head/><body><p>Another drastic option. If you use it, be prepared to add your friends' IPs into the whitelist when needed.</p></body></html> - - - Ban every masquerading IP reported by your DHT - - - - - - - - - <html><head/><body><p>If used alone, this option protects you quite well from large scale IP masquerading.</p></body></html> - + + true + + - Automatically ban ranges of DHT masquerading IPs starting at + IP range - - - - - - IPs + + + + Status - - 2 + + + + Origin - - 255 + + + + Reason - - - - - - Qt::Horizontal + + + + Comment - - - 40 - 20 - - - - - - - - - - - - - IP whitelist - - - - - - Qt::CustomContextMenu - - - <html><head/><body><p>White listed IPs are gathered from the following sources: IPs coming inside a manually exchanged certificate, IP ranges entered by you in this window, or in the security feed items.</p><p>The default behavior for Retroshare is to (1) always allow connection to peers with IP in the whitelist, even if that IP is also blacklisted; (2) optionally require IPs to be in the whitelist. You can change this behavior for each peer in the &quot;Details&quot; window of each Retroshare node. </p></body></html> - - - true - - - QAbstractItemView::SingleSelection - - - false - - - true - - - - IP range + + + + + + + <html><head/><body><p>This is very drastic, be careful. Since masquerading IPs might be actual real IPs, this option might cause disconnection, and will probably force you to add your friends' IPs into the whitelist.</p></body></html> - - - Status + Ban every IP reported by your friends + + + + + + + <html><head/><body><p>Another drastic option. If you use it, be prepared to add your friends' IPs into the whitelist when needed.</p></body></html> - - - Origin + Ban every masquerading IP reported by your DHT - - - - Reason + + + + + + + + <html><head/><body><p>If used alone, this option protects you quite well from large scale IP masquerading.</p></body></html> + + + Automatically ban ranges of DHT masquerading IPs starting at + + + + + + + IPs + + + 2 + + + 255 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + IP whitelist + + + + + + Qt::CustomContextMenu - - - - Comment + + <html><head/><body><p>White listed IPs are gathered from the following sources: IPs coming inside a manually exchanged certificate, IP ranges entered by you in this window, or in the security feed items.</p><p>The default behavior for Retroshare is to (1) always allow connection to peers with IP in the whitelist, even if that IP is also blacklisted; (2) optionally require IPs to be in the whitelist. You can change this behavior for each peer in the &quot;Details&quot; window of each Retroshare node. </p></body></html> - - - - + + true + + + QAbstractItemView::SingleSelection + + + false + + + true + + + + IP range + + + + + Status + + + + + Origin + + + + + Reason + + + + + Comment + + + + + + From 37316175c00e1107feecd6bb7780a36431e1cf18 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Thu, 13 Aug 2015 15:34:44 +0200 Subject: [PATCH 045/165] Fixed typo in debug output. --- libretroshare/src/gxs/rsdataservice.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretroshare/src/gxs/rsdataservice.cc b/libretroshare/src/gxs/rsdataservice.cc index 18bd745b5..5661627b3 100644 --- a/libretroshare/src/gxs/rsdataservice.cc +++ b/libretroshare/src/gxs/rsdataservice.cc @@ -1109,7 +1109,7 @@ int RsDataService::retrieveNxsMsgs(const GxsMsgReq &reqIds, GxsMsgResult &msg, b } #ifdef RS_DATA_SERVICE_DEBUG_TIME - std::cerr << "RsDataService::retrieveNxsMsgs() " << mDbName << ", Requests: " << reqIds.size() << "Results: " << resultCount << ", Time: " << timer.duration() << std::endl; + std::cerr << "RsDataService::retrieveNxsMsgs() " << mDbName << ", Requests: " << reqIds.size() << ", Results: " << resultCount << ", Time: " << timer.duration() << std::endl; #endif // tres expensive !? From b1101ed4292fc04faeedf26ac1717c01bde0b9a8 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Thu, 13 Aug 2015 14:01:43 +0200 Subject: [PATCH 046/165] Prevent selecting data from the database in RsGxsNetService::syncWithPeers without online friends. --- libretroshare/src/gxs/rsgxsnetservice.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index ff70fe89e..26767f175 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -235,6 +235,10 @@ void RsGxsNetService::syncWithPeers() std::set peers; mNetMgr->getOnlineList(mServiceInfo.mServiceType, peers); + if (peers.empty()) { + // nothing to do + return; + } std::set::iterator sit = peers.begin(); From 4095d9d5c9ce5f711acf3f898906f48ec926a096 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Thu, 13 Aug 2015 15:22:48 +0200 Subject: [PATCH 047/165] Switched retrieve of posts in GxsMessageFramePostWidget from "requestMsgRelatedInfo" to "requestMsgInfo". --- .../src/gui/Posted/PostedListWidget.cpp | 16 ++-- .../src/gui/Posted/PostedListWidget.h | 4 +- .../src/gui/gxs/GxsMessageFramePostWidget.cpp | 89 +++++++++---------- .../src/gui/gxs/GxsMessageFramePostWidget.h | 14 +-- .../gui/gxschannels/GxsChannelPostsWidget.cpp | 16 ++-- .../gui/gxschannels/GxsChannelPostsWidget.h | 4 +- 6 files changed, 70 insertions(+), 73 deletions(-) diff --git a/retroshare-gui/src/gui/Posted/PostedListWidget.cpp b/retroshare-gui/src/gui/Posted/PostedListWidget.cpp index d5b191392..586b673ed 100644 --- a/retroshare-gui/src/gui/Posted/PostedListWidget.cpp +++ b/retroshare-gui/src/gui/Posted/PostedListWidget.cpp @@ -44,14 +44,14 @@ PostedListWidget::PostedListWidget(const RsGxsGroupId &postedId, QWidget *parent ui->setupUi(this); /* Setup UI helper */ + mStateHelper->addWidget(mTokenTypeAllPosts, ui->hotSortButton); + mStateHelper->addWidget(mTokenTypeAllPosts, ui->newSortButton); + mStateHelper->addWidget(mTokenTypeAllPosts, ui->topSortButton); + mStateHelper->addWidget(mTokenTypePosts, ui->hotSortButton); mStateHelper->addWidget(mTokenTypePosts, ui->newSortButton); mStateHelper->addWidget(mTokenTypePosts, ui->topSortButton); - mStateHelper->addWidget(mTokenTypeRelatedPosts, ui->hotSortButton); - mStateHelper->addWidget(mTokenTypeRelatedPosts, ui->newSortButton); - mStateHelper->addWidget(mTokenTypeRelatedPosts, ui->topSortButton); - mStateHelper->addWidget(mTokenTypeGroupData, ui->submitPostButton); mStateHelper->addWidget(mTokenTypeGroupData, ui->subscribeToolButton); @@ -107,7 +107,7 @@ void PostedListWidget::processSettings(bool /*load*/) QIcon PostedListWidget::groupIcon() { - if (mStateHelper->isLoading(mTokenTypeGroupData) || mStateHelper->isLoading(mTokenTypePosts)) { + if (mStateHelper->isLoading(mTokenTypeGroupData) || mStateHelper->isLoading(mTokenTypeAllPosts)) { // return QIcon(":/images/kalarm.png"); } @@ -526,7 +526,7 @@ bool PostedListWidget::insertGroupData(const uint32_t &token, RsGroupMetaData &m return false; } -void PostedListWidget::insertPosts(const uint32_t &token, GxsMessageFramePostThread */*thread*/) +void PostedListWidget::insertAllPosts(const uint32_t &token, GxsMessageFramePostThread */*thread*/) { std::vector posts; rsPosted->getPostData(token, posts); @@ -541,10 +541,10 @@ void PostedListWidget::insertPosts(const uint32_t &token, GxsMessageFramePostThr applyRanking(); } -void PostedListWidget::insertRelatedPosts(const uint32_t &token) +void PostedListWidget::insertPosts(const uint32_t &token) { std::vector posts; - rsPosted->getRelatedPosts(token, posts); + rsPosted->getPostData(token, posts); std::vector::iterator vit; for(vit = posts.begin(); vit != posts.end(); ++vit) diff --git a/retroshare-gui/src/gui/Posted/PostedListWidget.h b/retroshare-gui/src/gui/Posted/PostedListWidget.h index 7a9348d64..be6c5411f 100644 --- a/retroshare-gui/src/gui/Posted/PostedListWidget.h +++ b/retroshare-gui/src/gui/Posted/PostedListWidget.h @@ -60,8 +60,8 @@ public: protected: /* GxsMessageFramePostWidget */ virtual bool insertGroupData(const uint32_t &token, RsGroupMetaData &metaData); - virtual void insertPosts(const uint32_t &token, GxsMessageFramePostThread *thread); - virtual void insertRelatedPosts(const uint32_t &token); + virtual void insertAllPosts(const uint32_t &token, GxsMessageFramePostThread *thread); + virtual void insertPosts(const uint32_t &token); virtual void clearPosts(); virtual bool navigatePostItem(const RsGxsMessageId& msgId); diff --git a/retroshare-gui/src/gui/gxs/GxsMessageFramePostWidget.cpp b/retroshare-gui/src/gui/gxs/GxsMessageFramePostWidget.cpp index 361910614..f9808a4d9 100644 --- a/retroshare-gui/src/gui/gxs/GxsMessageFramePostWidget.cpp +++ b/retroshare-gui/src/gui/gxs/GxsMessageFramePostWidget.cpp @@ -36,8 +36,8 @@ GxsMessageFramePostWidget::GxsMessageFramePostWidget(RsGxsIfaceHelper *ifaceImpl mFillThread = NULL; mTokenTypeGroupData = nextTokenType(); + mTokenTypeAllPosts = nextTokenType(); mTokenTypePosts = nextTokenType(); - mTokenTypeRelatedPosts = nextTokenType(); } GxsMessageFramePostWidget::~GxsMessageFramePostWidget() @@ -76,7 +76,7 @@ bool GxsMessageFramePostWidget::navigate(const RsGxsMessageId &msgId) return false; } - if (mStateHelper->isLoading(mTokenTypePosts) || mStateHelper->isLoading(mTokenTypeRelatedPosts)) { + if (mStateHelper->isLoading(mTokenTypeAllPosts) || mStateHelper->isLoading(mTokenTypePosts)) { mNavigatePendingMsgId = msgId; /* No information if group is available */ @@ -88,7 +88,7 @@ bool GxsMessageFramePostWidget::navigate(const RsGxsMessageId &msgId) bool GxsMessageFramePostWidget::isLoading() { - if (mStateHelper->isLoading(mTokenTypePosts) || mStateHelper->isLoading(mTokenTypeRelatedPosts)) { + if (mStateHelper->isLoading(mTokenTypeAllPosts) || mStateHelper->isLoading(mTokenTypePosts)) { return true; } @@ -100,7 +100,7 @@ void GxsMessageFramePostWidget::updateDisplay(bool complete) if (complete) { /* Fill complete */ requestGroupData(); - requestPosts(); + requestAllPosts(); return; } @@ -118,14 +118,14 @@ void GxsMessageFramePostWidget::updateDisplay(bool complete) if (!groupId().isNull() && std::find(grpIds.begin(), grpIds.end(), groupId()) != grpIds.end()) { updateGroup = true; /* Do we need to fill all posts? */ - requestPosts(); + requestAllPosts(); } else { std::map > msgs; getAllMsgIds(msgs); if (!msgs.empty()) { std::map >::const_iterator mit = msgs.find(groupId()); if (mit != msgs.end()) { - requestRelatedPosts(mit->second); + requestPosts(mit->second); } } } @@ -155,7 +155,7 @@ void GxsMessageFramePostWidget::fillThreadFinished() /* Current thread has finished */ mFillThread = NULL; - mStateHelper->setLoading(mTokenTypePosts, false); + mStateHelper->setLoading(mTokenTypeAllPosts, false); emit groupChanged(this); if (!mNavigatePendingMsgId.isNull()) { @@ -258,10 +258,10 @@ void GxsMessageFramePostWidget::loadGroupData(const uint32_t &token) emit groupChanged(this); } -void GxsMessageFramePostWidget::requestPosts() +void GxsMessageFramePostWidget::requestAllPosts() { #ifdef ENABLE_DEBUG - std::cerr << "GxsMessageFramePostWidget::requestPosts()"; + std::cerr << "GxsMessageFramePostWidget::requestAllPosts()"; std::cerr << std::endl; #endif @@ -269,7 +269,7 @@ void GxsMessageFramePostWidget::requestPosts() /* Request all posts */ - mTokenQueue->cancelActiveRequestTokens(mTokenTypePosts); + mTokenQueue->cancelActiveRequestTokens(mTokenTypeAllPosts); if (mFillThread) { /* Stop current fill thread */ @@ -277,20 +277,20 @@ void GxsMessageFramePostWidget::requestPosts() mFillThread = NULL; thread->stop(false); - mStateHelper->setLoading(mTokenTypePosts, false); + mStateHelper->setLoading(mTokenTypeAllPosts, false); } clearPosts(); if (groupId().isNull()) { - mStateHelper->setActive(mTokenTypePosts, false); - mStateHelper->setLoading(mTokenTypePosts, false); - mStateHelper->clear(mTokenTypePosts); + mStateHelper->setActive(mTokenTypeAllPosts, false); + mStateHelper->setLoading(mTokenTypeAllPosts, false); + mStateHelper->clear(mTokenTypeAllPosts); emit groupChanged(this); return; } - mStateHelper->setLoading(mTokenTypePosts, true); + mStateHelper->setLoading(mTokenTypeAllPosts, true); emit groupChanged(this); std::list groupIds; @@ -300,17 +300,17 @@ void GxsMessageFramePostWidget::requestPosts() opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; uint32_t token; - mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, groupIds, mTokenTypePosts); + mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, groupIds, mTokenTypeAllPosts); } -void GxsMessageFramePostWidget::loadPosts(const uint32_t &token) +void GxsMessageFramePostWidget::loadAllPosts(const uint32_t &token) { #ifdef ENABLE_DEBUG - std::cerr << "GxsMessageFramePostWidget::loadPosts()"; + std::cerr << "GxsMessageFramePostWidget::loadAllPosts()"; std::cerr << std::endl; #endif - mStateHelper->setActive(mTokenTypePosts, true); + mStateHelper->setActive(mTokenTypeAllPosts, true); if (useThread()) { /* Create fill thread */ @@ -321,15 +321,15 @@ void GxsMessageFramePostWidget::loadPosts(const uint32_t &token) connect(mFillThread, SIGNAL(addPost(QVariant,bool,int,int)), this, SLOT(fillThreadAddPost(QVariant,bool,int,int)), Qt::BlockingQueuedConnection); #ifdef ENABLE_DEBUG - std::cerr << "GxsMessageFramePostWidget::loadPosts() Start fill thread" << std::endl; + std::cerr << "GxsMessageFramePostWidget::loadAllPosts() Start fill thread" << std::endl; #endif /* Start thread */ mFillThread->start(); } else { - insertPosts(token, NULL); + insertAllPosts(token, NULL); - mStateHelper->setLoading(mTokenTypePosts, false); + mStateHelper->setLoading(mTokenTypeAllPosts, false); if (!mNavigatePendingMsgId.isNull()) { navigate(mNavigatePendingMsgId); @@ -341,21 +341,21 @@ void GxsMessageFramePostWidget::loadPosts(const uint32_t &token) emit groupChanged(this); } -void GxsMessageFramePostWidget::requestRelatedPosts(const std::vector &msgIds) +void GxsMessageFramePostWidget::requestPosts(const std::vector &msgIds) { #ifdef ENABLE_DEBUG - std::cerr << "GxsMessageFramePostWidget::requestRelatedPosts()"; + std::cerr << "GxsMessageFramePostWidget::requestPosts()"; std::cerr << std::endl; #endif mNavigatePendingMsgId.clear(); - mTokenQueue->cancelActiveRequestTokens(mTokenTypeRelatedPosts); + mTokenQueue->cancelActiveRequestTokens(mTokenTypePosts); if (groupId().isNull()) { - mStateHelper->setActive(mTokenTypeRelatedPosts, false); - mStateHelper->setLoading(mTokenTypeRelatedPosts, false); - mStateHelper->clear(mTokenTypeRelatedPosts); + mStateHelper->setActive(mTokenTypePosts, false); + mStateHelper->setLoading(mTokenTypePosts, false); + mStateHelper->clear(mTokenTypePosts); emit groupChanged(this); return; } @@ -364,33 +364,30 @@ void GxsMessageFramePostWidget::requestRelatedPosts(const std::vectorsetLoading(mTokenTypeRelatedPosts, true); + mStateHelper->setLoading(mTokenTypePosts, true); emit groupChanged(this); RsTokReqOptions opts; - opts.mReqType = GXS_REQUEST_TYPE_MSG_RELATED_DATA; - opts.mOptions = RS_TOKREQOPT_MSG_VERSIONS; + opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; uint32_t token; - std::vector relatedMsgIds; - for (std::vector::const_iterator msgIt = msgIds.begin(); msgIt != msgIds.end(); ++msgIt) { - relatedMsgIds.push_back(RsGxsGrpMsgIdPair(groupId(), *msgIt)); - } - mTokenQueue->requestMsgRelatedInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, relatedMsgIds, mTokenTypeRelatedPosts); + GxsMsgReq requestMsgIds; + requestMsgIds[groupId()] = msgIds; + mTokenQueue->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, requestMsgIds, mTokenTypePosts); } -void GxsMessageFramePostWidget::loadRelatedPosts(const uint32_t &token) +void GxsMessageFramePostWidget::loadPosts(const uint32_t &token) { #ifdef ENABLE_DEBUG - std::cerr << "GxsMessageFramePostWidget::loadRelatedPosts()"; + std::cerr << "GxsMessageFramePostWidget::loadPosts()"; std::cerr << std::endl; #endif - mStateHelper->setActive(mTokenTypeRelatedPosts, true); + mStateHelper->setActive(mTokenTypePosts, true); - insertRelatedPosts(token); + insertPosts(token); - mStateHelper->setLoading(mTokenTypeRelatedPosts, false); + mStateHelper->setLoading(mTokenTypePosts, false); emit groupChanged(this); if (!mNavigatePendingMsgId.isNull()) { @@ -414,13 +411,13 @@ void GxsMessageFramePostWidget::loadRequest(const TokenQueue *queue, const Token return; } - if (req.mUserType == mTokenTypePosts) { - loadPosts(req.mToken); + if (req.mUserType == mTokenTypeAllPosts) { + loadAllPosts(req.mToken); return; } - if (req.mUserType == mTokenTypeRelatedPosts) { - loadRelatedPosts(req.mToken); + if (req.mUserType == mTokenTypePosts) { + loadPosts(req.mToken); return; } } @@ -465,7 +462,7 @@ void GxsMessageFramePostThread::run() std::cerr << "GxsMessageFramePostThread::run()" << std::endl; #endif - mParent->insertPosts(mToken, this); + mParent->insertAllPosts(mToken, this); #ifdef ENABLE_DEBUG std::cerr << "GxsMessageFramePostThread::run() stopped: " << (stopped() ? "yes" : "no") << std::endl; diff --git a/retroshare-gui/src/gui/gxs/GxsMessageFramePostWidget.h b/retroshare-gui/src/gui/gxs/GxsMessageFramePostWidget.h index 2b9e54fa1..d01a0ca42 100644 --- a/retroshare-gui/src/gui/gxs/GxsMessageFramePostWidget.h +++ b/retroshare-gui/src/gui/gxs/GxsMessageFramePostWidget.h @@ -68,13 +68,13 @@ protected: void loadGroupData(const uint32_t &token); virtual bool insertGroupData(const uint32_t &token, RsGroupMetaData &metaData) = 0; - void requestPosts(); - void loadPosts(const uint32_t &token); - virtual void insertPosts(const uint32_t &token, GxsMessageFramePostThread *thread) = 0; + void requestAllPosts(); + void loadAllPosts(const uint32_t &token); + virtual void insertAllPosts(const uint32_t &token, GxsMessageFramePostThread *thread) = 0; - void requestRelatedPosts(const std::vector &msgIds); - void loadRelatedPosts(const uint32_t &token); - virtual void insertRelatedPosts(const uint32_t &token) = 0; + void requestPosts(const std::vector &msgIds); + void loadPosts(const uint32_t &token); + virtual void insertPosts(const uint32_t &token) = 0; private slots: void fillThreadFinished(); @@ -82,8 +82,8 @@ private slots: protected: uint32_t mTokenTypeGroupData; + uint32_t mTokenTypeAllPosts; uint32_t mTokenTypePosts; - uint32_t mTokenTypeRelatedPosts; RsGxsMessageId mNavigatePendingMsgId; private: diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp index bf9ef2fdd..e6ddc8b8a 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.cpp @@ -55,11 +55,11 @@ GxsChannelPostsWidget::GxsChannelPostsWidget(const RsGxsGroupId &channelId, QWid /* Setup UI helper */ - mStateHelper->addWidget(mTokenTypePosts, ui->progressBar, UISTATE_LOADING_VISIBLE); - mStateHelper->addWidget(mTokenTypePosts, ui->loadingLabel, UISTATE_LOADING_VISIBLE); - mStateHelper->addWidget(mTokenTypePosts, ui->filterLineEdit); + mStateHelper->addWidget(mTokenTypeAllPosts, ui->progressBar, UISTATE_LOADING_VISIBLE); + mStateHelper->addWidget(mTokenTypeAllPosts, ui->loadingLabel, UISTATE_LOADING_VISIBLE); + mStateHelper->addWidget(mTokenTypeAllPosts, ui->filterLineEdit); - mStateHelper->addWidget(mTokenTypeRelatedPosts, ui->loadingLabel, UISTATE_LOADING_VISIBLE); + mStateHelper->addWidget(mTokenTypePosts, ui->loadingLabel, UISTATE_LOADING_VISIBLE); mStateHelper->addLoadPlaceholder(mTokenTypeGroupData, ui->nameLabel); @@ -175,7 +175,7 @@ void GxsChannelPostsWidget::groupNameChanged(const QString &name) QIcon GxsChannelPostsWidget::groupIcon() { - if (mStateHelper->isLoading(mTokenTypeGroupData) || mStateHelper->isLoading(mTokenTypePosts)) { + if (mStateHelper->isLoading(mTokenTypeGroupData) || mStateHelper->isLoading(mTokenTypeAllPosts)) { return QIcon(":/images/kalarm.png"); } @@ -488,7 +488,7 @@ bool GxsChannelPostsWidget::insertGroupData(const uint32_t &token, RsGroupMetaDa return false; } -void GxsChannelPostsWidget::insertPosts(const uint32_t &token, GxsMessageFramePostThread *thread) +void GxsChannelPostsWidget::insertAllPosts(const uint32_t &token, GxsMessageFramePostThread *thread) { std::vector posts; rsGxsChannels->getPostData(token, posts); @@ -496,10 +496,10 @@ void GxsChannelPostsWidget::insertPosts(const uint32_t &token, GxsMessageFramePo insertChannelPosts(posts, thread, false); } -void GxsChannelPostsWidget::insertRelatedPosts(const uint32_t &token) +void GxsChannelPostsWidget::insertPosts(const uint32_t &token) { std::vector posts; - rsGxsChannels->getRelatedPosts(token, posts); + rsGxsChannels->getPostData(token, posts); insertChannelPosts(posts, NULL, true); } diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h index eb537f3f0..541fcc506 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsWidget.h @@ -67,8 +67,8 @@ protected: /* GxsMessageFramePostWidget */ virtual void groupNameChanged(const QString &name); virtual bool insertGroupData(const uint32_t &token, RsGroupMetaData &metaData); - virtual void insertPosts(const uint32_t &token, GxsMessageFramePostThread *thread); - virtual void insertRelatedPosts(const uint32_t &token); + virtual void insertAllPosts(const uint32_t &token, GxsMessageFramePostThread *thread); + virtual void insertPosts(const uint32_t &token); virtual void clearPosts(); virtual bool useThread() { return mUseThread; } virtual void fillThreadCreatePost(const QVariant &post, bool related, int current, int count); From 0402e53f15a6ebafa5ce3f3640283f2d75c235c5 Mon Sep 17 00:00:00 2001 From: hunbernd Date: Tue, 14 Jul 2015 22:41:11 +0200 Subject: [PATCH 048/165] Fix: empty line duplication bug to reproduce: hit: ab the result will be: a


b the empty line is two lines high --- retroshare-gui/src/util/HandleRichText.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/util/HandleRichText.cpp b/retroshare-gui/src/util/HandleRichText.cpp index edfef3a80..1f2c35354 100644 --- a/retroshare-gui/src/util/HandleRichText.cpp +++ b/retroshare-gui/src/util/HandleRichText.cpp @@ -681,7 +681,8 @@ static void optimizeHtml(QDomDocument& doc, QDomElement& currentElement, unsigne // remove Qt standard

or empty

index += element.childNodes().length(); removeElement(currentElement, element); - addBR = true; + // do not add extra
after empty paragraph, the paragraph already contains one + addBR = ! style.startsWith("-qt-paragraph-type:empty"); continue; } From 3084d2a5ee41db5e5dade5e5b59761a6dbce14e5 Mon Sep 17 00:00:00 2001 From: csoler Date: Thu, 13 Aug 2015 21:49:57 -0400 Subject: [PATCH 049/165] improved security message in console for whitelisted peers --- libretroshare/src/pqi/pqissl.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libretroshare/src/pqi/pqissl.cc b/libretroshare/src/pqi/pqissl.cc index 083e4a047..12f54f87a 100644 --- a/libretroshare/src/pqi/pqissl.cc +++ b/libretroshare/src/pqi/pqissl.cc @@ -1322,7 +1322,9 @@ int pqissl::Authorise_SSL_Connection() if(!rsBanList->isAddressAccepted(remote_addr,checking_flags,&check_result)) { - std::cerr << "(SS) connection attempt from banned IP address " << sockaddr_storage_iptostring(remote_addr) << ". Refusing it. Reason: " << check_result << ". Attack??" << std::endl; + std::cerr << "(SS) refusing connection attempt from IP address " << sockaddr_storage_iptostring(remote_addr) << ". Reason: " << + ((check_result == RSBANLIST_CHECK_RESULT_NOT_WHITELISTED)?"not whitelisted (peer requires whitelist)":"blacklisted") << std::endl; + RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_IP_BLACKLISTED, PeerId().toStdString(), sockaddr_storage_iptostring(remote_addr), "", "", check_result); reset_locked(); return 0 ; From 384e7ba0357ad5e73005d2a2966c5fc83774a32e Mon Sep 17 00:00:00 2001 From: thunder2 Date: Thu, 13 Aug 2015 19:44:27 +0200 Subject: [PATCH 050/165] Reworked processing of requests in RsGxsDataAccess to prevent freezes of the gui. --- libretroshare/src/gxs/rsgxsdataaccess.cc | 246 ++++++++++-------- libretroshare/src/retroshare/rstokenservice.h | 1 + 2 files changed, 145 insertions(+), 102 deletions(-) diff --git a/libretroshare/src/gxs/rsgxsdataaccess.cc b/libretroshare/src/gxs/rsgxsdataaccess.cc index 55c4de7d6..e1c922d61 100644 --- a/libretroshare/src/gxs/rsgxsdataaccess.cc +++ b/libretroshare/src/gxs/rsgxsdataaccess.cc @@ -59,7 +59,7 @@ const uint8_t RsTokenService::GXS_REQUEST_V2_STATUS_FINISHED_INCOMPLETE = 3; const uint8_t RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE = 4; const uint8_t RsTokenService::GXS_REQUEST_V2_STATUS_DONE = 5; // ONCE ALL DATA RETRIEVED. - + const uint8_t RsTokenService::GXS_REQUEST_V2_STATUS_CANCELLED = 6; /*********** * #define DATA_DEBUG 1 @@ -367,13 +367,19 @@ uint32_t RsGxsDataAccess::requestStatus(uint32_t token) return status; } - - - - bool RsGxsDataAccess::cancelRequest(const uint32_t& token) { - return clearRequest(token); + RsStackMutex stack(mDataMutex); /****** LOCKED *****/ + + GxsRequest* req = locked_retrieveRequest(token); + if (!req) + { + return false; + } + + req->status = GXS_REQUEST_V2_STATUS_CANCELLED; + + return true; } bool RsGxsDataAccess::clearRequest(const uint32_t& token) @@ -389,7 +395,7 @@ bool RsGxsDataAccess::clearRequest(const uint32_t& token) } delete it->second; - mRequests.erase(it->first); + mRequests.erase(it); return true; } @@ -707,7 +713,6 @@ bool RsGxsDataAccess::getGroupList(const uint32_t& token, std::list toClear; - std::list::iterator cit; time_t now = time(NULL); + std::map::iterator it; { RsStackMutex stack(mDataMutex); /******* LOCKED *******/ - std::map::iterator it; + // process status of the requests + for (it = mRequests.begin(); it != mRequests.end(); ++it) + { + GxsRequest* req = it->second; + + switch (req->status) + { + case GXS_REQUEST_V2_STATUS_PENDING: + // process request later + break; + case GXS_REQUEST_V2_STATUS_PARTIAL: + // should not happen + req->status = GXS_REQUEST_V2_STATUS_COMPLETE; + break; + case GXS_REQUEST_V2_STATUS_DONE: +#ifdef DATA_DEBUG + std::cerr << "RsGxsDataAccess::processrequests() Clearing Done Request Token: " << req->token; + std::cerr << std::endl; +#endif + toClear.push_back(req->token); + break; + case GXS_REQUEST_V2_STATUS_CANCELLED: +#ifdef DATA_DEBUG + std::cerr << "RsGxsDataAccess::processrequests() Clearing Cancelled Request Token: " << req->token; + std::cerr << std::endl; +#endif + toClear.push_back(req->token); + break; + default: + if (now - req->reqTime > MAX_REQUEST_AGE) + { +#ifdef DATA_DEBUG + std::cerr << "RsGxsDataAccess::processrequests() Clearing Old Request Token: " << req->token; + std::cerr << std::endl; +#endif + toClear.push_back(req->token); + } + } + } + } // END OF MUTEX. + + // clear requests + std::list::iterator cit; + for (cit = toClear.begin(); cit != toClear.end(); ++cit) + { + clearRequest(*cit); + } + + // process requests + while (true) + { + GxsRequest* req = NULL; + { + RsStackMutex stack(mDataMutex); /******* LOCKED *******/ + + // get the first pending request + for (it = mRequests.begin(); it != mRequests.end(); ++it) + { + GxsRequest* reqCheck = it->second; + if (reqCheck->status == GXS_REQUEST_V2_STATUS_PENDING) + { + req = reqCheck; + req->status = GXS_REQUEST_V2_STATUS_PARTIAL; + break; + } + } + } // END OF MUTEX. + + if (!req) { + break; + } GroupMetaReq* gmr; GroupDataReq* gdr; @@ -739,101 +813,69 @@ void RsGxsDataAccess::processRequests() MsgMetaReq* mmr; MsgDataReq* mdr; MsgIdReq* mir; - MsgRelatedInfoReq* mri; - GroupStatisticRequest* gsr; - ServiceStatisticRequest* ssr; + MsgRelatedInfoReq* mri; + GroupStatisticRequest* gsr; + ServiceStatisticRequest* ssr; - for(it = mRequests.begin(); it != mRequests.end(); ++it) +#ifdef DATA_DEBUG + std::cerr << "RsGxsDataAccess::processRequests() Processing Token: " << req->token << " Status: " + << req->status << " ReqType: " << req->reqType << " Age: " + << now - req->reqTime << std::endl; +#endif + + /* PROCESS REQUEST! */ + bool ok = false; + + if((gmr = dynamic_cast(req)) != NULL) { - - GxsRequest* req = it->second; - if (req->status == GXS_REQUEST_V2_STATUS_PENDING) - { -#ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::processRequests() Processing Token: " << req->token << " Status: " - << req->status << " ReqType: " << req->reqType << " Age: " - << now - req->reqTime << std::endl; -#endif - - req->status = GXS_REQUEST_V2_STATUS_PARTIAL; - - /* PROCESS REQUEST! */ - - if((gmr = dynamic_cast(req)) != NULL) - { - getGroupSummary(gmr); - } - else if((gdr = dynamic_cast(req)) != NULL) - { - getGroupData(gdr); - } - else if((gir = dynamic_cast(req)) != NULL) - { - getGroupList(gir); - } - else if((mmr = dynamic_cast(req)) != NULL) - { - getMsgSummary(mmr); - } - else if((mdr = dynamic_cast(req)) != NULL) - { - getMsgData(mdr); - } - else if((mir = dynamic_cast(req)) != NULL) - { - getMsgList(mir); - } - else if((mri = dynamic_cast(req)) != NULL) - { - getMsgRelatedInfo(mri); - } - else if((gsr = dynamic_cast(req)) != NULL) - { - getGroupStatistic(gsr); - } - else if((ssr = dynamic_cast(req)) != NULL) - { - getServiceStatistic(ssr); - } - else - { - std::cerr << "RsGxsDataAccess::processRequests() Failed to process request, token: " - << req->token << std::endl; - - req->status = GXS_REQUEST_V2_STATUS_FAILED; - } - } - else if (req->status == GXS_REQUEST_V2_STATUS_PARTIAL) - { - req->status = GXS_REQUEST_V2_STATUS_COMPLETE; - } - else if (req->status == GXS_REQUEST_V2_STATUS_DONE) - { -#ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::processrequests() Clearing Done Request Token: " - << req->token; - std::cerr << std::endl; -#endif - toClear.push_back(req->token); - } - else if (now - req->reqTime > MAX_REQUEST_AGE) - { -#ifdef DATA_DEBUG - std::cerr << "RsGxsDataAccess::processrequests() Clearing Old Request Token: " << req->token; - std::cerr << std::endl; -#endif - toClear.push_back(req->token); - } + ok = getGroupSummary(gmr); + } + else if((gdr = dynamic_cast(req)) != NULL) + { + ok = getGroupData(gdr); + } + else if((gir = dynamic_cast(req)) != NULL) + { + ok = getGroupList(gir); + } + else if((mmr = dynamic_cast(req)) != NULL) + { + ok = getMsgSummary(mmr); + } + else if((mdr = dynamic_cast(req)) != NULL) + { + ok = getMsgData(mdr); + } + else if((mir = dynamic_cast(req)) != NULL) + { + ok = getMsgList(mir); + } + else if((mri = dynamic_cast(req)) != NULL) + { + ok = getMsgRelatedInfo(mri); + } + else if((gsr = dynamic_cast(req)) != NULL) + { + ok = getGroupStatistic(gsr); + } + else if((ssr = dynamic_cast(req)) != NULL) + { + ok = getServiceStatistic(ssr); + } + else + { + std::cerr << "RsGxsDataAccess::processRequests() Failed to process request, token: " + << req->token << std::endl; } - } // END OF MUTEX. - - for(cit = toClear.begin(); cit != toClear.end(); ++cit) - { - clearRequest(*cit); + { + RsStackMutex stack(mDataMutex); /******* LOCKED *******/ + if (req->status == GXS_REQUEST_V2_STATUS_PARTIAL) + { + req->status = ok ? GXS_REQUEST_V2_STATUS_COMPLETE : GXS_REQUEST_V2_STATUS_FAILED; + } + } // END OF MUTEX. } - - return; } bool RsGxsDataAccess::getGroupStatistic(const uint32_t &token, GxsGroupStatistic &grpStatistic) @@ -1719,7 +1761,7 @@ bool RsGxsDataAccess::checkRequestStatus(const uint32_t& token, GxsRequest* req = locked_retrieveRequest(token); - if(req == NULL) + if (req == NULL || req->status == GXS_REQUEST_V2_STATUS_CANCELLED) return false; anstype = req->ansType; diff --git a/libretroshare/src/retroshare/rstokenservice.h b/libretroshare/src/retroshare/rstokenservice.h index 97f406222..954148359 100644 --- a/libretroshare/src/retroshare/rstokenservice.h +++ b/libretroshare/src/retroshare/rstokenservice.h @@ -121,6 +121,7 @@ public: static const uint8_t GXS_REQUEST_V2_STATUS_FINISHED_INCOMPLETE; static const uint8_t GXS_REQUEST_V2_STATUS_COMPLETE; static const uint8_t GXS_REQUEST_V2_STATUS_DONE; // ONCE ALL DATA RETRIEVED. + static const uint8_t GXS_REQUEST_V2_STATUS_CANCELLED; public: From cd97fd9682aebb365bfd808693f8a23a12923739 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 14 Aug 2015 16:44:20 -0400 Subject: [PATCH 051/165] refactored video processing classes, to allow multiple codecs. Not working yet. --- plugins/VOIP/gui/AudioInputConfig.cpp | 50 +++--- plugins/VOIP/gui/AudioInputConfig.h | 2 +- plugins/VOIP/gui/QVideoDevice.cpp | 10 +- plugins/VOIP/gui/QVideoDevice.h | 5 +- plugins/VOIP/gui/VOIPChatWidgetHolder.cpp | 80 +++++---- plugins/VOIP/gui/VOIPChatWidgetHolder.h | 6 +- plugins/VOIP/gui/VideoProcessor.cpp | 200 ++++++++++++++-------- plugins/VOIP/gui/VideoProcessor.h | 168 +++++++++--------- 8 files changed, 284 insertions(+), 237 deletions(-) diff --git a/plugins/VOIP/gui/AudioInputConfig.cpp b/plugins/VOIP/gui/AudioInputConfig.cpp index 29a27026a..5f6aacfb8 100644 --- a/plugins/VOIP/gui/AudioInputConfig.cpp +++ b/plugins/VOIP/gui/AudioInputConfig.cpp @@ -34,6 +34,7 @@ #include "AudioInputConfig.h" #include "audiodevicehelper.h" #include "AudioWizard.h" +#include "gui/VideoProcessor.h" #include "gui/common/RSGraphWidget.h" #include "util/RsProtectedTimer.h" @@ -99,35 +100,36 @@ voipGraph::voipGraph(QWidget *parent) AudioInputConfig::AudioInputConfig(QWidget * parent, Qt::WindowFlags flags) : ConfigPage(parent, flags) { - std::cerr << "Creating audioInputConfig object" << std::endl; + std::cerr << "Creating audioInputConfig object" << std::endl; - /* Invoke the Qt Designer generated object setup routine */ - ui.setupUi(this); + /* Invoke the Qt Designer generated object setup routine */ + ui.setupUi(this); - loaded = false; + loaded = false; - inputAudioProcessor = NULL; - inputAudioDevice = NULL; - abSpeech = NULL; - qtTick = NULL; + inputAudioProcessor = NULL; + inputAudioDevice = NULL; + abSpeech = NULL; + qtTick = NULL; - // Create the video pipeline. - // - videoInput = new QVideoInputDevice(this) ; - videoInput->setEchoVideoTarget(ui.videoDisplay) ; - videoInput->setVideoEncoder(new JPEGVideoEncoder()) ; + // Create the video pipeline. + // + videoInput = new QVideoInputDevice(this) ; + videoInput->setEchoVideoTarget(ui.videoDisplay) ; - videoDecoder = new JPEGVideoDecoder; - videoDecoder->setDisplayTarget(NULL) ; + videoProcessor = new VideoProcessor() ; + videoProcessor->setDisplayTarget(NULL) ; - graph_source = new voipGraphSource ; - ui.voipBwGraph->setSource(graph_source); + videoInput->setVideoProcessor(videoProcessor) ; - graph_source->setVideoInput(videoInput) ; - graph_source->setCollectionTimeLimit(1000*300) ; - graph_source->start() ; + graph_source = new voipGraphSource ; + ui.voipBwGraph->setSource(graph_source); - QObject::connect(ui.showEncoded_CB,SIGNAL(toggled(bool)),this,SLOT(togglePreview(bool))) ; + graph_source->setVideoInput(videoInput) ; + graph_source->setCollectionTimeLimit(1000*300) ; + graph_source->start() ; + + QObject::connect(ui.showEncoded_CB,SIGNAL(toggled(bool)),this,SLOT(togglePreview(bool))) ; } void AudioInputConfig::togglePreview(bool b) @@ -135,12 +137,12 @@ void AudioInputConfig::togglePreview(bool b) if(b) { videoInput->setEchoVideoTarget(NULL) ; - videoDecoder->setDisplayTarget(ui.videoDisplay) ; + videoProcessor->setDisplayTarget(ui.videoDisplay) ; } else { videoInput->setEchoVideoTarget(ui.videoDisplay) ; - videoDecoder->setDisplayTarget(NULL) ; + videoProcessor->setDisplayTarget(NULL) ; } } @@ -367,7 +369,7 @@ void AudioInputConfig::on_Tick_timeout() { while(videoInput->getNextEncodedPacket(chunk)) { - videoDecoder->receiveEncodedData(static_cast(chunk.data),chunk.size) ; + videoProcessor->receiveEncodedData(chunk) ; chunk.clear() ; } } diff --git a/plugins/VOIP/gui/AudioInputConfig.h b/plugins/VOIP/gui/AudioInputConfig.h index faaadb63e..e838744b4 100644 --- a/plugins/VOIP/gui/AudioInputConfig.h +++ b/plugins/VOIP/gui/AudioInputConfig.h @@ -69,7 +69,7 @@ class AudioInputConfig : public ConfigPage //VideoDecoder *videoDecoder ; //VideoEncoder *videoEncoder ; QVideoInputDevice *videoInput ; - VideoDecoder *videoDecoder ; + VideoProcessor *videoProcessor ; bool loaded; voipGraphSource *graph_source ; diff --git a/plugins/VOIP/gui/QVideoDevice.cpp b/plugins/VOIP/gui/QVideoDevice.cpp index 3a7ee029e..e9ace94f9 100644 --- a/plugins/VOIP/gui/QVideoDevice.cpp +++ b/plugins/VOIP/gui/QVideoDevice.cpp @@ -11,7 +11,7 @@ QVideoInputDevice::QVideoInputDevice(QWidget *parent) { _timer = NULL ; _capture_device = NULL ; - _video_encoder = NULL ; + _video_processor = NULL ; _echo_output_device = NULL ; _estimated_bw = 0 ; _total_encoded_size = 0 ; @@ -78,11 +78,11 @@ void QVideoInputDevice::grabFrame() QImage image = QImage(img_rgb.data,img_rgb.cols,img_rgb.rows,QImage::Format_RGB888); - if(_video_encoder != NULL) + if(_video_processor != NULL) { uint32_t encoded_size ; - _video_encoder->addImage(image,0,encoded_size) ; + _video_processor->processImage(image,0,encoded_size) ; std::cerr << "Encoded size = " << encoded_size << std::endl; _total_encoded_size += encoded_size ; @@ -107,8 +107,8 @@ void QVideoInputDevice::grabFrame() bool QVideoInputDevice::getNextEncodedPacket(RsVOIPDataChunk& chunk) { - if(_video_encoder) - return _video_encoder->nextPacket(chunk) ; + if(_video_processor) + return _video_processor->nextEncodedPacket(chunk) ; else return false ; } diff --git a/plugins/VOIP/gui/QVideoDevice.h b/plugins/VOIP/gui/QVideoDevice.h index 513932487..d12fe5f38 100644 --- a/plugins/VOIP/gui/QVideoDevice.h +++ b/plugins/VOIP/gui/QVideoDevice.h @@ -2,6 +2,7 @@ #include #include "interface/rsVOIP.h" +#include "gui/VideoProcessor.h" class VideoEncoder ; class CvCapture ; @@ -31,7 +32,7 @@ class QVideoInputDevice: public QObject // Captured images are sent to this encoder. Can be NULL. // - void setVideoEncoder(VideoEncoder *venc) { _video_encoder = venc ; } + void setVideoProcessor(VideoProcessor *venc) { _video_processor = venc ; } // All images received will be echoed to this target. We could use signal/slots, but it's // probably faster this way. Can be NULL. @@ -58,7 +59,7 @@ class QVideoInputDevice: public QObject void networkPacketReady() ; private: - VideoEncoder *_video_encoder ; + VideoProcessor *_video_processor ; QTimer *_timer ; CvCapture *_capture_device ; diff --git a/plugins/VOIP/gui/VOIPChatWidgetHolder.cpp b/plugins/VOIP/gui/VOIPChatWidgetHolder.cpp index 1d94960d7..4d1f8ff49 100644 --- a/plugins/VOIP/gui/VOIPChatWidgetHolder.cpp +++ b/plugins/VOIP/gui/VOIPChatWidgetHolder.cpp @@ -123,8 +123,7 @@ VOIPChatWidgetHolder::VOIPChatWidgetHolder(ChatWidget *chatWidget, VOIPNotify *n inputAudioDevice = NULL ; inputVideoDevice = new QVideoInputDevice(mChatWidget) ; // not started yet ;-) - inputVideoProcessor = new JPEGVideoEncoder ; - outputVideoProcessor = new JPEGVideoDecoder ; + videoProcessor = new VideoProcessor ; // Make a widget with two video devices, one for echo, and one for the talking peer. videoWidget = new QWidget(mChatWidget) ; @@ -144,8 +143,8 @@ VOIPChatWidgetHolder::VOIPChatWidgetHolder(ChatWidget *chatWidget, VOIPNotify *n mChatWidget->addChatHorizontalWidget(videoWidget) ; inputVideoDevice->setEchoVideoTarget(echoVideoDevice) ; - inputVideoDevice->setVideoEncoder(inputVideoProcessor) ; - outputVideoProcessor->setDisplayTarget(outputVideoDevice) ; + inputVideoDevice->setVideoProcessor(videoProcessor) ; + videoProcessor->setDisplayTarget(outputVideoDevice) ; } VOIPChatWidgetHolder::~VOIPChatWidgetHolder() @@ -154,8 +153,7 @@ VOIPChatWidgetHolder::~VOIPChatWidgetHolder() inputAudioDevice->stop() ; delete inputVideoDevice ; - delete inputVideoProcessor ; - delete outputVideoProcessor ; + delete videoProcessor ; button_map::iterator it = buttonMapTakeVideo.begin(); while (it != buttonMapTakeVideo.end()) { @@ -287,42 +285,50 @@ void VOIPChatWidgetHolder::toggleVideoCapture() void VOIPChatWidgetHolder::addVideoData(const RsPeerId &peer_id, QByteArray* array) { - if (!videoCaptureToggleButton->isChecked()) { - if (mChatWidget) { - QString buttonName = QString::fromUtf8(rsPeers->getPeerName(peer_id).c_str()); - if (buttonName.isEmpty()) buttonName = "VoIP";//TODO maybe change all with GxsId - button_map::iterator it = buttonMapTakeVideo.find(buttonName); - if (it == buttonMapTakeVideo.end()){ - mChatWidget->addChatMsg(true, tr("VoIP Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime() - , tr("%1 inviting you to start a video conversation. do you want Accept or Decline the invitation?").arg(buttonName), ChatWidget::MSGTYPE_SYSTEM); - RSButtonOnText *button = mChatWidget->getNewButtonOnTextBrowser(tr("Accept Video Call")); - button->setToolTip(tr("Activate camera")); - button->setStyleSheet(QString("border: 1px solid #199909;") - .append("font-size: 12pt; color: white;") - .append("min-width: 128px; min-height: 24px;") - .append("border-radius: 6px;") - .append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, " - "stop: 0 #22c70d, stop: 1 #116a06);") + if (!videoCaptureToggleButton->isChecked()) + { + if (mChatWidget) { + QString buttonName = QString::fromUtf8(rsPeers->getPeerName(peer_id).c_str()); + if (buttonName.isEmpty()) buttonName = "VoIP";//TODO maybe change all with GxsId + button_map::iterator it = buttonMapTakeVideo.find(buttonName); + if (it == buttonMapTakeVideo.end()){ + mChatWidget->addChatMsg(true, tr("VoIP Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime() + , tr("%1 inviting you to start a video conversation. do you want Accept or Decline the invitation?").arg(buttonName), ChatWidget::MSGTYPE_SYSTEM); + RSButtonOnText *button = mChatWidget->getNewButtonOnTextBrowser(tr("Accept Video Call")); + button->setToolTip(tr("Activate camera")); + button->setStyleSheet(QString("border: 1px solid #199909;") + .append("font-size: 12pt; color: white;") + .append("min-width: 128px; min-height: 24px;") + .append("border-radius: 6px;") + .append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, " + "stop: 0 #22c70d, stop: 1 #116a06);") - ); + ); - button->updateImage(); + button->updateImage(); - connect(button,SIGNAL(clicked()),this,SLOT(startVideoCapture())); - connect(button,SIGNAL(mouseEnter()),this,SLOT(botMouseEnter())); - connect(button,SIGNAL(mouseLeave()),this,SLOT(botMouseLeave())); + connect(button,SIGNAL(clicked()),this,SLOT(startVideoCapture())); + connect(button,SIGNAL(mouseEnter()),this,SLOT(botMouseEnter())); + connect(button,SIGNAL(mouseLeave()),this,SLOT(botMouseLeave())); - buttonMapTakeVideo.insert(buttonName, button); - } - } + buttonMapTakeVideo.insert(buttonName, button); + } + } - //TODO make a sound for the incoming call -// soundManager->play(VOIP_SOUND_INCOMING_CALL); - if (mVOIPNotify) mVOIPNotify->notifyReceivedVoipVideoCall(peer_id); + //TODO make a sound for the incoming call + // soundManager->play(VOIP_SOUND_INCOMING_CALL); + if (mVOIPNotify) mVOIPNotify->notifyReceivedVoipVideoCall(peer_id); - } else { - outputVideoProcessor->receiveEncodedData((unsigned char *)array->data(),array->size()) ; - } + } + else + { + RsVOIPDataChunk chunk ; + chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; + chunk.size = array->size() ; + chunk.data = array->data() ; + + videoProcessor->receiveEncodedData(chunk) ; + } } void VOIPChatWidgetHolder::botMouseEnter() @@ -359,7 +365,7 @@ void VOIPChatWidgetHolder::botMouseLeave() void VOIPChatWidgetHolder::setAcceptedBandwidth(uint32_t bytes_per_sec) { - inputVideoProcessor->setMaximumFrameRate(bytes_per_sec) ; + videoProcessor->setMaximumFrameRate(bytes_per_sec) ; } void VOIPChatWidgetHolder::addAudioData(const RsPeerId &peer_id, QByteArray* array) diff --git a/plugins/VOIP/gui/VOIPChatWidgetHolder.h b/plugins/VOIP/gui/VOIPChatWidgetHolder.h index 791a2dcf8..350f49f2c 100644 --- a/plugins/VOIP/gui/VOIPChatWidgetHolder.h +++ b/plugins/VOIP/gui/VOIPChatWidgetHolder.h @@ -34,8 +34,7 @@ class QAudioInput; class QAudioOutput; class QVideoInputDevice ; class QVideoOutputDevice ; -class VideoEncoder ; -class VideoDecoder ; +class VideoProcessor ; #define VOIP_SOUND_INCOMING_CALL "VOIP_incoming_call" @@ -82,8 +81,7 @@ protected: QWidget *videoWidget ; // pointer to call show/hide - VideoEncoder *inputVideoProcessor; - VideoDecoder *outputVideoProcessor; + VideoProcessor *videoProcessor; // Additional buttons to the chat bar QToolButton *audioListenToggleButton ; diff --git a/plugins/VOIP/gui/VideoProcessor.cpp b/plugins/VOIP/gui/VideoProcessor.cpp index b19ee03d0..b3d0a7c27 100644 --- a/plugins/VOIP/gui/VideoProcessor.cpp +++ b/plugins/VOIP/gui/VideoProcessor.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -7,127 +8,182 @@ #include "VideoProcessor.h" #include "QVideoDevice.h" -VideoDecoder::VideoDecoder() +VideoProcessor::VideoProcessor() + :_encoded_frame_size(256,256) { - _output_device = NULL ; + _decoded_output_device = NULL ; } -VideoEncoder::VideoEncoder() - :_frame_size(256,256) +bool VideoProcessor::processImage(const QImage& img,uint32_t size_hint,uint32_t& encoded_size) { + VideoCodec *codec ; + + switch(_encoding_current_codec) + { + case VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO: codec = &_jpeg_video_codec ; + break ; + case VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO: codec = &_ddwt_video_codec ; + break ; + default: + codec = NULL ; + } + + // std::cerr << "reducing to " << _frame_size.width() << " x " << _frame_size.height() << std::endl; + + void *data = NULL; + encoded_size = 0 ; + + if(codec) + { + RsVOIPDataChunk chunk ; + + codec->encodeData(img.scaled(_encoded_frame_size,Qt::IgnoreAspectRatio,Qt::SmoothTransformation),size_hint,chunk) ; + + if(chunk.size == 0) // the codec might be buffering the frame for compression reasons + return true ; + + _encoded_out_queue.push_back(chunk) ; + + return true ; + } + else + return false ; } -bool VideoEncoder::addImage(const QImage& img,uint32_t size_hint,uint32_t& encoded_size) +bool VideoProcessor::nextEncodedPacket(RsVOIPDataChunk& chunk) { -// std::cerr << "reducing to " << _frame_size.width() << " x " << _frame_size.height() << std::endl; - encodeData(img.scaled(_frame_size,Qt::IgnoreAspectRatio,Qt::SmoothTransformation),size_hint,encoded_size) ; - //encodeData(img,size_hint,encoded_size) ; - - return true ; -} - -bool VideoEncoder::nextPacket(RsVOIPDataChunk& chunk) -{ - if(_out_queue.empty()) + if(_encoded_out_queue.empty()) return false ; - chunk = _out_queue.front() ; - _out_queue.pop_front() ; + chunk = _encoded_out_queue.front() ; + _encoded_out_queue.pop_front() ; return true ; } -void VideoDecoder::receiveEncodedData(const unsigned char *data,uint32_t size) +void VideoProcessor::setInternalFrameSize(QSize s) { - if(_output_device) - _output_device->showFrame(decodeData(data,size)) ; + _encoded_frame_size = s ; } -QImage JPEGVideoDecoder::decodeData(const unsigned char *encoded_image_data,uint32_t size) +void VideoProcessor::receiveEncodedData(const RsVOIPDataChunk& chunk) { static const int HEADER_SIZE = 4 ; // read frame type. Use first 4 bytes to give info about content. + // + // Byte Meaning Values + // 00 Codec CODEC_ID_JPEG_VIDEO Basic Jpeg codec + // CODEC_ID_DDWT_VIDEO Differential wavelet compression + // + // 01 Unused Might be useful later + // + // 0203 Flags Codec specific flags. + // - if(size < HEADER_SIZE) + if(chunk.size < HEADER_SIZE) { - std::cerr << "JPEGVideoDecoder::decodeData(): Too small a data packet. size=" << size << std::endl; - return QImage() ; + std::cerr << "JPEGVideoDecoder::decodeData(): Too small a data packet. size=" << chunk.size << std::endl; + return ; } - uint32_t flags = encoded_image_data[0] + (encoded_image_data[1] << 8) ; + uint32_t codid = ((unsigned char *)chunk.data)[0] + (((unsigned char *)chunk.data)[1] << 8) ; + uint16_t flags = ((unsigned char *)chunk.data)[2] + (((unsigned char *)chunk.data)[3] << 8) ; - // un-compress image data + VideoCodec *codec ; - QByteArray qb((char*)&encoded_image_data[HEADER_SIZE],(int)size - HEADER_SIZE) ; - QImage image ; - if(!image.loadFromData(qb,"JPEG")) + switch(codid) { - std::cerr << "image.loadFromData(): returned an error.: " << std::endl; - return QImage() ; + case VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO: codec = &_jpeg_video_codec ; + break ; + case VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO: codec = &_ddwt_video_codec ; + break ; + default: + codec = NULL ; } + QImage img ; - // now see if the frame is a differential frame, or just a reference frame. + if(codec != NULL) + codec->decodeData(chunk,img) ; - if(flags & JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME) - { - if(_reference_frame.size() != image.size()) - { - std::cerr << "Bad reference frame!" << std::endl; - return image ; - } - - QImage res = _reference_frame ; - - for(uint32_t i=0;ishowFrame(img) ; } -void VideoEncoder::setMaximumFrameRate(uint32_t bytes_per_sec) +void VideoProcessor::setMaximumFrameRate(uint32_t bytes_per_sec) { std::cerr << "Video Encoder: maximum frame rate is set to " << bytes_per_sec << " Bps" << std::endl; } -void VideoEncoder::setInternalFrameSize(QSize s) -{ - _frame_size = s ; -} +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// -JPEGVideoEncoder::JPEGVideoEncoder() - : _ref_frame_max_distance(50),_ref_frame_count(50) +JPEGVideo::JPEGVideo() + : _encoded_ref_frame_max_distance(50),_encoded_ref_frame_count(50) { } -void JPEGVideoEncoder::encodeData(const QImage& image,uint32_t /* size_hint */,uint32_t& encoded_size) +bool JPEGVideo::decodeData(const RsVOIPDataChunk& chunk,QImage& image) +{ + // now see if the frame is a differential frame, or just a reference frame. + + uint16_t codec = ((unsigned char *)chunk.data)[0] + (((unsigned char *)chunk.data)[1] << 8) ; + uint16_t flags = ((unsigned char *)chunk.data)[2] + (((unsigned char *)chunk.data)[3] << 8) ; + + assert(codec == VideoProcessor::VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO) ; + + // un-compress image data + + QByteArray qb((char*)&((uint8_t*)chunk.data)[HEADER_SIZE],(int)chunk.size - HEADER_SIZE) ; + + if(!image.loadFromData(qb,"JPEG")) + { + std::cerr << "image.loadFromData(): returned an error.: " << std::endl; + return false ; + } + + + if(flags & JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME) + { + if(_decoded_reference_frame.size() != image.size()) + { + std::cerr << "Bad reference frame!" << std::endl; + return false ; + } + + QImage res = _decoded_reference_frame ; + + for(uint32_t i=0;i> 8) & 0xff ; - ((unsigned char *)voip_chunk.data)[2] = 0 ; - ((unsigned char *)voip_chunk.data)[3] = 0 ; + ((unsigned char *)voip_chunk.data)[0] = VideoProcessor::VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO & 0xff ; + ((unsigned char *)voip_chunk.data)[1] = (VideoProcessor::VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO >> 8) & 0xff ; + ((unsigned char *)voip_chunk.data)[2] = flags & 0xff ; + ((unsigned char *)voip_chunk.data)[3] = (flags >> 8) & 0xff ; memcpy(voip_chunk.data+HEADER_SIZE,qb.data(),qb.size()) ; + voip_chunk.size = HEADER_SIZE + qb.size() ; voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; - _out_queue.push_back(voip_chunk) ; - - encoded_size = voip_chunk.size ; + return true ; } diff --git a/plugins/VOIP/gui/VideoProcessor.h b/plugins/VOIP/gui/VideoProcessor.h index 42124b4f4..d103207af 100644 --- a/plugins/VOIP/gui/VideoProcessor.h +++ b/plugins/VOIP/gui/VideoProcessor.h @@ -6,58 +6,91 @@ class QVideoOutputDevice ; +class VideoCodec +{ +public: + virtual bool encodeData(const QImage& Image, uint32_t size_hint, RsVOIPDataChunk& chunk) = 0; + virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) = 0; +}; + +// Now derive various image encoding/decoding algorithms. +// + +class JPEGVideo: public VideoCodec +{ +public: + JPEGVideo() ; + +protected: + virtual bool encodeData(const QImage& Image, uint32_t size_hint, RsVOIPDataChunk& chunk) ; + virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) ; + + static const uint32_t HEADER_SIZE = 0x04 ; + static const uint32_t JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME = 0x0001 ; +private: + QImage _decoded_reference_frame ; + QImage _encoded_reference_frame ; + + uint32_t _encoded_ref_frame_max_distance ; // max distance between two reference frames. + uint32_t _encoded_ref_frame_count ; +}; + +class DifferentialWaveletVideo: public VideoCodec +{ +public: + DifferentialWaveletVideo() {} + +protected: + virtual bool encodeData(const QImage& Image, uint32_t size_hint, RsVOIPDataChunk& chunk) { return true ; } + virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) { return true ; } + +private: + QImage _last_reference_frame ; +}; + // This class decodes video from a stream. It keeps a queue of // decoded frame that needs to be retrieved using the getNextImage() method. // -class VideoDecoder +class VideoProcessor { public: - VideoDecoder() ; - virtual ~VideoDecoder() {} + VideoProcessor() ; + virtual ~VideoProcessor() {} + enum CodecId { + VIDEO_PROCESSOR_CODEC_ID_UNKNOWN = 0x0000, + VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO = 0x0001, + VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO = 0x0002 + }; + +// ===================================================================================== +// =------------------------------------ DECODING -------------------------------------= +// ===================================================================================== + // Gets the next image to be displayed. Once returned, the image should // be cleared from the incoming queue. // - void setDisplayTarget(QVideoOutputDevice *odev) { _output_device = odev ; } - - virtual void receiveEncodedData(const unsigned char *data,uint32_t size) ; + void setDisplayTarget(QVideoOutputDevice *odev) { _decoded_output_device = odev ; } + virtual void receiveEncodedData(const RsVOIPDataChunk& chunk) ; // returns the current (measured) frame rate in bytes per second. // - uint32_t currentFrameRate() const; + uint32_t currentDecodingFrameRate() const; private: - QVideoOutputDevice *_output_device ; + QVideoOutputDevice *_decoded_output_device ; + std::list _decoded_image_queue ; - std::list _image_queue ; - - // Incoming data is processed by a video codec and converted into images. - // - virtual QImage decodeData(const unsigned char *encoded_image,uint32_t encoded_image_size) = 0 ; - -// // This buffer accumulated incoming encoded data, until a full packet is obtained, -// // since the stream might not send images at once. When incoming images are decoded, the -// // data is removed from the buffer. -// // -// unsigned char *buffer ; -// uint32_t buffer_size ; -}; - -// This class encodes video using a video codec (possibly homemade, or based on existing codecs) -// and produces a data stream that is sent to the network transfer service (e.g. p3VOIP). -// -class VideoEncoder -{ +// ===================================================================================== +// =------------------------------------ ENCODING -------------------------------------= +// ===================================================================================== + public: - VideoEncoder() ; - virtual ~VideoEncoder() {} - // Takes the next image to be encoded. // - bool addImage(const QImage& Image, uint32_t size_hint, uint32_t &encoded_size) ; - - bool packetReady() const { return !_out_queue.empty() ; } - bool nextPacket(RsVOIPDataChunk& ) ; + bool processImage(const QImage& Image, uint32_t size_hint, uint32_t &encoded_size) ; + bool encodedPacketReady() const { return !_encoded_out_queue.empty() ; } + bool nextEncodedPacket(RsVOIPDataChunk& ) ; // Used to tweak the compression ratio so that the video can stream ok. // @@ -65,63 +98,16 @@ class VideoEncoder void setInternalFrameSize(QSize) ; protected: - virtual void encodeData(const QImage& Image, uint32_t size_hint, uint32_t &encoded_size) =0; - - std::list _out_queue ; + std::list _encoded_out_queue ; + QSize _encoded_frame_size ; + +// ===================================================================================== +// =------------------------------------- Codecs --------------------------------------= +// ===================================================================================== - QSize _frame_size ; + JPEGVideo _jpeg_video_codec ; + DifferentialWaveletVideo _ddwt_video_codec ; + + uint16_t _encoding_current_codec ; }; -// Now derive various image encoding/decoding algorithms. -// - -class JPEGVideoDecoder: public VideoDecoder -{ -protected: - virtual QImage decodeData(const unsigned char *encoded_image,uint32_t encoded_image_size) ; - - static const uint32_t HEADER_SIZE = 0x04 ; - - static const uint32_t JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME = 0x0001 ; -private: - QImage _reference_frame ; -}; - -class JPEGVideoEncoder: public VideoEncoder -{ -public: - JPEGVideoEncoder() ; - -protected: - virtual void encodeData(const QImage& Image, uint32_t size_hint, uint32_t &encoded_size) ; - - static const uint32_t HEADER_SIZE = 0x04 ; - - static const uint32_t JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME = 0x0001 ; -private: - QImage _reference_frame ; - uint32_t _ref_frame_max_distance ; // max distance between two reference frames. - uint32_t _ref_frame_count ; -}; - -class DifferentialWaveletEncoder: public VideoEncoder -{ -public: - DifferentialWaveletEncoder() {} - -protected: - virtual void encodeData(const QImage& Image, uint32_t size_hint, uint32_t &encoded_size) ; - -}; - -class DifferentialWaveletDecoder: public VideoDecoder -{ -public: - DifferentialWaveletDecoder() {} - -protected: - virtual QImage decodeData(const unsigned char *encoded_image,uint32_t encoded_image_size) ; - -private: - QImage _last_reference_frame ; -}; From 5aac92fc97bf976a954d5381f4bce168b2015ff7 Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 14 Aug 2015 20:15:44 -0400 Subject: [PATCH 052/165] fixed bug in differential frame encoding --- plugins/VOIP/gui/VideoProcessor.cpp | 35 ++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/plugins/VOIP/gui/VideoProcessor.cpp b/plugins/VOIP/gui/VideoProcessor.cpp index b3d0a7c27..7a43058df 100644 --- a/plugins/VOIP/gui/VideoProcessor.cpp +++ b/plugins/VOIP/gui/VideoProcessor.cpp @@ -12,6 +12,7 @@ VideoProcessor::VideoProcessor() :_encoded_frame_size(256,256) { _decoded_output_device = NULL ; + _encoding_current_codec = VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO; } bool VideoProcessor::processImage(const QImage& img,uint32_t size_hint,uint32_t& encoded_size) @@ -47,7 +48,10 @@ bool VideoProcessor::processImage(const QImage& img,uint32_t size_hint,uint32_t& return true ; } else + { + std::cerr << "No codec for codec ID = " << _encoding_current_codec << ". Please call VideoProcessor::setCurrentCodec()" << std::endl; return false ; + } } bool VideoProcessor::nextEncodedPacket(RsVOIPDataChunk& chunk) @@ -120,7 +124,7 @@ void VideoProcessor::setMaximumFrameRate(uint32_t bytes_per_sec) ////////////////////////////////////////////////////////////////////////////////////////////////////////////// JPEGVideo::JPEGVideo() - : _encoded_ref_frame_max_distance(50),_encoded_ref_frame_count(50) + : _encoded_ref_frame_max_distance(10),_encoded_ref_frame_count(10) { } @@ -146,19 +150,25 @@ bool JPEGVideo::decodeData(const RsVOIPDataChunk& chunk,QImage& image) if(flags & JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME) { - if(_decoded_reference_frame.size() != image.size()) - { - std::cerr << "Bad reference frame!" << std::endl; - return false ; - } - + if(_decoded_reference_frame.size() != image.size()) + { + std::cerr << "Bad reference frame!" << std::endl; + return false ; + } + QImage res = _decoded_reference_frame ; for(uint32_t i=0;i Date: Fri, 14 Aug 2015 22:44:39 -0400 Subject: [PATCH 053/165] restored original params for JPEG codec --- plugins/VOIP/gui/VideoProcessor.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/plugins/VOIP/gui/VideoProcessor.cpp b/plugins/VOIP/gui/VideoProcessor.cpp index 7a43058df..4e1979a5d 100644 --- a/plugins/VOIP/gui/VideoProcessor.cpp +++ b/plugins/VOIP/gui/VideoProcessor.cpp @@ -9,7 +9,7 @@ #include "QVideoDevice.h" VideoProcessor::VideoProcessor() - :_encoded_frame_size(256,256) + :_encoded_frame_size(128,128) { _decoded_output_device = NULL ; _encoding_current_codec = VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO; @@ -40,6 +40,8 @@ bool VideoProcessor::processImage(const QImage& img,uint32_t size_hint,uint32_t& codec->encodeData(img.scaled(_encoded_frame_size,Qt::IgnoreAspectRatio,Qt::SmoothTransformation),size_hint,chunk) ; + encoded_size = chunk.size ; + if(chunk.size == 0) // the codec might be buffering the frame for compression reasons return true ; @@ -146,7 +148,6 @@ bool JPEGVideo::decodeData(const RsVOIPDataChunk& chunk,QImage& image) std::cerr << "image.loadFromData(): returned an error.: " << std::endl; return false ; } - if(flags & JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME) { @@ -187,6 +188,9 @@ bool JPEGVideo::encodeData(const QImage& image,uint32_t /* size_hint */,RsVOIPDa for(uint32_t i=0;i> 8) & 0xff ; ((unsigned char *)voip_chunk.data)[2] = flags & 0xff ; ((unsigned char *)voip_chunk.data)[3] = (flags >> 8) & 0xff ; - + memcpy(voip_chunk.data+HEADER_SIZE,qb.data(),qb.size()) ; - + voip_chunk.size = HEADER_SIZE + qb.size() ; voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; From 2e08dde32be689e33f755f944abcf12a3c223445 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 15 Aug 2015 10:09:16 -0400 Subject: [PATCH 054/165] additional check for pqissl::sockfd before using it (patch from Jenster) --- libretroshare/src/pqi/pqissl.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libretroshare/src/pqi/pqissl.cc b/libretroshare/src/pqi/pqissl.cc index 12f54f87a..de30910fb 100644 --- a/libretroshare/src/pqi/pqissl.cc +++ b/libretroshare/src/pqi/pqissl.cc @@ -1827,6 +1827,12 @@ bool pqissl::moretoread(uint32_t usec) } #endif + if(sockfd == -1) + { + std::cerr << "pqissl::moretoread(): socket is invalid or closed." << std::endl; + return 0 ; + } + fd_set ReadFDs, WriteFDs, ExceptFDs; FD_ZERO(&ReadFDs); FD_ZERO(&WriteFDs); @@ -1889,6 +1895,12 @@ bool pqissl::cansend(uint32_t usec) "pqissl::cansend() polling socket!"); #endif + if(sockfd == -1) + { + std::cerr << "pqissl::moretoread(): socket is invalid or closed." << std::endl; + return 0 ; + } + // Interestingly - This code might be portable.... fd_set ReadFDs, WriteFDs, ExceptFDs; From 16859a1d3ac7866712ee32864c343816f989f02e Mon Sep 17 00:00:00 2001 From: hunbernd Date: Sat, 15 Aug 2015 23:37:33 +0200 Subject: [PATCH 055/165] Fix: chatlobby toaster not working --- libretroshare/src/chat/distributedchat.cc | 2 +- retroshare-gui/src/gui/notifyqt.cpp | 31 ++++++++++--------- .../src/gui/toaster/ChatLobbyToaster.cpp | 12 +++++-- .../src/gui/toaster/ChatLobbyToaster.h | 2 +- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/libretroshare/src/chat/distributedchat.cc b/libretroshare/src/chat/distributedchat.cc index 8e759fadc..ec7ccff95 100644 --- a/libretroshare/src/chat/distributedchat.cc +++ b/libretroshare/src/chat/distributedchat.cc @@ -157,7 +157,7 @@ bool DistributedChatService::handleRecvChatLobbyMsgItem(RsChatMsgItem *ci) //name = cli->nick; //popupChatFlag = RS_POPUP_CHATLOBBY; - RsServer::notify()->AddPopupMessage(RS_POPUP_CHATLOBBY, cli->signature.keyId.toStdString(), cli->nick, cli->message); /* notify private chat message */ + RsServer::notify()->AddPopupMessage(RS_POPUP_CHATLOBBY, virtual_peer_id.toStdString(), cli->signature.keyId.toStdString(), cli->message); /* notify private chat message */ return true ; } diff --git a/retroshare-gui/src/gui/notifyqt.cpp b/retroshare-gui/src/gui/notifyqt.cpp index 9e32b09bf..a6b8b5457 100644 --- a/retroshare-gui/src/gui/notifyqt.cpp +++ b/retroshare-gui/src/gui/notifyqt.cpp @@ -29,6 +29,7 @@ #include "notifyqt.h" #include #include +#include #include #include "RsAutoUpdatePage.h" @@ -862,28 +863,23 @@ void NotifyQt::UpdateGUI() case RS_POPUP_CHATLOBBY: if ((popupflags & RS_POPUP_CHATLOBBY) && !_disableAllToaster) { - if(RsPeerId::SIZE_IN_BYTES < sizeof(ChatLobbyId)) - { - std::cerr << "NotifyQt::UpdateGUI() Error: ChatLobbyId does not fit into a RsPeerId, this should not happen!" << std::endl; - break; - } - RsPeerId vpid(id); // create virtual peer id - ChatLobbyId lobby_id; - // copy first bytes of virtual peer id, to make a chat lobby id - memcpy(&lobby_id, vpid.toByteArray(), sizeof(ChatLobbyId)); + ChatLobbyId lobby_id; + if(!rsMsgs->isLobbyId(RsPeerId(id), lobby_id)) + break; - ChatDialog *chatDialog = ChatDialog::getChat(ChatId(lobby_id)); - ChatWidget *chatWidget; + ChatDialog *chatDialog = ChatDialog::getChat(ChatId(lobby_id)); + ChatWidget *chatWidget; if (chatDialog && (chatWidget = chatDialog->getChatWidget()) && chatWidget->isActive()) { // do not show when active break; } ChatLobbyDialog *chatLobbyDialog = dynamic_cast(chatDialog); - if (!chatLobbyDialog || chatLobbyDialog->isParticipantMuted(RsGxsId(title))) + RsGxsId sender(title); + if (!chatLobbyDialog || chatLobbyDialog->isParticipantMuted(sender)) break; // participant is muted - toaster = new ToasterItem(new ChatLobbyToaster(lobby_id, QString::fromUtf8(title.c_str()), QString::fromUtf8(msg.c_str()))); + toaster = new ToasterItem(new ChatLobbyToaster(lobby_id, sender, QString::fromUtf8(msg.c_str()))); } break; case RS_POPUP_CONNECT_ATTEMPT: @@ -1002,8 +998,13 @@ void NotifyQt::testToasters(uint notifyFlags, /*RshareSettings::enumToasterPosit toaster = new ToasterItem(new GroupChatToaster(id, message)); break; case RS_POPUP_CHATLOBBY: - toaster = new ToasterItem(new ChatLobbyToaster(0, title, message)); - break; + { + std::list gxsid; + if(rsIdentity->getOwnIds(gxsid) && (gxsid.size() > 0)){ + toaster = new ToasterItem(new ChatLobbyToaster(0, gxsid.front(), message)); + } + break; + } case RS_POPUP_CONNECT_ATTEMPT: toaster = new ToasterItem(new FriendRequestToaster(pgpid, title, id)); break; diff --git a/retroshare-gui/src/gui/toaster/ChatLobbyToaster.cpp b/retroshare-gui/src/gui/toaster/ChatLobbyToaster.cpp index 325d56f30..882004975 100644 --- a/retroshare-gui/src/gui/toaster/ChatLobbyToaster.cpp +++ b/retroshare-gui/src/gui/toaster/ChatLobbyToaster.cpp @@ -22,10 +22,11 @@ #include "ChatLobbyToaster.h" #include "gui/chat/ChatDialog.h" #include "util/HandleRichText.h" +#include #include -ChatLobbyToaster::ChatLobbyToaster(const ChatLobbyId &lobby_id, const QString &name, const QString &message): +ChatLobbyToaster::ChatLobbyToaster(const ChatLobbyId &lobby_id, const RsGxsId &sender_id, const QString &message): QWidget(NULL), mLobbyId(lobby_id) { /* Invoke the Qt Designer generated object setup routine */ @@ -39,7 +40,14 @@ ChatLobbyToaster::ChatLobbyToaster(const ChatLobbyId &lobby_id, const QString &n ui.avatarWidget->setFrameType(AvatarWidget::NORMAL_FRAME); ui.avatarWidget->setDefaultAvatar(":images/chat_64.png"); - QString lobbyName = RsHtml::plainText(name); + /* Get sender info */ + RsIdentityDetails idd; + if(!rsIdentity->getIdDetails(sender_id, idd)) + return; + + ui.avatarWidget->setId(ChatId(sender_id)); + + QString lobbyName = RsHtml::plainText(idd.mNickname); ChatLobbyInfo clinfo ; if(rsMsgs->getChatLobbyInfo(mLobbyId,clinfo)) diff --git a/retroshare-gui/src/gui/toaster/ChatLobbyToaster.h b/retroshare-gui/src/gui/toaster/ChatLobbyToaster.h index bc7c3d262..a5c18d8f2 100644 --- a/retroshare-gui/src/gui/toaster/ChatLobbyToaster.h +++ b/retroshare-gui/src/gui/toaster/ChatLobbyToaster.h @@ -36,7 +36,7 @@ class ChatLobbyToaster : public QWidget Q_OBJECT public: - ChatLobbyToaster(const ChatLobbyId &lobby_id, const QString &name, const QString &message); + ChatLobbyToaster(const ChatLobbyId &lobby_id, const RsGxsId &sender_id, const QString &message); private slots: void chatButtonSlot(); From 9734f32ac517544b654592f4ea26fcba96501609 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 16 Aug 2015 21:05:07 -0400 Subject: [PATCH 056/165] updated ubuntu changelog. improved ubuntu packaging script --- build_scripts/Debian+Ubuntu/changelog | 46 +++++++++++++++++++ .../Debian+Ubuntu/makeSourcePackage.sh | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/build_scripts/Debian+Ubuntu/changelog b/build_scripts/Debian+Ubuntu/changelog index 6c74c0948..8bbc69eae 100644 --- a/build_scripts/Debian+Ubuntu/changelog +++ b/build_scripts/Debian+Ubuntu/changelog @@ -1,5 +1,51 @@ retroshare06 (0.6.0-1.XXXXXX~YYYYYY) YYYYYY; urgency=low + f6b830d (branch merging) Merge pull request #35 from hunbernd/chat-fix + 16859a1 (GUI ) Fix: chatlobby toaster not working + 2e08dde (Bug fix ) additional check for pqissl::sockfd before using it (patch from Jenster) + 384e7ba (GXS ) Reworked processing of requests in RsGxsDataAccess to prevent freezes of the gui. + 4a50a62 (Git management) Merge branch 'master' of https://github.com/RetroShare/RetroShare + 6eccd57 (Git management) merging before commit + 3084d2a (Debug info ) improved security message in console for whitelisted peers + 0402e53 (GUI ) Fix: empty line duplication bug + 4095d9d (GXS ) Switched retrieve of posts in GxsMessageFramePostWidget from "requestMsgRelatedInfo" to "requestMsgInfo". + b1101ed (GXS ) Prevent selecting data from the database in RsGxsNetService::syncWithPeers without online friends. + 3731617 (Debug info ) Fixed typo in debug output. + e667071 (GUI ) Moved IP Filter Widgets into Tabs + caa97cc (GXS ) Added database name to the debug output in RsDataService. + 2a6b623 (GXS ) Added extended debug outputs of times in RsDataService. + 7472f81 (Git management) Merge branch 'master' of https://github.com/RetroShare/RetroShare + 9d291aa (GUI ) update windows build scripts changed gxs id icon for linked with profile. + a765016 (GUI ) Moved column show/hide from context menu of the tree to the context menu of the header in IdDialog. + e73e68d (GUI ) Reduced the size of the status icon on the avatar image in FriendList. + 442ec23 (GXS ) Added index in database for column grpId in table MESSAGES. + b8edb75 (GXS ) Optimized SELECT creation in RetroDb::sqlQuery + ab538c6 (GXS ) Avoid error messages "table already exists" in RsDataService::initialise by using "IF NOT EXISTS" + 783465b (GUI ) forget to commit this, for the Search Filter DHT IPs + 13e77fb (Bugs ) Merge pull request #19 from sehraf/pr-fix_crash_on_shutdown + 9d0b066 (Bugs ) Fixed hide offline friends in ServicePermissionsPage + c919786 (GUI ) Fixed typo. Updated english translation. + d5c95c4 (GUI ) Fixed layout of the ServicePermissionsPage + 9265145 (GUI ) Updated english translation + 87f2e6d (GUI ) FriendList: - Removed avatar column, state column. Added combined avatar and status icon + ec67ee0 (VOIP ) added graph display of instantly required bandwidth for VOIP, in preparation to chosing new + video codec. GUI layout + d5c33f5 (Packaging ) fixed windows build script + c168765 (GUI ) Added tab for the DHT TreeWidgets for better view Added a search Filter for DHT IP addresses + 48bb8b4 (Git management) sequel to 6b2ed2fb2d84d7e48b15fa917aa4eb8015922d15 + fabc3a3 (Git management) added some rules to .gitignore + 168eb45 (Debug info ) removed debug info about missing keys; added debug info about deserialization checking of string + 311358b (Git management) merged changes from master + a87adb8 (Debug info ) improved README file + 51ab1fc (Debug info ) updated readme file + 43db562 (Packaging ) Fixed build script for Windows installer + 789df68 (Packaging ) Added update of version information for Windows build - Added template file version.html.in - Removed RS_BUILD_NUM + 1412dc6 (Packaging ) Removed utopic, added new ppa name + + -- Cyril Soler Sun, 16 Aug 2015 20:00:00 +0100 + +retroshare06 (0.6.0-1.20150802.34ec6dfd~precise) precise; urgency=low + GUI - improved filtering method against lol bombs. Thx to ConcernedCitizen for pointing this out - fix #21 typo "defaut" instead of "default" in switch statement in RSGraphWidget (patch from Chozabu) diff --git a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh index da096fb7f..67cc9df05 100755 --- a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh +++ b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh @@ -80,7 +80,7 @@ echo Extracting base archive... mkdir -p ${workdir}/src echo Checking out latest snapshot... cd ${workdir}/src -git clone https://github.com/RetroShare/RetroShare.git . +git clone -depth 1 https://github.com/RetroShare/RetroShare.git . cd - if ! test -d ${workdir}/src/libretroshare/; then From 4d7f7331fc750e9af4c961c5b9f7e003198e0b81 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 16 Aug 2015 21:44:38 -0400 Subject: [PATCH 057/165] fixed bug in git parameter in packaging script --- build_scripts/Debian+Ubuntu/makeSourcePackage.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh index 67cc9df05..42f1145bf 100755 --- a/build_scripts/Debian+Ubuntu/makeSourcePackage.sh +++ b/build_scripts/Debian+Ubuntu/makeSourcePackage.sh @@ -80,7 +80,7 @@ echo Extracting base archive... mkdir -p ${workdir}/src echo Checking out latest snapshot... cd ${workdir}/src -git clone -depth 1 https://github.com/RetroShare/RetroShare.git . +git clone --depth 1 https://github.com/RetroShare/RetroShare.git . cd - if ! test -d ${workdir}/src/libretroshare/; then From d28c1898fd74d09c455a34f1754bc0fb9916e207 Mon Sep 17 00:00:00 2001 From: csoler Date: Sun, 16 Aug 2015 22:59:49 -0400 Subject: [PATCH 058/165] first workign implementation of wavelet-based codec --- plugins/VOIP/gui/DaubechyWavelets.h | 267 ++++++++++++++++++++++++++++ plugins/VOIP/gui/VideoProcessor.cpp | 240 ++++++++++++++++++++++++- plugins/VOIP/gui/VideoProcessor.h | 25 ++- 3 files changed, 519 insertions(+), 13 deletions(-) create mode 100644 plugins/VOIP/gui/DaubechyWavelets.h diff --git a/plugins/VOIP/gui/DaubechyWavelets.h b/plugins/VOIP/gui/DaubechyWavelets.h new file mode 100644 index 000000000..c69f025b0 --- /dev/null +++ b/plugins/VOIP/gui/DaubechyWavelets.h @@ -0,0 +1,267 @@ +#pragma once + +#include +#include +#include +#include +#include + +#ifdef USE_SSE_INSTRUCTIONS +#include +#endif + +template class DaubechyWavelets +{ + public: + typedef enum { DWT_DAUB02=2, DWT_DAUB04=4, DWT_DAUB12=12, DWT_DAUB20=20 } WaveletType ; + typedef enum { DWT_FORWARD=1, DWT_BACKWARD=0 } TransformType ; + + static void DWT2D(FLOAT *data,unsigned long int W,unsigned long int H,WaveletType type,TransformType tr) + { + unsigned long int nn[2] = {W,H} ; + wtn(&data[-1], &nn[-1],2, tr, waveletFilter(type), pwt) ; + } + static void DWT1D(FLOAT *data,unsigned long int W,WaveletType type,TransformType tr) + { + unsigned long int nn[1] = {W} ; + wtn(&data[-1], &nn[-1],1, tr, waveletFilter(type), pwt) ; + } + + + private: + class wavefilt + { + public: + wavefilt(int n) + { + int k; + FLOAT sig = -1.0; + static const FLOAT c2[5]={ 0.0, sqrt(2.0)/2.0, sqrt(2.0)/2.0, 0.0, 0.0 }; + + static const FLOAT c4[5]={ 0.0, 0.4829629131445341, 0.8365163037378079, 0.2241438680420134,-0.1294095225512604 }; + + static const FLOAT c12[13]={0.0,0.111540743350, 0.494623890398, 0.751133908021, + 0.315250351709,-0.226264693965,-0.129766867567, + 0.097501605587, 0.027522865530,-0.031582039318, + 0.000553842201, 0.004777257511,-0.001077301085}; + + static const FLOAT c20[21]={0.0,0.026670057901, 0.188176800078, 0.527201188932, + 0.688459039454, 0.281172343661,-0.249846424327, + -0.195946274377, 0.127369340336, 0.093057364604, + -0.071394147166,-0.029457536822, 0.033212674059, + 0.003606553567,-0.010733175483, 0.001395351747, + 0.001992405295,-0.000685856695,-0.000116466855, + 0.000093588670,-0.000013264203 }; + + ncof= (n==2)?4:n; + const FLOAT *tmpcc ; + cc.resize(ncof+1) ; + cr.resize(ncof+1) ; + + if (n == 2) + { + tmpcc=c2; + cc[1] = tmpcc[1] ; + cc[2] = tmpcc[2] ; + cc[3] = 0.0f ; + cc[4] = 0.0f ; + cr[1] = tmpcc[1] ; + cr[2] =-tmpcc[2] ; + cr[3] = 0.0f ; + cr[4] = 0.0f ; + + ioff = joff = -1 ; + } + else + { + if (n == 4) + tmpcc=c4; + else if (n == 12) + tmpcc=c12; + else if (n == 20) + tmpcc=c20; + else + throw std::runtime_error("unimplemented value n in pwtset"); + + for (k=1;k<=n;k++) + { + cc[k] = tmpcc[k] ; + cr[ncof+1-k]=sig*tmpcc[k]; + sig = -sig; + } + ioff = joff = -(n >> 1); + } + } + + ~wavefilt() {} + + int ncof,ioff,joff; + std::vector cc; + std::vector cr; + } ; + + static const wavefilt& waveletFilter(WaveletType type) + { + static wavefilt *daub02filt = NULL ; + static wavefilt *daub04filt = NULL ; + static wavefilt *daub12filt = NULL ; + static wavefilt *daub20filt = NULL ; + + switch(type) + { + case DWT_DAUB02: if(daub02filt == NULL) + daub02filt = new wavefilt(2) ; + return *daub02filt ; + + case DWT_DAUB04: if(daub04filt == NULL) + daub04filt = new wavefilt(4) ; + return *daub04filt ; + + case DWT_DAUB12: if(daub12filt == NULL) + daub12filt = new wavefilt(12) ; + return *daub12filt ; + + case DWT_DAUB20: if(daub20filt == NULL) + daub20filt = new wavefilt(20) ; + return *daub20filt ; + + default: + throw std::runtime_error("Unknown wavelet type.") ; + } + } + + static void pwt(FLOAT a[], unsigned long n, int isign,const wavefilt& wfilt) + { +/********************** BEGIN SIGNED PART *************************/ +/** md5sum = 2b9e1e38ac690f50806873cdb4a061ea **/ +/** Validation date = 08/10/10 **/ +/******************************************************************/ + unsigned long i,ii,ni,nj ; + + if (n < 4) + return; + + FLOAT *wksp=new FLOAT[n+1];//vector(1,n); + FLOAT ai,ai1 ; + unsigned long int nmod=wfilt.ncof*n; + unsigned long int n1=n-1; + unsigned long int nh=n >> 1; + + memset(wksp,0,(n+1)*sizeof(FLOAT)) ; + + if (isign == DWT_FORWARD) + for (ii=1,i=1;i<=n;i+=2,ii++) + { + ni=i+nmod+wfilt.ioff; + nj=i+nmod+wfilt.joff; + +#ifdef USE_SSE_INSTRUCTIONS +#warning Using SSE2 Instruction set for wavelet internal loops + for (int k=1;k<=wfilt.ncof;k+=4) + { + int jf=ni+k; + int jr=nj+k; + + sse_block w1(wfilt.cc[k],wfilt.cc[k+1],wfilt.cc[k+2],wfilt.cc[k+3]) ; + sse_block w2(wfilt.cr[k],wfilt.cr[k+1],wfilt.cr[k+2],wfilt.cr[k+3]) ; + + sse_block a1( a[1+((jf+0)&n1)], a[1+((jf+1)&n1)], a[1+((jf+2)&n1)], a[1+((jf+3)&n1)]) ; + sse_block a2( a[1+((jr+0)&n1)], a[1+((jr+1)&n1)], a[1+((jr+2)&n1)], a[1+((jr+3)&n1)]) ; + + sse_block wk1( w1*a1 ) ; + sse_block wk2( w2*a2 ) ; + + wksp[ii ] += wk1.sum() ; + wksp[ii+nh] += wk2.sum() ; + } +#else + for (int k=1;k<=wfilt.ncof;k++) + { + int jf=n1 & (ni+k); + int jr=n1 & (nj+k); + wksp[ii] += wfilt.cc[k]*a[jf+1]; + wksp[ii+nh] += wfilt.cr[k]*a[jr+1]; + } +#endif + } + else + for (ii=1,i=1;i<=n;i+=2,ii++) + { + ai=a[ii]; + ai1=a[ii+nh]; + ni=i+nmod+wfilt.ioff; + nj=i+nmod+wfilt.joff; + +#ifdef USE_SSE_INSTRUCTIONS + sse_block ai_sse( ai,ai,ai,ai ) ; + sse_block ai1_sse( ai1,ai1,ai1,ai1 ) ; + + for (int k=1;k<=wfilt.ncof;k+=4) + { + int jf=ni+k ; + int jr=nj+k ; // in fact we have jf==jr, so the code is simpler. + + sse_block w1(wksp[1+((jf+0) & n1)],wksp[1+((jf+1) & n1)],wksp[1+((jf+2) & n1)],wksp[1+((jf+3) & n1)]) ; + + w1 += sse_block(wfilt.cc[k+0],wfilt.cc[k+1],wfilt.cc[k+2],wfilt.cc[k+3]) * ai_sse ; + w1 += sse_block(wfilt.cr[k+0],wfilt.cr[k+1],wfilt.cr[k+2],wfilt.cr[k+3]) * ai1_sse ; + + wksp[1+((jr+0) & n1)] = w1[0] ; + wksp[1+((jr+1) & n1)] = w1[1] ; + wksp[1+((jr+2) & n1)] = w1[2] ; + wksp[1+((jr+3) & n1)] = w1[3] ; + } +#else + for (int k=1;k<=wfilt.ncof;++k) + { + wksp[(n1 & (ni+k))+1] += wfilt.cc[k]*ai; + wksp[(n1 & (nj+k))+1] += wfilt.cr[k]*ai1; + } +#endif + } + + for (uint j=1;j<=n;j++) + a[j]=wksp[j]; + + delete[] wksp ;//free_vector(wksp,1,n); +/********************** END SIGNED PART *************************/ + } + + static void wtn(FLOAT a[], unsigned long nn[], int ndim, int isign, const wavefilt& w,void (*wtstep)(FLOAT [], unsigned long, int,const wavefilt&)) + { + unsigned long i1,i2,i3,k,n,nnew,nprev=1,nt,ntot=1; + int idim; + FLOAT *wksp; + + for (idim=1;idim<=ndim;idim++) + ntot *= nn[idim]; + + wksp=new FLOAT[ntot+1] ; //vector(1,ntot); + + for (idim=1;idim<=ndim;idim++) + { + n=nn[idim]; + nnew=n*nprev; + + if (n > 4) + for (i2=0;i2=4;nt >>= 1) + (*wtstep)(wksp,nt,isign,w); + else + for(nt=4;nt<=n;nt <<= 1) + (*wtstep)(wksp,nt,isign,w); + + for (i3=i1+i2,k=1;k<=n;k++,i3+=nprev) a[i3]=wksp[k]; + } + + nprev=nnew; + } + delete[] wksp ;//free_vector(wksp,1,ntot); + } +}; + diff --git a/plugins/VOIP/gui/VideoProcessor.cpp b/plugins/VOIP/gui/VideoProcessor.cpp index 4e1979a5d..9f4ac7a7c 100644 --- a/plugins/VOIP/gui/VideoProcessor.cpp +++ b/plugins/VOIP/gui/VideoProcessor.cpp @@ -7,12 +7,14 @@ #include "VideoProcessor.h" #include "QVideoDevice.h" +#include "DaubechyWavelets.h" VideoProcessor::VideoProcessor() :_encoded_frame_size(128,128) { _decoded_output_device = NULL ; - _encoding_current_codec = VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO; + //_encoding_current_codec = VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO; + _encoding_current_codec = VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO; } bool VideoProcessor::processImage(const QImage& img,uint32_t size_hint,uint32_t& encoded_size) @@ -31,7 +33,6 @@ bool VideoProcessor::processImage(const QImage& img,uint32_t size_hint,uint32_t& // std::cerr << "reducing to " << _frame_size.width() << " x " << _frame_size.height() << std::endl; - void *data = NULL; encoded_size = 0 ; if(codec) @@ -111,6 +112,8 @@ void VideoProcessor::receiveEncodedData(const RsVOIPDataChunk& chunk) if(codec != NULL) codec->decodeData(chunk,img) ; + else + std::cerr << "Unknown decoding codec: " << codid << std::endl; if(_decoded_output_device) _decoded_output_device->showFrame(img) ; @@ -159,7 +162,7 @@ bool JPEGVideo::decodeData(const RsVOIPDataChunk& chunk,QImage& image) QImage res = _decoded_reference_frame ; - for(uint32_t i=0;i> 8) & 0xff ; - memcpy(voip_chunk.data+HEADER_SIZE,qb.data(),qb.size()) ; + memcpy(&((unsigned char*)voip_chunk.data)[HEADER_SIZE],qb.data(),qb.size()) ; voip_chunk.size = HEADER_SIZE + qb.size() ; voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; @@ -230,3 +233,230 @@ bool JPEGVideo::encodeData(const QImage& image,uint32_t /* size_hint */,RsVOIPDa return true ; } + +bool WaveletVideo::encodeData(const QImage& image,uint32_t size_hint,RsVOIPDataChunk& voip_chunk) +{ + static const int WAVELET_IMG_SIZE = 128 ; + static const float W_THRESHOLD = 0.005 ; // low quality + //static const float W_THRESHOLD = 0.0001; // high quality + //static const float W_THRESHOLD = 0.0005; // medium quality + + static const int W2 = WAVELET_IMG_SIZE ; + static const int H2 = WAVELET_IMG_SIZE ; + + assert(image.width() == W2) ; + assert(image.height() == H2) ; + + float *temp = new float[W2*H2] ; + + std::cerr << " codec type: wavelets." << std::endl; + + // We should perform some interpolation here ;-) + // + for(int i=0;i::DWT2D(temp,W2,H2,DaubechyWavelets::DWT_DAUB04,DaubechyWavelets::DWT_FORWARD) ; + + // Now estimate the max energy in the W coefs, and only keep the largest. + + float mx = 0.0f ; + for(int i=0;i compressed_values ; + compressed_values.reserve(W2*H2) ; + + for(int i=0;i= W_THRESHOLD*mx) // This needs to be improved. Wavelets do not all have the same visual impact. + { + // add one value, using 16 bits for coordinates and 16 bits for the value. + + compressed_values.push_back((uint16_t)i) ; + compressed_values.push_back(quantize_16b(temp[i],mx)) ; + + //float f2 = from_quantized_16b(quantize_16b(temp[i],mx),mx) ; + + //if(fabs(f2 - temp[i]) >= 0.01*(fabs(temp[i])+fabs(f2))) + //std::cerr << " before: " << temp[i] << ", quantised=" << quantize_16b(temp[i],mx)<< ", after: " << f2 << std::endl; + } + delete[] temp ; + + // Serialise all values into a memory buffer. This needs to be taken care of because of endian issues. + + int compressed_size = 4 + compressed_values.size()*2 ; + + std::cerr << " threshold : " << W_THRESHOLD << std::endl; + std::cerr << " values kept: " << compressed_values.size()/2 << std::endl; + std::cerr << " compression: " << compressed_size/float(W2*H2*3)*100 << " %" << std::endl; + + voip_chunk.data = malloc(HEADER_SIZE + compressed_size) ; + + // build header + uint32_t flags = 0 ; + + ((unsigned char *)voip_chunk.data)[0] = VideoProcessor::VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO & 0xff ; + ((unsigned char *)voip_chunk.data)[1] = (VideoProcessor::VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO >> 8) & 0xff ; + ((unsigned char *)voip_chunk.data)[2] = flags & 0xff ; + ((unsigned char *)voip_chunk.data)[3] = (flags >> 8) & 0xff ; + + unsigned char *compressed_mem = &((unsigned char *)voip_chunk.data)[HEADER_SIZE] ; + serialise_ufloat(compressed_mem,mx) ; + + for(uint32_t i=0;i> 8 ; + } + + voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; + voip_chunk.size = HEADER_SIZE + compressed_size ; + + return true ; +} + +bool WaveletVideo::decodeData(const RsVOIPDataChunk& chunk,QImage& image) +{ + static const int WAVELET_IMG_SIZE = 128 ; + + static const int W2 = WAVELET_IMG_SIZE ; + static const int H2 = WAVELET_IMG_SIZE ; + + float *temp = new float[W2*H2] ; + + const unsigned char *compressed_mem = &static_cast(chunk.data)[HEADER_SIZE] ; + int compressed_size = chunk.size - HEADER_SIZE; + + memset(temp,0,W2*H2*sizeof(float)) ; + float M = deserialise_ufloat(compressed_mem); + +#ifdef VOIP_CODEC_DEBUG + std::cerr << " codec type: wavelets." << std::endl; + std::cerr << " max coef: " << M << std::endl; +#endif + + for(int i=4;i::DWT2D(temp,W2,H2,DaubechyWavelets::DWT_DAUB04,DaubechyWavelets::DWT_BACKWARD) ; + +#ifdef VOIP_CODEC_DEBUG + std::cerr << " resizing image to: " << w << "x" << h << std::endl; +#endif + + image = QImage(W2,H2,QImage::Format_RGB32) ; + + int indx = 0 ; + + for(int j=0;j1023), and p is coded on 6 bits (0->63). + // Packing [mp] into a 16bit uint16_t. M is the maximum coefficient over the quantization + // process. + // + // So this represents numbers from M * 1 * 2^{-73} to M + // + // All calculatoins are performed on x/M*2^10 + // + static const float LOG2 = log(2.0f) ; + + int m,p ; + + if(fabs(x) < 1e-8*M) + { + m = 0 ; + p = 0 ; + } + else + { + float log2f = log(fabsf(x)/M)/LOG2 ; + int mexp = (int)floor(MANTISSE_BITS - log2f) ; + + m = (int)floor(pow(2.0f,mexp+log2f)) ; + p = mexp ; + + if(p > (1<> EXPONENT_BITS ; + + if(p > 10) + return M * m / 1024.0f / (float)(1 << (p-10)) ; + else + return M * m / (float)(1 << p) ; +} + +void WaveletVideo::serialise_ufloat(unsigned char *mem, float f) +{ + if(f < 0.0f) + { + std::cerr << "(EE) Cannot serialise invalid negative float value " << f << " in " << __PRETTY_FUNCTION__ << std::endl; + return ; + } + // This serialisation is quite accurate. The max relative error is approx. + // 0.01% and most of the time less than 1e-05% The error is well distributed + // over numbers also. + // + uint32_t n = (f < 1e-7)?(~(uint32_t)0): ((uint32_t)( (1.0f/(1.0f+f) * (~(uint32_t)0)))) ; + + mem[0] = n & 0xff ; n >>= 8 ; + mem[1] = n & 0xff ; n >>= 8 ; + mem[2] = n & 0xff ; n >>= 8 ; + mem[3] = n & 0xff ; +} +float WaveletVideo::deserialise_ufloat(const unsigned char *mem) +{ + uint32_t n = mem[3] ; + n = (n << 8) + mem[2] ; + n = (n << 8) + mem[1] ; + n = (n << 8) + mem[0] ; + + return 1.0f/ ( n/(float)(~(uint32_t)0)) - 1.0f ; +} diff --git a/plugins/VOIP/gui/VideoProcessor.h b/plugins/VOIP/gui/VideoProcessor.h index d103207af..da12d76ae 100644 --- a/plugins/VOIP/gui/VideoProcessor.h +++ b/plugins/VOIP/gui/VideoProcessor.h @@ -11,6 +11,9 @@ class VideoCodec public: virtual bool encodeData(const QImage& Image, uint32_t size_hint, RsVOIPDataChunk& chunk) = 0; virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) = 0; + +protected: + static const uint32_t HEADER_SIZE = 0x04 ; }; // Now derive various image encoding/decoding algorithms. @@ -25,7 +28,6 @@ protected: virtual bool encodeData(const QImage& Image, uint32_t size_hint, RsVOIPDataChunk& chunk) ; virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) ; - static const uint32_t HEADER_SIZE = 0x04 ; static const uint32_t JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME = 0x0001 ; private: QImage _decoded_reference_frame ; @@ -35,17 +37,24 @@ private: uint32_t _encoded_ref_frame_count ; }; -class DifferentialWaveletVideo: public VideoCodec +class WaveletVideo: public VideoCodec { public: - DifferentialWaveletVideo() {} + WaveletVideo() {} protected: - virtual bool encodeData(const QImage& Image, uint32_t size_hint, RsVOIPDataChunk& chunk) { return true ; } - virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) { return true ; } - + virtual bool encodeData(const QImage& Image, uint32_t size_hint, RsVOIPDataChunk& chunk) ; + virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) ; private: - QImage _last_reference_frame ; + + static const int MANTISSE_BITS = 9 ; + static const int EXPONENT_BITS = 6 ; + + static void serialise_ufloat(unsigned char *mem, float f); + static float deserialise_ufloat(const unsigned char *mem); + + static float from_quantized_16b(uint16_t n, float M); + static uint16_t quantize_16b(float x, float M); }; // This class decodes video from a stream. It keeps a queue of @@ -106,7 +115,7 @@ class VideoProcessor // ===================================================================================== JPEGVideo _jpeg_video_codec ; - DifferentialWaveletVideo _ddwt_video_codec ; + WaveletVideo _ddwt_video_codec ; uint16_t _encoding_current_codec ; }; From 36349814a6b7e6c91279047f15a6494fb12efe43 Mon Sep 17 00:00:00 2001 From: sehraf Date: Tue, 18 Aug 2015 23:05:22 +0200 Subject: [PATCH 059/165] added import/export friendlist --- retroshare-gui/src/gui/common/FriendList.cpp | 350 +++++++++++++++++++ retroshare-gui/src/gui/common/FriendList.h | 10 + retroshare-gui/src/gui/common/FriendList.ui | 40 ++- 3 files changed, 397 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/common/FriendList.cpp b/retroshare-gui/src/gui/common/FriendList.cpp index 07bfad25e..93caf4d23 100644 --- a/retroshare-gui/src/gui/common/FriendList.cpp +++ b/retroshare-gui/src/gui/common/FriendList.cpp @@ -28,6 +28,7 @@ #include #include +#include "rsserver/rsaccounts.h" #include "retroshare/rspeers.h" #include "GroupDefs.h" @@ -126,6 +127,8 @@ FriendList::FriendList(QWidget *parent) : connect(ui->actionHideOfflineFriends, SIGNAL(triggered(bool)), this, SLOT(setHideUnconnected(bool))); connect(ui->actionShowState, SIGNAL(triggered(bool)), this, SLOT(setShowState(bool))); connect(ui->actionShowGroups, SIGNAL(triggered(bool)), this, SLOT(setShowGroups(bool))); + connect(ui->actionExportFriendlist, SIGNAL(triggered()), this, SLOT(exportFriendlistClicked())); + connect(ui->actionImportFriendlist, SIGNAL(triggered()), this, SLOT(importFriendlistClicked())); connect(ui->actionSortByName, SIGNAL(triggered()), this, SLOT(setSortByName())); connect(ui->actionSortByState, SIGNAL(triggered()), this, SLOT(setSortByState())); @@ -1648,6 +1651,351 @@ void FriendList::removeGroup() rsPeers->removeGroup(groupId); } +void FriendList::exportFriendlistClicked() +{ + QString fileName; + if(!importExportFriendlistFileDialog(fileName, false)) + // error was already shown - just return + return; + + if(!exportFriendlist(fileName)) + // error was already shown - just return + return; + + QMessageBox mbox; + mbox.setIcon(QMessageBox::Information); + mbox.setText(tr("Done!")); + mbox.setInformativeText("Your friendlist is stored at:\n" + fileName + + "\n(keep in mind that the file is unencrypted!)"); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); +} + +void FriendList::importFriendlistClicked() +{ + QString fileName; + if(!importExportFriendlistFileDialog(fileName, true)) + // error was already shown - just return + return; + + bool errorPeers, errorGroups; + if(importFriendlist(fileName, errorPeers, errorGroups)) { + QMessageBox mbox; + mbox.setIcon(QMessageBox::Information); + mbox.setText(tr("Done!")); + mbox.setInformativeText("Your friendlist was imported from:\n" + fileName); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); + } else { + QMessageBox mbox; + mbox.setIcon(QMessageBox::Warning); + mbox.setText(tr("Done - but errors happened!")); + mbox.setInformativeText("Your friendlist was imported from:\n" + fileName + + (errorPeers ? "\nat least one peer was not added" : "") + + (errorGroups ? "\nat least one peer was not added to a group" : "") + ); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); + } +} + +/** + * @brief opens a file dialog to select a file containing a friendlist + * @param fileName file containing a friendlist + * @param import show dialog for importing (true) or exporting (false) friendlist + * @return success or failure + * + * This function also shows an error message when no valid file was selected + */ +bool FriendList::importExportFriendlistFileDialog(QString &fileName, bool import) +{ + if(!misc::getSaveFileName(this, + RshareSettings::LASTDIR_CERT, + (import ? tr("Select file for importing yoour friendlist from") : + tr("Select a file for exporting your friendlist to")), + tr("Text file (*.txt);; Ini File (*.ini);;All Files (*)"), + fileName, + NULL, + (import ? QFileDialog::DontConfirmOverwrite : (QFileDialog::Options)0) + )) { + // show error to user + QMessageBox mbox; + mbox.setIcon(QMessageBox::Warning); + mbox.setText(tr("Error")); + mbox.setInformativeText("Failed to get a file!"); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); + return false; + } + return true; +} + +/** + * @brief exports friendlist to a given file + * @param fileName file for storing friendlist + * @return success or failure + * + * This function also shows an error message when the selected file is invalid/not writable + */ +bool FriendList::exportFriendlist(QString &fileName) +{ + // this has to be IniFormat because it is platform idependet (qsettings documentation) + QSettings s(fileName, QSettings::IniFormat); + s.clear(); + if(!s.isWritable()) { + // show error to user + QMessageBox mbox; + mbox.setIcon(QMessageBox::Warning); + mbox.setText(tr("Error")); + mbox.setInformativeText("File is not writeable!\n" + fileName + "\nStatus: " + + ( + (s.status() == QSettings::NoError) ? "no error" : + ( + (s.status() == QSettings::AccessError) ? "access error" : "format error" + ) + ) + ); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); + return false; + } + + std::list gpg_ids; + rsPeers->getGPGAcceptedList(gpg_ids); + + std::list group_info_list; + rsPeers->getGroupInfoList(group_info_list); + + s.beginGroup("pgpIDs"); + RsPeerDetails details; + for(std::list::iterator list_iter = gpg_ids.begin(); list_iter != gpg_ids.end(); list_iter++) { + rsPeers->getGPGDetails(*list_iter, details); + s.beginGroup(details.gpg_id.toStdString().c_str()); + // since everything is loaded from the public key there is no need to save these + //s.setValue("pgpID", details.gpg_id.toStdString().c_str()); + s.setValue("name", details.name.c_str()); // storing name for better human readability + //s.setValue("email", details.email.c_str()); + //s.setValue("trustLvl", details.trustLvl); + + s.beginGroup("sslIDs"); + std::list ssl_ids; + rsPeers->getAssociatedSSLIds(*list_iter, ssl_ids); + for(std::list::iterator list_iter = ssl_ids.begin(); list_iter != ssl_ids.end(); list_iter++) { + RsPeerDetails detail2; + if (!rsPeers->getPeerDetails(*list_iter, detail2)) + continue; + + std::string invite = rsPeers->GetRetroshareInvite(detail2.id, true); + std::string sid = detail2.id.toStdString(); + + s.beginGroup(sid.c_str()); + // since everything is loaded from the public key there is no need to save these + //s.setValue("sslID", sid.c_str()); + //s.setValue("location", detail2.location.c_str()); + s.setValue("pubkey", invite.c_str()); + s.setValue("service_perm_flags", detail2.service_perm_flags.toUInt32()); + s.endGroup(); // sid + } + s.endGroup(); // sslIDs + + s.endGroup(); // details.gpg_id + } + s.endGroup(); // pgpIDs + + s.beginGroup("groups"); + for(std::list::iterator list_iter = group_info_list.begin(); list_iter != group_info_list.end(); list_iter++) { + RsGroupInfo group_info = *list_iter; + s.beginGroup(group_info.id.c_str()); + // id is not needed since it may differ between locatiosn / pgp ids (groups are identified by name) + s.setValue("name", group_info.name.c_str()); + s.setValue("flag", group_info.flag); + + s.beginGroup("peerIDs"); + for(std::set::iterator i = group_info.peerIds.begin(); i != group_info.peerIds.end(); i++) { + std::string pid = i->toStdString(); + // key = peerId, value = arbitrary + s.setValue(pid.c_str(), 0); + } + s.endGroup(); // peerIDs + + s.endGroup(); // group_info.id + } + s.endGroup(); // groups + + return true; +} + +/** + * @brief Imports friends from a given file + * @param fileName file to load friends from + * @param errorPeers an error occured while adding a peer + * @param errorGroups an error occured while adding a peer to a group + * @return success or failure (an error means that adding a peer and/or adding a peer to a group failed at least once) + */ +bool FriendList::importFriendlist(QString &fileName, bool &errorPeers, bool &errorGroups) +{ + // this has to be IniFormat because it is platform idependet (qsettings documentation) + QSettings s(fileName, QSettings::IniFormat); + errorPeers = false; + errorGroups = false; + + uint32_t error_code; + std::string error_string; + RsPeerDetails rsPeerDetails; + RsPeerId rsPeerID; + RsPgpId rsPgpID; + + // lock all events for faster processing + RsAutoUpdatePage::lockAllEvents(); + + s.beginGroup("pgpIDs"); + QStringList pgpIDs = s.childGroups(); + foreach (QString pgpID, pgpIDs) { + s.beginGroup(pgpID); + + // enter sslIDs group and iterate over all ssl IDs + s.beginGroup("sslIDs"); + QStringList sslIDs = s.childGroups(); + foreach (QString sslID, sslIDs) { + s.beginGroup(sslID); + + rsPeerID.clear(); + rsPgpID.clear(); + + // load everything needed from the pubkey string + std::string pubkey = s.value("pubkey").toString().toStdString(); + if(rsPeers->loadDetailsFromStringCert(pubkey, rsPeerDetails, error_code)) { + if(rsPeers->loadCertificateFromString(pubkey, rsPeerID, rsPgpID, error_string)) { + ServicePermissionFlags service_perm_flags(s.value("service_perm_flags").toInt()); + + // everything is loaded - start setting things + if (!rsPeerDetails.id.isNull() && !rsPeerDetails.gpg_id.isNull()) { + // pgp and ssl ID are available + rsPeers->addFriend(rsPeerDetails.id, rsPeerDetails.gpg_id, service_perm_flags); + if(rsPeerDetails.isHiddenNode) { + // for hidden notes + if (!rsPeerDetails.hiddenNodeAddress.empty() && rsPeerDetails.hiddenNodePort) + rsPeers->setHiddenNode(rsPeerDetails.id, rsPeerDetails.hiddenNodeAddress, rsPeerDetails.hiddenNodePort); + } else { + // for normal nodes + if (!rsPeerDetails.extAddr.empty() && rsPeerDetails.extPort) + rsPeers->setExtAddress(rsPeerDetails.id, rsPeerDetails.extAddr, rsPeerDetails.extPort); + if (!rsPeerDetails.localAddr.empty() && rsPeerDetails.localPort) + rsPeers->setLocalAddress(rsPeerDetails.id, rsPeerDetails.localAddr, rsPeerDetails.localPort); + if (!rsPeerDetails.dyndns.empty()) + rsPeers->setDynDNS(rsPeerDetails.id, rsPeerDetails.dyndns); + if (!rsPeerDetails.location.empty()) + rsPeers->setLocation(rsPeerDetails.id, rsPeerDetails.location); + } + } else if (!rsPeerDetails.gpg_id.isNull()) { + // only pgp id is avaiable + RsPeerId pid; + rsPeers->addFriend(pid, rsPeerDetails.gpg_id, service_perm_flags); + } else { + errorPeers = true; + std::cerr << "FriendList::importFriendlist(): error while procvessing SSL id " << sslID.toStdString() << std::endl; + } + } else { + errorPeers = true; + std::cerr << "FriendList::importFriendlist(): failed to get peer detaisl from public key (SSL id: " << sslID.toStdString() << " - error: " << error_string << ")" << std::endl; + } + } else { + errorPeers = true; + std::cerr << "FriendList::importFriendlist(): failed to get peer detaisl from public key (SSL id: " << sslID.toStdString() << " - error: " << error_code << ")" << std::endl; + } + s.endGroup(); // sslID + } + s.endGroup(); // sslIDs + s.endGroup(); // pgpID + } + s.endGroup(); // pgpIDs + + // enter groups group and iterate over all groups + s.beginGroup("groups"); + QStringList groupList = s.childGroups(); + foreach (QString group, groupList) { + s.beginGroup(group); + + // get name and flags and try to get the group ID + std::string groupName = s.value("name").toString().toStdString(); + uint32_t flag = s.value("flag").toUInt(); + std::string groupId; + if(getOrCreateGroup(groupName, flag, groupId)) { + // group id found! + // enter peerIDs group and iterate over all pgpIDs of this group + s.beginGroup("peerIDs"); + QStringList pgpIDsForGroup = s.allKeys(); + foreach (QString pgpIDForGroup, pgpIDsForGroup) { + // add pgp id to group + RsPgpId rsPgpId(pgpIDForGroup.toStdString()); + if(rsPeers->assignPeerToGroup(groupId, rsPgpId, true)) { + errorPeers = true; + std::cerr << "FriendList::importFriendlist(): failed to add '" << rsPeers->getGPGName(rsPgpId) << "'' to group '" << groupName << "'" << std::endl; + } + } + s.endGroup(); // peerIDs + } else { + errorGroups = true; + std::cerr << "FriendList::importFriendlist(): failed to find/create group '" << groupName << "'" << std::endl; + } + s.endGroup(); // group + } + s.endGroup(); // groups + + // unlock events + RsAutoUpdatePage::unlockAllEvents(); + + return !(errorPeers || errorGroups); +} + +/** + * @brief Gets the groups ID for a given group name + * @param name group name to search for + * @param id groupd id for the given name + * @return success or fail + */ +bool FriendList::getGroupIdByName(const std::string &name, std::string &id) +{ + std::list grpList; + if(!rsPeers->getGroupInfoList(grpList)) + return false; + + foreach (const RsGroupInfo &grp, grpList) { + if(grp.name == name) { + id = grp.id; + return true; + } + } + + return false; +} + +/** + * @brief Gets the groups ID for a given group name. If no groupd was it will create one + * @param name group name to search for + * @param flag flag to use when creating the group + * @param id groupd id + * @return success or failure + */ +bool FriendList::getOrCreateGroup(const std::string &name, const uint &flag, std::string &id) +{ + if(getGroupIdByName(name, id)) + return true; + + // -> create one + RsGroupInfo grp; + grp.id = "0"; // RS will generate an ID + grp.name = name; + grp.flag = flag; + + if(!rsPeers->addGroup(grp)) + return false; + + // try again + return getGroupIdByName(name, id); +} + + void FriendList::setHideUnconnected(bool hidden) { if (mHideUnconnected != hidden) { @@ -1793,6 +2141,8 @@ void FriendList::createDisplayMenu() displayMenu->addAction(ui->actionHideOfflineFriends); displayMenu->addAction(ui->actionShowState); displayMenu->addAction(ui->actionShowGroups); + displayMenu->addAction(ui->actionExportFriendlist); + displayMenu->addAction(ui->actionImportFriendlist); ui->displayButton->setMenu(displayMenu); } diff --git a/retroshare-gui/src/gui/common/FriendList.h b/retroshare-gui/src/gui/common/FriendList.h index aa8965ad2..daa0de9db 100644 --- a/retroshare-gui/src/gui/common/FriendList.h +++ b/retroshare-gui/src/gui/common/FriendList.h @@ -134,6 +134,13 @@ private: QTreeWidgetItem *getCurrentPeer() const; void getSslIdsFromItem(QTreeWidgetItem *item, std::list &sslIds); + bool getOrCreateGroup(const std::string &name, const uint &flag, std::string &id); + bool getGroupIdByName(const std::string &name, std::string &id); + + bool importExportFriendlistFileDialog(QString &fileName, bool import); + bool exportFriendlist(QString &fileName); + bool importFriendlist(QString &fileName, bool &errorPeers, bool &errorGroups); + private slots: void groupsChanged(); void insertPeers(); @@ -165,6 +172,9 @@ private slots: void editGroup(); void removeGroup(); + void exportFriendlistClicked(); + void importFriendlistClicked(); + // void inviteToLobby(); // void createchatlobby(); // void unsubscribeToLobby(); diff --git a/retroshare-gui/src/gui/common/FriendList.ui b/retroshare-gui/src/gui/common/FriendList.ui index 70e323ff0..ea65c3176 100644 --- a/retroshare-gui/src/gui/common/FriendList.ui +++ b/retroshare-gui/src/gui/common/FriendList.ui @@ -14,7 +14,16 @@ 0 - + + 0 + + + 0 + + + 0 + + 0 @@ -29,7 +38,16 @@ 3 - + + 2 + + + 2 + + + 2 + + 2 @@ -98,7 +116,7 @@ Friend nodes - AlignHCenter|AlignVCenter|AlignCenter + AlignCenter @@ -166,6 +184,22 @@ Show Groups + + + export friendlist + + + export your friendlist including groups + + + + + import friendlist + + + import your friendlist including groups + + From 80d765e1d6def16e90e143f9f80c1d5621769510 Mon Sep 17 00:00:00 2001 From: sehraf Date: Tue, 18 Aug 2015 23:17:29 +0200 Subject: [PATCH 060/165] small fix --- retroshare-gui/src/gui/common/FriendList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/common/FriendList.cpp b/retroshare-gui/src/gui/common/FriendList.cpp index 93caf4d23..c952a5b5c 100644 --- a/retroshare-gui/src/gui/common/FriendList.cpp +++ b/retroshare-gui/src/gui/common/FriendList.cpp @@ -1929,7 +1929,7 @@ bool FriendList::importFriendlist(QString &fileName, bool &errorPeers, bool &err // add pgp id to group RsPgpId rsPgpId(pgpIDForGroup.toStdString()); if(rsPeers->assignPeerToGroup(groupId, rsPgpId, true)) { - errorPeers = true; + errorGroups = true; std::cerr << "FriendList::importFriendlist(): failed to add '" << rsPeers->getGPGName(rsPgpId) << "'' to group '" << groupName << "'" << std::endl; } } From 42bbf76035187cd362e4aaa28a62b0209023de7c Mon Sep 17 00:00:00 2001 From: csoler Date: Tue, 18 Aug 2015 20:21:45 -0400 Subject: [PATCH 061/165] fixed display of software revision in main window (patch from ASmith) --- retroshare-gui/src/gui/MainWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index 05aaade2d..be269db84 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -202,7 +202,7 @@ MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) nameAndLocation = QString("%1 (%2)").arg(QString::fromUtf8(pd.name.c_str())).arg(QString::fromUtf8(pd.location.c_str())); } - setWindowTitle(tr("RetroShare %1 a secure decentralized communication platform").arg(Rshare::retroshareVersion(false)) + " - " + nameAndLocation); + setWindowTitle(tr("RetroShare %1 a secure decentralized communication platform").arg(Rshare::retroshareVersion(true)) + " - " + nameAndLocation); /* add url handler for RetroShare links */ QDesktopServices::setUrlHandler(RSLINK_SCHEME, this, "retroshareLinkActivated"); From 3b40f0e0c845f2ec8b1825b36d8245e19ac9d316 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Wed, 19 Aug 2015 09:59:14 +0200 Subject: [PATCH 062/165] FriendList: - Show information of the "best" ssl item on the gpg item only when the gpg item is not expanded. - Calculate the icon height from the font metrics - Show the information text with normal font and color --- retroshare-gui/src/gui/common/FriendList.cpp | 200 ++++++++++++++----- retroshare-gui/src/gui/common/FriendList.h | 1 + retroshare-gui/src/gui/common/FriendList.ui | 6 - 3 files changed, 148 insertions(+), 59 deletions(-) diff --git a/retroshare-gui/src/gui/common/FriendList.cpp b/retroshare-gui/src/gui/common/FriendList.cpp index 07bfad25e..95ac04807 100644 --- a/retroshare-gui/src/gui/common/FriendList.cpp +++ b/retroshare-gui/src/gui/common/FriendList.cpp @@ -53,6 +53,7 @@ #include "util/QtVersion.h" #include "gui/chat/ChatUserNotify.h" #include "gui/connect/ConnectProgressDialog.h" +#include "gui/common/ElidedLabel.h" #include "FriendList.h" #include "ui_FriendList.h" @@ -104,6 +105,8 @@ * #define FRIENDS_DEBUG 1 *****/ +Q_DECLARE_METATYPE(ElidedLabel*) + FriendList::FriendList(QWidget *parent) : RsAutoUpdatePage(1500, parent), ui(new Ui::FriendList), @@ -147,13 +150,20 @@ FriendList::FriendList(QWidget *parent) : ui->peerTreeWidget->enableColumnCustomize(true); ui->peerTreeWidget->setColumnCustomizable(COLUMN_NAME, false); connect(ui->peerTreeWidget, SIGNAL(columnVisibleChanged(int,bool)), this, SLOT(peerTreeColumnVisibleChanged(int,bool))); + connect(ui->peerTreeWidget, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SLOT(peerTreeItemCollapsedExpanded(QTreeWidgetItem*))); + connect(ui->peerTreeWidget, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(peerTreeItemCollapsedExpanded(QTreeWidgetItem*))); + + QFontMetricsF fontMetrics(ui->peerTreeWidget->font()); /* Set initial column width */ - int fontWidth = QFontMetricsF(ui->peerTreeWidget->font()).width("W"); + int fontWidth = fontMetrics.width("W"); ui->peerTreeWidget->setColumnWidth(COLUMN_NAME, 22 * fontWidth); ui->peerTreeWidget->setColumnWidth(COLUMN_LAST_CONTACT, 12 * fontWidth); ui->peerTreeWidget->setColumnWidth(COLUMN_IP, 15 * fontWidth); + int avatarHeight = fontMetrics.height() * 3; + ui->peerTreeWidget->setIconSize(QSize(avatarHeight, avatarHeight)); + /* Initialize display menu */ createDisplayMenu(); } @@ -474,6 +484,37 @@ static QIcon createAvatar(const QPixmap &avatar, const QPixmap &overlay) return icon; } +static void getNameWidget(QTreeWidget *treeWidget, QTreeWidgetItem *item, ElidedLabel *&nameLabel, ElidedLabel *&textLabel) +{ + QWidget *widget = treeWidget->itemWidget(item, FriendList::COLUMN_NAME); + + if (!widget) { + widget = new QWidget; + nameLabel = new ElidedLabel(widget); + textLabel = new ElidedLabel(widget); + + widget->setProperty("nameLabel", qVariantFromValue(nameLabel)); + widget->setProperty("textLabel", qVariantFromValue(textLabel)); + + QVBoxLayout *layout = new QVBoxLayout; + layout->setSpacing(0); + layout->setContentsMargins(3, 0, 0, 0); + + nameLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); + textLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); + + layout->addWidget(nameLabel); + layout->addWidget(textLabel); + + widget->setLayout(layout); + + treeWidget->setItemWidget(item, FriendList::COLUMN_NAME, widget); + } else { + nameLabel = widget->property("nameLabel").value(); + textLabel = widget->property("textLabel").value(); + } +} + /** * Get the list of peers from the RsIface. * Adds all friend gpg ids, with their nodes as children to the peerTreeWidget. @@ -752,9 +793,6 @@ void FriendList::insertPeers() ++availableCount; - QString gpgName = QString::fromUtf8(detail.name.c_str()); - QString gpgItemText = gpgName; - // remove items that are not friends anymore int childCount = gpgItem->childCount(); int childIndex = 0; @@ -953,31 +991,50 @@ void FriendList::insertPeers() } /* Location */ - QString sName = QString::fromUtf8(sslDetail.location.c_str()); - QString sText = sName; + QString sslName = QString::fromUtf8(sslDetail.location.c_str()); + QString sslText; if (mShowState) { if (!connectStateString.isEmpty()) { - sText += "\n" + connectStateString; + sslText = connectStateString; if (!customStateString.isEmpty()) { - sText += " [" + customStateString + "]"; + sslText += " [" + customStateString + "]"; } } else { if (!customStateString.isEmpty()) { - sText += "\n" + customStateString; + sslText = customStateString; } } sslItem->setToolTip(COLUMN_NAME, ""); } else { if (!customStateString.isEmpty()) { - sText += "\n" + customStateString; + sslText = customStateString; } /* Show the state as tooltip */ sslItem->setToolTip(COLUMN_NAME, connectStateString); } - sslItem->setText(COLUMN_NAME, sText); + + /* Create or get ssl label */ + ElidedLabel *sslNameLabel = NULL; + ElidedLabel *sslTextLabel = NULL; + + getNameWidget(ui->peerTreeWidget, sslItem, sslNameLabel, sslTextLabel); + + if (sslNameLabel) { + sslNameLabel->setText(sslName); + sslNameLabel->setFont(sslFont); + + QPalette palette = sslNameLabel->palette(); + palette.setColor(sslNameLabel->foregroundRole(), sslColor); + + sslNameLabel->setPalette(palette); + } + if (sslTextLabel) { + sslTextLabel->setText(sslText); + sslTextLabel->setVisible(!sslText.isEmpty()); + } if (std::find(privateChatIds.begin(), privateChatIds.end(), sslDetail.id) != privateChatIds.end()) { // private chat is available @@ -987,7 +1044,7 @@ void FriendList::insertPeers() sslItem->setIcon(COLUMN_NAME, createAvatar(sslAvatar, sslOverlayIcon)); /* Sort data */ - sslItem->setData(COLUMN_SORT, ROLE_SORT_NAME, sName); + sslItem->setData(COLUMN_SORT, ROLE_SORT_NAME, sslName); sslItem->setData(COLUMN_SORT, ROLE_SORT_STATE, peerState); for (int i = 0; i < columnCount; ++i) { @@ -996,6 +1053,13 @@ void FriendList::insertPeers() } } + QString gpgName = QString::fromUtf8(detail.name.c_str()); + QString gpgText; + QFont gpgFont; + QColor gpgColor; + + bool showInfoAtGpgItem = !gpgItem->isExpanded(); + QPixmap gpgOverlayIcon; if (gpg_connected) { gpgItem->setHidden(false); @@ -1008,56 +1072,51 @@ void FriendList::insertPeers() bestRSState = RS_STATUS_ONLINE; } - QColor textColor = mTextColorStatus[bestRSState]; - QFont font = StatusDefs::font(bestRSState); - for(int i = 0; i < columnCount; ++i) { - gpgItem->setTextColor(i, textColor); - gpgItem->setFont(i, font); - } + gpgColor = mTextColorStatus[bestRSState]; + gpgFont = StatusDefs::font(bestRSState); - gpgOverlayIcon = QPixmap(StatusDefs::imageStatus(bestRSState)); + if (showInfoAtGpgItem) { + gpgOverlayIcon = QPixmap(StatusDefs::imageStatus(bestRSState)); - if (mShowState) { - gpgItemText += "\n" + StatusDefs::name(bestRSState); - if (!bestCustomStateString.isEmpty()) { - gpgItemText += " [" + bestCustomStateString + "]"; - } - } else { - if (!bestCustomStateString.isEmpty()) { - gpgItemText += "\n" + bestCustomStateString; + if (mShowState) { + gpgText = StatusDefs::name(bestRSState); + if (!bestCustomStateString.isEmpty()) { + gpgText += " [" + bestCustomStateString + "]"; + } + } else { + if (!bestCustomStateString.isEmpty()) { + gpgText = bestCustomStateString; + } } } } else if (gpg_online) { - if (mShowState) { - gpgItemText += "\n" + tr("Available"); - } - - bestPeerState = PEER_STATE_AVAILABLE; - ++onlineCount; gpgItem->setHidden(mHideUnconnected); - gpgOverlayIcon = QPixmap(IMAGE_AVAILABLE); + ++onlineCount; + bestPeerState = PEER_STATE_AVAILABLE; - QFont font; - font.setBold(true); - QColor textColor = mTextColorStatus[RS_STATUS_ONLINE]; - for(int i = 0; i < columnCount; ++i) { - gpgItem->setTextColor(i, textColor); - gpgItem->setFont(i,font); + gpgFont.setBold(true); + gpgColor = mTextColorStatus[RS_STATUS_ONLINE]; + + if (showInfoAtGpgItem) { + if (mShowState) { + gpgText += tr("Available"); + } + + gpgOverlayIcon = QPixmap(IMAGE_AVAILABLE); } } else { - if (mShowState) { - gpgItemText += "\n" + StatusDefs::name(RS_STATUS_OFFLINE); - } - bestPeerState = PEER_STATE_OFFLINE; gpgItem->setHidden(mHideUnconnected); - gpgOverlayIcon = QPixmap(StatusDefs::imageStatus(RS_STATUS_OFFLINE)); - QColor textColor = mTextColorStatus[RS_STATUS_OFFLINE]; - QFont font = StatusDefs::font(RS_STATUS_OFFLINE); - for(int i = 0; i < columnCount; ++i) { - gpgItem->setTextColor(i, textColor); - gpgItem->setFont(i, font); + gpgFont = StatusDefs::font(RS_STATUS_OFFLINE); + gpgColor = mTextColorStatus[RS_STATUS_OFFLINE]; + + if (showInfoAtGpgItem) { + if (mShowState) { + gpgText += StatusDefs::name(RS_STATUS_OFFLINE); + } + + gpgOverlayIcon = QPixmap(StatusDefs::imageStatus(RS_STATUS_OFFLINE)); } } @@ -1067,14 +1126,38 @@ void FriendList::insertPeers() gpgItem->setIcon(COLUMN_NAME, createAvatar(bestAvatar.isNull() ? QPixmap(AVATAR_DEFAULT_IMAGE) : bestAvatar, gpgOverlayIcon)); - gpgItem->setText(COLUMN_NAME, gpgItemText); - gpgItem->setData(COLUMN_LAST_CONTACT, Qt::DisplayRole, QVariant(bestLastContact)); - gpgItem->setText(COLUMN_IP, bestIP); + /* Create or get gpg label */ + ElidedLabel *gpgNameLabel = NULL; + ElidedLabel *gpgTextLabel = NULL; + + getNameWidget(ui->peerTreeWidget, gpgItem, gpgNameLabel, gpgTextLabel); + + if (gpgNameLabel) { + gpgNameLabel->setText(gpgName); + gpgNameLabel->setFont(gpgFont); + + QPalette palette = gpgNameLabel->palette(); + palette.setColor(gpgNameLabel->foregroundRole(), gpgColor); + + gpgNameLabel->setPalette(palette); + } + if (gpgTextLabel) { + gpgTextLabel->setText(gpgText); + gpgTextLabel->setVisible(!gpgText.isEmpty()); + } + + gpgItem->setData(COLUMN_LAST_CONTACT, Qt::DisplayRole, showInfoAtGpgItem ? QVariant(bestLastContact) : ""); + gpgItem->setText(COLUMN_IP, showInfoAtGpgItem ? bestIP : ""); /* Sort data */ gpgItem->setData(COLUMN_SORT, ROLE_SORT_NAME, gpgName); gpgItem->setData(COLUMN_SORT, ROLE_SORT_STATE, bestPeerState); + for (int i = 0; i < columnCount; ++i) { + gpgItem->setTextColor(i, gpgColor); + gpgItem->setFont(i, gpgFont); + } + if (openPeers != NULL && openPeers->find(gpgId.toStdString()) != openPeers->end()) { gpgItem->setExpanded(true); } @@ -1669,6 +1752,17 @@ void FriendList::peerTreeColumnVisibleChanged(int /*column*/, bool visible) } } +void FriendList::peerTreeItemCollapsedExpanded(QTreeWidgetItem *item) +{ + if (!item) { + return; + } + + if (item->type() == TYPE_GPG) { + insertPeers(); + } +} + void FriendList::setShowState(bool show) { if (mShowState != show) { diff --git a/retroshare-gui/src/gui/common/FriendList.h b/retroshare-gui/src/gui/common/FriendList.h index aa8965ad2..5522c775f 100644 --- a/retroshare-gui/src/gui/common/FriendList.h +++ b/retroshare-gui/src/gui/common/FriendList.h @@ -107,6 +107,7 @@ public slots: private slots: void peerTreeColumnVisibleChanged(int column, bool visible); + void peerTreeItemCollapsedExpanded(QTreeWidgetItem *item); protected: void changeEvent(QEvent *e); diff --git a/retroshare-gui/src/gui/common/FriendList.ui b/retroshare-gui/src/gui/common/FriendList.ui index 70e323ff0..fa4a44223 100644 --- a/retroshare-gui/src/gui/common/FriendList.ui +++ b/retroshare-gui/src/gui/common/FriendList.ui @@ -75,12 +75,6 @@ Qt::CustomContextMenu - - - 38 - 38 - - true From 48c3eedcf5616bf855d562fefce713933c37508d Mon Sep 17 00:00:00 2001 From: thunder2 Date: Wed, 19 Aug 2015 13:22:31 +0200 Subject: [PATCH 063/165] Removed "CONFIG += console" for Windows release build. --- retroshare-gui/src/retroshare-gui.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 79988dce8..85c4e7148 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -164,7 +164,7 @@ win32-x-g++ { #################################### Windows ##################################### win32 { - debug { + CONFIG(debug, debug|release) { # show console output CONFIG += console } From 941959cc861a2d19c47aead1c9be8f630f5d1a08 Mon Sep 17 00:00:00 2001 From: sehraf Date: Wed, 19 Aug 2015 19:02:28 +0200 Subject: [PATCH 064/165] conversion from QSettings to XML --- retroshare-gui/src/gui/common/FriendList.cpp | 238 ++++++++++++------- 1 file changed, 149 insertions(+), 89 deletions(-) diff --git a/retroshare-gui/src/gui/common/FriendList.cpp b/retroshare-gui/src/gui/common/FriendList.cpp index c952a5b5c..b298fc461 100644 --- a/retroshare-gui/src/gui/common/FriendList.cpp +++ b/retroshare-gui/src/gui/common/FriendList.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "rsserver/rsaccounts.h" #include "retroshare/rspeers.h" @@ -1665,8 +1666,8 @@ void FriendList::exportFriendlistClicked() QMessageBox mbox; mbox.setIcon(QMessageBox::Information); mbox.setText(tr("Done!")); - mbox.setInformativeText("Your friendlist is stored at:\n" + fileName + - "\n(keep in mind that the file is unencrypted!)"); + mbox.setInformativeText(tr("Your friendlist is stored at:\n") + fileName + + tr("\n(keep in mind that the file is unencrypted!)")); mbox.setStandardButtons(QMessageBox::Ok); mbox.exec(); } @@ -1683,16 +1684,16 @@ void FriendList::importFriendlistClicked() QMessageBox mbox; mbox.setIcon(QMessageBox::Information); mbox.setText(tr("Done!")); - mbox.setInformativeText("Your friendlist was imported from:\n" + fileName); + mbox.setInformativeText(tr("Your friendlist was imported from:\n") + fileName); mbox.setStandardButtons(QMessageBox::Ok); mbox.exec(); } else { QMessageBox mbox; mbox.setIcon(QMessageBox::Warning); mbox.setText(tr("Done - but errors happened!")); - mbox.setInformativeText("Your friendlist was imported from:\n" + fileName + - (errorPeers ? "\nat least one peer was not added" : "") + - (errorGroups ? "\nat least one peer was not added to a group" : "") + mbox.setInformativeText(tr("Your friendlist was imported from:\n") + fileName + + (errorPeers ? tr("\nat least one peer was not added") : "") + + (errorGroups ? tr("\nat least one peer was not added to a group") : "") ); mbox.setStandardButtons(QMessageBox::Ok); mbox.exec(); @@ -1713,7 +1714,7 @@ bool FriendList::importExportFriendlistFileDialog(QString &fileName, bool import RshareSettings::LASTDIR_CERT, (import ? tr("Select file for importing yoour friendlist from") : tr("Select a file for exporting your friendlist to")), - tr("Text file (*.txt);; Ini File (*.ini);;All Files (*)"), + tr("XML File (*.xml);;All Files (*)"), fileName, NULL, (import ? QFileDialog::DontConfirmOverwrite : (QFileDialog::Options)0) @@ -1722,7 +1723,7 @@ bool FriendList::importExportFriendlistFileDialog(QString &fileName, bool import QMessageBox mbox; mbox.setIcon(QMessageBox::Warning); mbox.setText(tr("Error")); - mbox.setInformativeText("Failed to get a file!"); + mbox.setInformativeText(tr("Failed to get a file!")); mbox.setStandardButtons(QMessageBox::Ok); mbox.exec(); return false; @@ -1739,22 +1740,17 @@ bool FriendList::importExportFriendlistFileDialog(QString &fileName, bool import */ bool FriendList::exportFriendlist(QString &fileName) { - // this has to be IniFormat because it is platform idependet (qsettings documentation) - QSettings s(fileName, QSettings::IniFormat); - s.clear(); - if(!s.isWritable()) { + QDomDocument doc("FriendListWithGroups"); + QDomElement root = doc.createElement("root"); + doc.appendChild(root); + + QFile file(fileName); + if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { // show error to user QMessageBox mbox; mbox.setIcon(QMessageBox::Warning); mbox.setText(tr("Error")); - mbox.setInformativeText("File is not writeable!\n" + fileName + "\nStatus: " + - ( - (s.status() == QSettings::NoError) ? "no error" : - ( - (s.status() == QSettings::AccessError) ? "access error" : "format error" - ) - ) - ); + mbox.setInformativeText(tr("File is not writeable!\n") + fileName); mbox.setStandardButtons(QMessageBox::Ok); mbox.exec(); return false; @@ -1766,18 +1762,15 @@ bool FriendList::exportFriendlist(QString &fileName) std::list group_info_list; rsPeers->getGroupInfoList(group_info_list); - s.beginGroup("pgpIDs"); + QDomElement pgpIDs = doc.createElement("pgpIDs"); RsPeerDetails details; for(std::list::iterator list_iter = gpg_ids.begin(); list_iter != gpg_ids.end(); list_iter++) { rsPeers->getGPGDetails(*list_iter, details); - s.beginGroup(details.gpg_id.toStdString().c_str()); - // since everything is loaded from the public key there is no need to save these - //s.setValue("pgpID", details.gpg_id.toStdString().c_str()); - s.setValue("name", details.name.c_str()); // storing name for better human readability - //s.setValue("email", details.email.c_str()); - //s.setValue("trustLvl", details.trustLvl); + QDomElement pgpID = doc.createElement("pgpID"); + // these values aren't used and just stored for better human readability + pgpID.setAttribute("id", QString::fromStdString(details.gpg_id.toStdString())); + pgpID.setAttribute("name", QString::fromUtf8(details.name.c_str())); - s.beginGroup("sslIDs"); std::list ssl_ids; rsPeers->getAssociatedSSLIds(*list_iter, ssl_ids); for(std::list::iterator list_iter = ssl_ids.begin(); list_iter != ssl_ids.end(); list_iter++) { @@ -1786,56 +1779,107 @@ bool FriendList::exportFriendlist(QString &fileName) continue; std::string invite = rsPeers->GetRetroshareInvite(detail2.id, true); - std::string sid = detail2.id.toStdString(); - s.beginGroup(sid.c_str()); - // since everything is loaded from the public key there is no need to save these - //s.setValue("sslID", sid.c_str()); - //s.setValue("location", detail2.location.c_str()); - s.setValue("pubkey", invite.c_str()); - s.setValue("service_perm_flags", detail2.service_perm_flags.toUInt32()); - s.endGroup(); // sid + QDomElement sslID = doc.createElement("sslID"); + // these values aren't used and just stored for better human readability + sslID.setAttribute("sslID", QString::fromStdString(detail2.id.toStdString())); + sslID.setAttribute("location", QString::fromUtf8(detail2.location.c_str())); + + // required values + sslID.setAttribute("pubkey", QString::fromStdString(invite)); + sslID.setAttribute("service_perm_flags", detail2.service_perm_flags.toUInt32()); + + pgpID.appendChild(sslID); } - s.endGroup(); // sslIDs - - s.endGroup(); // details.gpg_id + pgpIDs.appendChild(pgpID); } - s.endGroup(); // pgpIDs + root.appendChild(pgpIDs); - s.beginGroup("groups"); + QDomElement groups = doc.createElement("groups"); for(std::list::iterator list_iter = group_info_list.begin(); list_iter != group_info_list.end(); list_iter++) { RsGroupInfo group_info = *list_iter; - s.beginGroup(group_info.id.c_str()); + + //skip groups without peers + if(group_info.peerIds.empty()) + continue; + + QDomElement group = doc.createElement("group"); // id is not needed since it may differ between locatiosn / pgp ids (groups are identified by name) - s.setValue("name", group_info.name.c_str()); - s.setValue("flag", group_info.flag); + group.setAttribute("name", QString::fromStdString(group_info.name)); + group.setAttribute("flag", group_info.flag); - s.beginGroup("peerIDs"); for(std::set::iterator i = group_info.peerIds.begin(); i != group_info.peerIds.end(); i++) { + QDomElement pgpID = doc.createElement("pgpID"); std::string pid = i->toStdString(); - // key = peerId, value = arbitrary - s.setValue(pid.c_str(), 0); + pgpID.setAttribute("id", QString::fromStdString(pid)); + group.appendChild(pgpID); } - s.endGroup(); // peerIDs - - s.endGroup(); // group_info.id + groups.appendChild(group); } - s.endGroup(); // groups + root.appendChild(groups); + + QTextStream ts(&file); + ts.setCodec("UTF-8"); + ts << doc.toString(); + file.close(); return true; } +/** + * @brief helper function to show a message box + */ +void showXMLParsingError() +{ + // show error to user + QMessageBox mbox; + mbox.setIcon(QMessageBox::Warning); + mbox.setText(QObject::tr("Error")); + mbox.setInformativeText(QObject::tr("unable to parse XML file!")); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); +} + /** * @brief Imports friends from a given file * @param fileName file to load friends from * @param errorPeers an error occured while adding a peer * @param errorGroups an error occured while adding a peer to a group - * @return success or failure (an error means that adding a peer and/or adding a peer to a group failed at least once) + * @return success or failure (an error can also happen when adding a peer and/or adding a peer to a group fails at least once) */ bool FriendList::importFriendlist(QString &fileName, bool &errorPeers, bool &errorGroups) { - // this has to be IniFormat because it is platform idependet (qsettings documentation) - QSettings s(fileName, QSettings::IniFormat); + QDomDocument doc; + // load from file + { + QFile file(fileName); + + if (!file.open(QIODevice::ReadOnly)) { + // show error to user + QMessageBox mbox; + mbox.setIcon(QMessageBox::Warning); + mbox.setText(tr("Error")); + mbox.setInformativeText(tr("File is not readable!\n") + fileName); + mbox.setStandardButtons(QMessageBox::Ok); + mbox.exec(); + return false; + } + + bool ok = doc.setContent(&file); + file.close(); + + if(!ok) { + showXMLParsingError(); + return false; + } + } + + QDomElement root = doc.documentElement(); + if(root.tagName() != "root") { + showXMLParsingError(); + return false; + } + errorPeers = false; errorGroups = false; @@ -1848,25 +1892,33 @@ bool FriendList::importFriendlist(QString &fileName, bool &errorPeers, bool &err // lock all events for faster processing RsAutoUpdatePage::lockAllEvents(); - s.beginGroup("pgpIDs"); - QStringList pgpIDs = s.childGroups(); - foreach (QString pgpID, pgpIDs) { - s.beginGroup(pgpID); - - // enter sslIDs group and iterate over all ssl IDs - s.beginGroup("sslIDs"); - QStringList sslIDs = s.childGroups(); - foreach (QString sslID, sslIDs) { - s.beginGroup(sslID); + // pgp and ssl IDs + QDomElement pgpIDs; + { + QDomNodeList nodes = root.elementsByTagName("pgpIDs"); + if(nodes.isEmpty() || nodes.size() != 1){ + showXMLParsingError(); + return false; + } + pgpIDs = nodes.item(0).toElement(); + if(pgpIDs.isNull()){ + showXMLParsingError(); + return false; + } + } + QDomNode pgpIDElem = pgpIDs.firstChildElement("pgpID"); + while (!pgpIDElem.isNull()) { + QDomElement sslIDElem = pgpIDElem.firstChildElement("sslID"); + while (!sslIDElem.isNull()) { rsPeerID.clear(); rsPgpID.clear(); // load everything needed from the pubkey string - std::string pubkey = s.value("pubkey").toString().toStdString(); + std::string pubkey = sslIDElem.attribute("pubkey").toStdString(); if(rsPeers->loadDetailsFromStringCert(pubkey, rsPeerDetails, error_code)) { if(rsPeers->loadCertificateFromString(pubkey, rsPeerID, rsPgpID, error_string)) { - ServicePermissionFlags service_perm_flags(s.value("service_perm_flags").toInt()); + ServicePermissionFlags service_perm_flags(sslIDElem.attribute("service_perm_flags").toInt()); // everything is loaded - start setting things if (!rsPeerDetails.id.isNull() && !rsPeerDetails.gpg_id.isNull()) { @@ -1893,54 +1945,62 @@ bool FriendList::importFriendlist(QString &fileName, bool &errorPeers, bool &err rsPeers->addFriend(pid, rsPeerDetails.gpg_id, service_perm_flags); } else { errorPeers = true; - std::cerr << "FriendList::importFriendlist(): error while procvessing SSL id " << sslID.toStdString() << std::endl; + std::cerr << "FriendList::importFriendlist(): error while processing SSL id: " << sslIDElem.attribute("sslID", "invalid").toStdString() << std::endl; } } else { errorPeers = true; - std::cerr << "FriendList::importFriendlist(): failed to get peer detaisl from public key (SSL id: " << sslID.toStdString() << " - error: " << error_string << ")" << std::endl; + std::cerr << "FriendList::importFriendlist(): failed to get peer detaisl from public key (SSL id: " << sslIDElem.attribute("sslID", "invalid").toStdString() << " - error: " << error_string << ")" << std::endl; } } else { errorPeers = true; - std::cerr << "FriendList::importFriendlist(): failed to get peer detaisl from public key (SSL id: " << sslID.toStdString() << " - error: " << error_code << ")" << std::endl; + std::cerr << "FriendList::importFriendlist(): failed to get peer detaisl from public key (SSL id: " << sslIDElem.attribute("sslID", "invalid").toStdString() << " - error: " << error_code << ")" << std::endl; } - s.endGroup(); // sslID + sslIDElem = sslIDElem.nextSiblingElement("sslID"); } - s.endGroup(); // sslIDs - s.endGroup(); // pgpID + pgpIDElem = pgpIDElem.nextSiblingElement("pgpID"); } - s.endGroup(); // pgpIDs - // enter groups group and iterate over all groups - s.beginGroup("groups"); - QStringList groupList = s.childGroups(); - foreach (QString group, groupList) { - s.beginGroup(group); + // groups + QDomElement groups; + { + QDomNodeList nodes = root.elementsByTagName("groups"); + if(nodes.isEmpty() || nodes.size() != 1){ + showXMLParsingError(); + return false; + } + groups = nodes.item(0).toElement(); + if(groups.isNull()){ + showXMLParsingError(); + return false; + } + } + QDomElement group = groups.firstChildElement("group"); + while (!group.isNull()) { // get name and flags and try to get the group ID - std::string groupName = s.value("name").toString().toStdString(); - uint32_t flag = s.value("flag").toUInt(); + std::string groupName = group.attribute("name").toStdString(); + uint32_t flag = group.attribute("flag").toInt(); std::string groupId; if(getOrCreateGroup(groupName, flag, groupId)) { // group id found! - // enter peerIDs group and iterate over all pgpIDs of this group - s.beginGroup("peerIDs"); - QStringList pgpIDsForGroup = s.allKeys(); - foreach (QString pgpIDForGroup, pgpIDsForGroup) { + QDomElement pgpID = group.firstChildElement("pgpID"); + while (!pgpID.isNull()) { // add pgp id to group - RsPgpId rsPgpId(pgpIDForGroup.toStdString()); - if(rsPeers->assignPeerToGroup(groupId, rsPgpId, true)) { + RsPgpId rsPgpId(pgpID.attribute("id").toStdString()); + if(rsPgpID.isNull() || !rsPeers->assignPeerToGroup(groupId, rsPgpId, true)) { errorGroups = true; std::cerr << "FriendList::importFriendlist(): failed to add '" << rsPeers->getGPGName(rsPgpId) << "'' to group '" << groupName << "'" << std::endl; } + + pgpID = pgpID.nextSiblingElement("pgpID"); } - s.endGroup(); // peerIDs + pgpID = pgpID.nextSiblingElement("pgpID"); } else { errorGroups = true; std::cerr << "FriendList::importFriendlist(): failed to find/create group '" << groupName << "'" << std::endl; } - s.endGroup(); // group + group = group.nextSiblingElement("group"); } - s.endGroup(); // groups // unlock events RsAutoUpdatePage::unlockAllEvents(); From 04a1c10a56cdbd8baeb4b09b0116d0ad41b1a511 Mon Sep 17 00:00:00 2001 From: sehraf Date: Wed, 19 Aug 2015 19:12:38 +0200 Subject: [PATCH 065/165] fixed UTF-8 group names --- retroshare-gui/src/gui/common/FriendList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/common/FriendList.cpp b/retroshare-gui/src/gui/common/FriendList.cpp index b298fc461..082ac352a 100644 --- a/retroshare-gui/src/gui/common/FriendList.cpp +++ b/retroshare-gui/src/gui/common/FriendList.cpp @@ -1805,7 +1805,7 @@ bool FriendList::exportFriendlist(QString &fileName) QDomElement group = doc.createElement("group"); // id is not needed since it may differ between locatiosn / pgp ids (groups are identified by name) - group.setAttribute("name", QString::fromStdString(group_info.name)); + group.setAttribute("name", QString::fromUtf8(group_info.name.c_str())); group.setAttribute("flag", group_info.flag); for(std::set::iterator i = group_info.peerIds.begin(); i != group_info.peerIds.end(); i++) { From 1d9e3988a34919ae8de2f252c0a5540e93f42dce Mon Sep 17 00:00:00 2001 From: cave beat Date: Wed, 19 Aug 2015 20:26:23 +0200 Subject: [PATCH 066/165] removed LinksCloud LinksCloud has been replaced by Posted and is hosted for archiving reasons in https://github.com/RetroShare/LinksCloud --- plugins/LinksCloud/AddLinksDialog.cpp | 122 -- plugins/LinksCloud/AddLinksDialog.h | 48 - plugins/LinksCloud/AddLinksDialog.ui | 244 ---- plugins/LinksCloud/LinksCloud.pro | 37 - plugins/LinksCloud/LinksCloudPlugin.cpp | 117 -- plugins/LinksCloud/LinksCloudPlugin.h | 35 - plugins/LinksCloud/LinksCloud_images.qrc | 5 - plugins/LinksCloud/LinksDialog.cpp | 994 -------------- plugins/LinksCloud/LinksDialog.h | 97 -- plugins/LinksCloud/LinksDialog.ui | 572 -------- plugins/LinksCloud/images/irkick.png | Bin 2231 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_ca_ES.qm | Bin 5014 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_ca_ES.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_cs.qm | Bin 4843 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_cs.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_da.qm | Bin 98 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_da.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_de.qm | Bin 4975 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_de.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_el.qm | Bin 5103 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_el.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_en.qm | Bin 23 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_en.ts | 331 ----- plugins/LinksCloud/lang/LinksCloud_es.qm | Bin 5053 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_es.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_fi.qm | Bin 4935 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_fi.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_fr.qm | Bin 4945 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_fr.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_hu.qm | Bin 5122 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_hu.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_it.qm | Bin 5285 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_it.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_ja_JP.qm | Bin 245 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_ja_JP.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_ko.qm | Bin 4118 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_ko.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_lang.qrc | 24 - plugins/LinksCloud/lang/LinksCloud_nl.qm | Bin 4905 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_nl.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_pl.qm | Bin 3634 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_pl.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_ru.qm | Bin 702 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_ru.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_sv.qm | Bin 4827 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_sv.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_tr.qm | Bin 4968 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_tr.ts | 329 ----- plugins/LinksCloud/lang/LinksCloud_zh_CN.qm | Bin 3874 -> 0 bytes plugins/LinksCloud/lang/LinksCloud_zh_CN.ts | 329 ----- plugins/LinksCloud/p3ranking.cc | 1350 ------------------- plugins/LinksCloud/p3ranking.h | 165 --- plugins/LinksCloud/rsrank.h | 96 -- plugins/LinksCloud/rsrankitems.cc | 253 ---- plugins/LinksCloud/rsrankitems.h | 110 -- 55 files changed, 10522 deletions(-) delete mode 100644 plugins/LinksCloud/AddLinksDialog.cpp delete mode 100644 plugins/LinksCloud/AddLinksDialog.h delete mode 100644 plugins/LinksCloud/AddLinksDialog.ui delete mode 100644 plugins/LinksCloud/LinksCloud.pro delete mode 100644 plugins/LinksCloud/LinksCloudPlugin.cpp delete mode 100644 plugins/LinksCloud/LinksCloudPlugin.h delete mode 100644 plugins/LinksCloud/LinksCloud_images.qrc delete mode 100644 plugins/LinksCloud/LinksDialog.cpp delete mode 100644 plugins/LinksCloud/LinksDialog.h delete mode 100644 plugins/LinksCloud/LinksDialog.ui delete mode 100644 plugins/LinksCloud/images/irkick.png delete mode 100644 plugins/LinksCloud/lang/LinksCloud_ca_ES.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_ca_ES.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_cs.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_cs.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_da.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_da.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_de.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_de.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_el.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_el.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_en.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_en.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_es.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_es.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_fi.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_fi.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_fr.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_fr.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_hu.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_hu.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_it.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_it.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_ja_JP.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_ja_JP.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_ko.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_ko.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_lang.qrc delete mode 100644 plugins/LinksCloud/lang/LinksCloud_nl.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_nl.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_pl.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_pl.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_ru.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_ru.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_sv.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_sv.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_tr.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_tr.ts delete mode 100644 plugins/LinksCloud/lang/LinksCloud_zh_CN.qm delete mode 100644 plugins/LinksCloud/lang/LinksCloud_zh_CN.ts delete mode 100644 plugins/LinksCloud/p3ranking.cc delete mode 100644 plugins/LinksCloud/p3ranking.h delete mode 100644 plugins/LinksCloud/rsrank.h delete mode 100644 plugins/LinksCloud/rsrankitems.cc delete mode 100644 plugins/LinksCloud/rsrankitems.h diff --git a/plugins/LinksCloud/AddLinksDialog.cpp b/plugins/LinksCloud/AddLinksDialog.cpp deleted file mode 100644 index 366e2ccff..000000000 --- a/plugins/LinksCloud/AddLinksDialog.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/**************************************************************** - * RetroShare is distributed under the following license: - * - * Copyright (C) 2008 Robert Fernie - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - ****************************************************************/ - -#include - -#include "AddLinksDialog.h" -//#include -#include "rsrank.h" - -/* Images for context menu icons */ -#define IMAGE_EXPORTFRIEND ":/images/exportpeers_16x16.png" -#define IMAGE_GREAT ":/images/filerating5.png" -#define IMAGE_GOOD ":/images/filerating4.png" -#define IMAGE_OK ":/images/filerating3.png" -#define IMAGE_SUX ":/images/filerating2.png" -#define IMAGE_BADLINK ":/images/filerating1.png" - -/** Constructor */ -AddLinksDialog::AddLinksDialog(QString url, QWidget *parent) -: QDialog(parent) -{ - /* Invoke the Qt Designer generated object setup routine */ - ui.setupUi(this); - - ui.headerFrame->setHeaderImage(QPixmap(":/images/irkick.png")); - ui.headerFrame->setHeaderText(tr("Add Link to Cloud")); - - setAttribute ( Qt::WA_DeleteOnClose, true ); - - /* add button */ - connect(ui.addLinkButton, SIGNAL(clicked()), this, SLOT(addLinkComment())); - connect(ui.closepushButton, SIGNAL(clicked()), this, SLOT(close())); - - connect( ui.anonBox, SIGNAL( stateChanged ( int ) ), this, SLOT( load ( void ) ) ); - - ui.linkLineEdit->setText(url); - - // RetroShareLink link(url); - -// if(link.valid() && link.type() == RetroShareLink::TYPE_FILE) -// ui.titleLineEdit->setText(link.name()); -// else - ui.titleLineEdit->setText(tr("New Link")); - - load(); -} - -int AddLinksDialog::IndexToScore(int index) -{ - if ((index == -1) || (index > 4)) - return 0; - int score = 2 - index; - return score; -} - -void AddLinksDialog::addLinkComment() -{ - /* get the title / link / comment */ - QString title = ui.titleLineEdit->text(); - QString link = ui.linkLineEdit->text(); - QString comment = ui.linkTextEdit->toPlainText(); - int32_t score = AddLinksDialog::IndexToScore(ui.scoreBox->currentIndex()); - - if ((link == "") || (title == "")) - { - QMessageBox::warning(NULL, tr("Add Link Failure"), tr("Missing Link and/or Title"), QMessageBox::Ok); - /* can't do anything */ - return; - } - - /* add it either way */ - if (ui.anonBox->isChecked()) - { - rsRanks->anonRankMsg("", link.toStdWString(), title.toStdWString()); - } - else - { - rsRanks->newRankMsg(link.toStdWString(), - title.toStdWString(), - comment.toStdWString(), score); - } - - close(); -} - -void AddLinksDialog::load() -{ - if (ui.anonBox->isChecked()) - { - - /* disable comment + score */ - ui.scoreBox->setEnabled(false); - ui.linkTextEdit->setEnabled(false); - - /* done! */ - return; - } - else - { - /* enable comment + score */ - ui.scoreBox->setEnabled(true); - ui.linkTextEdit->setEnabled(true); - } -} diff --git a/plugins/LinksCloud/AddLinksDialog.h b/plugins/LinksCloud/AddLinksDialog.h deleted file mode 100644 index 9e4451117..000000000 --- a/plugins/LinksCloud/AddLinksDialog.h +++ /dev/null @@ -1,48 +0,0 @@ -/**************************************************************** - * RetroShare GUI is distributed under the following license: - * - * Copyright (C) 2008 Robert Fernie - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - ****************************************************************/ - -#ifndef _ADDLINKS_DIALOG_H -#define _ADDLINKS_DIALOG_H - -#include "ui_AddLinksDialog.h" - -class AddLinksDialog : public QDialog -{ - Q_OBJECT - -public: - /** Default Constructor */ - AddLinksDialog(QString url, QWidget *parent = 0); - /** Default Destructor */ - - static int IndexToScore(int index); - -public slots: - void addLinkComment(); - - void load(); - -private: - /** Qt Designer generated object */ - Ui::AddLinksDialog ui; -}; - -#endif diff --git a/plugins/LinksCloud/AddLinksDialog.ui b/plugins/LinksCloud/AddLinksDialog.ui deleted file mode 100644 index 26018091d..000000000 --- a/plugins/LinksCloud/AddLinksDialog.ui +++ /dev/null @@ -1,244 +0,0 @@ - - - AddLinksDialog - - - - 0 - 0 - 614 - 415 - - - - Add Link - - - - :/images/rstray3.png:/images/rstray3.png - - - - 0 - - - 0 - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - - - - QFrame::NoFrame - - - QFrame::Raised - - - - - - Cancel - - - - - - - Add Link - - - false - - - true - - - - - - - Qt::Horizontal - - - - 375 - 20 - - - - - - - - Add a new Link - - - - 1 - - - - - - - - - Title: - - - - - - - Url: - - - - - - - - - - - - - - - 0 - 0 - - - - - - - - - - - - - 16777215 - 40 - - - - - - - Add Anonymous Link - - - - - - - - +2 Great! - - - - :/images/filerating5.png:/images/filerating5.png - - - - - +1 Good - - - - :/images/filerating4.png:/images/filerating4.png - - - - - 0 Okay - - - - :/images/filerating3.png:/images/filerating3.png - - - - - -1 Sux - - - - :/images/filerating2.png:/images/filerating2.png - - - - - -2 Bad Link - - - - :/images/filerating1.png:/images/filerating1.png - - - - - - - - Qt::Horizontal - - - - 299 - 20 - - - - - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - - - - - - - - - - - - HeaderFrame - QFrame -
gui/common/HeaderFrame.h
- 1 -
-
- - - - -
diff --git a/plugins/LinksCloud/LinksCloud.pro b/plugins/LinksCloud/LinksCloud.pro deleted file mode 100644 index fe904d930..000000000 --- a/plugins/LinksCloud/LinksCloud.pro +++ /dev/null @@ -1,37 +0,0 @@ -!include("../Common/retroshare_plugin.pri"): error("Could not include file ../Common/retroshare_plugin.pri") - -CONFIG += qt uic qrc resources - -greaterThan(QT_MAJOR_VERSION, 4) { - # Qt 5 - QT += widgets -} - -SOURCES = p3ranking.cc LinksDialog.cpp rsrankitems.cc AddLinksDialog.cpp LinksCloudPlugin.cpp -HEADERS = rsrank.h p3ranking.h LinksDialog.h rsrankitems.h AddLinksDialog.h LinksCloudPlugin.h -FORMS = LinksDialog.ui AddLinksDialog.ui - -TARGET = LinksCloud - -RESOURCES = LinksCloud_images.qrc lang/LinksCloud_lang.qrc - -TRANSLATIONS += \ - lang/LinksCloud_ca_ES.ts \ - lang/LinksCloud_cs.ts \ - lang/LinksCloud_da.ts \ - lang/LinksCloud_de.ts \ - lang/LinksCloud_el.ts \ - lang/LinksCloud_en.ts \ - lang/LinksCloud_es.ts \ - lang/LinksCloud_fi.ts \ - lang/LinksCloud_fr.ts \ - lang/LinksCloud_hu.ts \ - lang/LinksCloud_it.ts \ - lang/LinksCloud_ja_JP.ts \ - lang/LinksCloud_ko.ts \ - lang/LinksCloud_nl.ts \ - lang/LinksCloud_pl.ts \ - lang/LinksCloud_ru.ts \ - lang/LinksCloud_sv.ts \ - lang/LinksCloud_tr.ts \ - lang/LinksCloud_zh_CN.ts \ No newline at end of file diff --git a/plugins/LinksCloud/LinksCloudPlugin.cpp b/plugins/LinksCloud/LinksCloudPlugin.cpp deleted file mode 100644 index f1993988b..000000000 --- a/plugins/LinksCloud/LinksCloudPlugin.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include -#include -#include - -#include "LinksCloudPlugin.h" -#include "LinksDialog.h" - -static void *inited = new LinksCloudPlugin() ; - -extern "C" { - void *RETROSHARE_PLUGIN_provide() - { - static LinksCloudPlugin *p = new LinksCloudPlugin() ; - - return (void*)p ; - } - // This symbol contains the svn revision number grabbed from the executable. - // It will be tested by RS to load the plugin automatically, since it is safe to load plugins - // with same revision numbers, assuming that the revision numbers are up-to-date. - // - uint32_t RETROSHARE_PLUGIN_revision = SVN_REVISION_NUMBER ; - - // This symbol contains the svn revision number grabbed from the executable. - // It will be tested by RS to load the plugin automatically, since it is safe to load plugins - // with same revision numbers, assuming that the revision numbers are up-to-date. - // - uint32_t RETROSHARE_PLUGIN_api = RS_PLUGIN_API_VERSION ; -} - -#define IMAGE_LINKS ":/images/irkick.png" - -void LinksCloudPlugin::getPluginVersion(int& major,int& minor,int& svn_rev) const -{ - major = 5 ; - minor = 4 ; - svn_rev = SVN_REVISION_NUMBER ; -} - -LinksCloudPlugin::LinksCloudPlugin() -{ - mRanking = NULL ; - mainpage = NULL ; - mIcon = NULL ; - mPlugInHandler = NULL; - mPeers = NULL; - mFiles = NULL; -} - -void LinksCloudPlugin::setInterfaces(RsPlugInInterfaces &interfaces){ - - mPeers = interfaces.mPeers; - mFiles = interfaces.mFiles; -} - -MainPage *LinksCloudPlugin::qt_page() const -{ - if(mainpage == NULL) - mainpage = new LinksDialog(mPeers, mFiles) ; - - return mainpage ; -} - -RsCacheService *LinksCloudPlugin::rs_cache_service() const -{ - if(mRanking == NULL) - { - mRanking = new p3Ranking(mPlugInHandler) ; // , 3600 * 24 * 30 * 6); // 6 Months - rsRanks = mRanking ; - } - - return mRanking ; -} - -void LinksCloudPlugin::setPlugInHandler(RsPluginHandler *pgHandler){ - mPlugInHandler = pgHandler; - -} - -QIcon *LinksCloudPlugin::qt_icon() const -{ - if(mIcon == NULL) - { - Q_INIT_RESOURCE(LinksCloud_images) ; - - mIcon = new QIcon(IMAGE_LINKS) ; - } - - return mIcon ; -} - -std::string LinksCloudPlugin::getShortPluginDescription() const -{ - return QApplication::translate("LinksCloudPlugin", "This plugin provides a set of cached links, and a voting system to promote them.").toUtf8().constData(); -} - -std::string LinksCloudPlugin::getPluginName() const -{ - return QApplication::translate("LinksCloudPlugin", "LinksCloud").toUtf8().constData(); -} - -QTranslator* LinksCloudPlugin::qt_translator(QApplication */*app*/, const QString& languageCode, const QString& externalDir) const -{ - if (languageCode == "en") { - return NULL; - } - - QTranslator* translator = new QTranslator(); - - if (translator->load(externalDir + "/LinksCloud_" + languageCode + ".qm")) { - return translator; - } else if (translator->load(":/lang/LinksCloud_" + languageCode + ".qm")) { - return translator; - } - - delete(translator); - return NULL; -} diff --git a/plugins/LinksCloud/LinksCloudPlugin.h b/plugins/LinksCloud/LinksCloudPlugin.h deleted file mode 100644 index e1c590ca5..000000000 --- a/plugins/LinksCloud/LinksCloudPlugin.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include -#include "p3ranking.h" - -class LinksCloudPlugin: public RsPlugin -{ - public: - LinksCloudPlugin() ; - virtual ~LinksCloudPlugin() {} - - virtual RsCacheService *rs_cache_service() const ; - virtual MainPage *qt_page() const ; - virtual QIcon *qt_icon() const ; - virtual uint16_t rs_service_id() const { return RS_SERVICE_TYPE_RANK ; } - virtual QTranslator *qt_translator(QApplication *app, const QString& languageCode, const QString& externalDir) const; - - virtual void getPluginVersion(int& major,int& minor,int& svn_rev) const ; - virtual void setPlugInHandler(RsPluginHandler *pgHandler); - - virtual std::string configurationFileName() const { return std::string() ; } - - virtual std::string getShortPluginDescription() const ; - virtual std::string getPluginName() const; - virtual void setInterfaces(RsPlugInInterfaces& interfaces); - private: - mutable p3Ranking *mRanking ; - mutable RsPluginHandler *mPlugInHandler; - mutable RsFiles* mFiles; - mutable RsPeers* mPeers; - mutable MainPage* mainpage ; - mutable QIcon* mIcon ; -}; - diff --git a/plugins/LinksCloud/LinksCloud_images.qrc b/plugins/LinksCloud/LinksCloud_images.qrc deleted file mode 100644 index 8b2550249..000000000 --- a/plugins/LinksCloud/LinksCloud_images.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - images/irkick.png - - diff --git a/plugins/LinksCloud/LinksDialog.cpp b/plugins/LinksCloud/LinksDialog.cpp deleted file mode 100644 index 08ee39609..000000000 --- a/plugins/LinksCloud/LinksDialog.cpp +++ /dev/null @@ -1,994 +0,0 @@ -/**************************************************************** - * RetroShare is distributed under the following license: - * - * Copyright (C) 2008 Robert Fernie - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - ****************************************************************/ - -#include -#include -#include -#include -#include -#include "LinksDialog.h" -#include -#include "AddLinksDialog.h" -#include "rsrank.h" -#include "util/QtVersion.h" - -#include - - -/* Images for context menu icons */ -#define IMAGE_EXPORTFRIEND ":/images/exportpeers_16x16.png" -#define IMAGE_GREAT ":/images/filerating5.png" -#define IMAGE_GOOD ":/images/filerating4.png" -#define IMAGE_OK ":/images/filerating3.png" -#define IMAGE_SUX ":/images/filerating2.png" -#define IMAGE_BADLINK ":/images/filerating1.png" -#define IMAGE_NOCOMMENTRATING ":/images/filerating0.png" -#define IMAGE_DOWNLOAD ":/images/download16.png" - -/****** - * #define LINKS_DEBUG 1 - *****/ - -/** Constructor */ -LinksDialog::LinksDialog(RsPeers *peers, RsFiles *files, QWidget *parent) -: MainPage(parent), mPeers(peers), mFiles(files) -{ - /* Invoke the Qt Designer generated object setup routine */ - ui.setupUi(this); - - connect( ui.linkTreeWidget, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( linkTreeWidgetCostumPopupMenu( QPoint ) ) ); - - - /* link combos */ - connect( ui.rankComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( changedSortRank( int ) ) ); - connect( ui.periodComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( changedSortPeriod( int ) ) ); - connect( ui.fromComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( changedSortFrom( int ) ) ); - connect( ui.topComboBox, SIGNAL( currentIndexChanged( int ) ), this, SLOT( changedSortTop( int ) ) ); - - /* add button */ - connect( ui.addButton, SIGNAL( clicked( void ) ), this, SLOT( addLinkComment( void ) ) ); - connect( ui.expandButton, SIGNAL( clicked( void ) ), this, SLOT( toggleWindows( void ) ) ); - - connect( ui.addToolButton, SIGNAL( clicked( ) ), this, SLOT( addNewLink( ) ) ); - - connect( ui.linkTreeWidget, SIGNAL( currentItemChanged ( QTreeWidgetItem *, QTreeWidgetItem * ) ), - this, SLOT( changedItem ( QTreeWidgetItem *, QTreeWidgetItem * ) ) ); - - connect( ui.linkTreeWidget, SIGNAL( itemDoubleClicked ( QTreeWidgetItem *, int ) ), - this, SLOT( openLink ( QTreeWidgetItem *, int ) ) ); - - connect( ui.anonBox, SIGNAL( stateChanged ( int ) ), this, SLOT( checkAnon ( void ) ) ); - - mStart = 0; - - - /* Set header resize modes and initial section sizes */ - QHeaderView * _header = ui.linkTreeWidget->header () ; - QHeaderView_setSectionResizeMode(_header, 0, QHeaderView::Interactive); - QHeaderView_setSectionResizeMode(_header, 1, QHeaderView::Interactive); - QHeaderView_setSectionResizeMode(_header, 2, QHeaderView::Interactive); - - _header->resizeSection ( 0, 400 ); - _header->resizeSection ( 1, 60 ); - _header->resizeSection ( 2, 150 ); - - ui.linkTreeWidget->setSortingEnabled(true); - - ui.linklabel->setMinimumWidth(20); - - - /* Set a GUI update timer - much cleaner than - * doing everything through the notify agent - */ - - QTimer *timer = new QTimer(this); - timer->connect(timer, SIGNAL(timeout()), this, SLOT(checkUpdate())); - timer->start(1000); -} - -void LinksDialog::checkUpdate() -{ - /* update */ - if (!rsRanks) - { - std::cerr << " rsRanks = 0 !!!!" << std::endl; - return; - } - - if (rsRanks->updated()) - { -#ifdef LINKS_DEBUG - std::cerr << " rsRanks was updated -> redraw()" << std::endl; -#endif - updateLinks(); - } - - return; -} - -void LinksDialog::linkTreeWidgetCostumPopupMenu( QPoint point ) -{ - - QMenu contextMnu( this ); - - QAction *voteupAct = new QAction(QIcon(IMAGE_EXPORTFRIEND), tr( "Share Link Anonymously" ), &contextMnu ); - connect( voteupAct , SIGNAL( triggered() ), this, SLOT( voteup_anon() ) ); - - - QMenu *voteMenu = new QMenu( tr("Vote on Link"), &contextMnu ); - voteMenu->setIcon(QIcon(IMAGE_EXPORTFRIEND)); - - QAction *vote_p2 = new QAction( QIcon(IMAGE_GREAT), tr("+2 Great!"), &contextMnu ); - connect( vote_p2 , SIGNAL( triggered() ), this, SLOT( voteup_p2() ) ); - voteMenu->addAction(vote_p2); - QAction *vote_p1 = new QAction( QIcon(IMAGE_GOOD), tr("+1 Good"), &contextMnu ); - connect( vote_p1 , SIGNAL( triggered() ), this, SLOT( voteup_p1() ) ); - voteMenu->addAction(vote_p1); - QAction *vote_p0 = new QAction( QIcon(IMAGE_OK), tr("0 Okay"), &contextMnu ); - connect( vote_p0 , SIGNAL( triggered() ), this, SLOT( voteup_p0() ) ); - voteMenu->addAction(vote_p0); - QAction *vote_m1 = new QAction( QIcon(IMAGE_SUX), tr("-1 Sux"), &contextMnu ); - connect( vote_m1 , SIGNAL( triggered() ), this, SLOT( voteup_m1() ) ); - voteMenu->addAction(vote_m1); - QAction *vote_m2 = new QAction( QIcon(IMAGE_BADLINK), tr("-2 Bad Link"), &contextMnu ); - connect( vote_m2 , SIGNAL( triggered() ), this, SLOT( voteup_m2() ) ); - voteMenu->addAction(vote_m2); - - QAction *downloadAct = new QAction(QIcon(IMAGE_DOWNLOAD), tr("Download"), &contextMnu); - connect(downloadAct, SIGNAL(triggered()), this, SLOT(downloadSelected())); - - contextMnu.addAction(voteupAct); - contextMnu.addSeparator(); - contextMnu.addMenu(voteMenu); - contextMnu.addSeparator(); - contextMnu.addAction(downloadAct); - - contextMnu.exec(ui.linkTreeWidget->viewport()->mapToGlobal(point)); -} - -void LinksDialog::changedSortRank( int index ) -{ - /* update */ - if (!rsRanks) - return; - - /* translate */ - uint32_t type = 0; - switch (index) - { - case 1: - type = RS_RANK_TIME; - break; - case 2: - type = RS_RANK_SCORE; - break; - default: - case 0: - type = RS_RANK_ALG; - break; - } - - if (type) - { - rsRanks->setSortMethod(type); - } - updateLinks(); -} - -void LinksDialog::changedSortPeriod( int index ) -{ - /* update */ - if (!rsRanks) - return; - - /* translate */ - uint32_t period = 0; - switch (index) - { - case 1: - period = 60 * 60 * 24 * 7; /* WEEK */ - break; - case 2: - period = 60 * 60 * 24; /* DAY */ - break; - default: - case 0: - period = 60 * 60 * 24 * 30; /* MONTH */ - break; - } - - if (period) - { - rsRanks->setSortPeriod(period); - } - updateLinks(); -} - -void LinksDialog::changedSortFrom( int index ) -{ - /* update */ - if (!rsRanks) - return; - - std::list peers; - - /* translate */ - switch (index) - { - default: - case 0: - break; - case 1: - peers.push_back(mPeers->getOwnId()); - break; - } - - if (peers.size() < 1) - { - rsRanks->clearPeerFilter(); - } - else - { - rsRanks->setPeerFilter(peers); - } - updateLinks(); -} - -#define ENTRIES_PER_BLOCK 100 - -void LinksDialog::changedSortTop( int index ) -{ - /* update */ - if (!rsRanks) - return; - - std::list peers; - - /* translate */ - switch (index) - { - default: - case 0: - mStart = 0; - break; - case 1: - mStart = 1 * ENTRIES_PER_BLOCK; - break; - case 2: - mStart = 2 * ENTRIES_PER_BLOCK; - break; - case 3: - mStart = 3 * ENTRIES_PER_BLOCK; - break; - case 4: - mStart = 4 * ENTRIES_PER_BLOCK; - break; - case 5: - mStart = -1; - break; - } - updateLinks(); -} - - -/* get the list of Links from the RsRanks. */ -void LinksDialog::updateLinks() -{ - - std::list rids; - std::list::iterator rit; - std::list::iterator cit; - -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::updateLinks()" << std::endl; -#endif - - /* Work out the number/entries to show */ - uint32_t count = rsRanks->getRankingsCount(); - uint32_t start; - - uint32_t entries = ENTRIES_PER_BLOCK; - if (count < entries) - { - entries = count; - } - - if (mStart == -1) - { - /* backwards */ - start = count-entries; - } - else - { - start = mStart; - if (start + entries > count) - { - start = count - entries; - } - } - - /* get a link to the table */ - QTreeWidget *linkWidget = ui.linkTreeWidget; - QList items; - - rsRanks->getRankings(start, entries, rids); - float maxRank = rsRanks->getMaxRank(); - - for(rit = rids.begin(); rit != rids.end(); rit++) - { - RsRankDetails detail; - if (!rsRanks->getRankDetails(*rit, detail)) - { - continue; - } - - /* create items */ - QTreeWidgetItem *item = new QTreeWidgetItem((QTreeWidget*)0); - - /* (0) Title */ - { - item -> setText(0, QString::fromStdWString(detail.title)); - item -> setSizeHint(0, QSize( 20,20 ) ); - - /* Bold and bigger */ - /*QFont font = item->font(0); - font.setBold(true); - font.setPointSize(font.pointSize() + 2); - item->setFont(0, font);*/ - } - - /* (1) Rank */ - { - std::ostringstream out; - out << 100 * (detail.rank / (maxRank + 0.01)); - item -> setText(1, QString::fromStdString(out.str())); - item -> setSizeHint(1, QSize( 20,20 ) ); - - /* Bold and bigger */ - /*QFont font = item->font(1); - font.setBold(true); - font.setPointSize(font.pointSize() + 2); - item->setFont(1, font);*/ - } - - /* (2) Link */ - { - item -> setText(2, QString::fromStdWString(detail.link)); - item -> setSizeHint(2, QSize( 20,20 ) ); - - /* Bold and bigger */ - /*QFont font = item->font(2); - font.setBold(true); - font.setPointSize(font.pointSize() + 2); - item->setFont(2, font);*/ - } - - /* (3) Date */ - /*{ - QDateTime qtime; - qtime.setTime_t(it->lastPost); - QString timestamp = qtime.toString("yyyy-MM-dd hh:mm:ss"); - item -> setText(3, timestamp); - }*/ - - - /* (4) rid */ - item -> setText(4, QString::fromStdString(detail.rid)); - - - /* add children */ - int i = 0; - for(cit = detail.comments.begin(); - cit != detail.comments.end(); cit++, i++) - { - /* create items */ - QTreeWidgetItem *child = new QTreeWidgetItem((QTreeWidget*)0); - - QString commentText; - QString peerScore; - if (cit->score > 1) - { - peerScore = "[+2] "; - child -> setIcon(0,(QIcon(IMAGE_GREAT))); - item -> setIcon(0,(QIcon(IMAGE_GREAT))); - //peerScore = "[+2 Great Link] "; - } - else if (cit->score == 1) - { - peerScore = "[+1] "; - child -> setIcon(0,(QIcon(IMAGE_GOOD))); - item -> setIcon(0,(QIcon(IMAGE_GOOD))); - //peerScore = "[+1 Good] "; - } - else if (cit->score == 0) - { - peerScore = "[+0] "; - child -> setIcon(0,(QIcon(IMAGE_OK))); - item -> setIcon(0,(QIcon(IMAGE_OK))); - //peerScore = "[+0 Okay] "; - } - else if (cit->score == -1) - { - peerScore = "[-1] "; - child -> setIcon(0,(QIcon(IMAGE_SUX))); - item -> setIcon(0,(QIcon(IMAGE_SUX))); - //peerScore = "[-1 Not Worth It] "; - } - else //if (cit->score < -1) - { - peerScore = "[-2 BAD] "; - child -> setIcon(0,(QIcon(IMAGE_BADLINK))); - item -> setIcon(0,(QIcon(IMAGE_BADLINK))); - //peerScore = "[-2 BAD Link] "; - } - - /* (0) Comment */ - if (cit->comment != L"") - { - commentText = peerScore + QString::fromStdWString(cit->comment); - } - else - { - commentText = peerScore + "No Comment"; - } - child -> setText(0, commentText); - - /* (2) Peer / Date */ - { - QDateTime qtime; - qtime.setTime_t(cit->timestamp); - QString timestamp = qtime.toString("yyyy-MM-dd hh:mm:ss"); - - QString peerLabel = QString::fromStdString(mPeers->getPeerName(cit->id)); - if (peerLabel == "") - { - peerLabel = "<"; - peerLabel += QString::fromStdString(cit->id); - peerLabel += ">"; - } - peerLabel += " "; - - peerLabel += timestamp; - child -> setText(2, peerLabel); - - } - - /* (4) Id */ - child -> setText(4, QString::fromStdString(cit->id)); - - if (i % 2 == 1) - { - /* set to light gray background */ - child->setBackground(0,QBrush(Qt::lightGray)); - child->setBackground(1,QBrush(Qt::lightGray)); - child->setBackground(2,QBrush(Qt::lightGray)); - } - - /* push to items */ - item->addChild(child); - } - - /* add to the list */ - items.append(item); - } - - /* remove old items */ - linkWidget->clear(); - linkWidget->setColumnCount(3); - - /* add the items in! */ - linkWidget->insertTopLevelItems(0, items); - - linkWidget->update(); /* update display */ - - -} - -void LinksDialog::openLink ( QTreeWidgetItem * item, int ) -{ -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::openLink()" << std::endl; -#endif - - /* work out the ids */ - if (!item) - { - -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::openLink() Failed Item" << std::endl; -#endif - return; - } - - std::string rid; - std::string pid; - - QTreeWidgetItem *parent = item->parent(); - if (parent) - { - /* a child comment -> ignore double click */ -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::openLink() Failed Child" << std::endl; -#endif - return; - } - -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::openLink() " << (item->text(2)).toStdString() << std::endl; -#endif - /* open a browser */ - QUrl url(item->text(2)); - QDesktopServices::openUrl ( url ); - - /* close expansion */ - bool state = item->isExpanded(); - item->setExpanded(!state); -} - -void LinksDialog::changedItem(QTreeWidgetItem *curr, QTreeWidgetItem *) -{ - /* work out the ids */ - if (!curr) - { - updateComments("", ""); - return; - } - - std::string rid; - std::string pid; - - QTreeWidgetItem *parent = curr->parent(); - if (parent) - { - rid = (parent->text(4)).toStdString(); - pid = (curr->text(4)).toStdString(); - -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::changedItem() Rid: " << rid << " Pid: " << pid; - std::cerr << std::endl; -#endif - - updateComments(rid, pid); - } - else - { - rid = (curr->text(4)).toStdString(); - -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::changedItem() Rid: " << rid << " Pid: NULL"; - std::cerr << std::endl; -#endif - - updateComments(rid, ""); - } -} - -void LinksDialog::checkAnon() -{ - changedItem(ui.linkTreeWidget->currentItem(), NULL); -} - - -int IndexToScore(int index) -{ - if ((index == -1) || (index > 4)) - return 0; - int score = 2 - index; - return score; -} - -int ScoreToIndex(int score) -{ - if ((score < -2) || (score > 2)) - return 2; - int index = 2 - score; - return index; -} - - -/* get the list of Links from the RsRanks. */ -void LinksDialog::updateComments(std::string rid, std::string ) -{ - std::list::iterator cit; - - - if (ui.anonBox->isChecked()) - { - /* empty everything */ - ui.titleLineEdit->setText(""); - ui.linkLineEdit->setText(""); - ui.linkTextEdit->setText(""); - ui.scoreBox->setCurrentIndex(ScoreToIndex(0)); - mLinkId = rid; /* must be set for Context Menu */ - - /* disable comment + score */ - ui.scoreBox->setEnabled(false); - ui.linkTextEdit->setEnabled(false); - - /* done! */ - return; - } - else - { - /* enable comment + score */ - ui.scoreBox->setEnabled(true); - ui.linkTextEdit->setEnabled(true); - } - - - RsRankDetails detail; - if ((rid == "") || (!rsRanks->getRankDetails(rid, detail))) - { - /* clear it up */ - ui.titleLineEdit->setText(""); - ui.linkLineEdit->setText(""); - ui.linkTextEdit->setText(""); - ui.scoreBox->setCurrentIndex(ScoreToIndex(0)); - mLinkId = rid; - return; - } - - - /* set Link details */ - ui.titleLineEdit->setText(QString::fromStdWString(detail.title)); - ui.linkLineEdit->setText(QString::fromStdWString(detail.link)); - ui.linklabel->setText(" " + QString::fromStdWString(detail.link) +""); - - - if (mLinkId == rid) - { - /* leave comments */ - //ui.linkTextEdit->setText(""); - return; - } - - mLinkId = rid; - - /* Add your text to the comment */ - std::string ownId = mPeers->getOwnId(); - - for(cit = detail.comments.begin(); cit != detail.comments.end(); cit++) - { - if (cit->id == ownId) - break; - } - - if (cit != detail.comments.end()) - { - QString comment = QString::fromStdWString(cit->comment); - ui.linkTextEdit->setText(comment); - ui.scoreBox->setCurrentIndex(ScoreToIndex(cit->score)); - } - else - { - ui.linkTextEdit->setText(""); - ui.scoreBox->setCurrentIndex(ScoreToIndex(0)); - - } - - return; -} - -void LinksDialog::addLinkComment( void ) -{ - /* get the title / link / comment */ - QString title = ui.titleLineEdit->text(); - QString link = ui.linkLineEdit->text(); - QString comment = ui.linkTextEdit->toPlainText(); - int32_t score = IndexToScore(ui.scoreBox->currentIndex()); - - if ((mLinkId == "") || (ui.anonBox->isChecked())) - { - if ((link == "") || (title == "")) - { - QMessageBox::warning ( NULL, tr("Add Link Failure"), tr("Missing Link and/or Title"), QMessageBox::Ok); - /* can't do anything */ - return; - } - - /* add it either way */ - if (ui.anonBox->isChecked()) - { - rsRanks->anonRankMsg("", link.toStdWString(), title.toStdWString()); - } - else - { - rsRanks->newRankMsg( - link.toStdWString(), - title.toStdWString(), - comment.toStdWString(), score); - } - - updateLinks(); - return; - } - - /* get existing details */ - - RsRankDetails detail; - if (!rsRanks->getRankDetails(mLinkId, detail)) - { - /* strange error! */ - QMessageBox::warning ( NULL, tr("Add Link Failure"), tr("Missing Link Data"), QMessageBox::Ok); - return; - } - - if (link.toStdWString() == detail.link) /* same link! - we can add a comment */ - { - if (comment == "") /* no comment! */ - { - QMessageBox::warning ( NULL, tr("Add Link Failure"), tr("Missing Comment"), QMessageBox::Ok); - return; - } - - rsRanks->updateComment(mLinkId, - comment.toStdWString(), - score); - } - else - { - QMessageBox::StandardButton sb = QMessageBox::Yes; - - if ((title.toStdWString() == detail.title) /* same title! - wrong */ - || (title == "")) - { - sb = QMessageBox::question ( NULL, tr("Link Title Not Changed"), tr("Do you want to continue?"), (QMessageBox::Yes | QMessageBox::No)); - } - - /* add Link! */ - if (sb == QMessageBox::Yes) - { - rsRanks->newRankMsg( - link.toStdWString(), - title.toStdWString(), - comment.toStdWString(), - score); - } - } - updateLinks(); - return; -} - -void LinksDialog::toggleWindows( void ) -{ - /* if msg header visible -> hide by changing splitter - */ - - QList sizeList = ui.msgSplitter->sizes(); - QList::iterator it; - - int listSize = 0; - int msgSize = 0; - int i = 0; - - for(it = sizeList.begin(); it != sizeList.end(); it++, i++) - { - if (i == 0) - { - listSize = (*it); - } - else if (i == 1) - { - msgSize = (*it); - } - } - - int totalSize = listSize + msgSize; - - bool toShrink = true; - if (msgSize < (int) totalSize / 10) - { - toShrink = false; - } - - QList newSizeList; - if (toShrink) - { - newSizeList.push_back(totalSize); - newSizeList.push_back(0); - ui.expandButton->setIcon(QIcon(QString(":/images/edit_add24.png"))); - ui.expandButton->setToolTip(tr("Expand")); - } - else - { - newSizeList.push_back(totalSize * 3/4); - newSizeList.push_back(totalSize * 1/4); - ui.expandButton->setIcon(QIcon(QString(":/images/edit_remove24.png"))); - ui.expandButton->setToolTip(tr("Hide")); - } - - ui.msgSplitter->setSizes(newSizeList); - return; -} - - -QTreeWidgetItem *LinksDialog::getCurrentLine() -{ - /* get the current, and extract the Id */ - - /* get a link to the table */ - QTreeWidget *peerWidget = ui.linkTreeWidget; - QTreeWidgetItem *item = peerWidget -> currentItem(); - if (!item) - { -#ifdef LINKS_DEBUG - std::cerr << "Invalid Current Item" << std::endl; -#endif - return NULL; - } - -#ifdef LINKS_DEBUG - /* Display the columns of this item. */ - std::ostringstream out; - out << "CurrentPeerItem: " << std::endl; - - for(int i = 1; i < 6; i++) - { - QString txt = item -> text(i); - out << "\t" << i << ":" << txt.toStdString() << std::endl; - } - std::cerr << out.str(); -#endif - - return item; -} - -void LinksDialog::voteup_anon() -{ - //QTreeWidgetItem *c = getCurrentLine(); - - if (mLinkId == "") - { - return; - } - - RsRankDetails detail; - if (!rsRanks->getRankDetails(mLinkId, detail)) - { - /* not there! */ - return; - } - - QString link = QString::fromStdWString(detail.link); -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::voteup_anon() : " << link.toStdString() << std::endl; -#endif - // need a proper anon sharing option. - rsRanks->anonRankMsg(mLinkId, detail.link, detail.title); -} - - - - -void LinksDialog::voteup_score(int score) -{ - if (mLinkId == "") - { - return; - } - - RsRankDetails detail; - if (!rsRanks->getRankDetails(mLinkId, detail)) - { - /* not there! */ - return; - } - - QString link = QString::fromStdWString(detail.link); - std::wstring comment; -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::voteup_score() : " << link.toStdString() << std::endl; -#endif - - - std::list::iterator cit; - /* Add your text to the comment */ - std::string ownId = mPeers->getOwnId(); - - for(cit = detail.comments.begin(); cit != detail.comments.end(); cit++) - { - if (cit->id == ownId) - break; - } - - if (cit != detail.comments.end()) - { - comment = cit->comment; - } - - rsRanks->updateComment(mLinkId, comment, score); -} - - -void LinksDialog::voteup_p2() -{ - voteup_score(2); -} - -void LinksDialog::voteup_p1() -{ - voteup_score(1); -} - -void LinksDialog::voteup_p0() -{ - voteup_score(0); -} - -void LinksDialog::voteup_m1() -{ - voteup_score(-1); -} - -void LinksDialog::voteup_m2() -{ - voteup_score(-2); -} - -void LinksDialog::downloadSelected() -{ - if (mLinkId == "") - { - return; - } - - RsRankDetails detail; - if (!rsRanks->getRankDetails(mLinkId, detail)) - { - /* not there! */ - return; - } - - QString link = QString::fromStdWString(detail.link); - std::wstring comment; -#ifdef LINKS_DEBUG - std::cerr << "LinksDialog::downloadSelected() : " << link.toStdString() << std::endl; -#endif - - //RetroShareLink rslink(QString::fromStdWString(detail.link)); - - //if(!rslink.valid() || rslink.type() != RetroShareLink::TYPE_FILE) - //{ -// QMessageBox::critical(NULL,"Badly formed link","This link is badly formed. Can't parse/use it. This is a bug. Please contact the developers.") ; -// return ; -// } - - /* retrieve all peers id for this file */ -// FileInfo info; -// rsFiles->FileDetails(rslink.hash().toStdString(), 0, info); - -// std::list srcIds; -// std::list::iterator pit; -// for (pit = info.peers.begin(); pit != info.peers.end(); pit ++) -// srcIds.push_back(pit->peerId); - -// rsFiles->FileRequest(rslink.name().toStdString(), rslink.hash().toStdString(), rslink.size(), "", 0, srcIds); -} - -void LinksDialog::addNewLink() -{ - - AddLinksDialog *nAddLinksDialog = new AddLinksDialog(""); - - nAddLinksDialog->show(); - - /* window will destroy itself! */ -} diff --git a/plugins/LinksCloud/LinksDialog.h b/plugins/LinksCloud/LinksDialog.h deleted file mode 100644 index 58c763449..000000000 --- a/plugins/LinksCloud/LinksDialog.h +++ /dev/null @@ -1,97 +0,0 @@ -/**************************************************************** - * RetroShare GUI is distributed under the following license: - * - * Copyright (C) 2008 Robert Fernie - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - ****************************************************************/ - -#ifndef _LINKS_DIALOG_H -#define _LINKS_DIALOG_H - -#include -#include -#include -#include "ui_LinksDialog.h" - - -class LinksDialog : public MainPage -{ - Q_OBJECT - -public: - /** Default Constructor */ - LinksDialog(RsPeers* peers, RsFiles* files, QWidget *parent = 0); - /** Default Destructor */ - - void insertExample(); - -private slots: - /** Create the context popup menu and it's submenus */ - void linkTreeWidgetCostumPopupMenu( QPoint point ); - - void voteup_anon(); - void voteup_score(int score); - void voteup_p2(); - void voteup_p1(); - void voteup_p0(); - void voteup_m1(); - void voteup_m2(); - void downloadSelected(); - - void changedSortRank( int index ); - void changedSortPeriod( int index ); - void changedSortFrom( int index ); - void changedSortTop( int index ); - - void updateLinks(); - void addLinkComment( void ); - void toggleWindows( void ); - - void openLink ( QTreeWidgetItem * item, int column ); - void changedItem(QTreeWidgetItem *curr, QTreeWidgetItem *prev); - void checkAnon(); - - void checkUpdate(); - - void addNewLink(); - -private: - -void updateComments(std::string rid, std::string pid); - - int mStart; /* start of rank list */ - std::string mLinkId; - - /* Worker Functions */ - /* (1) Update Display */ - - /* (2) Utility Fns */ - QTreeWidgetItem *getCurrentLine(); - - QTreeWidget *exampletreeWidget; - - // gui interface - RsPeers* mPeers; - RsFiles* mFiles; - - - /** Qt Designer generated object */ - Ui::LinksDialog ui; -}; - -#endif - diff --git a/plugins/LinksCloud/LinksDialog.ui b/plugins/LinksCloud/LinksDialog.ui deleted file mode 100644 index 6c2b06ab4..000000000 --- a/plugins/LinksCloud/LinksDialog.ui +++ /dev/null @@ -1,572 +0,0 @@ - - - LinksDialog - - - - 0 - 0 - 738 - 583 - - - - - 6 - - - 0 - - - - - - 0 - 0 - - - - Qt::Vertical - - - - - - - Qt::CustomContextMenu - - - - Title / Comment - - - - - Score - - - - - Peer / Link - - - - - - - - - - - - :/images/edit_remove24.png:/images/edit_remove24.png - - - - - - - Qt::Horizontal - - - - 16 - 20 - - - - - - - - - 75 - true - - - - Sort by - - - - - - - - Combo - - - - - Time - - - - :/images/kalarm.png:/images/kalarm.png - - - - - Ranking - - - - :/images/records.png:/images/records.png - - - - - - - - Qt::Horizontal - - - - 16 - 20 - - - - - - - - - 75 - true - - - - In last - - - - - - - - Month - - - - :/images/view_calendar_month.png:/images/view_calendar_month.png - - - - - Week - - - - :/images/view_calendar_week.png:/images/view_calendar_week.png - - - - - Day - - - - :/images/view_calendar_day.png:/images/view_calendar_day.png - - - - - - - - Qt::Horizontal - - - - 16 - 20 - - - - - - - - - 75 - true - - - - From - - - - - - - - All Peers - - - - :/images/user/friends24.png:/images/user/friends24.png - - - - - Own Links - - - - :/images/user/identity16.png:/images/user/identity16.png - - - - - - - - Qt::Horizontal - - - - 16 - 20 - - - - - - - - - 75 - true - - - - Show - - - - - - - - Top 100 - - - - :/images/records.png:/images/records.png - - - - - 101-200 - - - - - 201-300 - - - - - 301-400 - - - - - 401-500 - - - - - Bottom 100 - - - - - - - - QLabel{border: 2px solid #CCCCCC; -border-radius: 10px; -background: white; -padding:2} - - - true - - - Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - 75 - true - - - - Link: - - - - - - - - - - - - - Qt::Horizontal - - - - 311 - 32 - - - - - - - - - 50 - false - - - - Add Anonymous Link - - - - - - - Add Link/Comment - - - - - - - - - - - Title: - - - - - - - QLineEdit{border: 2px solid #CCCCCC; -border-radius: 10px; -background: white;} - - - - - - - Score: - - - - - - - - +2 Great! - - - - :/images/filerating5.png:/images/filerating5.png - - - - - +1 Good - - - - :/images/filerating4.png:/images/filerating4.png - - - - - 0 Okay - - - - :/images/filerating3.png:/images/filerating3.png - - - - - -1 Sux - - - - :/images/filerating2.png:/images/filerating2.png - - - - - -2 Bad Link - - - - :/images/filerating1.png:/images/filerating1.png - - - - - - - - - - - - Url: - - - - - - - QLineEdit{border: 2px solid #CCCCCC; -border-radius: 10px; -background: white;} - - - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - QTextEdit{border: 2px solid #CCCCCC; -border-radius: 10px; -background: white;} - - - - - - - - - - - - 16777215 - 32 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 2 - - - - - - 24 - 24 - - - - - - - :/images/irkick.png - - - true - - - - - - - - 75 - true - - - - Links Cloud - - - - - - - Qt::Horizontal - - - - 596 - 15 - - - - - - - - Add new link - - - - :/images/edit_add24.png:/images/edit_add24.png - - - - 24 - 16 - - - - true - - - - - - - - - - - - - - diff --git a/plugins/LinksCloud/images/irkick.png b/plugins/LinksCloud/images/irkick.png deleted file mode 100644 index b399814ff4a9fd45cdcd7e7562ba9e43ce42fb9e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2231 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 H7|Q$!wf^)a diff --git a/plugins/LinksCloud/lang/LinksCloud_ca_ES.ts b/plugins/LinksCloud/lang/LinksCloud_ca_ES.ts deleted file mode 100644 index a85af322f..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_ca_ES.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Afegir enllaç - - - - Cancel - Cancel·la - - - - Add a new Link - Afegir un nou enllaç - - - - Title: - Títol: - - - - Url: - URL: - - - - Add Anonymous Link - Afegir enllaç anònim - - - - +2 Great! - +2 Fantàstic! - - - - +1 Good - +1 Molt bo - - - - 0 Okay - 0 Està bé - - - - -1 Sux - -1 És dolent - - - - -2 Bad Link - -2 Enllaç dolent - - - - Add Link to Cloud - Afegir enllaç al núvol - - - - New Link - Nou enllaç - - - - Add Link Failure - Afegir enllaç que falla - - - - Missing Link and/or Title - Enllaç i/o títol perdut - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Aquest complement proporciona un conjunt d'enllaços en cau i un sistema de votar-los i promocionar-los. - - - - LinksCloud - NúvolEnllaços - - - - LinksDialog - - - Title / Comment - Títol / Comentari - - - - Score - Puntuació - - - - Peer / Link - Contacte / Enllaç - - - - Sort by - Ordenat per - - - - Combo - Combinació - - - - Time - Temps - - - - Ranking - Classificació - - - - In last - En l'últim - - - - Month - Mes - - - - Week - Setmana - - - - Day - Dia - - - - From - Des de - - - - All Peers - Tots els contactes - - - - Own Links - Enllaços propis - - - - Show - Mostra - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Els últims 100 - - - - Link: - Enllaç: - - - - Add Anonymous Link - Afegir enllaç anònim - - - - Add Link/Comment - Afegir Enllaç/Comentari - - - - Title: - Títol: - - - - Score: - Puntuació: - - - - - +2 Great! - +2 Fantàstic! - - - - - +1 Good - +1 Molt bo - - - - - 0 Okay - 0 Està bé - - - - - -1 Sux - -1 És dolent - - - - - -2 Bad Link - -2 Enllaç dolent - - - - Url: - URL: - - - - Links Cloud - Núvol d'enllaços - - - - Add new link - Afegir nou enllaç - - - - Share Link Anonymously - Compartir enllaç anònimament - - - - Vote on Link - Votar un enllaç - - - - Download - Descarregar - - - - - - Add Link Failure - Afegir enllaç que falla - - - - Missing Link and/or Title - Enllaç i/o títol perdut - - - - Missing Link Data - Dades d'enllaç perdudes - - - - Missing Comment - Comentari perdut - - - - Link Title Not Changed - Títol d'enllaç no canviat - - - - Do you want to continue? - Vols continuar? - - - - Expand - Ampliar - - - - Hide - Amagar - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_cs.qm b/plugins/LinksCloud/lang/LinksCloud_cs.qm deleted file mode 100644 index 99e2ed5b8bf74da668a6e53b8755f995bcb7ab60..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4843 zcmcIoYiJx*6h70PeI&b0wl&l~RBlD9w29dyTYpqh+C*!sebA(pv?!hIOtag}&J8=W ziHQjQDZUUDACxMHf-n3dK0v4hUkuUi8kvXWss93z0TMwEaG!mKR9><~E|%W2B#X4(EH6e0r3q z?Ia~%*+|rW6D2?XohUIIocUf#etVoK|01QY{0;YKXnW})$nj{;Ywr^+9i~D37ozNw zG-SPq-`CUd^G6_WxpwltYk<35`|9d5xc}vnyViYAq<1C~`#&b4>EKM|5|PbBp#ASZW0a!nuOKTj4@jGsv!E8h>Eo0G4+iZk(HaJGMxDyH#$ z`tsBdJs&_`XX@<5cS6sj>0*YT?@#ZwKf{0C2+q_%X3K%=V3*7s5f_5@x0%!1z(4a` z%TN~n)xHYO^slW}C;Xv3(pow63G7N|m%aBA^t;&u&)yCHT%8>$9>nw6+~XU7Pu#QA zzV~I^?+woMLrWjlb;#Y?R{YU}ehSXy(YAfRy@uy!+ecTy?};_RnR~Ya=YO5R#XN1G z9uhP_l18XTvup>k6Ve-c#8xRyHn?rGY2H$C#@vC5VarjCksUzx0=bW7ft0{HA#}@z zUa_@i8Q$7v_~q2anze&8P6m1N(5bE-F<8H&8T1lBp*jo&5lJSELDaM|A=}j}wiu>h z>dj=!81+i<)m}&-CPrJ2Ysz4dD7WnBvwL?=>#n02RM3%#UVzVQisj95I zi}G2yKz!7y3=3P#q)sK`)Ivs72S1lAvZ)N_Hc4f6eom~o(Wuz4E|^T9tMgN z*YLmRn-)!j47ZM|w#JV`C_gkwow#q{Q-(AHNX{XHN`5R|NOghv8FDz9e2+C8hQtyO zfp*j9fV5F2?j9;vTruvOBgSiTqGDPu($BR#ArFa?Q7T)eu(?roa@g_Jg!DKO+$qG@nr^WoDV7jw6O{3KO8O* z(;I#JUyp@|?5h^^?C?zJMm>$8{!XTdboQRDCY~3O~PgX@w zlOVTY+nRtwxZR)$DWysHU_{0$OaTJ#sjG>BU_prl;xd0|m2la^Cun42FwM}Go@;>~ zU9ZHf9FSs4*2SdZc-)*y(m}hbTi3^u$ir%c4-Jw>ay>LjGXrwcv8Cb9^a!Us?ZN$N zj7;7*=1t%m?ifd(jMb)NDKiyQ{YLc7*n6#D#TL$n_~bIl?yF_*^VvQuFkm@~6}^gqd)O199_q0sP*mfyM+`!3{fD1;kG2iT<+Tj9T#y z$gu-J6&r16LMK^*KcXXkz90_~Y*xYTbGy!B z1-yQ4l{zOf>>Or#3hoN_X+!Z`HYeD3*?{30u>t+RwzP;_T4@K^yX+9fF}VW;Q;y}e z0(oNieI{&dsKe}L`%*uKmU3tOH)1|K26sHVZx1Ec>Ds@sFMXR zQ`#CuV8vkBs9C{2t=^+-{~ayDD34`7c$wwO3AY=4uq-EIjb05-7Cgn(%uRW20|ZCK zAw4K-o*0Q&n$mIryXvw&RH?>ypmpgvP8I(f - - AddLinksDialog - - - - Add Link - Přidat odkaz - - - - Cancel - Zrušit - - - - Add a new Link - Přidat nový odkaz - - - - Title: - Titulek - - - - Url: - Url: - - - - Add Anonymous Link - Přidat anonymní odkaz - - - - +2 Great! - +2 Výborný - - - - +1 Good - +1 Dobrý - - - - 0 Okay - 0 OK - - - - -1 Sux - -1 Špatný - - - - -2 Bad Link - -2 Špatný odkaz - - - - Add Link to Cloud - Přidat odkaz do Cloudu - - - - New Link - Nový odkaz - - - - Add Link Failure - Přidání odkazu selhalo - - - - Missing Link and/or Title - Chybí odkaz nebo titulek - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Tento zásuvný modul poskytuje sadu mezipaměti odkazů, a hlasovací systém na jejich podporu - - - - LinksCloud - LinksCloud - - - - LinksDialog - - - Title / Comment - Titulek / Komentáře - - - - Score - Skóre - - - - Peer / Link - Peer / Odkaz - - - - Sort by - Seřadit podle - - - - Combo - Dvojité - - - - Time - Čas - - - - Ranking - Žebříček - - - - In last - Jako poslední - - - - Month - Měsíc - - - - Week - Týden - - - - Day - Den - - - - From - Od - - - - All Peers - Všechny peery - - - - Own Links - Naše odkazy - - - - Show - Zobrazit - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Spodní 100 - - - - Link: - Odkaz: - - - - Add Anonymous Link - Přidat anonymní odkaz - - - - Add Link/Comment - Přidat odkaz / komentář - - - - Title: - Titulek: - - - - Score: - Skóre: - - - - - +2 Great! - +2 Výborný - - - - - +1 Good - +1 Dobrý - - - - - 0 Okay - 0 OK - - - - - -1 Sux - -1 Špatný - - - - - -2 Bad Link - -2 Špatný odkaz - - - - Url: - Url: - - - - Links Cloud - Odkazový Cloud - - - - Add new link - Přidat nový odkaz - - - - Share Link Anonymously - Sdílet odkaz anonymně - - - - Vote on Link - Volte na odkaze - - - - Download - Stáhnout - - - - - - Add Link Failure - Přidání odkazu selhalo - - - - Missing Link and/or Title - Chybí odkaz nebo titulek - - - - Missing Link Data - Chybějí odkazová data - - - - Missing Comment - Chybějící komentář - - - - Link Title Not Changed - Nebyl zadán titulek odkazu - - - - Do you want to continue? - Chcete pokračovat? - - - - Expand - Rozbalit - - - - Hide - Skrýt - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_da.qm b/plugins/LinksCloud/lang/LinksCloud_da.qm deleted file mode 100644 index 552d8b3f4ef4e8b189c57c85ec370bc78c12570b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 98 zcmcE7ks@*G{hX<16=n7(EZlq7iGhKEgJp*29w5z-3B;DnKth1Qks%KVOBr&2FqNT* o10>A`!p@0#$*DQ)KqjAKN{UZrUUsodW@1i$I%5Y=jERvE02oac_5c6? diff --git a/plugins/LinksCloud/lang/LinksCloud_da.ts b/plugins/LinksCloud/lang/LinksCloud_da.ts deleted file mode 100644 index c0f97a460..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_da.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - - - - - Cancel - Annuller - - - - Add a new Link - - - - - Title: - - - - - Url: - - - - - Add Anonymous Link - - - - - +2 Great! - - - - - +1 Good - - - - - 0 Okay - - - - - -1 Sux - - - - - -2 Bad Link - - - - - Add Link to Cloud - - - - - New Link - - - - - Add Link Failure - - - - - Missing Link and/or Title - - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - - - - - LinksCloud - - - - - LinksDialog - - - Title / Comment - - - - - Score - - - - - Peer / Link - - - - - Sort by - - - - - Combo - - - - - Time - - - - - Ranking - - - - - In last - - - - - Month - - - - - Week - - - - - Day - - - - - From - - - - - All Peers - - - - - Own Links - - - - - Show - - - - - Top 100 - - - - - 101-200 - - - - - 201-300 - - - - - 301-400 - - - - - 401-500 - - - - - Bottom 100 - - - - - Link: - - - - - Add Anonymous Link - - - - - Add Link/Comment - - - - - Title: - - - - - Score: - - - - - - +2 Great! - - - - - - +1 Good - - - - - - 0 Okay - - - - - - -1 Sux - - - - - - -2 Bad Link - - - - - Url: - - - - - Links Cloud - - - - - Add new link - - - - - Share Link Anonymously - - - - - Vote on Link - - - - - Download - - - - - - - Add Link Failure - - - - - Missing Link and/or Title - - - - - Missing Link Data - - - - - Missing Comment - - - - - Link Title Not Changed - - - - - Do you want to continue? - - - - - Expand - - - - - Hide - - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_de.qm b/plugins/LinksCloud/lang/LinksCloud_de.qm deleted file mode 100644 index 699706eaafd71c664cda8b33cb79a98b19deec03..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4975 zcmcInYls_F6h3Jtk4@5jl(lZFmfPZsw(Dkh(;~Gf?Z!UTwu{-es3^{EW|Od!nKhYo zyH&wI1*<<)Xhl>g3Km7s(kh5rijN;wQGZkfQSpx!5u^qCORD&tdp9>}XOgu(2$P$~ z{m$b%=bm%!`gihupPqg3(C5pqKKbBFC%)fE6go$A#{r^57a8B&Pn7H>7lL z0#R3iB1hL?{hA`5{7z&HtF`-GihTPXQBRs;H=f6SkM5Xwim2mjy8HM?L<_&Cobd}$ z>IxdOUd8t}=$<3{i8@~noj!02QTLh9S8LBg@68Jyz5YkY9S?`^{e*}fQEN0CzRrYQ zp_p2ur@|u#lfW+v??2WH{DSb4`L~D`><*vqJ_!A98kq>-v6%7P*7u3Rea5MCA3*;Z zG3Wh0p=)5|Vt+8(xK5ZC~`$A{tj0gRs*2ou~yUrg6KG#)P0^Y-O>%v<~2-*W-Y)sKA z8YDrRsYV|AK$3t}gJQGm=GocK4f*_CC1OZLQ7`YhGe` zcU_IxWR~n&#cD;zP?I_)p#lZFL61#S5Z|7j9<9W4#fa_JTBhMj;?$|(;keDkeIDtY z&cYOqHPe=_MTqA(UKI%E-nn8R>xPFyc+-3KK24yY=4Fi;E3F6HRT5~Zd z1JIflp#PvH`CR@V+lWtBqlXO8ohTJ$ytvYPa@=U&Lv*7W7;(#G%kcsO_)q#riu(t5 z4?eJgQkSB2*m!ZD+YVc~eT+++8zVr+2HO^+mQ|?+idc+NZo$!gvXpVD;`D5!Wn!c2 zd2U$@wg`Ri9AV?K&~dTEe5R8+0#3%=K*dos1T=lUHJnu=k1seYQ9Mi1O)i`Q&8>#_ zNrZ_f!AS@y;uDAKHZ80#>xx;oCT2{>$X5smeLk!H!Dr(lx*aym0HKOAENgmZU>Mi=gf`7!2(OwpnkPR!7i#OdDGme}#gX_@MmlQC8K~{^=LXup_#DJcs zeP%C~GaA#p5B6{|lJk@n5WCxSrZDgXI*|gHw@-1DG$fLnaMkt0r>(OYK#dHJN=R@D zuhiTKklTEbQ?nf>2$#F&G+CT0niWgU>iRZk%NwH4rUcz9B_I~s1tV83$$9S0p}T%%(-x8jNMV0H01b&V`B#!BVjYP6#14xr-eYqnZxm%JGu)a?%2yq5|e zJDo7W#ns@_HWwRnr(5>8HrEiJf@L6-3#J+&xKCX`68bYawTp*rR~?DK&?MwFR^A9T SE5>fi@{a - - AddLinksDialog - - - - Add Link - Link hinzufügen - - - - Cancel - Abbrechen - - - - Add a new Link - Neuen Link hinzufügen - - - - Title: - Titel: - - - - Url: - Url: - - - - Add Anonymous Link - Anonym hinzufügen - - - - +2 Great! - +2 Großartig! - - - - +1 Good - +1 Gut - - - - 0 Okay - 0 In Ordnung - - - - -1 Sux - -1 Nervt - - - - -2 Bad Link - -2 Schlechter Link - - - - Add Link to Cloud - Link zur Wolke hinzufügen - - - - New Link - Neuer Link - - - - Add Link Failure - Link hinzufügen fehlgeschlagen - - - - Missing Link and/or Title - Titel und/oder Url fehlt - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Dieses Plug-in stellt Links und ein Wahlsystem zur Verfügung, um sie zu verbreiten. - - - - LinksCloud - Verknüpfungswolke - - - - LinksDialog - - - Title / Comment - Titel / Kommentar - - - - Score - Punkte - - - - Peer / Link - Nachbar / Link - - - - Sort by - Sortiere nach - - - - Combo - Kombiniert - - - - Time - Zeit - - - - Ranking - Platzierung - - - - In last - Im letzten - - - - Month - Monat - - - - Week - Woche - - - - Day - Tag - - - - From - Von - - - - All Peers - Alle Nachbarn - - - - Own Links - Eigene Links - - - - Show - Zeige - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Letzten 100 - - - - Link: - Link: - - - - Add Anonymous Link - Anonym hinzufügen - - - - Add Link/Comment - Link/Kommentar hinzufügen - - - - Title: - Titel: - - - - Score: - Punkte: - - - - - +2 Great! - +2 Großartig! - - - - - +1 Good - +1 Gut - - - - - 0 Okay - 0 In Ordnung - - - - - -1 Sux - -1 Nervt - - - - - -2 Bad Link - -2 Schlechter Link - - - - Url: - Url: - - - - Links Cloud - Verknüpfungswolke - - - - Add new link - Neuen Link hinzufügen - - - - Share Link Anonymously - Link anonym verteilen - - - - Vote on Link - Stimme für Link - - - - Download - Herunterladen - - - - - - Add Link Failure - Link hinzufügen fehlgeschlagen - - - - Missing Link and/or Title - Fehlender Link und/oder Titel - - - - Missing Link Data - Fehlende Linkdaten - - - - Missing Comment - Fehlender Kommentar - - - - Link Title Not Changed - Linktitel nicht geändert - - - - Do you want to continue? - Willst du fortfahren? - - - - Expand - Erweitern - - - - Hide - Verbergen - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_el.qm b/plugins/LinksCloud/lang/LinksCloud_el.qm deleted file mode 100644 index aafec7fb1861982a1d8f4d8445f50839f7801a3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5103 zcmcInYit}>6+W9g`>@y9tgFbh5UOhgrE22X-fXJML7>E@ZK|Y=Vy7rng-*Ov@5;L~ z);{V)1c^V9+JJzfq*P52k3uQnM>dJE9mhD19f+w@egq^CfjJNMeN z8_$ee6;;;y&hFgroO8ePydRs&-1+mHFQ2~Nx@GREZ_oa24^ikXqDP)1YJ8H6-#kea zKS;*S?_oVo;cpHQZMs3>vpb2B`zUSDNdZ*4111?FJ>+fZRiy@lBb~m??yU|?a{-=i+e8- ziF=Kux8{j9ri@=?d+>gX@s}4`vEc!|Msi`}qma||hwuk>0N?aNI2~d9m%}e*Pr}aj z@Y!=%jTXHomm=vXzh8*_sdEu_|26WD4}K2%=cDNu|NgJ&q5SK37}aa!*RefMd>r_> z*a`VQ*!_C!Z+l^X!{LU$IQR{{sn^)^jn+2s5jxYDdwL1yipHC-`~dm~<4=6&3)p`v zekA=Ae*bUN>8-$vUv11k`y=d6>owN4@vDYG6#Hi){pT|DlU^g~#N)Tl13$iL;4bhk zKC9P_XL2C__kuUlR_Y`vUJ_L?BgXg?q$t?hDIap23?DbKJCoU$vjta@1fDsE~(iIbLOUXTEMzYaCvhEP4fn0>?KLL6grgXUYNQZoE&^#6dO^I)b zc`*l-Q(_eV7sUijsY2Wv_*@m2z(tU0cYsT|+ji_@1*cM4*TN6`s;NKmB{ApP9Am-j z9r%7U>qvu1GjI+)*RV1NG0l~JUOTZ8CO@MDmkw2leMo0@|A&{&1EP=;(749 zD3%p-@G}iTP=yARUMI*pwpc&8I&N=(8- z6Dqk`#%ctwjp}VcuqUTb3bdcKSL^k1!I(smVEH7_;APSsOv4!&W_HuR7VHX>jUD=4BBx!C;>uQuh;;(wAgy%kk?0hMDJRbslX9=naOz1t}iEW7OM%KPfN zU~Nd?ZWLUXo46NoC*m~qmAXZIiEEbX6#73`k9kz4@w!&susffZ2P~^t@)eTA05yUV zvV?NUL0TJp8uvKmvQv8_@i3~lFXsK?6V-1P_|A9c#IJ8RklmOmXy71o%4fTsV6Kw4|+3u)9R$PUSdChs9;jGNN&Rm-jrUU@B#?s z1W*HmOJDP<8bxD|SvGxL-Q|+NVgFvtjvlIFxX+Ej+FH7X_amjUzV_XtMq-|dc+vq0 zE9)A^xyNpJY}i&atbbK%p#x;$uZXJDj?c<$=)&V%&}6$irF)F$vQ`CCT-vI*)z#89 zdeF27G3xjpBL?t@^&5pSG@};S6Kvq!ypiY5Y)NCaC z2-wo|Uwy}!RQ%OnBWrGG>CKu&OWy$8+hbncP(3zs*}8;@k|j+;Q;i3sH|q@hl5jVw z0&~Vw?=sMh7ZW$tQt#KhnU#{R^%UJ2kWrvT>UWd6p zX{l}O(sl^0dKdpEDHL1J}9acoazSni}xOgB - - AddLinksDialog - - - - Add Link - Προσθέστε σύνδεσμο - - - - Cancel - Διακοπη - - - - Add a new Link - Προσθέσετε ένα νέο σύνδεσμο - - - - Title: - Τίτλος: - - - - Url: - URL: - - - - Add Anonymous Link - Προσθέστε ανώνυμη σύνδεση - - - - +2 Great! - +2 Μεγάλη! - - - - +1 Good - +1 Καλή - - - - 0 Okay - Εντάξει 0 - - - - -1 Sux - -1 Sux - - - - -2 Bad Link - -2 Κακή σύνδεση - - - - Add Link to Cloud - Προσθήκη συνδέσεων σε σύννεφο - - - - New Link - Νέα σύνδεση - - - - Add Link Failure - Προσθέστε αποτυχία σύνδεσης - - - - Missing Link and/or Title - Συνδετικός κρίκος ή/και τίτλο - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Αυτό το plugin παρέχει ένα σύνολο των προσωρινά αποθηκευμένων συνδέσεων, καθώς και ένα σύστημα ψηφοφορίας για την προώθηση τους. - - - - LinksCloud - LinksCloud - - - - LinksDialog - - - Title / Comment - Τίτλος / σχόλιο - - - - Score - Σκορ - - - - Peer / Link - Peer / Link - - - - Sort by - Ταξινόμηση κατά - - - - Combo - Combo - - - - Time - Χρόνος - - - - Ranking - Κατάταξη - - - - In last - Στο τελευταίο - - - - Month - Μήνα - - - - Week - Εβδομάδα - - - - Day - Ημέρα - - - - From - Απο - - - - All Peers - Όλοι οι φορείς - - - - Own Links - Δικες σας συνδέσεις - - - - Show - Εμφανιση - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Κάτω 100 - - - - Link: - Σύνδεση: - - - - Add Anonymous Link - Προσθέστε ανώνυμη σύνδεση - - - - Add Link/Comment - Προσθέστε σύνδεσμο/σχόλιο - - - - Title: - Τίτλος: - - - - Score: - Βαθμολογία: - - - - - +2 Great! - +2 Μεγάλη! - - - - - +1 Good - +1 Καλή - - - - - 0 Okay - Εντάξει 0 - - - - - -1 Sux - -1 Sux - - - - - -2 Bad Link - -2 Κακή σύνδεση - - - - Url: - URL: - - - - Links Cloud - Συνδέσεις σύννεφο - - - - Add new link - Προσθέστε νέα σύνδεση - - - - Share Link Anonymously - Μοιράσμα σύνδεσης ανώνυμα - - - - Vote on Link - Ψηφίσμα σύνδεσης - - - - Download - Λυψη - - - - - - Add Link Failure - Προσθέστε αποτυχία σύνδεσης - - - - Missing Link and/or Title - Συνδετικός κρίκος ή/και τίτλο - - - - Missing Link Data - Ελλείπουσα σύνδεση δεδομένων - - - - Missing Comment - Λείπει το σχόλιο - - - - Link Title Not Changed - Τίτλος συνδέσμου, δεν αλλάζει - - - - Do you want to continue? - Θέλετε να συνεχίσετε; - - - - Expand - Επεκταση - - - - Hide - Αποκρυψη - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_en.qm b/plugins/LinksCloud/lang/LinksCloud_en.qm deleted file mode 100644 index 9dad8dffceb9623e88f8b96d9cd0caf25574c6fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23 fcmcE7ks@*G{hX<16=n7(EZlpygMop8iIEWihQJ9+ diff --git a/plugins/LinksCloud/lang/LinksCloud_en.ts b/plugins/LinksCloud/lang/LinksCloud_en.ts deleted file mode 100644 index 4ca524d76..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_en.ts +++ /dev/null @@ -1,331 +0,0 @@ - - - - - AddLinksDialog - - - - Add Link - - - - - Cancel - - - - - Add a new Link - - - - - Title: - - - - - Url: - - - - - Add Anonymous Link - - - - - +2 Great! - - - - - +1 Good - - - - - 0 Okay - - - - - -1 Sux - - - - - -2 Bad Link - - - - - Add Link to Cloud - - - - - New Link - - - - - Add Link Failure - - - - - Missing Link and/or Title - - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - - - - - LinksCloud - - - - - LinksDialog - - - Title / Comment - - - - - Score - - - - - Peer / Link - - - - - Sort by - - - - - Combo - - - - - Time - - - - - Ranking - - - - - In last - - - - - Month - - - - - Week - - - - - Day - - - - - From - - - - - All Peers - - - - - Own Links - - - - - Show - - - - - Top 100 - - - - - 101-200 - - - - - 201-300 - - - - - 301-400 - - - - - 401-500 - - - - - Bottom 100 - - - - - Link: - - - - - Add Anonymous Link - - - - - Add Link/Comment - - - - - Title: - - - - - Score: - - - - - - +2 Great! - - - - - - +1 Good - - - - - - 0 Okay - - - - - - -1 Sux - - - - - - -2 Bad Link - - - - - Url: - - - - - Links Cloud - - - - - Add new link - - - - - Share Link Anonymously - - - - - Vote on Link - - - - - Download - - - - - - - Add Link Failure - - - - - Missing Link and/or Title - - - - - Missing Link Data - - - - - Missing Comment - - - - - Link Title Not Changed - - - - - Do you want to continue? - - - - - Expand - - - - - Hide - - - - diff --git a/plugins/LinksCloud/lang/LinksCloud_es.qm b/plugins/LinksCloud/lang/LinksCloud_es.qm deleted file mode 100644 index 33893d88400419c6dc0021a232261b8f75099171..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5053 zcmcInU2GiH6+WAt{jt|s+YvGjnCLnpPDOs~wKu2=ZPVC}lc2`2@DFWKCC0mB??dV8EGc9rPP2Z=gwA>&^^ zBFglTaph^O-=xIvmWjI0Q{uutqMiXtT>65@*s0gvBqjdy2cq7eQ0g0>VgCubv+xU| zjt}Xs7hWaW{5j1U9}{)$pgHSVJpYY;@XQ&a?4{US58eT}(bzw4zXH2co9-KW4|*5k z@gH6yqKEXFT#D~7;a99%ugUl06Axz~|K0eR=Wl>NN8&#(zDTs`aQv;FhhhJmkxxK8 zwbl6b(LWN!lg8^;UxxiJjlY*BVdvk*hrb%chHUeiZAt=+&Q_H<`?>2=tBC)4}NIjrB# z-1Fr9*#Br|F@G=O{YTd$yC5GwzuA7^_t-zB*VN_BzcdV@^i$dV2QKWBUK8(T7e0Fd z^7GxxTY-E0fL=Ej$^ielI5zgvF3ORhV^pU#tczGJa!7JKq`=sf6NjZNa^Ts6#p3tM z&dJ(j*|gr=vs%Aj&Qrg5x%s$_W7lCZ3vsWcG}TakD5mfGAB_8iAhi00_wuar~sY z7A1BY9i&fSt_Z)YP{0T_9Wn9rDL$<+Z2^|zpd+2Nimcb#dUaE@dJo_2v?*{)ZuC;;|Gdk8p8d>9S^5b7u~%k#R|GvG=wVas}CneE=en73o^SEm@VloVal4u8-j}3jY6*-UCXm zk=p}u{~fUh)La9rhsfm63v#NnjL?Xexm0c>w`X)@gaHo`8eJC}!|D?nh0s`}5N~En z`BtGZ2<0P%cry#_YZb~vXkUa-`xbCrZ7L9Yd)?R3UILm&HZZ^c><;6+N_2XD$7iw1 z4B+L;YhS|?vQn`eH#BKO8}xIJYS&Y`xTkPO;o}*qaT`chawApTqR)PV9W1JO{&gI* zZ82k6)mo^U?KA@wJWnubEh4-Vcy7=SmuIuWI>)8!%8JNEq@Ft*1GT7V)8F9|z-Cc~ zI*_DEGz-)7H$JIHpg@YY(@WTj(C}e`)U@j=TXmI|1D=xpNh#K3U96gp%QRMy4v4L8 z9SC({%er2s<|;_v?|FJst~$0f)yxp^sRu3Nw4!83wO(IOKXiHpoEmD+V0)gg#uPX< zbYGT^BT8=Ys_dE)N5JHv68)+tHoD*!N|GnSCcLSmjE*I?VaHE|#%xKhhQiVZn&O)WTjexy7eY&EVmd3Uu2>8=m!>1U*~d`ET)7g?ZbL2i z3S9}h5NT_JOwGxa$nMzYdJ{0PjTT@)4;u|C p^3kscZPx-1=TaY@(ByQ{EE2<43M9vqGw!ym;8^hh#?4K!*jK@x?&|;m diff --git a/plugins/LinksCloud/lang/LinksCloud_es.ts b/plugins/LinksCloud/lang/LinksCloud_es.ts deleted file mode 100644 index c112ac9b0..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_es.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Añadir enlace - - - - Cancel - Cancelar - - - - Add a new Link - Añadir un nuevo enlace - - - - Title: - Título: - - - - Url: - Url: - - - - Add Anonymous Link - Añadir enlace anónimo - - - - +2 Great! - +2 ¡Excelente! - - - - +1 Good - +1 Muy bueno - - - - 0 Okay - 0 Bueno - - - - -1 Sux - -1 Pésimo - - - - -2 Bad Link - -2 Enlace malo - - - - Add Link to Cloud - Añadir enlace a la nube - - - - New Link - Nuevo enlace - - - - Add Link Failure - Añadir enlace fallido - - - - Missing Link and/or Title - Enlace y/o título perdido - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Este plugin proporciona un conjunto de enlaces en caché, y un sistema de votación para promoverlos. - - - - LinksCloud - Enlace en la nube - - - - LinksDialog - - - Title / Comment - Título / Comentario - - - - Score - Puntuación - - - - Peer / Link - Pares / Enlace - - - - Sort by - Ordenar por - - - - Combo - Combinar - - - - Time - Hora - - - - Ranking - Clasificación - - - - In last - En la última - - - - Month - Mes - - - - Week - Semana - - - - Day - Día - - - - From - De - - - - All Peers - Todos los pares - - - - Own Links - Enlaces propios - - - - Show - Mostrar - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Por debajo de 100 - - - - Link: - Enlace: - - - - Add Anonymous Link - Añadir enlace anónimo - - - - Add Link/Comment - Añadir enlace/comentario - - - - Title: - Título: - - - - Score: - Puntuación: - - - - - +2 Great! - +2 ¡Excelente! - - - - - +1 Good - +1 Muy bueno - - - - - 0 Okay - 0 Bueno - - - - - -1 Sux - -1 Pésimo - - - - - -2 Bad Link - -2 Enlace malo - - - - Url: - Url: - - - - Links Cloud - Enlaces en la nube - - - - Add new link - Añadir nuevo enlace - - - - Share Link Anonymously - Compartir enlace anónimamente - - - - Vote on Link - Votar el enlace - - - - Download - Descargar - - - - - - Add Link Failure - Añadir enlace fallido - - - - Missing Link and/or Title - Enlace y/o título perdido - - - - Missing Link Data - Faltan los datos del enlace - - - - Missing Comment - Falta el comentario - - - - Link Title Not Changed - El título del enlace no ha cambiado - - - - Do you want to continue? - ¿Desea continuar? - - - - Expand - Expandir - - - - Hide - Ocultar - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_fi.qm b/plugins/LinksCloud/lang/LinksCloud_fi.qm deleted file mode 100644 index 8a5a61a38928075381c22f8471e9350ec81b3bd2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4935 zcmcgvZ-^9S7=PBC{d0TkxhHaJf9yRm6ZE{jyH&y@(Ys79{~X?Fs05C;GKQTHLDx~rsJd4?!;nY0_niRx1n zdwYOrMhC@CEyH@0Vi*1*(jIcx%*zz}@iU^vX_Q!W3-7O_?*3OG=R?|Z=4+zq?@_OI z9rv$LpK${JOSJv{14Ipl$fZM%5oOLsE-$|UeY2)LziK3<)CrgIzG}n@mp_Vb-6-cp3df0eNo9M0VuLWEHAS-{046>kBLOlx*_-A4r z#ASNI>RZ~y8a*%Ag<2BtqpXrAsi0i3;0jAJ$oAyKvtsk0K2l4>B5=V>jN%f2np6bb zp+9RHHWR#x)wZ-pin3Ck(!M!W!o$2wvaqRK%+fa4GziCBn%GhY*C?zkE4!=cn~)2c zanWL}Zd#R+aeEX@uo5bVpqyi6RB_tqiFTyuv}C1b!p*N@ph6XxY>v4yIpUnKLKn6% zJS8JZ>VYvOs`w%9)a`!5s^#BG09Z5AR#E9*O_`v*ptluIIeUc4OSY2p(NFHV8_jar zvVp@r>%|OBZ_@@ zlkHUsz^&S1C|_#-7opTGN&M|1C7u|FnCYdzn==L?#@n@wr-SMjOXhvgC2a)X{Jey3 z_YT(^w#}xco?AVA1+y%MlnY|0B=?zlqm1+`8;+2BM8Do&F!I9U0=k65jYs>W!wFCx zDLY0{AoT$&O2-gR!6+`}V1$!%JJq^g(Rvr9Iw0V->U02gcSSlN?hY$-0N;RClf{QS zN0zc)^b&2^wwCs6mPro*@yiVAs0OtI)KL?}FEc1t4e9_WR};i9GiX^gC~PwW(}Tr081xOv)Yult?cYecP`vRE{1Cp2hx(kas1DY#GY_6(KA zQwCRaHB+Eca0e^FF22WA!|^hyZnb5J9>XY=Lj^U_>ap@v1lWNnPDnoyQ){H-$f9Vg z5$svC9m7d}th9|4B2Re?jO>=7iW|^-M*-vdhzjaKqFwGV69^7ZgF0-jC_6bEZew#m zf{tsICt^;Q6eF@ChIQNFGS)9`6t;@7D%6k^g3g{ph9@D}C5LTG>Z3b`1|{6nr>#Y$4MjDextqASYr#ezu@3b-6p>OBm74Rs zw-f7aVd>@Y%v`Rro;wfEmXqcK&>~0(t zmoNve7}x_Gp=!Z=_VBl2IIA^FWA6t zcrGNi==LDSnouX)-Ni!{9{~JF#d`atd!Pu>#2eCsOvvH50);2>66)px1NX+c;{2a@ zAmbyMJHz>9p{ci^mkf6z_fBM%I_m}OO3@}16`n(Vyw+Qg!=a96V9&$}(#IrvWyuk{ z!<8h_E!1hvqgU%Qi{W)>;iT!_jc#BodXi?SnIA!(YU|zBks-iM6PgtB&i$K@my?@Z zqE8Oh>~K>YHUf&~(RnBsAJln-pBQeR - - AddLinksDialog - - - - Add Link - Lisää linkki - - - - Cancel - Peru - - - - Add a new Link - Lisää uusi linkki - - - - Title: - Otsikko: - - - - Url: - Url: - - - - Add Anonymous Link - Lisää nimetön linkki - - - - +2 Great! - +2 Loistava! - - - - +1 Good - +1 Hyvä - - - - 0 Okay - 0 Kohtalainen - - - - -1 Sux - -1 Huono - - - - -2 Bad Link - -2 Kelvoton linkki - - - - Add Link to Cloud - Lisää linkki pilveen - - - - New Link - Uusi linkki - - - - Add Link Failure - Vika lisättäessä linkkiä - - - - Missing Link and/or Title - Puuttuva linkki ja/tai otsikko - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Tämä lisäosa näyttää joukon välimuistissa olevia linkkejä sekä äänestysjärjestelmän. - - - - LinksCloud - LinksCloud - - - - LinksDialog - - - Title / Comment - Otsikko / Kommentti - - - - Score - Pisteet - - - - Peer / Link - Vertainen / Linkki - - - - Sort by - Järjestä - - - - Combo - Yhdistelmä - - - - Time - Aika - - - - Ranking - Sijoitus - - - - In last - Viime - - - - Month - kuussa - - - - Week - viikolla - - - - Day - päivänä - - - - From - Lähettäjä - - - - All Peers - Kaikki vertaiset - - - - Own Links - Omat linkit - - - - Show - Näytä - - - - Top 100 - Ylimmät 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Alimmat 100 - - - - Link: - Linkki: - - - - Add Anonymous Link - Lisää nimetön linkki - - - - Add Link/Comment - Lisää linkki/kommentti - - - - Title: - Otsikko: - - - - Score: - Pisteet: - - - - - +2 Great! - +2 Loistava! - - - - - +1 Good - +1 Hyvä - - - - - 0 Okay - 0 Kohtalainen - - - - - -1 Sux - -1 Huono - - - - - -2 Bad Link - -2 Kelvoton linkki - - - - Url: - Url: - - - - Links Cloud - Links Cloud - - - - Add new link - Lisää uusi linkki - - - - Share Link Anonymously - Jaa linkki nimettömänä - - - - Vote on Link - Äänestä linkkiä - - - - Download - Lataa - - - - - - Add Link Failure - Vika lisättäessä linkkiä - - - - Missing Link and/or Title - Puuttuva linkki ja/tai otsikko - - - - Missing Link Data - Linkin tiedot puuttuvat - - - - Missing Comment - Kommentti puuttuu - - - - Link Title Not Changed - Linkin otsikkoa ei muutettu - - - - Do you want to continue? - Haluatko jatkaa? - - - - Expand - Laajenna - - - - Hide - Piilota - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_fr.qm b/plugins/LinksCloud/lang/LinksCloud_fr.qm deleted file mode 100644 index 7d54ddc03a1808877eceecf9eac4930990b43b14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4945 zcmbtXYiL~67GCL`c_cHPBob=mYS|TUAEr$v$yAE>p-p17#Xc};FDjxZGbfp2&YV5Y zIny-N3;rpn_s3Q6g$knJMG?7P6%nk6)gSg=F8!ehD*jV3#nOuY5(K}scjlZ)=A5aI zA2a(r_Im7Zt@W*S{`^*X@W1DudF=n2E`Rr~=id2Zf~e~P(Y^@!A0V`6Tg=@*70!#uFdG7s}pa6qDGV`rLSO?@2tr zV4S}29#QU1<4k1=cHT0+d3+N#?9yxUyQHxNdUAIr|1b{u+{R=vh1co6TL#bk#-`|k>YV-r>JD&RfihE(_k#sS`&yS}MJO9JQfApFvXC`j{E6#Ny zb3$ASeWRIkd*OfPO!rI{_;!7!*GzAZwH$5h3c71|3(h!Z3pb4_cB9~7=3WA|gaif%FK5l+@xqP$jE_hS6>B#vmmK%iJ7~~F- zNp+gTzfC^wHw7BHhsMN>b<6ZO#p%e=juqRI<^s9Yj!`k)I2I?g5khQuKTJ00s50!~ z-dS^i?2a)pVU`6u9;Yiq1xOyGh0u6G99%G$;sl0iH{DGVhJBz_hj4@3&^WG4+)MnH zs7h9#_7Wf{cDvGDs>+7f(Wi}_O#~`4tg_SLHq&V;Q3ZaMlwVE11(orv9k9NpLb1oR zokrb?1L5j64_B~PW*Yc+0gFlVEdcZf%6%y&9odLYtT>1nR*ts?&1_?Byg5mQDO_u@ zBPw|~?3zjVee?)mBaAm8+uPaEaD*X4T)4Svc$}ih* zd!FsiE6;@KmPce=%-FsYi}4^GxX5`k2QGTjnHJZs4V+0S!`H^0w1*BOu^pT<6fq9h zomhbZ1&vD!$40-IB6 z>$ui5qstD2g*_HZZ5D=Ec2#QQ9cyFx5+b9EVY_<9RHb!zC{+*kzTtw!Q?21B>}hXm zE0#IqETypqd?a@3e3bC0PQ$^056x6;Pt?@mM6E85+GWc_VtSS@XunUvM4<@%A~i^Jz)-6O}{gL?-TW~AmTX+~ANo;5TRl<-9RT7t)3kYU}s z9Y-9pthyJeY7kLJLavaFCN-WWLIph&()VRmjK-uveg&*qfaKD0U^oeEW@V(&4DD0? zhb=ELr3an1APv(IwUr6)IP#Opu%W20d0@8Mz+0Yxt_!RWPD!yO8)DIPeWtOJbU|zl z>$*sXHUQ9Nkm|A`W}YH3Ftl{!%#>Vo9cijbq0PrU20#ryx8CqjsT+>fz^aiJ4Vr36 zC}R&;HgaDM=r-F$sM)v)Odh#ErKjKkhxA@oIHnh!p?lCSxzF(A;B$tnG-#Q*U7Lcf(N&GJ#LY^*%~`2anO}uSngE4CVgljmBVJ{HQ>B7x%Jj|1Fz#wW zXYGvFjMN&hX)EHhEeL$)Ij;?zjLKoVrS6maQ8JZC?*@@%Ja_Q)!8y}p{E#%d4=%cD z!i;8}%T*{sx)K;-HF_Z2;0Rf!Ein?z&}~i+s5Icb)RUKD>p(nxi|H<4n29_>4^1P5 zB_ALVNKTie{?ur*ln=MV(J)_AN+ddAcddMoa%w0#QAoAowdND8*>3`eHcVH{x}_)e z;ET;sUxX1JMw5^+U6G5C5L^P%t0Q4Gb#i@&1e2bYbzjUzo9cle54yFMY%yl+YBVEl z#_o__IL@7$Yp?nyK-fDKU4E6)mUx686cGq<*Q~(-)$#(A(=)Ob+ub^Tg0z_ss$1z{ x-9uO6o}@npR!Sr=nmfWnwbVrt86HkKMwy2Xw - - AddLinksDialog - - - - Add Link - Ajouter un lien - - - - Cancel - Annuler - - - - Add a new Link - Ajouter un nouveau lien - - - - Title: - Titre : - - - - Url: - Url : - - - - Add Anonymous Link - Ajouter un lien anonyme - - - - +2 Great! - +2 Parfait ! - - - - +1 Good - +1 Bien - - - - 0 Okay - 0 Ok - - - - -1 Sux - -1 Bof - - - - -2 Bad Link - -2 Mauvais lien - - - - Add Link to Cloud - Ajouter lien au nuage - - - - New Link - Nouveau lien - - - - Add Link Failure - Échec ajout de lien - - - - Missing Link and/or Title - Lien et/ou tiitre manquant - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Cette extension fournit un ensemble de liens en cache, et un système de vote pour les promouvoir. - - - - LinksCloud - LinksCloud - - - - LinksDialog - - - Title / Comment - Titre / Commentaire - - - - Score - Score - - - - Peer / Link - Contact / Lien - - - - Sort by - Trier par - - - - Combo - Combiné - - - - Time - Temps - - - - Ranking - Classement - - - - In last - Par - - - - Month - Mois - - - - Week - Semaine - - - - Day - Jour - - - - From - De - - - - All Peers - Tous les contacts - - - - Own Links - Propre liens - - - - Show - Montrer - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - 100 derniers - - - - Link: - Lien : - - - - Add Anonymous Link - Ajouter un lien anonyme - - - - Add Link/Comment - Ajouter Lien/Commentaire - - - - Title: - Titre : - - - - Score: - Score : - - - - - +2 Great! - +2 Parfait ! - - - - - +1 Good - +1 Bien - - - - - 0 Okay - 0 Ok - - - - - -1 Sux - -1 Bof - - - - - -2 Bad Link - -2 Mauvais lien - - - - Url: - Url : - - - - Links Cloud - Links Cloud - - - - Add new link - Ajouter un nouveau lien - - - - Share Link Anonymously - Partager le lien anonymement - - - - Vote on Link - Vote sur le lien - - - - Download - Télécharger - - - - - - Add Link Failure - Échec de l'ajout du lien - - - - Missing Link and/or Title - Lien et/ou titre manquant(s) - - - - Missing Link Data - Data Link manquant - - - - Missing Comment - Commentaire manquant - - - - Link Title Not Changed - Le titre du lien n'a pas été changé - - - - Do you want to continue? - Voulez-vous continuer ? - - - - Expand - Montrer - - - - Hide - Cacher - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_hu.qm b/plugins/LinksCloud/lang/LinksCloud_hu.qm deleted file mode 100644 index 0c1c75ab0389fa496e7e3667b94c513758314cba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5122 zcmcgvTWl0n82-!7UfL~XOGvqh+P& zca7GCnhwSx=XhxU$!W0Xz0fP^_lYL$4P8ncg#O!FDhznk(B5eMh$z&ioxAo4(c}%< z#Y{84r?j6B&&7u2?i$I3wFe=m@<#Zc#lTk%gi{g59|<4HybL?D;enG_wMKVM+>E56 z{QY9&r~1!f_pQkAz0X7cuhCQt?_*kYi+LV@&bVvja;$ONa^SDV_KWGT`)2G)E9@_~ z%RA!WcT%Oh#!gfiwcw-dbVYW@Ir!BYum1F1=sz0Yc5EN?B;uW^?cnR7%0ml)58a+@ zzH|cn8{IYb*yPtV4f=0Xr7kn{6!e{+(mfNrhxWVc(`W(J zlb{YV$e{x5p)B>VFC>XrP%l>7cAA~8TA5C-%UV5!=B#eo-DQlP1#|<@8%U>a>L;5l zJnf`mnyX}#FK7^}^M>xs4U&?eh0=yL;0tVn!bTR>i}vE~AmAJTz3THGG4X{BqESx^ zHa|#Kf|4+O6`7O+6>w(Mh@{xqqxS~^pP)71Y!?`Cs0XU|&>(yel#&1WNvE`Yr{k?f zL)hy;g^8aNTGl+*}lK4S{LqEc2IMBKw2(6Q$#>pnAi>^>kDVe!G zTPS3$ZfTv+t#qB87adv04CH@SFc(T{Y{TF98>1#RgO(~tL@HexpQOGDJlDTsIy;MPV0`$vX@ z_nfp`Acc&}2TP&9;21f9v;iz(5Cpa-#j0=n@knd&Eh_@`Rp1M^aW`AJ9-F}}-K({( z${guV5ZadRU45bWUty9YIX-M z&#_IT7Rcoy>%bxh|I@TW!DckuqTeoxKHYM-q;=UAid@lH;j1(ueRMELn6khYl$=wYwM9)mK}LI?yUG^{L%j3o5Sf-by)$a+BCe&glL% zsOrA^6KJW-g^B%xICNcMqOF!N^@4viHU{K?oGYN5$5jJ|DA0=rB}tqYHdJvxlykCD zRKvyI9XG@V+YwC}-Rd^{si^VQJ30@9S(Y3KJls!o8gPN5qo7C7JZZ!Dnad~Zm48!4 zrmIrv{isJM&;A^z?#SUcbXrWUQd2#mM$*}=JG$?I{~r^hhq4NIH;jycs^ zUmNeIc5LNfA? z-UCDU%E>crsq1A;dq&S2?(IO`GEI4}^;lblOH2`RIdsPsIITTn_XUvBhFZZhtpSV1 zaoKL?9ntBpC_=52F59e#*E+H}{~CASU-yiWlP{U9@&?hWjQC9XUkMG2(MxC?{grgAHf=eC - - AddLinksDialog - - - - Add Link - Hivatkozás hozzáadása - - - - Cancel - Mégse - - - - Add a new Link - Új hivatkozás hozzáadása - - - - Title: - Cím: - - - - Url: - Url: - - - - Add Anonymous Link - Hivatkozás hozzáadása névtelenül - - - - +2 Great! - +2 Nagyon jó! - - - - +1 Good - +1 Tetszik - - - - 0 Okay - 0 Elmegy - - - - -1 Sux - -1 Rossz - - - - -2 Bad Link - -2 Nagyon rossz - - - - Add Link to Cloud - Hivatkozás hozzáadása a felhőhöz - - - - New Link - Új hivatkozás - - - - Add Link Failure - Hiba hozzáadása a hivatkozáshoz - - - - Missing Link and/or Title - Hiányzó hivatkozás és/vagy cím - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Ez a beépülő sok hivatkozást tesz elérhetővé, melyek egy szavazási rendszer segítségével értékelhetőek. - - - - LinksCloud - Hivatkozásfelhő - - - - LinksDialog - - - Title / Comment - Cím / Hozzászólás - - - - Score - Pontszám - - - - Peer / Link - Partner / Hivatkozás - - - - Sort by - Rendezés - - - - Combo - Kombó - - - - Time - Idő - - - - Ranking - Értékelés - - - - In last - Utoljára - - - - Month - Hónap - - - - Week - Hét - - - - Day - Nap - - - - From - Tőle - - - - All Peers - Összes partner - - - - Own Links - Saját hivatkozások - - - - Show - Mutatás - - - - Top 100 - 100 Legjobb - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - 100 Legrosszabb - - - - Link: - Hivatkozás: - - - - Add Anonymous Link - Hivatkozás hozzáadása névtelenül - - - - Add Link/Comment - Hivatkozás / Hozzászólás hozzáadása - - - - Title: - Cím: - - - - Score: - Pontszám: - - - - - +2 Great! - +2 Nagyon jó! - - - - - +1 Good - +1 Tetszik - - - - - 0 Okay - 0 Elmegy - - - - - -1 Sux - -1 Rossz - - - - - -2 Bad Link - -2 Nagyon rossz - - - - Url: - Url: - - - - Links Cloud - Hivatkozásfelhő - - - - Add new link - Új hivatkozás hozzáadása - - - - Share Link Anonymously - Hivatkozás megosztása névtelenül - - - - Vote on Link - Szavazás - - - - Download - Letöltés - - - - - - Add Link Failure - Hiba hozzáadása - - - - Missing Link and/or Title - Hiányzó hivatkozás és/vagy cím - - - - Missing Link Data - Hiányzó adat a hivatkozásnál - - - - Missing Comment - Hiányzó hozzászólás - - - - Link Title Not Changed - Hivatkozás címe nem változott meg - - - - Do you want to continue? - Folytatod? - - - - Expand - Lenyitás - - - - Hide - Elrejt - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_it.qm b/plugins/LinksCloud/lang/LinksCloud_it.qm deleted file mode 100644 index d3268be213845d8843c226421b86890117f99519..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5285 zcmcInYiJx*6h7(BKC+u^9>%xAZLPJ~rg?NL5=Cv2wzl>WnzW)t+v)B!J7jil*qKd? zBIu8zRZxG_A|i@{;sc?yfXf&CDhw5Pkj2*ds&)o+;t=z%F0j&3> zw#U~1uO-^82VcSbQE$xL-~O1U!S0@X;RhG~$s1E{e($-Hz+cfZc`c_OXh{svwP{3|8dgTkMK_ z7oGDi#Ae;JYE>hSuHmJ}uL9xysVl{ZC2O(idQF5^wkVgFIeY|! zE^K4ADUW%$u~n!lY(LP{h;A1RD~^+!Xhf|nl(|^9L4A0~TTt(AAWY#fN0R1|7njD%_cHS5$|I%YslLIQVO*x+GvHzEJQRu3qe~ig|bA z;Yw%HTD&oU6^MeZvPB1PcrKq3&ngqcTOeo}Z>nnK!(FNGH2-D+xz49yY@%#BVp=U( zOjqTMSuz|XykodR9uh^pST;(+;wG?`(+aOQycLQ8%_jxiQOiI{I6O~$Z%V|&rD(8=KOs~1-&MO$fIHQu>BEQlvFXv0EK0iX>rp#QOXhN!qUq6hFv z2-+S?k!JcKvdM+~Tp!^lxe|cC!`6+KCB_V+>O>mqL5a5jW97qUIGKYa&JIi0l@&1%lPK9b zQ3o4TQxeP^l#$NbAWTg#%au5gS&30k#)Y;_&|Xy<8<)pDqlQJYBD&FEmA~p6sbYhXttArn{z5dm}w* zG}3&o1Cb;7J&;k#XF;M6gA4ncwXei zJ8Z5-Lv&?m2hN()kX^|gI9}z*C|AW$!AE#n)pY(FY*y>8SzD>%=<2jinG4Dqizn8O zF@@XD{~Q-Q(dXX^LW}Bw3BJKNcuaMC8Vf;sw{A~CMnx{Mo5oOqI3~W(^35_h7Rm9V z^e$Nu9z(DOU7b?E=mW61P6DgQ8GM>)R3@nLG8^2tgPgu#ysTFZ?=IrsZY_0_4n^ID z&6nWF#jXV8=yhh~R3zrbMR6)D6HVHuhG-2n&t}Az_!bwEPLGGZy&( diff --git a/plugins/LinksCloud/lang/LinksCloud_it.ts b/plugins/LinksCloud/lang/LinksCloud_it.ts deleted file mode 100644 index 93efcb778..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_it.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Aggiungi collegamento - - - - Cancel - Annulla - - - - Add a new Link - Aggiungi nuovo collegamento - - - - Title: - Titolo: - - - - Url: - URL: - - - - Add Anonymous Link - Aggiungi collegamento anonimo - - - - +2 Great! - +2 Grande! - - - - +1 Good - +1 Buono - - - - 0 Okay - 0 OK - - - - -1 Sux - -1 Scoccia - - - - -2 Bad Link - -2 Cattivo collegamento - - - - Add Link to Cloud - Aggiungi collegamento alla nuvola - - - - New Link - Nuovo collegamento - - - - Add Link Failure - Errore aggiunta collegamento - - - - Missing Link and/or Title - Collegamento e/o autore mancanti - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Il modulo aggiuntivo fornisce un insieme di collegamenti memorizzati, ed un sistema di voto per promuoverli. - - - - LinksCloud - Nuvola Collegamenti / LinksCloud - - - - LinksDialog - - - Title / Comment - Titolo / Commento - - - - Score - Punteggio - - - - Peer / Link - Contatto / Collegamento - - - - Sort by - Ordina per - - - - Combo - Combo - - - - Time - Tempo - - - - Ranking - Classifica - - - - In last - Alla fine - - - - Month - Mese - - - - Week - Settimana - - - - Day - Giorno - - - - From - Da - - - - All Peers - Tutti i contatti - - - - Own Links - Collegamenti propri - - - - Show - Mostra - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Ultimi 100 - - - - Link: - Collegamento: - - - - Add Anonymous Link - Aggiungi collegamento anonimo - - - - Add Link/Comment - Aggiungi Collegamento/Commento - - - - Title: - Titolo: - - - - Score: - Punteggio: - - - - - +2 Great! - +2 Grande! - - - - - +1 Good - +1 Buono - - - - - 0 Okay - 0 Okay - - - - - -1 Sux - -1 Scoccia - - - - - -2 Bad Link - -2 Cattivo collegamento - - - - Url: - URL: - - - - Links Cloud - Nuvola collegamenti - - - - Add new link - Aggiungi nuovo collegamento - - - - Share Link Anonymously - Condividi collegamento anonimamente - - - - Vote on Link - Vota il collegamento - - - - Download - Scarica - - - - - - Add Link Failure - Aggiungi errore collegamento - - - - Missing Link and/or Title - Collegamento e/o titolo mancante - - - - Missing Link Data - Collegamento dati mancante - - - - Missing Comment - Commento mancante - - - - Link Title Not Changed - Titolo collegamento invariato - - - - Do you want to continue? - Vuoi continuare? - - - - Expand - Allarga - - - - Hide - Nascondi - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_ja_JP.qm b/plugins/LinksCloud/lang/LinksCloud_ja_JP.qm deleted file mode 100644 index 0fe587e780d1c98eb9a625185f1640f2d99a9ad7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 245 zcmcE7ks@*G{hX<16=n7(EZlq7iGhJZfq~`yQXoB%WrpV-AkDyXKEnk_rL#RXJOZSR zGl9fzW+1_3u-4$Q!DoZr2Cq4QTn07}c23MoPR(HlGWi@+QhYM=vWs0Z6La#@89`cj z3=SA918R9|@W&etBL_eqstp8#lThmYC3~-Eg&Rt`!A|dDvC5O^@rysI-Es MW%0;NNyRV|07?=*B>(^b diff --git a/plugins/LinksCloud/lang/LinksCloud_ja_JP.ts b/plugins/LinksCloud/lang/LinksCloud_ja_JP.ts deleted file mode 100644 index 7ca2214dc..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_ja_JP.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - - - - - Cancel - キャンセル - - - - Add a new Link - - - - - Title: - - - - - Url: - - - - - Add Anonymous Link - - - - - +2 Great! - - - - - +1 Good - - - - - 0 Okay - - - - - -1 Sux - - - - - -2 Bad Link - - - - - Add Link to Cloud - - - - - New Link - - - - - Add Link Failure - - - - - Missing Link and/or Title - - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - - - - - LinksCloud - - - - - LinksDialog - - - Title / Comment - - - - - Score - - - - - Peer / Link - - - - - Sort by - - - - - Combo - - - - - Time - - - - - Ranking - - - - - In last - - - - - Month - - - - - Week - - - - - Day - - - - - From - - - - - All Peers - - - - - Own Links - - - - - Show - - - - - Top 100 - - - - - 101-200 - - - - - 201-300 - - - - - 301-400 - - - - - 401-500 - - - - - Bottom 100 - - - - - Link: - - - - - Add Anonymous Link - - - - - Add Link/Comment - - - - - Title: - - - - - Score: - - - - - - +2 Great! - - - - - - +1 Good - - - - - - 0 Okay - - - - - - -1 Sux - - - - - - -2 Bad Link - - - - - Url: - - - - - Links Cloud - - - - - Add new link - - - - - Share Link Anonymously - - - - - Vote on Link - - - - - Download - ダウンロード - - - - - - Add Link Failure - - - - - Missing Link and/or Title - - - - - Missing Link Data - - - - - Missing Comment - - - - - Link Title Not Changed - - - - - Do you want to continue? - - - - - Expand - 展開 - - - - Hide - 非表示 - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_ko.qm b/plugins/LinksCloud/lang/LinksCloud_ko.qm deleted file mode 100644 index 789c669e8447f046bc3255478f8b3e7943a8a519..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4118 zcmb_eZEO=|9DlanUAwj`WtkInm}ehQ$Trq(#TZxwwhDsdMK%y+B;3|xt?TZV_R1Jy z;s=+AU?dR~jfp};A(my?ij0A}Rkk}`rXU-MVJ3V)LW~AfmKeeZ|IZzL3f$cU9 zR4*Ka&u;Yc=ba$WW?k4mA9!6^qfcK4{EF|cT(j*6Cc*zdY!|${!H&fES%9-c%-*FZ5X#=loVqcHkn>gMhfo0Q zsLZwZivUoiOXd>GJOz53v)RWh3I7J`=Lr86`%&m^urtAS_kgtdb(uSp^V{M7Tp9OE z`AN{Xm-}nRYhY)--48J%E@)p9IRk(6>XNN>RIh&)_-7oQ_)*Ze&++?G@ZY{6r``qm z%}VH!yW|u~ARk%n&hVyF5Z8OIsi{LCi(KpXzXABuu15bx$k&VRJ;lJcW#vZR`V#OJ zy5v60-Ni6~o8j?amBBvJC9~hN_GT}9|G|{z>5%vAFLdcV5(bFd2EaU2jLH#KcMJuF zcO#7Eq1hx7MABd{F2_qGDM&*0ED8o|!(vM;5auINb5@#LfpGr|>N9t^0m{uOuE0y8 z0xuU?vAw92SRP6acWZX*D3>cO$93^7R>XWDg4v5F)mk9yPS2ubS7`;V=7X3xYpubD z@ZrL6u`o5kLNtw%srqasvmtE(eLWfy zmX|m=_|Dk6)Og}kGMKw+(E_S_T0p`bQXIGQqD<{Uj&hLe2_$#Kee z1f+H`BJtWjGFWCVu2Bw9Ece`&Hkdl5nz<7vo95KgpZlOh&yLPdV`(F?{=RWfC;>8Xx)9AtbmL&eRbg#l8kFYyx1&QgrvRG z%tB%bS6eZLJbCm*YS=J3FthLt#5~dk7F%~pdh1Ts43FuSd)pNGye|O_WwO4frWI+y z2Y8t`P5A$F4H!bq9v-DtWS7J944GPY5AIZOdY@84&dPRCyE@Ff(?ePry0c7QyOic4 z4UNm_rDSl5Nfjy#h1*y2VhgNMQ^y$9o0>+UY+aM2pMeIQ90A^Sk#HK+{K4dtb62VA zqxVB%Lc!EXL0yQC3i`E0FW-oEI~%MrqYbG{J2Q15sogXTPJN`WBvnXl*z2UIj2kVK z!mP=php7*@n)j$jyV!mi!8EknV8kLhC gB8NLU(r66swd9PF^yg=q(rooMMKdo6f^q5m1Fatr2LJ#7 diff --git a/plugins/LinksCloud/lang/LinksCloud_ko.ts b/plugins/LinksCloud/lang/LinksCloud_ko.ts deleted file mode 100644 index c83b1b154..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_ko.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - 링크 추가 - - - - Cancel - 취소 - - - - Add a new Link - 새 링크 추가 - - - - Title: - 제목: - - - - Url: - 주소: - - - - Add Anonymous Link - 익명 링크 추가 - - - - +2 Great! - +2 멋져요 :D - - - - +1 Good - +1 좋아요 :) - - - - 0 Okay - 0 괜찮아요 : | - - - - -1 Sux - -1 어우 :S - - - - -2 Bad Link - -2 후졌어요 :( - - - - Add Link to Cloud - 클라우드에 링크 추가 - - - - New Link - 새 링크 - - - - Add Link Failure - 잘못된 링크 추가 - - - - Missing Link and/or Title - 링크 또는 제목이 빠졌습니다 - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - 이 플러그인은 캐시에 저장한 링크 모음과, 링크를 알리기 위한 투표 시스템을 제공합니다. - - - - LinksCloud - 링크클라우드 - - - - LinksDialog - - - Title / Comment - 제목 / 답글 - - - - Score - 점수 - - - - Peer / Link - 피어 / 링크 - - - - Sort by - 정렬순 - - - - Combo - 조합 - - - - Time - 시간 - - - - Ranking - 순위 - - - - In last - 최신 - - - - Month - - - - - Week - - - - - Day - - - - - From - 보낸이 - - - - All Peers - 모든 피어 - - - - Own Links - 소유한 링크 - - - - Show - 표시 - - - - Top 100 - 상위 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - 하위 100 - - - - Link: - 링크: - - - - Add Anonymous Link - 익명 링크 추가 - - - - Add Link/Comment - 링크/답글 추가 - - - - Title: - 제목: - - - - Score: - 점수: - - - - - +2 Great! - +2 멋져요 :D - - - - - +1 Good - +1 좋아요 :) - - - - - 0 Okay - 0 괜찮아요 : | - - - - - -1 Sux - -1 어우 :S - - - - - -2 Bad Link - -2 후졌어요 :( - - - - Url: - 주소: - - - - Links Cloud - 링크 클라우드 - - - - Add new link - 새 링크 추가 - - - - Share Link Anonymously - 익명으로 링크 공유 - - - - Vote on Link - 링크에 투표 - - - - Download - 다운로드 - - - - - - Add Link Failure - 잘못된 링크 추가 - - - - Missing Link and/or Title - 링크 또는 제목이 빠졌습니다 - - - - Missing Link Data - 링크 데이터가 빠졌습니다 - - - - Missing Comment - 답글이 빠졌습니다 - - - - Link Title Not Changed - 링크 제목이 바뀌지 않았습니다 - - - - Do you want to continue? - 계속하시겠습니까? - - - - Expand - 확장 - - - - Hide - 숨김 - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_lang.qrc b/plugins/LinksCloud/lang/LinksCloud_lang.qrc deleted file mode 100644 index dd737ab14..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_lang.qrc +++ /dev/null @@ -1,24 +0,0 @@ - - - LinksCloud_ca_ES.qm - LinksCloud_cs.qm - LinksCloud_da.qm - LinksCloud_de.qm - LinksCloud_el.qm - LinksCloud_en.qm - LinksCloud_es.qm - LinksCloud_fi.qm - LinksCloud_fr.qm - LinksCloud_hu.qm - LinksCloud_it.qm - LinksCloud_ja_JP.qm - LinksCloud_ko.qm - LinksCloud_nl.qm - LinksCloud_pl.qm - LinksCloud_ru.qm - LinksCloud_sv.qm - LinksCloud_tr.qm - LinksCloud_zh_CN.qm - - - diff --git a/plugins/LinksCloud/lang/LinksCloud_nl.qm b/plugins/LinksCloud/lang/LinksCloud_nl.qm deleted file mode 100644 index 48d6e3763e3565c6a9778c554c8280f910e9757c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4905 zcmcIoYiJx*6h7OXePlOHlM-X`-s}y$jJlO0Cyzv`IV=jZ`p#omwf}d#c1@_4~Xb4Z;f9cz0`zV zk*K%E-;NF+OheA^(S64|Vb5F9hw?8GEx0Lqvi%_R+-GECfX9C^9^ddfQMA+e@bue6 ztuGs&6-S`wW#jwDdaz-&x5oa88J9s$>yFrkD}itAj%DNcIk7DEMDan``AqECajb^n zt?lQJ$*(5)IG_l?O7++rT*7)A!+MU+{e>AyIoDX@! z$)7jC{^YkUV`=ak`N><8y(w!s_=p@%m3Ds!zjmZM-gzGTzew+V`d;w)aC#!U3w*6_ zJ=6<)^xcK_{-fA`rMD*DU-+nDK<)!=+3#HFCvS~?)HeRx3E+no6_$Ya=vHrC*ijZJh^w4NkclxHtUQP4Xe)=QaZciV>Y`AsEfvN}>SZCQvgt{b>Pg|lcHNSpFh zq5}132`#;YVtvIj-JUQRi>XiP9tGN>92Lpc=y>0N7_IFMgI)qCt8aorgrH3@!l6km zCfzqE)|z?2=7-5jQ3lAZG)b1m#WP~-q&X7?$b$ls4Nx@eqfcy-#m?vG@;W_rDD9c`!tSydcb>vhET5<}?LSZ`jepwM?CD#t+y^FS}r2B{WT4Hj`8T@T+m_b)-SX?Q+ zI?U4~ZHJF`6TsMBu|v0a>fEc6KlmwCUUbyk8@Jo+TA}2qlJf$MfT=rh37S%AT2NUg zPnU1yj4XCRxMY^-6Ch^idJ6OTwIrP zu<_F#>2mn1Gga3r3mgW(%F?xjTeQk6I2^(BoJ}Q9D`L-~jQa$fWexY?{%ryG2|7dd z_U&&&%gNy4{*j@KPWQw>W}t5{lVO4bK)jhjE9Zg+0a_Uf;>`@o&IPRmC>sjm%?w&K z7nB8PRR}1k9dWfir*`Bc;XiC2KG`dpYI?m=_M?_gsa9G+L*jGF?RIV})y=7YSeDC{ z;|7NB-*=2w?ik!J_=pC|UW#U689DggQ{cJ1O2euehMdw({kZp@?mQ|?+it1L) zgWE-Aw%`b4LUWR))=JlvWib$v2r1N7E>9CAwbB@vnUH}BpFN#uKHNCHHd|6Hwn20JhP_j$rGXmb2ofyT_8RL@T?2Qv>2Pv98YCGv zqK1bcHoy~ZDkjHI>qu;Hgl$%Xb8}EPM$YZoX#hgJiN@<*Yyi{jrAC9KE-vTZa3How zR}2?Tr(gv;p3-_6Ek4G0)v|pIcj@ii8vPyH12hITpMVvilaT*ZH=mJ3_4#MM1ARrP z@Ots!25o{+Q%9krE?AK^V!CEv5dZH9&PP;=Hp5aCUTte^GmcF$(7uc21ja(fs2Zb0 zRJ4GWt<#R0AcHFnzgGB5mB3i4hi5G+%>_&J>xntQfl(%!^HYNoH=E8R#+X1CQh064 zsru1)CyI^cr1xs!li%9d-ZX8-6(Bfym#RsTUrMz*_%;L!bw|{ec8wOzisen)`kl;H zZ+<>Yk{Fb^@HLf>(W0CVbg~mxbBXlk#tQUHn$lVmqq5?PiEuR~y1j``W2{sTt~tw^ zW_K@sXEmeA@DKNrkI(6mvb9dVoXkjcB^?_A$$tDK_^q`4dAS3_M~e{ jTgQ1wmR{Nih9rqD#zTDL-vh=imgR5j`!ND8h(!Jd+4jQp diff --git a/plugins/LinksCloud/lang/LinksCloud_nl.ts b/plugins/LinksCloud/lang/LinksCloud_nl.ts deleted file mode 100644 index 5ae75f5dc..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_nl.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Voeg een Link toe - - - - Cancel - Annuleren - - - - Add a new Link - Voeg een nieuwe Link toe - - - - Title: - Titel: - - - - Url: - Url: - - - - Add Anonymous Link - Voeg een Anonieme Link toe - - - - +2 Great! - +2 Geweldig! - - - - +1 Good - +1 Goed - - - - 0 Okay - 0 Oke - - - - -1 Sux - -1 Slecht - - - - -2 Bad Link - -2 Slechte Link - - - - Add Link to Cloud - Voeg link toe aan de Cloud - - - - New Link - Nieuwe Link - - - - Add Link Failure - Link toevoegen mislukt - - - - Missing Link and/or Title - Ontbrekende Link en/of Titel - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Deze plugin geeft u een set van gecachte links en een stem systeem om die te promoten - - - - LinksCloud - LinksCloud - - - - LinksDialog - - - Title / Comment - Titel / Opmerkingen - - - - Score - Score - - - - Peer / Link - Verbinding / Link - - - - Sort by - Sorteer op - - - - Combo - Combo - - - - Time - Tijd - - - - Ranking - Stand - - - - In last - In last - - - - Month - Maand - - - - Week - Week - - - - Day - Dag - - - - From - Van - - - - All Peers - Alle Verbindingen - - - - Own Links - Links eigenaar - - - - Show - Toon - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Onderste 100 - - - - Link: - Link: - - - - Add Anonymous Link - Voeg een anonieme Link toe - - - - Add Link/Comment - Voeg Link/Opmerking toe - - - - Title: - Titel: - - - - Score: - Score: - - - - - +2 Great! - +2 Geweldig! - - - - - +1 Good - +1 Goed - - - - - 0 Okay - 0 Oke - - - - - -1 Sux - -1 Slecht - - - - - -2 Bad Link - -2 Slechte Link - - - - Url: - Url: - - - - Links Cloud - Links Cloud - - - - Add new link - Voeg een nieuwe Link toe - - - - Share Link Anonymously - Deel Link Anoniem - - - - Vote on Link - Stem op Link - - - - Download - Download - - - - - - Add Link Failure - Link toevoegen mislukt - - - - Missing Link and/or Title - Ontbrekende Link en/of Titel - - - - Missing Link Data - Ontbrekende Link data - - - - Missing Comment - Ontbrekende Opmerkingen - - - - Link Title Not Changed - Link titel niet veranderd - - - - Do you want to continue? - Wilt u doorgaan? - - - - Expand - Uitbreiden - - - - Hide - Verberg - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_pl.qm b/plugins/LinksCloud/lang/LinksCloud_pl.qm deleted file mode 100644 index b44eddac2a99a644a8f355ecc000dfe6879d58e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3634 zcmcImU5Fc16h70;B-tcQw{=-}WtF@5SJ%+Dp!f$>u_{u;zKHm!h@eFjM6u|1XWW}?XJ%~?S+Zx6 zx!*b8IrrZ0ocrH220p!V_Vnk&L+>Aa>D_O}iIh`B51$}P5UF210sA|tS6(4X4wLp` zg(!82w8c$C=?6%=_y2b%9F>~&B(uy{BbAv#NCv+0eL8=Q`VE8 z;Pi{{O=a*Hc%1ibPu4UhFb8ga?U?kLFpqc_<3j z4;TW|0cD)pu)6?us4C&<(E=OS4JHUj`52%ako)mjK;m^etY~CVm73B^JjbT0dOOO& zdaq&z=``P=fTwMs!tt@F2HT>xbhr*RWZN9>v}?TCSdm>{m~-hUDIBeoTogA0j2KPO z9Jn=+bcfs8C6~C7=(D^ksP1#6NGLh}+FpU|CI z(~hcrk;cJZ7u!Yi*tpql2H;}RnCEZ?&(nD4Qd1e1&Ic#0M#FL{9xtXl#u%@&Y0I_E zsCesWcVwQ)-T#`Qq(GY`iMSVVb5z76?L&rk7eL)tw1SLO^nqliQKV=klY4Tu$sq2uLgzppDBx1%Nh2g2ZA0DlP|Y1gIDZ z5{m_B({fM|piL2=sM~(SN)$*u-18Xj9fyLLP&pU35aKE8*t?`7V-vhqGaWaypivrP zUnArh;Y}!r{g09d7!J@BdWT>kx{v5W4CU+I+0;09U0!4Pi0UPwX9C#~{#eOZ{XnpL zAf1OjshNd@&LUU?-}{-MHwh@*5*yt(j8am>nwL%%W0ZhLyME8 zJ@7H(CDUEnWQn&No9mu32e@TuFHna?D^^M}a(w%t1qfVd92KQA2n!)(0~ekxK+jl4_sG$C1@>;)p-71{(Ii9DKX zmSlgWllgykmOuu*H0kX!h99qqb&jAmi6b%>x*Y?wA7hV>0*h%&4nJhcBKJ(S9Iv-E zLLKzue3|&G13cDoAmQmfrdelWvTFxuXK~bYM6ZIpLlp^3?A4tr`f6y@0#1<_KX6%< zLCjp@%B?&&ap}0fJg3)9zg^4u$@V6*0J)TRd#a=>M5ka1`rWO-oGkg%t!X za&!m;7@{4>R_uzOzk`jHM@puYd6c^*11%-VnYl_Hne? Pl%o9Aw@SUbA$8N= - - AddLinksDialog - - - - Add Link - Dodaj Link - - - - Cancel - Anuluj - - - - Add a new Link - Dodaj nowy Link - - - - Title: - Tytuł: - - - - Url: - Url: - - - - Add Anonymous Link - Dodaj Link Anonimowy - - - - +2 Great! - +2 Świetne! - - - - +1 Good - +1 Dobre - - - - 0 Okay - 0 W porządku - - - - -1 Sux - -1 Ssie - - - - -2 Bad Link - -2 Zły Link - - - - Add Link to Cloud - Dodaj Link do Chmury - - - - New Link - Nowy Link - - - - Add Link Failure - - - - - Missing Link and/or Title - Brakujący Link i/lub Tytuł - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - - - - - LinksCloud - - - - - LinksDialog - - - Title / Comment - - - - - Score - - - - - Peer / Link - Peer / Link - - - - Sort by - Sortuj według - - - - Combo - - - - - Time - Czas - - - - Ranking - Ranking - - - - In last - W ostatnim - - - - Month - Miesiącu - - - - Week - Tygodniu - - - - Day - Dniu - - - - From - Od - - - - All Peers - - - - - Own Links - Własne Linki - - - - Show - Pokaż - - - - Top 100 - Top 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Ostatnie 100 - - - - Link: - Link: - - - - Add Anonymous Link - Dodaj Link Anonimowy - - - - Add Link/Comment - Dodaj Link/komentarz - - - - Title: - Tytuł: - - - - Score: - - - - - - +2 Great! - +2 Świetne! - - - - - +1 Good - +1 Dobre - - - - - 0 Okay - 0 W porządku - - - - - -1 Sux - -1 Ssie - - - - - -2 Bad Link - -2 Zły Link - - - - Url: - Url: - - - - Links Cloud - - - - - Add new link - Dodaj nowy link - - - - Share Link Anonymously - Udostępnij Link Anonimowo - - - - Vote on Link - Głosuj na Link - - - - Download - Pobierz - - - - - - Add Link Failure - - - - - Missing Link and/or Title - Brakujący Link i/lub Tytuł - - - - Missing Link Data - - - - - Missing Comment - Brakujący Komentarz - - - - Link Title Not Changed - - - - - Do you want to continue? - Czy chcesz kontynuować? - - - - Expand - Rozwiń - - - - Hide - Ukryj - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_ru.qm b/plugins/LinksCloud/lang/LinksCloud_ru.qm deleted file mode 100644 index f3b0a7d71ba8b307442e148f5941a1864bf99bda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 702 zcmcE7ks@*G{hX<16=n7(EZlq7iGhJ3fPv*^ERep(!18`60|O%)1MB>BAZ^Cnx=92` zuVtCxxd$lEz;Zsr1xT%6-LR<(NSi`vCJwfzhDU(>BCgD|lR))ZnG6g}PRu|N9u_$k zCl(tPQx;nm0}h}70~-iCC*~!m=CA{qe2yt8KACyh#V(nNIr-^~AWb4H;w%O%#w>O$ z)GC(`*fUb99u>g{wU<3P~L4n1d#SZR9_Tc=Y5{0BntVZat$bzi|X|)9! zW6Gewpbs>_3TT`SG!mVFat=T_OSqBz;P_C`S8&eH%}vcK!D=+oQHl~X9l)sK6=eLY O$^Bo1iRG^jmoNY(_J4E$ diff --git a/plugins/LinksCloud/lang/LinksCloud_ru.ts b/plugins/LinksCloud/lang/LinksCloud_ru.ts deleted file mode 100644 index 1193c8ade..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_ru.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - - - - - Cancel - Отмена - - - - Add a new Link - - - - - Title: - Заголовок: - - - - Url: - - - - - Add Anonymous Link - - - - - +2 Great! - - - - - +1 Good - - - - - 0 Okay - - - - - -1 Sux - - - - - -2 Bad Link - - - - - Add Link to Cloud - - - - - New Link - - - - - Add Link Failure - - - - - Missing Link and/or Title - - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - - - - - LinksCloud - - - - - LinksDialog - - - Title / Comment - Название / комментарий - - - - Score - - - - - Peer / Link - - - - - Sort by - Сортировать по - - - - Combo - - - - - Time - - - - - Ranking - - - - - In last - - - - - Month - - - - - Week - - - - - Day - - - - - From - От - - - - All Peers - - - - - Own Links - - - - - Show - Показать - - - - Top 100 - - - - - 101-200 - - - - - 201-300 - - - - - 301-400 - - - - - 401-500 - - - - - Bottom 100 - - - - - Link: - - - - - Add Anonymous Link - - - - - Add Link/Comment - - - - - Title: - Заголовок: - - - - Score: - - - - - - +2 Great! - - - - - - +1 Good - - - - - - 0 Okay - - - - - - -1 Sux - - - - - - -2 Bad Link - - - - - Url: - - - - - Links Cloud - - - - - Add new link - - - - - Share Link Anonymously - - - - - Vote on Link - - - - - Download - Скачать - - - - - - Add Link Failure - - - - - Missing Link and/or Title - - - - - Missing Link Data - - - - - Missing Comment - - - - - Link Title Not Changed - - - - - Do you want to continue? - - - - - Expand - Раскрыть - - - - Hide - Скрыть - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_sv.qm b/plugins/LinksCloud/lang/LinksCloud_sv.qm deleted file mode 100644 index cf26cabdc73c0166aa1fbc7e15a01516fd5f5a2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4827 zcmcInZ-`V?6hG^{H#0js?yh2HW^%RsL$2=ZI{Lw)aCg%*SH)e83aPg{&zWi8yt~YM zyXz291VVp^`k)nIMM6>ZAuFMxBCH5CBEcXc>Wdi_go08Oedu@Y+qtv$-dih@VfN0x zcYo)c`@84<&bc?fQ7JuiOnZ4Xh?Iik&v5H+7B+rV7Gc8LU^IU>jb*Ttz1F;XHRFFY^GUo;%`=}ZJ&HK{&BJeEOq>kH zwxh{>ir@Dq&vbnPd!^+0Ywm-e=TiAJKYu8-)AKdW9sdhPZ|d7)>`vF`0!7`Xnxwd>%v>WFKa7a1>O@&f-!rv4DwGT zFfmIjsEY*kP?aoR11SPlbcu~p7I?9(>kEY~Wp~8uD_f2%HZf`rP~AWclB7|5Y;tLl zMmMkM78|R!SGu)|9P_4)YQc04w81nRoNjS>x(&R#Q~+JZeDD# z%FbBTj-zAMbkQou0z^oVWc$zIDHww<_@u2pd$$KY4eFqNniE8^`(>Q0i$6mvRwpmzi-w#d`5UDaRq zys}$VkqOH!bjqq2Ec;F@x2?1_a+T?=mt5Z^OFm_g* z*y-(>j{abKwV#X<3caW8jeoa0W5u$o#N#`hUgQI~Dj^~3{4twBdU_C)DhwC#*FpwW zCTG`Eb`SlkP%JtEiOvG#0qf)As&r>n7zUPi%9=a|lPZD#tJHz_!9EIQn`0Tp6V{O; zY}N2(3M+VC_hu>k0(D$6D*_BniebJO&TE$z`R{Tc^ z4}t%Yeuq&1MZ7~sE~(rhL@P>74qvVuIm+q%Npy*P zGK2CLgH{8Sj|K5$2Ccamlm}={4CsF?MWMxCh5{1uk&D#!`YG+iIg^uTpUW3ct=>0X zpgMbHrDD5&yL$e9pPdk1MSxa9m{T$ePzXj@WM7RWH)W zLhLdUP>D*F&M5gB!ZKO7AZFT3rbqg|tcb3d&Cj5|GdaL&j0rA=WTe|9^wy%Ho|@OQCZYvFd8!ii~qtb}fCRaF?7oCGkb)n?iRqqgNx)(;c))Z9bC}?AIS)_x; zKx~!1=q*`p(T-kdM%!*wZIkh;Y=>BE)a=QYOgjyxHX5-IR7|ED*Wt;ti1?%WoVI$O zGu^>lr~~I*;G-RFY*yWvBBjsrt;mhJyuDe7j12XwlZ#x|44VB&{ZeFfbLkdz6xiv|4FWBQa{GN}O3X}MVSf`P8qwLk76HFuz7RqddM z*7qq#-PS^pghj&`D9MS)MJ~Y64rH$0$#I?sx68(@B{d+cz8H#jm&8rDJS8KH!Ez;9 zM;5D@bt&MT477a8;nGaEsjeNHI^A)~PBGX}f+-Duh?{nOZ5Kg7(hgIDax}K;Omj&H zxtNb+`&FqWC;li-j81>;EW3*vTN$K( - - AddLinksDialog - - - - Add Link - Lägg till länk - - - - Cancel - Avbryt - - - - Add a new Link - Lägg till ny länk - - - - Title: - Titel: - - - - Url: - URL: - - - - Add Anonymous Link - Lägg till länk anonymt - - - - +2 Great! - +2 Toppen! - - - - +1 Good - +1 Bra - - - - 0 Okay - 0 Okay - - - - -1 Sux - -1 Suger - - - - -2 Bad Link - -2 Dålig länk - - - - Add Link to Cloud - Lägg till länk i molnet - - - - New Link - Ny länk - - - - Add Link Failure - Kunde inte lägga till länk - - - - Missing Link and/or Title - Länk och/eller titel saknas - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Det här tilläggsprogrammet tillför en uppsättning cachade länkar, och ett poängsystem för att klassificera dem. - - - - LinksCloud - LänkMoln - - - - LinksDialog - - - Title / Comment - Titel / Kommentar - - - - Score - Poäng - - - - Peer / Link - Användare / Länk - - - - Sort by - Sortera enligt - - - - Combo - Kombo - - - - Time - Tid - - - - Ranking - Ranking - - - - In last - Sist in - - - - Month - Månad - - - - Week - Vecka - - - - Day - Dag - - - - From - Från - - - - All Peers - Alla användare - - - - Own Links - Egna länkar - - - - Show - Visa - - - - Top 100 - Topp 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - 100 från botten - - - - Link: - Länk: - - - - Add Anonymous Link - Lägg till länk anonymt - - - - Add Link/Comment - Lägg till länk/kommentar - - - - Title: - Titel: - - - - Score: - Poäng: - - - - - +2 Great! - +2 Toppen! - - - - - +1 Good - +1 Bra - - - - - 0 Okay - 0 Okay - - - - - -1 Sux - -1 Suger - - - - - -2 Bad Link - -2 Dålig länk - - - - Url: - URL: - - - - Links Cloud - Länkmoln - - - - Add new link - Lägg till ny länk - - - - Share Link Anonymously - Dela länk anonymt - - - - Vote on Link - Rösta på länk - - - - Download - Ladda ner - - - - - - Add Link Failure - Kunde inte lägga till länk - - - - Missing Link and/or Title - Länk och/eller titel saknas - - - - Missing Link Data - Länkdata saknas - - - - Missing Comment - Kommentar saknas - - - - Link Title Not Changed - Länktitel ej ändrad - - - - Do you want to continue? - Vill du fortsätta? - - - - Expand - Visa - - - - Hide - Dölj - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_tr.qm b/plugins/LinksCloud/lang/LinksCloud_tr.qm deleted file mode 100644 index 1d221ac5e30091eb6a7ef92b5e662031154490ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4968 zcmcIoTWl0n82-0AJG<>}mn|V!BA0_vG_<9=+l43^NpF;bv<)p7APUp&v^(kSOtU-N zvJesyLjq``Q7}e{1`~|N2MK62USdQaKw@~n7vm*9h#@8h5(!3wiQhRxXSmti)&4=!H%|~nYe>3!5^I`5 zuZ!Hx8)mT5I(78W}q=)P^ahyWmenixer0@gRv44~{jywxJXKBls&xz{aqe1Bx zy#I@a)Hm_{8QT8FL8AC%;L_oTi4s2szFu>csP3Mc{VRTg-UGqlj&npbX|Hl$@ID28 z1p@XeUkY{}jY2*WJa~Em{J9c*I{PkBO>gj0;wbFAAZ0=j4>w3J^?pngoG+cf_8C#^ ztaLHg1v}@YD=#j`hBfvoH-x17p(nOKbaxx%W0_D!=JM-9FXxWH&WX^e(^#b%drh>- znK1u-pL{v>1@t{H|F&cw?7tJvMELtt;jQ`wd^lsT@}Wq_&PO4CA##x21$~{7Uwh$y zLQkgU!1BnDQrC5(?W_hsj_H6bs%@{9sX^L)+1-R4#NTrF<22!X%8jWLJ?nu`* zrCCowRjlRy@-5sdZ5Q$i<+1K{rk?cyYHv1k&+_(tZ+qzHkGn?3XT>z$@<5YvY&!g)DE*I9u09Y>Zo=GZ@Q5m z9V(GwG90z@kyqAkm_|8omWp%wc;`wZT#lA+AxF`;SSFOq-cHUw3ue(S`ZpIz;i#BV;qGpT+TjN<0%4 zMbg%S?yF|8t8FR`Q*wN%69D9NMxyd{KrfAHh5)5kMXxdRS{YAXbe-J`&G798yyU&2 z;yn%{@PeOpMO4C|d>|FrC4R3$66^%Pi9Q~Kh62!r$9$7(5WP1kw3x7HqYnqNBK8|X zrszOHfmS)e3=HM8BAXD7vx$N^sb$q78ndWc%p7GS%1BPlGMz(iGj9g`G-+DAJ&NU` zrREt93B>ZIr7|n0=2!6&d8g#|=pGfR{Fl(~A$*6p?viwa`YarE(l;B_U8?>OqPwKy z7)(h#e8wax>6i_tlBt$-GRc$eA;dRxp|)zFG=$oGh4^MJl&KbKgHXm-h;QaXtE+`F z5L)dc^dFBXSNQ+QP;qH(c0ofc(BH(l)2DGdP;yhgu352u4_+jX4{sA{3;sU{8{p$i!04OnTsx(?H_%sfl^6n8$-WDml2 zq=rMV;+PB}2g9bPIhlGmnmJp8T{gvWmEl3^0?185GY^piJ?9AH_^biwE&MHuqA34ZvARUFYdoTnv`1h-oHYigcM%hHff?8@Rk& zfN%sc0E}~R=6+Rzle_m!07*UV#b^`u<^}1iNJ#5}u%7!9u%sbAH=~m_0LeXNWE$iQ z(aA`-*I>F*^zO}!tM6y9hQKm0Sx^#8Fb%=ZCTt5ipxfku^_dpy%qhm0>K!_7o$7g4 znc5+)M~rP(u9v#RxP#L)uQIi5!3v>sDOy;?o1C-lq-owXFPiHpudGrsJ0M2e&<*^K z0#f2AZkSdqlGUYHif7sWUtZ@*hXe#DJ3fXsHma{oDIAYpY z3zznYy>$kkl*MN6*6f%a2HCfe>ML5mU~3#KIgAZp75pu*i!(RJsfB|%rJ&lJ+_|Ue z;vVSovJs##n;%wR_oTs`Ipvv*1P#J2_l8#v4ASu+JZKgyHtcP(j&|7FXSgg4X?br1 zvU&D2%V*Szz&#F};QT1|TnFwBE)1^x#OXUREEuTE%;6RuGADc|o7WYieeNrU%kaHE n4bgv#vh((+lsvYLlWNmGD4xZt6aVuV#eAuhNqSsW-PGW3(@Dp| diff --git a/plugins/LinksCloud/lang/LinksCloud_tr.ts b/plugins/LinksCloud/lang/LinksCloud_tr.ts deleted file mode 100644 index 7f4d4b7aa..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_tr.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - Bağlantı Ekleyin - - - - Cancel - İptal - - - - Add a new Link - Yeni bir bağlantı ekleyin - - - - Title: - Başlık: - - - - Url: - İnternet adresi: - - - - Add Anonymous Link - Anonim Bağlantı Ekleyin - - - - +2 Great! - +2 Harika! - - - - +1 Good - +1 İyi - - - - 0 Okay - 0 İdare eder - - - - -1 Sux - -1 Yaramaz - - - - -2 Bad Link - -2 Kötü bağlantı - - - - Add Link to Cloud - Bağlantıyı Buluta Ekleyin - - - - New Link - Bağlantı Ekleyin - - - - Add Link Failure - Bağlantı Eklenemedi - - - - Missing Link and/or Title - Eksik Bağlantı ya da Başlık - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - Bu uyumlu ek, ön belleğe alınmış bağlantıları görüntüler ve oylanmasını sağlar. - - - - LinksCloud - BağlantıBulutu - - - - LinksDialog - - - Title / Comment - Başlık / Yorum - - - - Score - Not - - - - Peer / Link - Bağlantı - - - - Sort by - Sıralama - - - - Combo - Bir Arada - - - - Time - Zaman - - - - Ranking - Derece - - - - In last - Son - - - - Month - Ay - - - - Week - Hafta - - - - Day - Gün - - - - From - Kimden - - - - All Peers - Tüm Bağlantılar - - - - Own Links - Kendi Bağlantılarınız - - - - Show - Görüntüleyin - - - - Top 100 - Üst 100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - Alt 100 - - - - Link: - Bağlantı: - - - - Add Anonymous Link - Anonim Bağlantı Ekleyin - - - - Add Link/Comment - Bağlantı/Yorum Ekleyin - - - - Title: - Başlık: - - - - Score: - Not: - - - - - +2 Great! - +2 Harika! - - - - - +1 Good - +1 İyi - - - - - 0 Okay - 0 İdare eder - - - - - -1 Sux - -1 Yaramaz - - - - - -2 Bad Link - -2 Kötü Bağlantı - - - - Url: - İnternet Adresi: - - - - Links Cloud - Bağlantı Bulutu - - - - Add new link - Bağlantı ekleyin - - - - Share Link Anonymously - Bağlantıyı Anonim Olarak Paylaşın - - - - Vote on Link - Bağlantıyı Oylayın - - - - Download - İndirin - - - - - - Add Link Failure - Bağlantı Eklenemedi - - - - Missing Link and/or Title - Eksik Bağlantı ya da Başlık - - - - Missing Link Data - Eksik Bağlantı Verisi - - - - Missing Comment - Eksik Yorum - - - - Link Title Not Changed - Bağlantı Başlığı Değişmedi - - - - Do you want to continue? - Devam etmek istiyor musunuz? - - - - Expand - Genişletin - - - - Hide - Gizleyin - - - \ No newline at end of file diff --git a/plugins/LinksCloud/lang/LinksCloud_zh_CN.qm b/plugins/LinksCloud/lang/LinksCloud_zh_CN.qm deleted file mode 100644 index a0b21b5c1c3b5f483f0fe564038154c588653d8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3874 zcmbtWZERCz6h2#TZ$I~?%Y>le#RSBSxppfWC-Sk4&#(^K@-Y#&yY{Yac6;yAb{j(( z&ah-SbVwKy5kE*k4SyE!hZ6`9`2iXO0VNP(jENtFh(kesIKw<|uY22a@0}8VEN5-c zbDnd~`@YXP^F9ep`C|0#p|55Uu^qtD3*42B0M_}yjUGhX3g&mi z0FJF-9-fQ#5}42Y31FJ0TIVh>Up)rk{2eT_Z=?U~up&5!an^(H=;r|T)!^r@ryxZ^orKRJs2hjO>f`T^rEGnt+{0|1h0xdWz|0_FwZsMc&Y z)$Vp6ew(T9NHOMf*EA6N81o-7T`b&X}cuz6Y);%&3c9-iVO=C>lRV*DcW@Da4Rzo^#v6z{Rn-}m!B zx=&-?*Z5nHyomf`7LS#Ff5Eaw`V#-yuUhWBwPwS7tZTs9M;^kwPgrj($Nc$|wtxfs zo3mN9{9?N}2m6t;)E;d;i@YB=icWom_F2b<11}@bEJur{8T%D<4wWH3_gJ3Pe;ECF z)$*3Sog9a8d-FX%C6OOg%T?#Ey?qqF|Dzy075kpsrdr$8C_vs66FSSa&wx0}D@lzIA~Y!@oE2O^1~2!oOcS|CLz~cT1aQX2 zeDC=e1oC#@4IX5m2e5XsNLJ+Tn9`A$oRJ2|0$V9~vLsWS6w>H^Z6@O^oPd!fLR9LA zi$*EuPcZsi-ZwUnvH(RaKvE&KlG0&#jD<9U7rdq7aObwH-07hcfyiRlq!sY~OR;_+ zjGC_%uH7K&cF_OPCZx9V;}uy;IxnL z+}1MG9eHW2=Q~#}BU%-RL=&Vv6_m8cmCk5LOyE%_#3WH#Nl*wz#1N6_gPud1j6ZcM zN!s>AcOogq2wob5#gwE-k`XcX1Z|Ffx>N=5HBX`)j#QcVDI6NmKdRAwiWQlm8XE8a zA{iRcq!pWI|X`tHffWoYZZrood)UI^d-0 zMYW4wb6u3RWntL%$}8<7jLo)4lE^Aij3@K~0rk++hi$J>l1U{-+y)Khdj1MnS$H$n z(4y#u&TV|0xtZ$J5v6I8z4_Mm-kzU(Zj4W7&Qt0X(yermEloa^u+}=IOO_NNH5)W+-1BRifcf%^H?^Zu=tm8Uz1Nv1w*-|#-*3;(zH@26WvEK} ze!hBdn%S~kCX$fQKY3?rlH`R;#i#w3S?CffIqKLTUL{FtBZ3?j^^@mmgbaN*Q*27$ zH61C*PG z0M1()&bZI@c-bPltoGjP8-KfJpRhG_$*H-n|GM(&Q^ZM90fZh2tJ6UrB&lFKh&HL< zu8bYe;uGXH9A&y`aZPXfcoy004=UcarDYbiQ*tpjD-RXsd^GB2}-Sn-&T`vrZBTWUY1dCsZCrOJzSn0NI*}_|p+KRC4lU+>Sc$L!BX!X_OILexo0j1qgIStn?O<=pXnl_%UL9ABiTDrO@ T>UGm?Wo{tt&8-tf?TGjrg3Nu8 diff --git a/plugins/LinksCloud/lang/LinksCloud_zh_CN.ts b/plugins/LinksCloud/lang/LinksCloud_zh_CN.ts deleted file mode 100644 index 32d9d80e1..000000000 --- a/plugins/LinksCloud/lang/LinksCloud_zh_CN.ts +++ /dev/null @@ -1,329 +0,0 @@ - - - AddLinksDialog - - - - Add Link - 添加链接 - - - - Cancel - 取消 - - - - Add a new Link - 添加一个新的链接 - - - - Title: - 标题: - - - - Url: - 网址: - - - - Add Anonymous Link - 添加匿名链接 - - - - +2 Great! - +2 真棒! - - - - +1 Good - +1 不错 - - - - 0 Okay - 0 还行 - - - - -1 Sux - -1 差 - - - - -2 Bad Link - -2 很差 - - - - Add Link to Cloud - 添加链接到云端 - - - - New Link - 新链接 - - - - Add Link Failure - 添加链接失败 - - - - Missing Link and/or Title - 丢失链接和(或)标题 - - - - LinksCloudPlugin - - - This plugin provides a set of cached links, and a voting system to promote them. - 这个插件提供一些缓存链接,和一个给这些链接评分的投票系统。 - - - - LinksCloud - LinksCloud - - - - LinksDialog - - - Title / Comment - 标题/评论 - - - - Score - 得分 - - - - Peer / Link - 节点 / 链接 - - - - Sort by - 排序方式 - - - - Combo - 综合 - - - - Time - 时间 - - - - Ranking - 排行 - - - - In last - 前一 - - - - Month - 个月 - - - - Week - - - - - Day - - - - - From - 来自 - - - - All Peers - 所有节点 - - - - Own Links - 自己的链接 - - - - Show - 显示 - - - - Top 100 - 前100 - - - - 101-200 - 101-200 - - - - 201-300 - 201-300 - - - - 301-400 - 301-400 - - - - 401-500 - 401-500 - - - - Bottom 100 - 后100 - - - - Link: - 链接: - - - - Add Anonymous Link - 添加匿名链接 - - - - Add Link/Comment - 添加链接/评论 - - - - Title: - 标题: - - - - Score: - 得分: - - - - - +2 Great! - +2 真棒! - - - - - +1 Good - +1 不错 - - - - - 0 Okay - 0 还行 - - - - - -1 Sux - -1 烂 - - - - - -2 Bad Link - -2 很差 - - - - Url: - 网址: - - - - Links Cloud - Links Cloud - - - - Add new link - 添加新链接 - - - - Share Link Anonymously - 匿名分享链接 - - - - Vote on Link - 为链接投票 - - - - Download - 下载 - - - - - - Add Link Failure - 添加链接失败 - - - - Missing Link and/or Title - 丢失链接和(或)标题 - - - - Missing Link Data - 丢失链接信息 - - - - Missing Comment - 丢失评论 - - - - Link Title Not Changed - 链接名未改变 - - - - Do you want to continue? - 想要继续? - - - - Expand - 展开 - - - - Hide - 隐藏 - - - \ No newline at end of file diff --git a/plugins/LinksCloud/p3ranking.cc b/plugins/LinksCloud/p3ranking.cc deleted file mode 100644 index 2fb72b7a3..000000000 --- a/plugins/LinksCloud/p3ranking.cc +++ /dev/null @@ -1,1350 +0,0 @@ -/* - * libretroshare/src/services p3ranking.cc - * - * 3P/PQI network interface for RetroShare. - * - * Copyright 2007-2008 by Robert Fernie. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License Version 2 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - * - * Please report all bugs and problems to "retroshare@lunamutt.com". - * - */ - -#include "rsrankitems.h" -#include "p3ranking.h" -#include -#include - -#include "pqi/p3linkmgr.h" -#include "pqi/pqibin.h" -#include "pqi/authssl.h" -#include "pqi/pqistore.h" - -RsRanks *rsRanks = NULL ; - -const uint32_t RANK_MAX_FWD_OFFSET = (60 * 60 * 24 * 2); /* 2 Days */ -const uint32_t RANK_STORE_PERIOD = (60 * 60 * 24 * 30 * 6); /* 6 months */ - -const uint32_t FRIEND_RANK_REPUBLISH_PERIOD = 60; /* every minute for testing */ -//const uint32_t FRIEND_RANK_REPUBLISH_PERIOD = 1800; /* every 30 minutes */ - -std::string generateRandomLinkId(); - -/***** - * TODO - * (1) Streaming. - * (2) Ranking. - * - */ - -/********* - * #define RANK_DEBUG 1 - *********/ -#define RANK_DEBUG 1 - -p3Ranking::p3Ranking(RsPluginHandler* pgHandler) - : RsCacheService(RS_SERVICE_TYPE_RANK,CONFIG_TYPE_RANK_LINK,5, pgHandler), - mRepublish(false), mRepublishFriends(false), mRepublishFriendTS(0), mStorePeriod(RANK_STORE_PERIOD), mUpdated(true),mRankMtx(std::string("p3Ranking")) -{ - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - mOwnId = pgHandler->getLinkMgr()->getOwnId(); - mViewPeriod = 60 * 60 * 24 * 30; /* one Month */ - mSortType = RS_RANK_ALG; -} - -bool p3Ranking::loadLocalCache(const RsCacheData &data) -{ - std::string filename = data.path + '/' + data.name; - std::string hash = data.hash; - //uint64_t size = data.size; - std::string source = data.pid; - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadLocalCache()"; - std::cerr << std::endl; - std::cerr << "\tSource: " << source; - std::cerr << std::endl; - std::cerr << "\tFilename: " << filename; - std::cerr << std::endl; - std::cerr << "\tHash: " << hash; - std::cerr << std::endl; - std::cerr << "\tSize: " << data.size; - std::cerr << std::endl; -#endif - - loadRankFile(filename, source); - - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - mRepublish = false; - } - - if (data.size > 0) /* don't refresh zero sized caches */ - { - refreshCache(data); - } - return true; -} - -int p3Ranking::loadCache(const RsCacheData &data) -{ - std::string filename = data.path + '/' + data.name; - std::string hash = data.hash; - //uint64_t size = data.size; - std::string source = data.pid; - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadCache()"; - std::cerr << std::endl; - std::cerr << "\tSource: " << source; - std::cerr << std::endl; - std::cerr << "\tFilename: " << filename; - std::cerr << std::endl; - std::cerr << "\tHash: " << hash; - std::cerr << std::endl; - std::cerr << "\tSize: " << data.size; - std::cerr << std::endl; -#endif - - loadRankFile(filename, source); - - - CacheStore::lockData(); /***** LOCK ****/ - locked_storeCacheEntry(data); - CacheStore::unlockData(); /***** UNLOCK ****/ - - return 1; -} - - -void p3Ranking::loadRankFile(std::string filename, std::string src) -{ - /* create the serialiser to load info */ - RsSerialiser *rsSerialiser = new RsSerialiser(); - rsSerialiser->addSerialType(new RsRankSerialiser()); - - uint32_t bioflags = BIN_FLAGS_HASH_DATA | BIN_FLAGS_READABLE; - BinInterface *bio = new BinFileInterface(filename.c_str(), bioflags); - pqistore *store = new pqistore(rsSerialiser, src, bio, BIN_FLAGS_READABLE); - - time_t now = time(NULL); - time_t min, max; - - { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - min = now - mStorePeriod; - max = now + RANK_MAX_FWD_OFFSET; - - } /********** STACK LOCKED MTX ******/ - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadRankFile()"; - std::cerr << std::endl; - std::cerr << "\tSource: " << src; - std::cerr << std::endl; - std::cerr << "\tFilename: " << filename; - std::cerr << std::endl; -#endif - - RsItem *item; - RsRankLinkMsg *newMsg; - - while(NULL != (item = store->GetItem())) - { - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadRankFile() Got Item:"; - std::cerr << std::endl; - item->print(std::cerr, 10); - std::cerr << std::endl; -#endif - - if (NULL == (newMsg = dynamic_cast(item))) - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadRankFile() Item not LinkMsg (deleting):"; - std::cerr << std::endl; -#endif - - delete item; - } - /* check timestamp */ - else if (((time_t) newMsg->timestamp < min) || - ((time_t) newMsg->timestamp > max)) - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadRankFile() Outside TimeRange (deleting):"; - std::cerr << std::endl; -#endif - /* if outside range -> remove */ - delete newMsg; - } - else - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadRankFile() Loading Item"; - std::cerr << std::endl; -#endif - /* correct the source (if is a message from a friend) */ - newMsg->PeerId(newMsg->pid); - addRankMsg(newMsg); - } - } - - delete store; -} - - -void p3Ranking::publishMsgs(bool own) -{ - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::publishMsgs()"; - std::cerr << std::endl; -#endif - - std::string path = CacheSource::getCacheDir(); - uint16_t subid; - - - /* setup name / etc based on whether we're - * publishing own or friends... - */ - - /* determine filename */ - std::string tmpname; - if (own) - { - /* setup to publish own messages */ - rs_sprintf(tmpname, "rank-links-%ld.rsrl", time(NULL)); - subid = 1; - } - else - { - /* setup to publish friend messages */ - rs_sprintf(tmpname, "rank-friend-links-%ld.rsrl", time(NULL)); - subid = 2; - } - - std::string fname = path + "/" + tmpname; - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::publishMsgs() Storing to: " << fname; - std::cerr << std::endl; -#endif - - RsSerialiser *rsSerialiser = new RsSerialiser(); - rsSerialiser->addSerialType(new RsRankSerialiser()); - - uint32_t bioflags = BIN_FLAGS_HASH_DATA | BIN_FLAGS_WRITEABLE; - BinInterface *bio = new BinFileInterface(fname.c_str(), bioflags); - pqistore *store = new pqistore(rsSerialiser, mOwnId, bio, BIN_FLAGS_NO_DELETE | BIN_FLAGS_WRITEABLE); - - { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - /* iterate through list */ - std::map::iterator it; - std::map::iterator cit; - - for(it = mData.begin(); it != mData.end(); it++) - { - if (own) - { - if (it->second.ownTag) - { - /* write to serialiser */ - RsItem *item = it->second.comments[mOwnId]; - if (item) - { - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::publishMsgs() Storing Item:"; - std::cerr << std::endl; - item->print(std::cerr, 10); - std::cerr << std::endl; -#endif - store->SendItem(item); - } - } - else - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::publishMsgs() Skipping Foreign item"; - std::cerr << std::endl; -#endif - } - } - else - { - /* if we have pushed it out already - don't bother */ - if (it->second.ownTag) - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::publishMsgs() (Friends) Skipping Own Item"; - std::cerr << std::endl; -#endif - continue; - } - - /* if we have some comments ... then a friend has recommended it - * serialise a sanitized version. - */ - if (it->second.comments.size() > 0) - { - RsRankLinkMsg *origmsg = (it->second.comments.begin())->second; - RsRankLinkMsg *msg = new RsRankLinkMsg(); - - /* copy anon data */ - -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ - msg->clear(); - msg->PeerId(""); - msg->pid = ""; /* Anon */ - msg->rid = origmsg->rid; - msg->link = origmsg->link; - msg->title = origmsg->title; - msg->timestamp = origmsg->timestamp; - msg->score = 0; - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::publishMsgs() (Friends) Storing (Anon) Item:"; - std::cerr << std::endl; - msg->print(std::cerr, 10); - std::cerr << std::endl; -#endif - store->SendItem(msg); - - /* cleanup */ - delete msg; - } - } - } - - - /* now we also add our anon messages to the friends list */ - if (!own) - { - std::list::iterator ait; - for(ait=mAnon.begin(); ait != mAnon.end(); ait++) - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::publishMsgs() (Friends) Adding Own Anon Item:"; - std::cerr << std::endl; - (*ait)->print(std::cerr, 10); - std::cerr << std::endl; -#endif - store->SendItem(*ait); - } - } - - } /********** STACK LOCKED MTX ******/ - - /* flag as new info */ - RsCacheData data; - - { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - data.pid = mOwnId; - } /********** STACK LOCKED MTX ******/ - - data.cid = CacheId(CacheSource::getCacheType(), subid); - - data.path = path; - data.name = tmpname; - - data.hash = bio->gethash(); - data.size = bio->bytecount(); - data.recvd = time(NULL); - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::publishMsgs() refreshing Cache"; - std::cerr << std::endl; - std::cerr << "\tCache Path: " << data.path; - std::cerr << std::endl; - std::cerr << "\tCache Name: " << data.name; - std::cerr << std::endl; - std::cerr << "\tCache Hash: " << data.hash; - std::cerr << std::endl; - std::cerr << "\tCache Size: " << data.size; - std::cerr << std::endl; -#endif - if (data.size > 0) /* don't refresh zero sized caches */ - { - refreshCache(data); - } - - delete store; -} - - - -void p3Ranking::addRankMsg(RsRankLinkMsg *msg) -{ - /* find msg */ - std::string id = msg->PeerId(); - std::string rid = msg->rid; - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::addRankMsg() Item:"; - std::cerr << std::endl; - msg->print(std::cerr, 10); - std::cerr << std::endl; -#endif - - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it; - it = mData.find(rid); - if (it == mData.end()) - { - /* add a new one */ - RankGroup grp; - grp.rid = rid; - grp.ownTag = false; - grp.rank = 0.0f; - -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ - - grp.link = msg->link; - grp.title = msg->title; - -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ - - mData[rid] = grp; - it = mData.find(rid); - - if (id == "") - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::addRankMsg() New Anon Link: mUpdated = true"; - std::cerr << std::endl; -#endif - locked_reSortGroup(it->second); - mUpdated = true; - } - } - - /**** If it is an anonymous Link (ie Friend of a Friend) Drop out now ***/ - if (id == "") - { - return; - } - - /* check for old comment */ - std::map::iterator cit; - cit = (it->second).comments.find(id); - - /* Check that it is different! */ - bool newComment = false; - if ((it->second).comments.end() == cit) - { - newComment = true; - } - else - { - RsRankLinkMsg *old = cit->second; - if ((msg->timestamp != old->timestamp) || - (msg->comment != old->comment)) - { - newComment = true; - } - } - - if (newComment) - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::addRankMsg() New Comment"; - std::cerr << std::endl; -#endif - /* clean up old */ - if ((it->second).comments.end() != cit) - { - delete (cit->second); - (it->second).comments.erase(cit); - } - - /* add in */ - (it->second).comments[id] = msg; - - /* republish? */ - if (id == mOwnId) - { - it->second.ownTag = true; - mRepublish = true; -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::addRankMsg() Own Comment: mRepublish = true"; - std::cerr << std::endl; -#endif - } - else - { - mRepublishFriends = true; -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::addRankMsg() Other Comment: mRepublishFriends = true"; - std::cerr << "p3Ranking::addRankMsg() Old Comment ignoring"; - std::cerr << std::endl; -#endif - } - - locked_reSortGroup(it->second); - - mUpdated = true; - } - else - { - delete msg; -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::addRankMsg() Old Comment ignoring"; - std::cerr << std::endl; -#endif - } -} - - -/***************** Sorting ****************/ - -bool p3Ranking::setSortPeriod(uint32_t period) -{ - bool reSort = false; - - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - reSort = (mViewPeriod != period); - mViewPeriod = period; - } - - - if (reSort) - { - sortAllMsgs(); - } - - return true; -} - -bool p3Ranking::setSortMethod(uint32_t type) -{ - bool reSort = false; - - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - reSort = (mSortType != type); - mSortType = type; - } - - if (reSort) - { - sortAllMsgs(); - } - - return true; -} - -bool p3Ranking::clearPeerFilter() -{ - bool reSort = false; - - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - reSort = (mPeerFilter.size() > 0); - mPeerFilter.clear(); - } - - - if (reSort) - { - sortAllMsgs(); - } - - return true; -} - -bool p3Ranking::setPeerFilter(std::list peers) -{ - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - mPeerFilter = peers; - } - - sortAllMsgs(); - - return true; -} - -float p3Ranking::locked_calcRank(RankGroup &grp) -{ - /* Ranking Calculations ..... - */ - - time_t now = time(NULL); - time_t minTime = now-mViewPeriod; - bool doFilter = (mPeerFilter.size() > 0); - bool doScore = (mSortType & RS_RANK_SCORE); - bool doTime = (mSortType & RS_RANK_TIME); - - uint32_t count = 0; - float algScore = 0; - float comboScore = 0; - float popScore = 0; - -#ifdef RANK_DEBUG - std::string normlink(grp.link.begin(), grp.link.end()); - std::cerr << "p3Ranking::locked_calcRank() for: " << normlink; - std::cerr << std::endl; - std::cerr << "Period: " << mViewPeriod; - std::cerr << " doFilter: " << doFilter; - std::cerr << " doScore: " << doScore; - std::cerr << " doTime: " << doTime; - std::cerr << std::endl; -#endif - - std::map::iterator it; - for(it = grp.comments.begin(); it != grp.comments.end(); it++) - { -#ifdef RANK_DEBUG - std::cerr << "Comment by:" << it->first << " age: " << now - it->second->timestamp; - std::cerr << std::endl; -#endif - if (doFilter) - { - if (mPeerFilter.end() == - std::find(mPeerFilter.begin(), mPeerFilter.end(), it->first)) - { - continue; /* skip it */ -#ifdef RANK_DEBUG - std::cerr << "\tFiltered Out"; - std::cerr << std::endl; -#endif - - } - } - - /* if Scoring is involved... drop old ones */ - if ((doScore) && ((time_t) it->second->timestamp < minTime)) - { -#ifdef RANK_DEBUG - std::cerr << "\tToo Old"; - std::cerr << std::endl; -#endif - continue; - } - - time_t deltaT; - if ((time_t) it->second->timestamp > now) - { - deltaT = it->second->timestamp - now; - } - else - { - deltaT = now - it->second->timestamp; - } - float timeScore = ((float) mViewPeriod - deltaT) / (mViewPeriod + 0.01); - -#ifdef RANK_DEBUG - std::cerr << "\tTimeScore: " << timeScore; - std::cerr << std::endl; -#endif - - /* algScore is sum of (filtered) timeScores */ - /* timeScore is average of (all) timeScores */ - /* popScore is just count of valid scores */ - - algScore += timeScore; - count++; - - /* for more advanced scoring (where each peer gives a score +2 -> -2) */ - /* combo = SUM value * timeScore */ - /* time = same as before (average) */ - /* popScore = SUM value */ - - float value = it->second->score; - comboScore += value * timeScore; - popScore += value; - } - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::locked_calcRank() algScore: " << algScore; - std::cerr << " Count: " << count; - std::cerr << std::endl; -#endif - - if ((count <= 0) || (algScore <= 0)) - { -#ifdef RANK_DEBUG - std::cerr << "Final score: 0"; - std::cerr << std::endl; -#endif - return 0; - } - - if ((doScore) && (doTime)) - { -#ifdef RANK_DEBUG - std::cerr << "Old (alg) score:" << algScore; - std::cerr << std::endl; - std::cerr << "Final (Combo) score:" << comboScore; - std::cerr << std::endl; -#endif - - if (comboScore < 0) - { -#ifdef RANK_DEBUG - std::cerr << "Combo score reset = 0"; - std::cerr << std::endl; -#endif - comboScore = 0; - } - return comboScore; - - } - else if (doScore) - { -#ifdef RANK_DEBUG - std::cerr << "Old (tally) score:" << count; - std::cerr << std::endl; - std::cerr << "Final (pop) score:" << popScore; - std::cerr << std::endl; -#endif - if (popScore < 0) - { -#ifdef RANK_DEBUG - std::cerr << "Pop score reset = 0"; - std::cerr << std::endl; -#endif - popScore = 0; - } - return popScore; - } - else if (doTime) - { -#ifdef RANK_DEBUG - std::cerr << "Final (time) score:" << algScore / count; - std::cerr << std::endl; -#endif - return algScore / count; - } - return 0; -} - - -void p3Ranking::locked_reSortGroup(RankGroup &grp) -{ - std::string rid = grp.rid; - - /* remove from existings rankings */ - std::multimap::iterator rit; - rit = mRankings.lower_bound(grp.rank); - for(; (rit != mRankings.end()) && (rit->first == grp.rank); rit++) - { - if (rit->second == rid) - { - mRankings.erase(rit); - break; - } - } - - /* add it back in */ - grp.rank = locked_calcRank(grp); - mRankings.insert( - std::pair(grp.rank, rid)); -} - -void p3Ranking::sortAllMsgs() -{ - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - /* iterate through list and re-score each one */ - std::map::iterator it; - - mRankings.clear(); - - for(it = mData.begin(); it != mData.end(); it++) - { - (it->second).rank = locked_calcRank(it->second); - if (it->second.rank < 0) - { - it->second.rank = 0; - } - - mRankings.insert( - std::pair - (it->second.rank, it->first)); - } -} - -/******** ACCESS *************/ - - /* get Ids */ -uint32_t p3Ranking::getRankingsCount() -{ - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - return mRankings.size(); -} - -float p3Ranking::getMaxRank() -{ - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - if (mRankings.size() == 0) - return 0; - - return mRankings.rbegin()->first; -} - -bool p3Ranking::getRankings(uint32_t first, uint32_t count, std::list &rids) -{ - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::getRankings() First: " << first << " Count: " << count; - std::cerr << std::endl; -#endif - - uint32_t i = 0; - std::multimap::reverse_iterator rit; - for(rit = mRankings.rbegin(); (i < first) && (rit != mRankings.rend()); rit++, i++); - - i = 0; - for(; (i < count) && (rit != mRankings.rend()); rit++, i++) - { - rids.push_back(rit->second); - } - return true; -} - - -bool p3Ranking::getRankDetails(std::string rid, RsRankDetails &details) -{ - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - /* get the details. */ - - std::map::iterator it; - it = mData.find(rid); - if (mData.end() == it) - { - return false; - } - -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ - - details.rid = it->first; - details.link = (it->second).link; - details.title = (it->second).title; - details.rank = (it->second).rank; - details.ownTag = (it->second).ownTag; - -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ - - std::map::iterator cit; - for(cit = (it->second).comments.begin(); - cit != (it->second).comments.end(); cit++) - { - RsRankComment comm; - comm.id = (cit->second)->PeerId(); - comm.timestamp = (cit->second)->timestamp; - comm.comment = (cit->second)->comment; - comm.score = (cit->second)->score; - - details.comments.push_back(comm); - } - - return true; -} - - -void p3Ranking::tick() -{ - bool repub = false; - bool repubFriends = false; - - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - repub = mRepublish; - repubFriends = mRepublishFriends && (time(NULL) > mRepublishFriendTS); - } - - if (repub) - { - publishMsgs(true); - - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - mRepublish = false; - } - - - if (repubFriends) - { - publishMsgs(false); - - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - mRepublishFriends = false; - mRepublishFriendTS = time(NULL) + FRIEND_RANK_REPUBLISH_PERIOD; - } - - -} - -bool p3Ranking::updated() -{ - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - if (mUpdated) - { - mUpdated = false; - return true; - } - return false; -} - -/***** NEW CONTENT *****/ -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ -std::string p3Ranking::newRankMsg(std::wstring link, std::wstring title, std::wstring comment, int32_t score) -{ - /* generate an id */ - std::string rid = generateRandomLinkId(); - - RsRankLinkMsg *msg = new RsRankLinkMsg(); - - time_t now = time(NULL); - - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - msg->PeerId(mOwnId); - msg->pid = mOwnId; - } - - msg->rid = rid; - msg->title = title; - msg->timestamp = now; - msg->comment = comment; - msg->score = score; - - msg->linktype = RS_LINK_TYPE_WEB; - msg->link = link; - - - addRankMsg(msg); - - return rid; -} - - -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ -bool p3Ranking::updateComment(std::string rid, std::wstring comment, int32_t score) -{ - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::updateComment() rid:" << rid; - std::cerr << std::endl; -#endif - RsRankLinkMsg *msg = NULL; - - { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - std::map::iterator it; - it = mData.find(rid); - if (it == mData.end()) - { - /* missing group -> fail */ - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::updateComment() Failed - noData"; - std::cerr << std::endl; -#endif - return false; - } - - msg = new RsRankLinkMsg(); - - time_t now = time(NULL); - - msg->PeerId(mOwnId); - msg->pid = mOwnId; - msg->rid = rid; - msg->timestamp = now; - msg->title = (it->second).title; - msg->comment = comment; - msg->score = score; - - msg->linktype = RS_LINK_TYPE_WEB; - msg->link = (it->second).link; - - } /********** STACK UNLOCKED MTX ******/ - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::updateComment() Item:"; - std::cerr << std::endl; - msg->print(std::cerr, 10); - std::cerr << std::endl; -#endif - - addRankMsg(msg); - return true; -} - -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ -std::string p3Ranking::anonRankMsg(std::string rid, std::wstring link, std::wstring title) -{ - bool alreadyExists = true; - - if (rid == "") - { - alreadyExists = false; - /* generate an id */ - rid = generateRandomLinkId(); - } - - RsRankLinkMsg *msg1 = new RsRankLinkMsg(); - RsRankLinkMsg *msg2 = new RsRankLinkMsg(); - - time_t now = time(NULL); - - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - msg1->PeerId(""); - msg1->pid = ""; - - msg2->PeerId(""); - msg2->pid = ""; - } - - msg1->rid = rid; - msg1->title = title; - msg1->timestamp = now; - msg1->comment.clear(); - msg1->score = 0; - - msg1->linktype = RS_LINK_TYPE_WEB; - msg1->link = link; - - msg2->rid = rid; - msg2->title = title; - msg2->timestamp = now; - msg2->comment.clear(); - msg2->score = 0; - - msg2->linktype = RS_LINK_TYPE_WEB; - msg2->link = link; - - if (alreadyExists) - { - delete msg1; - } - else - { - addRankMsg(msg1); - } - - addAnonToList(msg2); - - return rid; -} - - - -pqistore *createStore(std::string file, std::string src, bool reading) -{ - - RsSerialiser *rsSerialiser = new RsSerialiser(); - rsSerialiser->addSerialType(new RsRankSerialiser()); - - uint32_t bioflags = BIN_FLAGS_HASH_DATA; - if (reading) - { - bioflags |= BIN_FLAGS_READABLE; - } - else - { - bioflags |= BIN_FLAGS_WRITEABLE; - } - - /* bin flags: READ | WRITE | HASH_DATA */ - BinInterface *bio = new BinFileInterface(file.c_str(), bioflags); - /* store flags: NO_DELETE (yes) | NO_CLOSE (no) */ - pqistore *store = new pqistore(rsSerialiser, src, bio, BIN_FLAGS_NO_DELETE | (bioflags & BIN_FLAGS_WRITEABLE)); - - return store; -} - -std::string generateRandomLinkId() -{ - std::string out; -/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ -#ifndef WINDOWS_SYS - /* 4 bytes per random number: 4 x 4 = 16 bytes */ - for(int i = 0; i < 4; i++) - { - uint32_t rint = random(); - rs_sprintf_append(out, "%08x", rint); - } -#else - srand(time(NULL)); - /* 2 bytes per random number: 8 x 2 = 16 bytes */ - for(int i = 0; i < 8; i++) - { - uint16_t rint = rand(); /* only gives 16 bits */ - rs_sprintf_append(out, "%04x", rint); - } -#endif -/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ - return out; -} - - -/*************************************************************************/ -/****************************** LINK SPECIFIC ****************************/ -/*************************************************************************/ -void p3Ranking::createDummyData() -{ - RsRankLinkMsg *msg = new RsRankLinkMsg(); - - time_t now = time(NULL); - - msg->PeerId(mOwnId); - msg->pid = mOwnId; - msg->rid = "0001"; - msg->title = L"Original Awesome Site!"; - msg->timestamp = now - 60 * 60 * 24 * 15; - msg->link = L"http://www.retroshare.org"; - msg->comment = L"Retroshares Website"; - msg->score = 1; - - addRankMsg(msg); - - msg = new RsRankLinkMsg(); - msg->PeerId(mOwnId); - msg->pid = mOwnId; - msg->rid = "0002"; - msg->title = L"Awesome Site!"; - msg->timestamp = now - 123; - msg->link = L"http://www.lunamutt.org"; - msg->comment = L"Lunamutt's Website"; - msg->score = 1; - - addRankMsg(msg); - - msg = new RsRankLinkMsg(); - msg->PeerId("ALTID"); - msg->pid = "ALTID"; - msg->rid = "0002"; - msg->title = L"Awesome Site!"; - msg->timestamp = now - 60 * 60 * 24 * 29; - msg->link = L"http://www.lunamutt.org"; - msg->comment = L"Lunamutt's Website (TWO) How Long can this comment be!\n"; - msg->comment += L"What happens to the second line?\n"; - msg->comment += L"And a 3rd!"; - msg->score = 1; - - addRankMsg(msg); - - msg = new RsRankLinkMsg(); - msg->PeerId("ALTID2"); - msg->pid = "ALTID2"; - msg->rid = "0002"; - msg->title = L"Awesome Site!"; - msg->timestamp = now - 60 * 60 * 7; - msg->link = L"http://www.lunamutt.org"; - msg->comment += L"A Short Comment"; - msg->score = 1; - - addRankMsg(msg); - - - /***** Third one ****/ - - msg = new RsRankLinkMsg(); - msg->PeerId(mOwnId); - msg->pid = mOwnId; - msg->rid = "0003"; - msg->title = L"Weird Site!"; - msg->timestamp = now - 60 * 60; - msg->link = L"http://www.lunamutt.com"; - msg->comment = L""; - msg->score = 1; - - addRankMsg(msg); - - msg = new RsRankLinkMsg(); - msg->PeerId("ALTID"); - msg->pid = "ALTID"; - msg->rid = "0003"; - msg->title = L"Weird Site!"; - msg->timestamp = now - 60 * 60 * 24 * 2; - msg->link = L"http://www.lunamutt.com"; - msg->comment = L""; - msg->score = 1; - - addRankMsg(msg); - -} - - -/***************************************************************************/ -/****************************** CONFIGURATION HANDLING *********************/ -/***************************************************************************/ - -/**** Store Anon Links: OVERLOADED FROM p3Config ****/ - -RsSerialiser *p3Ranking::setupSerialiser() -{ - RsSerialiser *rss = new RsSerialiser(); - - /* add in the types we need! */ - rss->addSerialType(new RsRankSerialiser()); - return rss; -} - -bool p3Ranking::addAnonToList(RsRankLinkMsg *msg) -{ - { - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - std::list::iterator it; - for(it = mAnon.begin(); it != mAnon.end(); it++) - { - if (msg->rid == (*it)->rid) - break; - } - - if (it != mAnon.end()) - { - delete msg; - return false; - } - - mAnon.push_back(msg); - mRepublishFriends = true; - } - - IndicateConfigChanged(); /**** INDICATE CONFIG CHANGED! *****/ - return true; -} - -bool p3Ranking::saveList(bool &cleanup, std::list & saveData) -{ - - mRankMtx.lock(); /*********************** LOCK *******/ - - cleanup = false; - - std::list::iterator it; - for(it = mAnon.begin(); it != mAnon.end(); it++) - { - saveData.push_back(*it); - } - - /* list completed! */ - return true; -} - -void p3Ranking::saveDone() -{ - mRankMtx.unlock(); /*********************** UNLOCK *******/ - return; -} - -bool p3Ranking::loadList(std::list& load) -{ - std::list::iterator it; - RsRankLinkMsg *msg; - -#ifdef SERVER_DEBUG - std::cerr << "p3Ranking::loadList() Item Count: " << load.size(); - std::cerr << std::endl; -#endif - - time_t now = time(NULL); - time_t min, max; - - { RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - - min = now - mStorePeriod; - max = now + RANK_MAX_FWD_OFFSET; - - } /********** STACK LOCKED MTX ******/ - - for(it = load.begin(); it != load.end(); it++) - { - /* switch on type */ - if (NULL != (msg = dynamic_cast(*it))) - { - /* check date -> if old expire */ - if (((time_t) msg->timestamp < min) || - ((time_t) msg->timestamp > max)) - { -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadList() Outside TimeRange (deleting Own Anon):"; - std::cerr << std::endl; -#endif - /* if outside range -> remove */ - delete msg; - continue; - } - -#ifdef RANK_DEBUG - std::cerr << "p3Ranking::loadList() Anon TimeRange ok"; - std::cerr << std::endl; -#endif - msg->PeerId(""); - msg->pid = ""; - - RsRankLinkMsg *msg2 = new RsRankLinkMsg(); - msg2->clear(); - msg2->PeerId(msg->PeerId()); - msg2->pid = msg->pid; - msg2->rid = msg->rid; - msg2->title = msg->title; - msg2->timestamp = msg->timestamp; - msg2->comment.clear(); - msg2->score = 0; - - msg2->linktype = msg->linktype; - msg2->link = msg->link; - - /* make a copy to add into standard map */ - addRankMsg(msg); - - RsStackMutex stack(mRankMtx); /********** STACK LOCKED MTX ******/ - mAnon.push_back(msg2); - } - else - { - /* cleanup */ - delete (*it); - } - } - - return true; - -} - diff --git a/plugins/LinksCloud/p3ranking.h b/plugins/LinksCloud/p3ranking.h deleted file mode 100644 index 13a5cdeac..000000000 --- a/plugins/LinksCloud/p3ranking.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * libretroshare/src/services: p3ranking.h - * - * 3P/PQI network interface for RetroShare. - * - * Copyright 2007-2008 by Robert Fernie. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License Version 2 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - * - * Please report all bugs and problems to "retroshare@lunamutt.com". - * - */ - -#ifndef P3_GENERIC_RANKING_HEADER -#define P3_GENERIC_RANKING_HEADER - -class pqistore ; - -#include "retroshare/rsplugin.h" -#include "plugins/rscacheservice.h" - -#include "rsrank.h" - -/* - * A Generic Ranking system. - * Each User provides one cache... - * - * can be overloaded for specific types - * (links, shares, photos etc) - * - * This is not generic yet!!! - */ - -class RsRankMsg; -class RsRankLinkMsg; - -const uint16_t RS_SERVICE_TYPE_RANK = 0x0002 ; -const uint32_t CONFIG_TYPE_RANK_LINK = 0x0011 ; - -class RankGroup -{ - public: - - std::string rid; /* Random Id */ - std::wstring link; - std::wstring title; - float rank; - bool ownTag; - std::map comments; -}; - -class p3Ranking: public RsCacheService, public RsRanks -{ - public: - - p3Ranking(RsPluginHandler* pgHandler) ; - - - /******************************* CACHE SOURCE / STORE Interface *********************/ - - /* overloaded functions from Cache Source */ - virtual bool loadLocalCache(const RsCacheData &data); - - /* overloaded functions from Cache Store */ - virtual int loadCache(const RsCacheData &data); - - /******************************* CACHE SOURCE / STORE Interface *********************/ - - public: - - /************* Extern Interface *******/ - - /* changed */ - virtual bool updated(); - - /* Set Sort Methods */ - virtual bool setSortPeriod(uint32_t period); - virtual bool setSortMethod(uint32_t type); - virtual bool clearPeerFilter(); - virtual bool setPeerFilter(std::list peers); - - /* get Ids */ - virtual uint32_t getRankingsCount(); - virtual float getMaxRank(); - virtual bool getRankings(uint32_t first, uint32_t count, std::list &rids); - virtual bool getRankDetails(std::string rid, RsRankDetails &details); - - /* Add New Comment / Msg */ - virtual std::string newRankMsg(std::wstring link, std::wstring title, std::wstring comment, int32_t score); - virtual bool updateComment(std::string rid, std::wstring comment, int32_t score); - virtual std::string anonRankMsg(std::string rid, std::wstring link, std::wstring title); - - - virtual void tick(); - - void loadRankFile(std::string filename, std::string src); - void addRankMsg(RsRankLinkMsg *msg); - void publishMsgs(bool own); - - float locked_calcRank(RankGroup &grp); /* returns 0->100 */ - void locked_reSortGroup(RankGroup &grp); - - void sortAllMsgs(); - pqistore *createStore(std::string file, std::string src, bool reading); - - - /****************** p3Config STUFF *******************/ - protected: - bool addAnonToList(RsRankLinkMsg *msg); - - virtual RsSerialiser *setupSerialiser(); - virtual bool saveList(bool &cleanup, std::list&); - virtual bool loadList(std::list& load); - virtual void saveDone(); - - private: - - void createDummyData(); - - uint32_t storePeriod; - p3LinkMgr *mConnMgr; - - RsMutex mRankMtx; - - /***** below here is locked *****/ - - bool mRepublish; - bool mRepublishFriends; - time_t mRepublishFriendTS; - - uint32_t mStorePeriod; - - std::string mOwnId; - bool mUpdated; - bool mRepost; - - std::map mData; - std::multimap mRankings; - - /* Filter/Sort params */ - std::list mPeerFilter; - uint32_t mViewPeriod; - uint32_t mSortType; - - /* Anonymous Link List */ - std::list mAnon; - -}; - -#endif - - - diff --git a/plugins/LinksCloud/rsrank.h b/plugins/LinksCloud/rsrank.h deleted file mode 100644 index a69425c91..000000000 --- a/plugins/LinksCloud/rsrank.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef RETROSHARE_RANKING_GUI_INTERFACE_H -#define RETROSHARE_RANKING_GUI_INTERFACE_H - -/* - * libretroshare/src/rsiface: rsrank.h - * - * RetroShare C++ Interface. - * - * Copyright 2007-2008 by Robert Fernie. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License Version 2 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - * - * Please report all bugs and problems to "retroshare@lunamutt.com". - * - */ - -#include -#include -#include - -/* The Main Interface Class - for information about your Peers */ -class RsRanks; -extern RsRanks *rsRanks; - -class RsRankComment -{ - public: - - std::string id; - std::wstring comment; - int32_t score; - time_t timestamp; -}; - -class RsRankDetails -{ - public: - - std::string rid; - std::wstring link; - std::wstring title; - float rank; - bool ownTag; - - std::list comments; -}; - -const uint32_t RS_RANK_SCORE = 0x0001; -const uint32_t RS_RANK_TIME = 0x0002; -const uint32_t RS_RANK_ALG = 0x0003; - -std::ostream &operator<<(std::ostream &out, const RsRankDetails &detail); - -class RsRanks -{ - public: - - RsRanks() { return; } -virtual ~RsRanks() { return; } - - /* needs update? */ -virtual bool updated() = 0; - - /* Set Sort Methods */ -virtual bool setSortPeriod(uint32_t period) = 0; -virtual bool setSortMethod(uint32_t type) = 0; -virtual bool clearPeerFilter() = 0; -virtual bool setPeerFilter(std::list peers) = 0; - - /* get Ids */ -virtual uint32_t getRankingsCount() = 0; -virtual float getMaxRank() = 0; -virtual bool getRankings(uint32_t first, uint32_t count, std::list &rids) = 0; -virtual bool getRankDetails(std::string rid, RsRankDetails &details) = 0; - - /* Add New Comment / Msg */ -virtual std::string newRankMsg(std::wstring link, std::wstring title, std::wstring comment, int32_t score) = 0; -virtual bool updateComment(std::string rid, std::wstring comment, int32_t score) = 0; - -virtual std::string anonRankMsg(std::string rid, std::wstring link, std::wstring title) = 0; - -}; - -#endif diff --git a/plugins/LinksCloud/rsrankitems.cc b/plugins/LinksCloud/rsrankitems.cc deleted file mode 100644 index dbae0de68..000000000 --- a/plugins/LinksCloud/rsrankitems.cc +++ /dev/null @@ -1,253 +0,0 @@ - -/* - * libretroshare/src/serialiser: rsbaseitems.cc - * - * RetroShare Serialiser. - * - * Copyright 2007-2008 by Robert Fernie. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License Version 2 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - * - * Please report all bugs and problems to "retroshare@lunamutt.com". - * - */ - -#include "serialiser/rsbaseserial.h" -#include "serialiser/rstlvbase.h" -#include "rsrankitems.h" - -#define RSSERIAL_DEBUG 1 -#include - -/*************************************************************************/ - -void RsRankMsg::clear() -{ - rid.clear(); - timestamp = 0; - title.clear(); - comment.clear(); -} - -std::ostream &RsRankMsg::print(std::ostream &out, uint16_t indent) -{ - printRsItemBase(out, "RsRankMsg", indent); - uint16_t int_Indent = indent + 2; - printIndent(out, int_Indent); - out << "rid: " << rid << std::endl; - - printIndent(out, int_Indent); - out << "timestamp: " << timestamp << std::endl; - - - printIndent(out, int_Indent); - - std::string cnv_title(title.begin(), title.end()); - out << "msg: " << cnv_title << std::endl; - - printIndent(out, int_Indent); - std::string cnv_comment(comment.begin(), comment.end()); - out << "comment: " << cnv_comment << std::endl; - - printIndent(out, int_Indent); - out << "score: " << score << std::endl; - - printRsItemEnd(out, "RsRankMsg", indent); - return out; -} - -/*************************************************************************/ - -void RsRankLinkMsg::clear() -{ - rid.clear(); - pid.clear(); - timestamp = 0; - title.clear(); - comment.clear(); - score = 0; - linktype = 0; - link.clear(); -} - -std::ostream &RsRankLinkMsg::print(std::ostream &out, uint16_t indent) -{ - printRsItemBase(out, "RsRankLinkMsg", indent); - uint16_t int_Indent = indent + 2; - printIndent(out, int_Indent); - out << "rid: " << rid << std::endl; - printIndent(out, int_Indent); - out << "pid: " << pid << std::endl; - - printIndent(out, int_Indent); - out << "timestamp: " << timestamp << std::endl; - - printIndent(out, int_Indent); - - std::string cnv_title(title.begin(), title.end()); - out << "msg: " << cnv_title << std::endl; - - printIndent(out, int_Indent); - std::string cnv_comment(comment.begin(), comment.end()); - out << "comment: " << cnv_comment << std::endl; - - printIndent(out, int_Indent); - out << "score: " << score << std::endl; - - printIndent(out, int_Indent); - out << "linktype: " << linktype << std::endl; - printIndent(out, int_Indent); - std::string cnv_link(link.begin(), link.end()); - out << "link: " << cnv_link << std::endl; - - printRsItemEnd(out, "RsRankLinkMsg", indent); - return out; -} - - -uint32_t RsRankSerialiser::sizeLink(RsRankLinkMsg *item) -{ - uint32_t s = 8; /* header */ - s += GetTlvStringSize(item->rid); - s += GetTlvStringSize(item->pid); - s += 4; /* timestamp */ - s += GetTlvWideStringSize(item->title); - s += GetTlvWideStringSize(item->comment); - s += 4; /* score */ - s += 4; /* linktype */ - s += GetTlvWideStringSize(item->link); - - return s; -} - -/* serialise the data to the buffer */ -bool RsRankSerialiser::serialiseLink(RsRankLinkMsg *item, void *data, uint32_t *pktsize) -{ - uint32_t tlvsize = sizeLink(item); - uint32_t offset = 0; - - if (*pktsize < tlvsize) - return false; /* not enough space */ - - *pktsize = tlvsize; - - bool ok = true; - - ok &= setRsItemHeader(data, tlvsize, item->PacketId(), tlvsize); - - /* skip the header */ - offset += 8; - - /* add mandatory parts first */ - ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_GENID, item->rid); - ok &= SetTlvString(data, tlvsize, &offset, TLV_TYPE_STR_PEERID, item->pid); - - ok &= setRawUInt32(data, tlvsize, &offset, item->timestamp); - - ok &= SetTlvWideString(data, tlvsize, &offset, TLV_TYPE_WSTR_TITLE, item->title); - ok &= SetTlvWideString(data, tlvsize, &offset, TLV_TYPE_WSTR_COMMENT, item->comment); - - ok &= setRawUInt32(data, tlvsize, &offset, *((uint32_t *) &(item->score))); - - ok &= setRawUInt32(data, tlvsize, &offset, item->linktype); - - ok &= SetTlvWideString(data, tlvsize, &offset, TLV_TYPE_WSTR_LINK, item->link); - - if (offset != tlvsize) - { - ok = false; - std::cerr << "RsRankLinkSerialiser::serialiseLink() Size Error! " << std::endl; - } - - return ok; -} - -RsRankLinkMsg *RsRankSerialiser::deserialiseLink(void *data, uint32_t *pktsize) -{ - /* get the type and size */ - uint32_t rstype = getRsItemId(data); - uint32_t rssize = getRsItemSize(data); - - uint32_t offset = 0; - - - if ((RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) || - (RS_SERVICE_TYPE_RANK != getRsItemService(rstype)) || - (RS_PKT_SUBTYPE_RANK_LINK3 != getRsItemSubType(rstype))) - { - return NULL; /* wrong type */ - } - - if (*pktsize < rssize) /* check size */ - return NULL; /* not enough data */ - - /* set the packet length */ - *pktsize = rssize; - - bool ok = true; - - /* ready to load */ - RsRankLinkMsg *item = new RsRankLinkMsg(); - item->clear(); - - /* skip the header */ - offset += 8; - - /* get mandatory parts first */ - ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_GENID, item->rid); - ok &= GetTlvString(data, rssize, &offset, TLV_TYPE_STR_PEERID, item->pid); - ok &= getRawUInt32(data, rssize, &offset, &(item->timestamp)); - ok &= GetTlvWideString(data, rssize, &offset, TLV_TYPE_WSTR_TITLE, item->title); - ok &= GetTlvWideString(data, rssize, &offset, TLV_TYPE_WSTR_COMMENT, item->comment); - ok &= getRawUInt32(data, rssize, &offset, (uint32_t *) &(item->score)); - ok &= getRawUInt32(data, rssize, &offset, &(item->linktype)); - ok &= GetTlvWideString(data, rssize, &offset, TLV_TYPE_WSTR_LINK, item->link); - - if (offset != rssize) - { - /* error */ - delete item; - return NULL; - } - - if (!ok) - { - delete item; - return NULL; - } - - return item; -} - - -uint32_t RsRankSerialiser::size(RsItem *item) -{ - return sizeLink((RsRankLinkMsg *) item); -} - -bool RsRankSerialiser::serialise(RsItem *item, void *data, uint32_t *pktsize) -{ - return serialiseLink((RsRankLinkMsg *) item, data, pktsize); -} - -RsItem *RsRankSerialiser::deserialise(void *data, uint32_t *pktsize) -{ - return deserialiseLink(data, pktsize); -} - - - -/*************************************************************************/ - diff --git a/plugins/LinksCloud/rsrankitems.h b/plugins/LinksCloud/rsrankitems.h deleted file mode 100644 index a3ddc78aa..000000000 --- a/plugins/LinksCloud/rsrankitems.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef RS_RANK_ITEMS_H -#define RS_RANK_ITEMS_H - -/* - * libretroshare/src/serialiser: rsrankitems.h - * - * RetroShare Serialiser. - * - * Copyright 2007-2008 by Robert Fernie. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License Version 2 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA. - * - * Please report all bugs and problems to "retroshare@lunamutt.com". - * - */ - -#include "serialiser/rsserial.h" -#include "serialiser/rstlvtypes.h" - -#include "p3ranking.h" - -const uint8_t RS_PKT_SUBTYPE_RANK_LINK3 = 0x04; -const uint8_t RS_PKT_SUBTYPE_RANK_PHOTO = 0x05; - -/**************************************************************************/ - - -class RsRankMsg: public RsItem -{ - public: - RsRankMsg(uint8_t subtype) :RsItem(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_RANK, subtype) { return; } - - virtual ~RsRankMsg() { return; } - virtual void clear(); - virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); - - std::string rid; /* Random Id */ - std::string pid; /* Peer Id (cannot use RsItem::PeerId - as FoF transport!) */ - uint32_t timestamp; - std::wstring title; - std::wstring comment; - int32_t score; -}; - - -/* Flags */ -const uint32_t RS_LINK_TYPE_WEB = 0x0001; -const uint32_t RS_LINK_TYPE_OFF = 0x0002; - -class RsRankLinkMsg: public RsRankMsg -{ - public: - RsRankLinkMsg() - :RsRankMsg(RS_PKT_SUBTYPE_RANK_LINK3) { return; } -virtual ~RsRankLinkMsg() { return; } -virtual void clear(); -virtual std::ostream& print(std::ostream &out, uint16_t indent = 0); - - /**** SAME as RsRankMsg **** - std::string rid; - uint32_t timestamp; - std::wstring title; - std::wstring comment; - int32_t score; - ***************************/ - - /* Link specific Fields */ - uint32_t linktype; /* to be used later! */ - std::wstring link; -}; - -class RsRankSerialiser: public RsSerialType -{ - public: - RsRankSerialiser() - :RsSerialType(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_RANK) - { return; } -virtual ~RsRankSerialiser() - { return; } - -virtual uint32_t size(RsItem *); -virtual bool serialise (RsItem *item, void *data, uint32_t *size); -virtual RsItem * deserialise(void *data, uint32_t *size); - - private: - - /* For RS_PKT_SUBTYPE_RANK_LINK */ -virtual uint32_t sizeLink(RsRankLinkMsg *); -virtual bool serialiseLink (RsRankLinkMsg *item, void *data, uint32_t *size); -virtual RsRankLinkMsg *deserialiseLink(void *data, uint32_t *size); - -}; - -/**************************************************************************/ - -#endif /* RS_RANK_ITEMS_H */ - - From 043fe537896458a5d2388eb9486796dcd76b88aa Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 19 Aug 2015 21:50:51 -0400 Subject: [PATCH 067/165] added avcodec encoding --- plugins/VOIP/VOIP.pro | 2 +- plugins/VOIP/gui/VideoProcessor.cpp | 190 +++++++++++++++++++++++++++- plugins/VOIP/gui/VideoProcessor.h | 27 +++- 3 files changed, 211 insertions(+), 8 deletions(-) diff --git a/plugins/VOIP/VOIP.pro b/plugins/VOIP/VOIP.pro index e7f054553..86a716309 100644 --- a/plugins/VOIP/VOIP.pro +++ b/plugins/VOIP/VOIP.pro @@ -96,4 +96,4 @@ TRANSLATIONS += \ lang/VOIP_tr.ts \ lang/VOIP_zh_CN.ts -LIBS += -lspeex -lspeexdsp +LIBS += -lspeex -lspeexdsp -lavformat -lavcodec -lavutil diff --git a/plugins/VOIP/gui/VideoProcessor.cpp b/plugins/VOIP/gui/VideoProcessor.cpp index 9f4ac7a7c..66a810b0a 100644 --- a/plugins/VOIP/gui/VideoProcessor.cpp +++ b/plugins/VOIP/gui/VideoProcessor.cpp @@ -9,12 +9,26 @@ #include "QVideoDevice.h" #include "DaubechyWavelets.h" +#include + +extern "C" { +#include + +#include +#include +#include +#include +#include +#include +} + VideoProcessor::VideoProcessor() :_encoded_frame_size(128,128) { _decoded_output_device = NULL ; - //_encoding_current_codec = VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO; - _encoding_current_codec = VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO; + //_encoding_current_codec = VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO; + //_encoding_current_codec = VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO; + _encoding_current_codec = VIDEO_PROCESSOR_CODEC_ID_MPEG_VIDEO; } bool VideoProcessor::processImage(const QImage& img,uint32_t size_hint,uint32_t& encoded_size) @@ -27,6 +41,8 @@ bool VideoProcessor::processImage(const QImage& img,uint32_t size_hint,uint32_t& break ; case VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO: codec = &_ddwt_video_codec ; break ; + case VIDEO_PROCESSOR_CODEC_ID_MPEG_VIDEO: codec = &_mpeg_video_codec ; + break ; default: codec = NULL ; } @@ -95,7 +111,7 @@ void VideoProcessor::receiveEncodedData(const RsVOIPDataChunk& chunk) } uint32_t codid = ((unsigned char *)chunk.data)[0] + (((unsigned char *)chunk.data)[1] << 8) ; - uint16_t flags = ((unsigned char *)chunk.data)[2] + (((unsigned char *)chunk.data)[3] << 8) ; + //uint16_t flags = ((unsigned char *)chunk.data)[2] + (((unsigned char *)chunk.data)[3] << 8) ; VideoCodec *codec ; @@ -105,6 +121,8 @@ void VideoProcessor::receiveEncodedData(const RsVOIPDataChunk& chunk) break ; case VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO: codec = &_ddwt_video_codec ; break ; + case VIDEO_PROCESSOR_CODEC_ID_MPEG_VIDEO: codec = &_mpeg_video_codec ; + break ; default: codec = NULL ; } @@ -258,7 +276,7 @@ bool WaveletVideo::encodeData(const QImage& image,uint32_t size_hint,RsVOIPDataC std::cerr << " resized image to B&W " << W2 << "x" << H2 << std::endl; - DaubechyWavelets::DWT2D(temp,W2,H2,DaubechyWavelets::DWT_DAUB04,DaubechyWavelets::DWT_FORWARD) ; + DaubechyWavelets::DWT2D(temp,W2,H2,DaubechyWavelets::DWT_DAUB12,DaubechyWavelets::DWT_FORWARD) ; // Now estimate the max energy in the W coefs, and only keep the largest. @@ -358,7 +376,7 @@ bool WaveletVideo::decodeData(const RsVOIPDataChunk& chunk,QImage& image) std::cerr << " values read: " << compressed_size/4-1 << std::endl; #endif - DaubechyWavelets::DWT2D(temp,W2,H2,DaubechyWavelets::DWT_DAUB04,DaubechyWavelets::DWT_BACKWARD) ; + DaubechyWavelets::DWT2D(temp,W2,H2,DaubechyWavelets::DWT_DAUB12,DaubechyWavelets::DWT_BACKWARD) ; #ifdef VOIP_CODEC_DEBUG std::cerr << " resizing image to: " << w << "x" << h << std::endl; @@ -460,3 +478,165 @@ float WaveletVideo::deserialise_ufloat(const unsigned char *mem) return 1.0f/ ( n/(float)(~(uint32_t)0)) - 1.0f ; } + +FFmpegVideo::FFmpegVideo() +{ + codec = NULL ; + frame_buffer = NULL ; + context = NULL ; + + AVCodecID codec_id = AV_CODEC_ID_H264 ; // AV_CODEC_ID_MPEG1VIDEO + + uint8_t endcode[] = { 0, 0, 1, 0xb7 }; + + /* find the mpeg1 video encoder */ + codec = avcodec_find_encoder(codec_id); + + if (!codec) + throw("AV codec not found for codec id ") ; + + context = avcodec_alloc_context3(codec); + + if (!context) + throw std::runtime_error("AV: Could not allocate video codec context"); + + /* put sample parameters */ + context->bit_rate = 400000; + /* resolution must be a multiple of two */ + context->width = 352; + context->height = 288; + /* frames per second */ + context->time_base = (AVRational){1,25}; + /* emit one intra frame every ten frames + * check frame pict_type before passing frame + * to encoder, if frame->pict_type is AV_PICTURE_TYPE_I + * then gop_size is ignored and the output of encoder + * will always be I frame irrespective to gop_size + */ + context->gop_size = 10; + context->max_b_frames = 1; + //context->pix_fmt = AV_PIX_FMT_RGB24; + context->pix_fmt = AV_PIX_FMT_YUV420P; + + if (codec_id == AV_CODEC_ID_H264) + av_opt_set(context->priv_data, "preset", "slow", 0); + + /* open it */ + if (avcodec_open2(context, codec, NULL) < 0) + throw std::runtime_error( "AV: Could not open codec context. Something's wrong."); + + frame_buffer = (AVFrame*)malloc(sizeof(AVFrame)) ; + + frame_buffer->format = context->pix_fmt; + frame_buffer->width = context->width; + frame_buffer->height = context->height; + + /* the image can be allocated by any means and av_image_alloc() is + * just the most convenient way if av_malloc() is to be used */ + + int ret = av_image_alloc(frame_buffer->data, frame_buffer->linesize, context->width, context->height, context->pix_fmt, 32); + + if (ret < 0) + throw std::runtime_error("AV: Could not allocate raw picture buffer"); + + frame_count = 0 ; +} + +FFmpegVideo::~FFmpegVideo() +{ + avcodec_close(context); + + av_free(context); + + av_freep(&frame_buffer->data[0]); + + free(frame_buffer); +} + + +bool FFmpegVideo::encodeData(const QImage& image,uint32_t size_hint,RsVOIPDataChunk& voip_chunk) +{ + AVPacket pkt ; + av_init_packet(&pkt); + pkt.data = NULL; // packet data will be allocated by the encoder + pkt.size = 0; + + QImage input ; + + if(image.width() != frame_buffer->width || image.height() != frame_buffer->height) + input = image.scaled(QSize(frame_buffer->width,frame_buffer->height),Qt::IgnoreAspectRatio,Qt::SmoothTransformation) ; + else + input = image ; + + /* prepare a dummy image */ + /* Y */ + for (int y = 0; y < context->height; y++) + for (int x = 0; x < context->width; x++) + { + QRgb pix = image.pixel(QPoint(x,y)) ; + + register int R = (pix >> 16) & 0xff ; + register int G = (pix >> 8) & 0xff ; + register int B = (pix >> 0) & 0xff ; + + register int y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16 ; + register int u = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128 ; + register int v = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128 ; + + frame_buffer->data[0][y * frame_buffer->linesize[0] + x] = std::min(255,std::max(0,y)); // Y + frame_buffer->data[0][y * frame_buffer->linesize[0] + x] = std::min(255,std::max(0,u));// Cr + frame_buffer->data[0][y * frame_buffer->linesize[0] + x] = std::min(255,std::max(0,v));// Cb + } + + + frame_buffer->pts = frame_count++; + + /* encode the image */ + + int got_output = 0; + + AVFrame *frame = frame_buffer ; + +// do +// { + int ret = avcodec_encode_video2(context, &pkt, frame, &got_output) ; + + if (ret < 0) + { + std::cerr << "Error encoding frame!" << std::endl; + return false ; + } +// frame = NULL ; // next attempts: do not encode anything. Do this to just flush the buffer +// +// } while(got_output) ; + + if(got_output) + { + voip_chunk.data = pkt.data ; + voip_chunk.size = pkt.size ; + voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; + + std::cerr << "Output : " << pkt.size << " bytes." << std::endl; + } + else + { + voip_chunk.data = NULL; + voip_chunk.size = 0; + voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; + + std::cerr << "No output produced." << std::endl; + } + + + pkt.data = NULL ; // transfer ownership to chunk + pkt.size = 0 ; + + av_free_packet(&pkt); + + return true ; +} +bool FFmpegVideo::decodeData(const RsVOIPDataChunk& chunk,QImage& image) +{ + return true ; +} + diff --git a/plugins/VOIP/gui/VideoProcessor.h b/plugins/VOIP/gui/VideoProcessor.h index da12d76ae..7cc7c1526 100644 --- a/plugins/VOIP/gui/VideoProcessor.h +++ b/plugins/VOIP/gui/VideoProcessor.h @@ -57,6 +57,27 @@ private: static uint16_t quantize_16b(float x, float M); }; +struct AVCodec ; +struct AVCodecContext ; +struct AVFrame ; + +class FFmpegVideo: public VideoCodec +{ +public: + FFmpegVideo() ; + ~FFmpegVideo() ; + +protected: + virtual bool encodeData(const QImage& Image, uint32_t size_hint, RsVOIPDataChunk& chunk) ; + virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) ; + +private: + AVCodec *codec; + AVCodecContext *context; + AVFrame *frame_buffer ; + uint64_t frame_count ; +}; + // This class decodes video from a stream. It keeps a queue of // decoded frame that needs to be retrieved using the getNextImage() method. // @@ -69,7 +90,8 @@ class VideoProcessor enum CodecId { VIDEO_PROCESSOR_CODEC_ID_UNKNOWN = 0x0000, VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO = 0x0001, - VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO = 0x0002 + VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO = 0x0002, + VIDEO_PROCESSOR_CODEC_ID_MPEG_VIDEO = 0x0003 }; // ===================================================================================== @@ -114,8 +136,9 @@ class VideoProcessor // =------------------------------------- Codecs --------------------------------------= // ===================================================================================== - JPEGVideo _jpeg_video_codec ; + JPEGVideo _jpeg_video_codec ; WaveletVideo _ddwt_video_codec ; + FFmpegVideo _mpeg_video_codec ; uint16_t _encoding_current_codec ; }; From 9798c78e2091b1edd6a7be7427aea707dbd67bc2 Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 19 Aug 2015 22:17:50 -0400 Subject: [PATCH 068/165] added decoding of avcodec --- plugins/VOIP/gui/VideoProcessor.cpp | 237 ++++++++++++++++------------ plugins/VOIP/gui/VideoProcessor.h | 11 +- 2 files changed, 146 insertions(+), 102 deletions(-) diff --git a/plugins/VOIP/gui/VideoProcessor.cpp b/plugins/VOIP/gui/VideoProcessor.cpp index 66a810b0a..97ef75271 100644 --- a/plugins/VOIP/gui/VideoProcessor.cpp +++ b/plugins/VOIP/gui/VideoProcessor.cpp @@ -481,162 +481,203 @@ float WaveletVideo::deserialise_ufloat(const unsigned char *mem) FFmpegVideo::FFmpegVideo() { - codec = NULL ; - frame_buffer = NULL ; - context = NULL ; + // Encoding + + encoding_codec = NULL ; + encoding_frame_buffer = NULL ; + encoding_context = NULL ; AVCodecID codec_id = AV_CODEC_ID_H264 ; // AV_CODEC_ID_MPEG1VIDEO uint8_t endcode[] = { 0, 0, 1, 0xb7 }; /* find the mpeg1 video encoder */ - codec = avcodec_find_encoder(codec_id); + encoding_codec = avcodec_find_encoder(codec_id); - if (!codec) - throw("AV codec not found for codec id ") ; + if (!encoding_codec) throw("AV codec not found for codec id ") ; - context = avcodec_alloc_context3(codec); + encoding_context = avcodec_alloc_context3(encoding_codec); - if (!context) - throw std::runtime_error("AV: Could not allocate video codec context"); + if (!encoding_context) throw std::runtime_error("AV: Could not allocate video codec encoding context"); + if (!decoding_context) throw std::runtime_error("AV: Could not allocate video codec decoding context"); /* put sample parameters */ - context->bit_rate = 400000; + encoding_context->bit_rate = 400000; /* resolution must be a multiple of two */ - context->width = 352; - context->height = 288; + encoding_context->width = 352; + encoding_context->height = 288; /* frames per second */ - context->time_base = (AVRational){1,25}; + encoding_context->time_base = (AVRational){1,25}; /* emit one intra frame every ten frames * check frame pict_type before passing frame * to encoder, if frame->pict_type is AV_PICTURE_TYPE_I * then gop_size is ignored and the output of encoder * will always be I frame irrespective to gop_size */ - context->gop_size = 10; - context->max_b_frames = 1; + encoding_context->gop_size = 10; + encoding_context->max_b_frames = 1; //context->pix_fmt = AV_PIX_FMT_RGB24; - context->pix_fmt = AV_PIX_FMT_YUV420P; + encoding_context->pix_fmt = AV_PIX_FMT_YUV420P; if (codec_id == AV_CODEC_ID_H264) - av_opt_set(context->priv_data, "preset", "slow", 0); + av_opt_set(encoding_context->priv_data, "preset", "slow", 0); /* open it */ - if (avcodec_open2(context, codec, NULL) < 0) + if (avcodec_open2(encoding_context, encoding_codec, NULL) < 0) throw std::runtime_error( "AV: Could not open codec context. Something's wrong."); - frame_buffer = (AVFrame*)malloc(sizeof(AVFrame)) ; + encoding_frame_buffer = (AVFrame*)malloc(sizeof(AVFrame)) ; - frame_buffer->format = context->pix_fmt; - frame_buffer->width = context->width; - frame_buffer->height = context->height; + encoding_frame_buffer->format = encoding_context->pix_fmt; + encoding_frame_buffer->width = encoding_context->width; + encoding_frame_buffer->height = encoding_context->height; /* the image can be allocated by any means and av_image_alloc() is * just the most convenient way if av_malloc() is to be used */ - int ret = av_image_alloc(frame_buffer->data, frame_buffer->linesize, context->width, context->height, context->pix_fmt, 32); + int ret = av_image_alloc(encoding_frame_buffer->data, encoding_frame_buffer->linesize, encoding_context->width, encoding_context->height, encoding_context->pix_fmt, 32); if (ret < 0) throw std::runtime_error("AV: Could not allocate raw picture buffer"); - frame_count = 0 ; + encoding_frame_count = 0 ; + + // Decoding + + + decoding_codec = avcodec_find_decoder(codec_id); + + if (!decoding_codec) + throw("AV codec not found for codec id ") ; + + decoding_context = avcodec_alloc_context3(decoding_codec); + } FFmpegVideo::~FFmpegVideo() { - avcodec_close(context); - - av_free(context); - - av_freep(&frame_buffer->data[0]); - - free(frame_buffer); + avcodec_close(encoding_context); + avcodec_close(decoding_context); + av_free(encoding_context); + av_free(decoding_context); + av_freep(&encoding_frame_buffer->data[0]); + av_freep(&decoding_frame_buffer->data[0]); + free(encoding_frame_buffer); + free(decoding_frame_buffer); } bool FFmpegVideo::encodeData(const QImage& image,uint32_t size_hint,RsVOIPDataChunk& voip_chunk) { - AVPacket pkt ; - av_init_packet(&pkt); - pkt.data = NULL; // packet data will be allocated by the encoder - pkt.size = 0; + AVPacket pkt ; + av_init_packet(&pkt); + pkt.data = NULL; // packet data will be allocated by the encoder + pkt.size = 0; - QImage input ; + QImage input ; - if(image.width() != frame_buffer->width || image.height() != frame_buffer->height) - input = image.scaled(QSize(frame_buffer->width,frame_buffer->height),Qt::IgnoreAspectRatio,Qt::SmoothTransformation) ; - else - input = image ; + if(image.width() != encoding_frame_buffer->width || image.height() != encoding_frame_buffer->height) + input = image.scaled(QSize(encoding_frame_buffer->width,encoding_frame_buffer->height),Qt::IgnoreAspectRatio,Qt::SmoothTransformation) ; + else + input = image ; - /* prepare a dummy image */ - /* Y */ - for (int y = 0; y < context->height; y++) - for (int x = 0; x < context->width; x++) + /* prepare a dummy image */ + /* Y */ + for (int y = 0; y < encoding_context->height; y++) + for (int x = 0; x < encoding_context->width; x++) + { + QRgb pix = image.pixel(QPoint(x,y)) ; + + register int R = (pix >> 16) & 0xff ; + register int G = (pix >> 8) & 0xff ; + register int B = (pix >> 0) & 0xff ; + + register int y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16 ; + register int u = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128 ; + register int v = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128 ; + + encoding_frame_buffer->data[0][y * encoding_frame_buffer->linesize[0] + x] = std::min(255,std::max(0,y)); // Y + encoding_frame_buffer->data[0][y * encoding_frame_buffer->linesize[0] + x] = std::min(255,std::max(0,u));// Cr + encoding_frame_buffer->data[0][y * encoding_frame_buffer->linesize[0] + x] = std::min(255,std::max(0,v));// Cb + } + + + encoding_frame_buffer->pts = encoding_frame_count++; + + /* encode the image */ + + int got_output = 0; + + AVFrame *frame = encoding_frame_buffer ; + + // do + // { + int ret = avcodec_encode_video2(encoding_context, &pkt, frame, &got_output) ; + + if (ret < 0) { - QRgb pix = image.pixel(QPoint(x,y)) ; + std::cerr << "Error encoding frame!" << std::endl; + return false ; + } + // frame = NULL ; // next attempts: do not encode anything. Do this to just flush the buffer + // + // } while(got_output) ; - register int R = (pix >> 16) & 0xff ; - register int G = (pix >> 8) & 0xff ; - register int B = (pix >> 0) & 0xff ; + if(got_output) + { + voip_chunk.data = pkt.data ; + voip_chunk.size = pkt.size ; + voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; - register int y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16 ; - register int u = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128 ; - register int v = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128 ; - - frame_buffer->data[0][y * frame_buffer->linesize[0] + x] = std::min(255,std::max(0,y)); // Y - frame_buffer->data[0][y * frame_buffer->linesize[0] + x] = std::min(255,std::max(0,u));// Cr - frame_buffer->data[0][y * frame_buffer->linesize[0] + x] = std::min(255,std::max(0,v));// Cb + std::cerr << "Output : " << pkt.size << " bytes." << std::endl; + } + else + { + voip_chunk.data = NULL; + voip_chunk.size = 0; + voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; + + std::cerr << "No output produced." << std::endl; } - frame_buffer->pts = frame_count++; + pkt.data = NULL ; // transfer ownership to chunk + pkt.size = 0 ; - /* encode the image */ + av_free_packet(&pkt); - int got_output = 0; - - AVFrame *frame = frame_buffer ; - -// do -// { - int ret = avcodec_encode_video2(context, &pkt, frame, &got_output) ; - - if (ret < 0) - { - std::cerr << "Error encoding frame!" << std::endl; - return false ; - } -// frame = NULL ; // next attempts: do not encode anything. Do this to just flush the buffer -// -// } while(got_output) ; - - if(got_output) - { - voip_chunk.data = pkt.data ; - voip_chunk.size = pkt.size ; - voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; - - std::cerr << "Output : " << pkt.size << " bytes." << std::endl; - } - else - { - voip_chunk.data = NULL; - voip_chunk.size = 0; - voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; - - std::cerr << "No output produced." << std::endl; - } - - - pkt.data = NULL ; // transfer ownership to chunk - pkt.size = 0 ; - - av_free_packet(&pkt); - - return true ; + return true ; } bool FFmpegVideo::decodeData(const RsVOIPDataChunk& chunk,QImage& image) { + AVPacket pkt ; + + av_init_packet(&pkt); + pkt.data = static_cast(chunk.data); // packet data will be allocated by the encoder + pkt.size = chunk.size; + + int got_frame = 0 ; + int len = avcodec_decode_video2(decoding_context,decoding_frame_buffer,&got_frame,&pkt) ; + + if(!got_frame) + return true; + + image = QImage(QSize(decoding_frame_buffer->width,decoding_frame_buffer->height),QImage::Format_ARGB32) ; + + for (int y = 0; y < decoding_frame_buffer->height; y++) + for (int x = 0; x < decoding_frame_buffer->width; x++) + { + int Y = decoding_frame_buffer->data[0][y * decoding_frame_buffer->linesize[0] + x] ; + int U = decoding_frame_buffer->data[0][y * decoding_frame_buffer->linesize[0] + x] ; + int V = decoding_frame_buffer->data[0][y * decoding_frame_buffer->linesize[0] + x] ; + + register int R = std::min(255,std::max(0,(int)(1.164*(Y - 16) + 1.596*(V - 128)))) ; + register int G = std::min(255,std::max(0,(int)(1.164*(Y - 16) - 0.813*(V - 128) - 0.391*(U - 128)))) ; + register int B = std::min(255,std::max(0,(int)(1.164*(Y - 16) + 2.018*(U - 128) +))) ; + image.setPixel(QPoint(x,y),QRgb( 0xff000000 + (R << 16) + (G << 8) + B)) ; + } + return true ; } diff --git a/plugins/VOIP/gui/VideoProcessor.h b/plugins/VOIP/gui/VideoProcessor.h index 7cc7c1526..c60fc9864 100644 --- a/plugins/VOIP/gui/VideoProcessor.h +++ b/plugins/VOIP/gui/VideoProcessor.h @@ -72,10 +72,13 @@ protected: virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) ; private: - AVCodec *codec; - AVCodecContext *context; - AVFrame *frame_buffer ; - uint64_t frame_count ; + AVCodec *encoding_codec; + AVCodec *decoding_codec; + AVCodecContext *encoding_context; + AVCodecContext *decoding_context; + AVFrame *encoding_frame_buffer ; + AVFrame *decoding_frame_buffer ; + uint64_t encoding_frame_count ; }; // This class decodes video from a stream. It keeps a queue of From 02775c6fb4dff8c348b28e8a19a7436ebe1aad09 Mon Sep 17 00:00:00 2001 From: Phenom Date: Thu, 20 Aug 2015 17:55:20 +0200 Subject: [PATCH 069/165] Add HTML Text Optimization by exporting styles. --- retroshare-gui/src/util/HandleRichText.cpp | 300 ++++++++++++++------- 1 file changed, 205 insertions(+), 95 deletions(-) diff --git a/retroshare-gui/src/util/HandleRichText.cpp b/retroshare-gui/src/util/HandleRichText.cpp index 1f2c35354..a63428b9b 100644 --- a/retroshare-gui/src/util/HandleRichText.cpp +++ b/retroshare-gui/src/util/HandleRichText.cpp @@ -556,8 +556,49 @@ static void findBestColor(QString &val, qreal bglum, qreal desiredContrast) #endif // QT_VERSION < 0x040600 } -static void optimizeHtml(QDomDocument& doc, QDomElement& currentElement, unsigned int flag, qreal bglum, qreal desiredContrast) +/** + * @brief optimizeHtml: Optimize HTML Text in DomDocument to reduce size + * @param doc: QDomDocument containing Text to optimize + * @param currentElement: Current element optimized + * @param stylesList: List where to save all differents styles used in text + * @param knownStyle: List of known styles + */ +static void optimizeHtml(QDomDocument& doc + , QDomElement& currentElement + , QHash &stylesList + , QHash &knownStyle) { + bool bFirstP=true; + if (doc.documentElement().namedItem("style").toElement().attributeNode("RSOptimized").isAttr()) { + //Already optimized only get StyleList + QDomElement styleElem = doc.documentElement().namedItem("style").toElement(); + if (!styleElem.isElement()) return; //Not an element so a bad message. + QDomAttr styleAttr = styleElem.attributeNode("RSOptimized"); + if (!styleAttr.isAttr()) return; //Not an attribute so a bad message. + QString version = styleAttr.value(); + if (version == "v2") { + + QStringList allStyles = styleElem.text().split('}'); + foreach (QString style, allStyles){ + QStringList pair = style.split('{'); + if (pair.length()!=2) return; //Malformed style list so a bad message or last item. + QString keyvalue = pair.at(1); + keyvalue.replace(";",""); + QStringList* classUsingIt = new QStringList(pair.at(0).split(',')); + QStringList* exported = new QStringList(); + foreach (QString keyVal, *classUsingIt) { + if(!keyVal.trimmed().isEmpty()) { + exported->append(keyVal.trimmed().replace(".","")); + } + } + + stylesList.insert(keyvalue, exported); + } + } + + return; + } + if (currentElement.tagName().toLower() == "html") { // change to
currentElement.setTagName("span"); @@ -570,62 +611,45 @@ static void optimizeHtml(QDomDocument& doc, QDomElement& currentElement, unsigne for (uint index = 0; index < children.length(); ) { QDomNode node = children.item(index); - // compress style attribute + // Compress style attribute styleNode = node.attributes().namedItem("style"); if (styleNode.isAttr()) { QDomAttr styleAttr = styleNode.toAttr(); - QString style = styleAttr.value().simplified(); + QString style = styleAttr.value().simplified().trimmed(); style.replace("margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;", "margin:0px 0px 0px 0px;"); style.replace("; ", ";"); - if (flag) { + QString className = knownStyle.value(style); + if (className.isEmpty()) { + // Create a new class + className = QString("S%1").arg(knownStyle.count()); + knownStyle.insert(style, className); + + // Now add this for each attribute values QStringList styles = style.split(';'); - style.clear(); foreach (QString pair, styles) { - if (!pair.trimmed().isEmpty()) { - QStringList keyvalue = pair.split(':'); - if (keyvalue.length() == 2) { - QString key = keyvalue.at(0).trimmed(); - QString val = keyvalue.at(1).trimmed(); + pair.replace(" ",""); + if (!pair.isEmpty()) { + QStringList* stylesListItem = stylesList.value(pair); + if(!stylesListItem){ + // If value doesn't exist create it + stylesListItem = new QStringList(); + stylesList.insert(pair, stylesListItem); + } + //Add the new class to this value + stylesListItem->push_back(className); + } + } + } + style.clear(); - if ((flag & RSHTML_FORMATTEXT_REMOVE_FONT_FAMILY && key == "font-family") || - (flag & RSHTML_FORMATTEXT_REMOVE_FONT_SIZE && key == "font-size") || - (flag & RSHTML_FORMATTEXT_REMOVE_FONT_WEIGHT && key == "font-weight") || - (flag & RSHTML_FORMATTEXT_REMOVE_FONT_STYLE && key == "font-style")) { - continue; - } - if (flag & RSHTML_FORMATTEXT_REMOVE_COLOR) { - if (key == "color") { - continue; - } - } - else if (flag & RSHTML_FORMATTEXT_FIX_COLORS) { - if (key == "color") { - findBestColor(val, bglum, desiredContrast); - } - } - if (flag & (RSHTML_FORMATTEXT_REMOVE_COLOR | RSHTML_FORMATTEXT_FIX_COLORS)) { - if (key == "background" || key == "background-color") { - // Remove background color because if we change the text color, - // it can become unreadable on the original background. - // Also, FIX_COLORS is intended to display text on the default - // background color of the operating system. - continue; - } - } - - style += key + ":" + val + ";"; - } else { - style += pair + ";"; - } - } - } - } - if (style.isEmpty()) { node.attributes().removeNamedItem("style"); styleNode.clear(); - } else { - styleAttr.setValue(style); + + if (!className.isEmpty()) { + QDomNode classNode = doc.createAttribute("class"); + classNode.setNodeValue(className); + node.attributes().setNamedItem(classNode); } } @@ -662,18 +686,23 @@ static void optimizeHtml(QDomDocument& doc, QDomElement& currentElement, unsigne } // iterate children - optimizeHtml(doc, element, flag, bglum, desiredContrast); + optimizeHtml(doc, element, stylesList, knownStyle); //

if (element.tagName().toLower() == "p") { + //If it's the first

, replace it as otherwise make "\n" before first line + if (bFirstP) { + element.setTagName("span"); + bFirstP = false; + } //

if (element.attributes().size() == 1 && styleNode.isAttr()) { QString style = styleNode.toAttr().value().simplified(); - if (style == "margin:0px 0px 0px 0px;-qt-block-indent:0;text-indent:0px;" || - style.startsWith("-qt-paragraph-type:empty;margin:0px 0px 0px 0px;-qt-block-indent:0;text-indent:0px;")) { + if (style == "margin:0px 0px 0px 0px;-qt-block-indent:0;text-indent:0px;" + || style.startsWith("-qt-paragraph-type:empty;margin:0px 0px 0px 0px;-qt-block-indent:0;text-indent:0px;")) { if (addBR) { - // add
after a removed

before a removed

+ // add
after a removed

but not before a removed

QDomElement elementBr = doc.createElement("br"); currentElement.insertBefore(elementBr, element); ++index; @@ -686,47 +715,6 @@ static void optimizeHtml(QDomDocument& doc, QDomElement& currentElement, unsigne continue; } - // check for blockquote (not ready) - // style="margin-top:12px;margin-bottom:12px;margin-left:40px;margin-right:40px;-qt-block-indent:0;text-indent:0px;" -// int count = 0; // should be 6 -// QStringList styles = style.split(';'); -// foreach (QString pair, styles) { -// if (!pair.trimmed().isEmpty()) { -// QStringList keyvalue = pair.split(':'); -// if (keyvalue.length() == 2) { -// QString key = keyvalue.at(0).trimmed(); -// QString value = keyvalue.at(1).trimmed(); - -// if ((key == "margin-top" || key == "margin-bottom") && value == "12px") { -// ++count; -// continue; -// } -// if (key == "margin-left" || key == "margin-right") { -// ++count; -// continue; -// } -// if (key == "-qt-block-indent" && value == "0") { -// ++count; -// continue; -// } -// if (key == "text-indent" && value == "0px") { -// ++count; -// continue; -// } -// count = 0; -// break; -// } else { -// count = 0; -// break; -// } -// } -// } -// if (count == 6) { -// // change to "blockquote" -// element.setTagName("blockquote"); -// element.attributes().removeNamedItem("style"); -// element.setAttribute("type", "cite"); -// } } addBR = false; } @@ -735,7 +723,124 @@ static void optimizeHtml(QDomDocument& doc, QDomElement& currentElement, unsigne } } -void RsHtml::optimizeHtml(QTextEdit *textEdit, QString &text, unsigned int flag) +/** + * @brief styleCreate: Add styles filtered in QDomDocument. + * @param doc: QDomDocument containing all text formatted + * @param stylesList: List of all styles recognized + * @param flag: Bitfield of RSHTML_FORMATTEXT_* constants (they must be part of + * RSHTML_OPTIMIZEHTML_MASK). + * @param bglum: Luminance background color of the widget where the text will be + * displayed. Needed only if RSHTML_FORMATTEXT_FIX_COLORS + * is passed inside flag. + * @param desiredContrast: Minimum contrast between text and background color, + * between 1 and 21. + */ +static void styleCreate(QDomDocument& doc + , QHash stylesList + , unsigned int flag + , qreal bglum + , qreal desiredContrast) +{ + QDomElement styleElem; + do{ + if (doc.documentElement().namedItem("style").toElement().attributeNode("RSOptimized").isAttr()) { + QDomElement ele = doc.documentElement().namedItem("style").toElement(); + //Remove child before filter + if (!ele.isElement()) break; //Not an element so a bad message. + QDomAttr styleAttr = ele.attributeNode("RSOptimized"); + if (!styleAttr.isAttr()) break; //Not an attribute so a bad message. + QString version = styleAttr.value(); + if (version == "v2") { + styleElem = ele; + } + } + }while (false); //for break + + if(!styleElem.isElement()) { + styleElem = doc.createElement("style"); + // Creation of Style class list: - +
+ + - - - + + + - - - + + + - - - + + +
%name% %time% - %message% + %message% +
+ + + + +
+   %name% - + %time% +
+ +
diff --git a/retroshare-gui/src/gui/qss/chat/Bubble/public/system.htm b/retroshare-gui/src/gui/qss/chat/Bubble/public/system.htm index 103d2bca1..ec98b3b43 100644 --- a/retroshare-gui/src/gui/qss/chat/Bubble/public/system.htm +++ b/retroshare-gui/src/gui/qss/chat/Bubble/public/system.htm @@ -3,21 +3,35 @@ - +
+ + - - - + + + - - - + + + - - - + + +
%name% %time% - %message% + %message% +
+ + + + +
+   %name% - + %time% +
+ +
diff --git a/retroshare-gui/src/gui/qss/chat/Bubble_Compact/private/system.htm b/retroshare-gui/src/gui/qss/chat/Bubble_Compact/private/system.htm index 103d2bca1..ad8287db2 100644 --- a/retroshare-gui/src/gui/qss/chat/Bubble_Compact/private/system.htm +++ b/retroshare-gui/src/gui/qss/chat/Bubble_Compact/private/system.htm @@ -2,22 +2,28 @@ %css-style% +
- +
- - - + + + + - - - + + + + - - - + + + +
 %time%
%name% %time% - %message% %name%%message%
+
+ From 2337b468e07164f9f7b056bdfd8b5001afe2ff7a Mon Sep 17 00:00:00 2001 From: AsamK Date: Sat, 29 Aug 2015 11:40:50 +0200 Subject: [PATCH 127/165] Specify plugins as plugins to qmake This way only libPLUGIN.so is generated and not the versioned files libPLUGIN.so.1.0.0 --- plugins/Common/retroshare_plugin.pri | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/Common/retroshare_plugin.pri b/plugins/Common/retroshare_plugin.pri index 36a4280cd..e77626dc6 100644 --- a/plugins/Common/retroshare_plugin.pri +++ b/plugins/Common/retroshare_plugin.pri @@ -1,4 +1,5 @@ TEMPLATE = lib +CONFIG *= plugin DEPENDPATH += ../../libretroshare/src/ ../../retroshare-gui/src/ INCLUDEPATH += ../../libretroshare/src/ ../../retroshare-gui/src/ From f002310cf298b1fc471e29458d8cfe0a0bbf0ff8 Mon Sep 17 00:00:00 2001 From: AsamK Date: Sat, 29 Aug 2015 12:36:35 +0200 Subject: [PATCH 128/165] Remove libpegmarkdown from win32 retroshare-nogui build It is only needed for gui --- retroshare-nogui/src/retroshare-nogui.pro | 1 - 1 file changed, 1 deletion(-) diff --git a/retroshare-nogui/src/retroshare-nogui.pro b/retroshare-nogui/src/retroshare-nogui.pro index a7a98f275..9d590efba 100644 --- a/retroshare-nogui/src/retroshare-nogui.pro +++ b/retroshare-nogui/src/retroshare-nogui.pro @@ -122,7 +122,6 @@ win32 { INCLUDEPATH += $$LIBS_DIR/include gxs { - LIBS += ../../supportlibs/pegmarkdown/lib/libpegmarkdown.a LIBS += -lsqlcipher } } From 21e99cf8d4d297deb57f92062b18b6772773c132 Mon Sep 17 00:00:00 2001 From: AsamK Date: Sat, 29 Aug 2015 13:10:03 +0200 Subject: [PATCH 129/165] Use explicit dependencies instead of CONFIG += ordered Makes inter-dependencies clearer and allows parallel build of independent libs on multi-core systems, e.g. with: $ make -j4 --- RetroShare.pro | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/RetroShare.pro b/RetroShare.pro index 9ec3de6fc..b6df6e491 100644 --- a/RetroShare.pro +++ b/RetroShare.pro @@ -1,16 +1,35 @@ TEMPLATE = subdirs -CONFIG += ordered - SUBDIRS += \ - openpgpsdk/src/openpgpsdk.pro \ - supportlibs/pegmarkdown/pegmarkdown.pro \ - libbitdht/src/libbitdht.pro \ - libretroshare/src/libretroshare.pro \ - libresapi/src/libresapi.pro \ - retroshare-gui/src/retroshare-gui.pro \ - retroshare-nogui/src/retroshare-nogui.pro \ - plugins/plugins.pro + openpgpsdk \ + libbitdht \ + libretroshare \ + libresapi \ + pegmarkdown \ + retroshare_gui \ + retroshare_nogui \ + plugins + +openpgpsdk.file = openpgpsdk/src/openpgpsdk.pro + +libbitdht.file = libbitdht/src/libbitdht.pro + +libretroshare.file = libretroshare/src/libretroshare.pro +libretroshare.depends = openpgpsdk libbitdht + +libresapi.file = libresapi/src/libresapi.pro +libresapi.depends = libretroshare + +pegmarkdown.file = supportlibs/pegmarkdown/pegmarkdown.pro + +retroshare_gui.file = retroshare-gui/src/retroshare-gui.pro +retroshare_gui.depends = libretroshare libresapi pegmarkdown + +retroshare_nogui.file = retroshare-nogui/src/retroshare-nogui.pro +retroshare_nogui.depends = libretroshare libresapi + +plugins.file = plugins/plugins.pro +plugins.depends = retroshare_gui unix { isEmpty(PREFIX) { PREFIX = /usr } From 88a6931758e2e030c83dd81627b981a9315cd494 Mon Sep 17 00:00:00 2001 From: Phenom Date: Thu, 27 Aug 2015 23:23:12 +0200 Subject: [PATCH 130/165] Allow Chat Text Format Option working. --- retroshare-gui/src/util/HandleRichText.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/util/HandleRichText.cpp b/retroshare-gui/src/util/HandleRichText.cpp index a63428b9b..980dcbd88 100644 --- a/retroshare-gui/src/util/HandleRichText.cpp +++ b/retroshare-gui/src/util/HandleRichText.cpp @@ -416,7 +416,7 @@ QString RsHtml::formatText(QTextDocument *textDocument, const QString &text, ulo formattedText = doc.toString(-1); // -1 removes any annoying carriage return misinterpreted by QTextEdit if (flag & RSHTML_OPTIMIZEHTML_MASK) { - optimizeHtml(formattedText, flag & RSHTML_OPTIMIZEHTML_MASK, backgroundColor, desiredContrast); + optimizeHtml(formattedText, flag, backgroundColor, desiredContrast); } return formattedText; From b11baa7a65296565300cec0719a96ee3d7687339 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 29 Aug 2015 14:44:16 -0400 Subject: [PATCH 131/165] updated ubuntu changelog --- build_scripts/Debian+Ubuntu/changelog | 102 ++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/build_scripts/Debian+Ubuntu/changelog b/build_scripts/Debian+Ubuntu/changelog index 8bbc69eae..ff2101d8a 100644 --- a/build_scripts/Debian+Ubuntu/changelog +++ b/build_scripts/Debian+Ubuntu/changelog @@ -1,5 +1,107 @@ retroshare06 (0.6.0-1.XXXXXX~YYYYYY) YYYYYY; urgency=low + a276986 ( ) Merge pull request #60 from PhenomRetroShare/Fix_AllowChatTextFormatOption + 88a6931 (GUI ) Allow Chat Text Format Option working. + 0b5b20d ( ) Merge pull request #59 from AsamK/qmake_improvements + 0409dd8 ( ) Merge pull request #58 from AsamK/debian_make_install + 21e99cf (Packaging ) Use explicit dependencies instead of CONFIG += ordered + f002310 (Packaging ) Remove libpegmarkdown from win32 retroshare-nogui build + 2337b46 (Packaging ) Specify plugins as plugins to qmake + ecb5d93 (GUI ) changed default color for the system chat bubble + d51b4b2 (Packaging ) Adapt debian/ubuntu package files to use "make install" + c07bef3 (GUI ) Fixed Create Lobby Dialog's window size + a45de1d (Chat ) Merge pull request #57 from csoler/v0.6-SignedLobbies + 40bffc3 (Chat ) fixed last GUI bugs for authed lobbies + 6d01461 (Chat ) fixed a few GUI bits for non anonymous chat lobbies + 627dcc0 (Forums ) Merge pull request #50 from chozabu/forum_additions + 7270ba9 (Chat ) Merge pull request #56 from AsamK/distant_chat_history + 5dad168 (Chat ) Implement history for distant chat + d7531b3 ( ) Merge pull request #54 from cavebeat/coverity + 9240512 ( ) Merge pull request #55 from AsamK/install_stylesheets + 622e942 (GUI ) Remove Thumbs.db files and add to .gitignore + 699213a (Packaging ) Load chat styles also from DATA_DIR/stylesheets + 66ba687 (Packaging ) Install qss and chat styles + 4d7f92e (GXS/NXS ) Removed unnecessary select of groups in RsGxsNetService::locked_genReqGrpTransaction. + 753846b (GXS/SQL ) Added count of requests and results to debug output in RsDataService::retrieveGxsGrpMetaData + d118a13 (GXS/NXS ) Fixed adding of empty group id to notify when removing a group. + 4cc1df3 (GXS/NXS ) Ignore updates of not existing groups in RsGenExchange::processGrpMask. Solves: "Error code: no such column: su + d8aa712 (Packaging ) travis/coverity tokens updated + 6e1a8fa ( ) Merge pull request #21 from AsamK/lobby_history + 040b4fb (Chat ) implemented gp-authed lobbies. Still needs some GUI + b8459b3 ( ) Merge pull request #44 from AsamK/improve_qmake + c622ca0 (Packaging ) Issue compile error if DATA_DIR is not set + ef499cd ( ) Merge pull request #46 from PhenomRetroShare/Fix_ChatWidgetSearchTextThreshold + 668394d ( ) Merge pull request #47 from PhenomRetroShare/AddHTML_TextOptimization_0.6 + 6ba2f68 ( ) Merge pull request #45 from PhenomRetroShare/Fix_ChatWidgetLastCursorFormatting + 1736ad8 ( ) Merge pull request #11 from cavebeat/coverity_scan + a39663d ( ) Merge branch 'master' of https://github.com/RetroShare/RetroShare + 17af892 (GUI ) set a default minimum column header size for comments. + c29ae55 (Code cleaning ) Merge pull request #38 from cavebeat/rm_linkscloud + 1a1a2aa (GXS/NXS ) Lowered update of server sync TS from 10 seconds to 60 seconds. + 641a433 (GUI ) Fixed filter in FriendList. + 217c9b9 ( ) Merge branch 'master' of https://github.com/RetroShare/RetroShare + 9d65b08 (GUI ) set default background color for system messages at private chat window + da66ac5 (GXS ) GxsGroupFrameDialog: Fixed restore of active group tree item when subscrube/unsubscribe a group. + 185220b (GUI ) enable customisation of columns in forum thread widget + 389f2f0 (GXS/SQL ) Removed delete of message files in RsDataService::resetDataStore. + 836b866 ( ) Merge pull request #37 from sehraf/pr-friendlist_import_export-V2 + 5aaf3e6 (Packaging ) Move data dir from build_scripts/ to root and adapt RedHat build files + 4dbffe0 ( ) Merge pull request #48 from PhenomRetroShare/AddRetroShareLinkOpenFileWhenExists + 5c67941 ( ) Update README.md + 5ae5d76 (Packaging ) Make file names consistent with packaging + 91e19fc (Packaging ) Disable installing of headers and libretroshare.a + d4a36ed (Packaging ) Make data and plugin directory configurable at compile time + 6b7a6e2 (Packaging ) Make RS installable with "make install" + fa54fce ( ) Merge pull request #49 from heini/redhat_build + 1fcae61 (GXS/SQL ) Removed static defines for column numbers in RsDataService and replaced it with members. Initialized members wh + 531ce34 ( ) Merge branch 'master' into AddRetroShareLinkOpenFileWhenExists + 860292d ( ) Merge branch 'master' into AddHTML_TextOptimization_0.6 + 70b9c45 ( ) Merge branch 'master' into Fix_ChatWidgetSearchTextThreshold + 79fb8df ( ) Merge branch 'master' into Fix_ChatWidgetLastCursorFormatting + e9aa4ff ( ) Merge pull request #3 from chozabu/copy_version_info_button + d1deef0 (GUI ) fixed new lines in certificate string + 7bd41e9 ( ) Merge pull request #4 from chozabu/grouter_stats_basic_names + 7fe46ed (Packaging ) Provide RedHat family packaging script. + f30ed24 (GXS/SQL ) Moved gxs data from files into database - Added update to RsDataService - Added new table "DATABASE_RELEASE" to + b1aae2d ( ) Merge branch 'master' into AddRetroShareLinkOpenFileWhenExists + 0234734 (GUI ) When the file in the link already exists, RS open it. + 791fb78 (GUI ) renaming details and details2 for better clarification + ad499e6 (GUI ) renamed 'pubkey' to 'certificate' and removed empty location names + 6893c58 ( ) Merge pull request #42 from cavebeat/comma + c66de1c (Packaging ) fixed comma in README for debian + f58e347 ( ) Merge pull request #23 from AsamK/patch-1 + 326a330 (GUI ) Fix ChatWidget last cursor formatting. To test it, search a text that will be colored a end. New messages lose + c44afc0 ( ) Merge branch 'master' into Fix_ChatWidgetSearchTextThreshold + b1fd290 ( ) Merge branch 'master' into AddHTML_TextOptimization_0.6 + eb4313f ( ) merge before commit + 58d29c3 (Bug fix ) fixed error message in pqissl::cansend() + 5c97010 (GUI ) Fix ChatWidget search text label threshold. + 5a32cca (Packaging ) README: Fix executable name + 339558f (Packaging ) Update and rename README.txt to README.md + 6ac107a (GXS/SQL ) Added method "tableExist" to RetroDb. + 3665238 (GXS/SQL ) Added new methods for transaction to RetroDb. + 4309642 ( ) merging before commit + 58c70ca ( ) moved [not] operator inside parenthesis. Does not change anything except improving readability + dea7c77 (Global router ) fixed missing removal of deleted data causing a crash when large messages cause an error in Global Router + 334ddf8 (GUI ) Enabled sort by columns other than name combined with sort by state in FriendList. + 176c3ab (GUI ) FriendSelectionWidget: - Added sort by state - Moved buttons "All"/"None" into context menu + 4923c47 (GUI ) RSTreeWidget: - Added possibility to add own actions to header context menu - Added resort of items + 02775c6 (GUI ) Add HTML Text Optimization by exporting styles. + 1d9e398 (Code cleaning ) removed LinksCloud LinksCloud has been replaced by Posted and is hosted for archiving reasons in https://github + 04a1c10 (GUI ) fixed UTF-8 group names + 941959c (GUI ) conversion from QSettings to XML + 48c3eed (Packaging ) Removed "CONFIG += console" for Windows release build. + 3b40f0e (GUI ) FriendList: - Show information of the "best" ssl item on the gpg item only when the gpg item is not expanded. - + 42bbf76 (GUI ) fixed display of software revision in main window (patch from ASmith) + 80d765e (GUI ) small fix + 3634981 (GUI ) added import/export friendlist + 4d7f733 (Packaging ) fixed bug in git parameter in packaging script + 9734f32 (Packaging ) updated ubuntu changelog. improved ubuntu packaging script + + -- Cyril Soler Sun, 16 Aug 2015 20:00:00 +0100 + +retroshare06 (0.6.0-1.20150816~9734f32a) trusty; urgency=low + f6b830d (branch merging) Merge pull request #35 from hunbernd/chat-fix 16859a1 (GUI ) Fix: chatlobby toaster not working 2e08dde (Bug fix ) additional check for pqissl::sockfd before using it (patch from Jenster) From f73ee2c7695b7b53376d0a99a22e7b98b2cbb9c5 Mon Sep 17 00:00:00 2001 From: Phenom Date: Sat, 29 Aug 2015 21:06:36 +0200 Subject: [PATCH 132/165] Improve ElidedLabel Now respect alignment and html text. Html is shown as plain text, no html in QTextLine... Test with: retroshare://file?name=Test_ElidedLabel.7z&size=7330&hash=bd19f1a486d34d08e434ca4309cf4b8f7a436e9e --- retroshare-gui/src/gui/common/ElidedLabel.cpp | 148 +++++++++++++++--- retroshare-gui/src/gui/common/ElidedLabel.h | 6 + 2 files changed, 134 insertions(+), 20 deletions(-) diff --git a/retroshare-gui/src/gui/common/ElidedLabel.cpp b/retroshare-gui/src/gui/common/ElidedLabel.cpp index ebc77f31f..a18aaf299 100644 --- a/retroshare-gui/src/gui/common/ElidedLabel.cpp +++ b/retroshare-gui/src/gui/common/ElidedLabel.cpp @@ -40,23 +40,30 @@ #include "ElidedLabel.h" -#include -#include #include +#include #include +#include +#include +#include ElidedLabel::ElidedLabel(const QString &text, QWidget *parent) : QLabel(parent) , mElided(false) + , mOnlyPlainText(false) , mContent(text) { + mRectElision = QRect(); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); } ElidedLabel::ElidedLabel(QWidget *parent) : QLabel(parent) , mElided(false) + , mOnlyPlainText(false) + , mContent("") { + mRectElision = QRect(); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); } @@ -66,6 +73,12 @@ void ElidedLabel::setText(const QString &newText) update(); } +void ElidedLabel::setOnlyPlainText(const bool &value) +{ + mOnlyPlainText = value; + update(); +} + void ElidedLabel::clear() { mContent.clear(); @@ -75,43 +88,138 @@ void ElidedLabel::clear() void ElidedLabel::paintEvent(QPaintEvent *event) { QLabel::paintEvent(event); - + QList > lLines; + QString elidedLastLine = ""; QPainter painter(this); QFontMetrics fontMetrics = painter.fontMetrics(); QRect cr = contentsRect(); cr.adjust(margin(), margin(), -margin(), -margin()); bool didElide = false; + QChar ellipsisChar(0x2026);//= "…" int lineSpacing = fontMetrics.lineSpacing(); - int x, y = x =cr.top()+(cr.height()-lineSpacing)/2; - - QTextLayout textLayout(mContent, painter.font()); + int y = 0; + + QString plainText = ""; + if (mOnlyPlainText) + { + plainText = mContent; + } else { + QTextDocument td; + td.setHtml(mContent); + plainText = td.toPlainText(); + } + plainText = plainText.replace("\n",QChar(QChar::LineSeparator)); + plainText = plainText.replace("\r",QChar(QChar::LineSeparator)); + + QTextLayout textLayout(plainText, painter.font()); + QTextOption to = textLayout.textOption(); + to.setAlignment(alignment()); + to.setWrapMode(wordWrap() ? QTextOption::WrapAtWordBoundaryOrAnywhere : QTextOption::NoWrap); + textLayout.setTextOption(to); + textLayout.beginLayout(); forever { + //Get new line for text. QTextLine line = textLayout.createLine(); - + if (!line.isValid()) - break; - - line.setLineWidth(cr.width()+2*x); + break;// No more line to write + + line.setLineWidth(cr.width()); int nextLineY = y + lineSpacing; - - if (cr.height() >= nextLineY + lineSpacing) { - line.draw(&painter, QPoint(x, y)); + + if ((cr.height() >= nextLineY + lineSpacing) && wordWrap()) { + //Line written normaly, next line will too + lLines.append(QPair(line, QPoint(0, y))); y = nextLineY; } else { - QString lastLine = mContent.mid(line.textStart()); - QString elidedLastLine = fontMetrics.elidedText(lastLine, Qt::ElideRight, cr.width()); - painter.drawText(QPoint(x, y + fontMetrics.ascent()), elidedLastLine); - line = textLayout.createLine(); - didElide = line.isValid(); - break; + //The next line can't be written. + QString lastLine = plainText.mid(line.textStart()).split(QChar(QChar::LineSeparator)).at(0); + QTextLine lineEnd = textLayout.createLine(); + if (!lineEnd.isValid() && (wordWrap() + || (fontMetrics.width(lastLine) < cr.width()))) { + //No more text for next line so this one is OK + lLines.append(QPair(line, QPoint(0, y))); + elidedLastLine=""; + didElide = false; + } else { + //Text is left, so get elided text + if (lastLine == "") { + elidedLastLine = ellipsisChar; + } else { + elidedLastLine = fontMetrics.elidedText(lastLine, Qt::ElideRight, cr.width()-1); + if (elidedLastLine.right(1) != ellipsisChar) + elidedLastLine.append(ellipsisChar);//New line at end + } + didElide = true; + break; + } } } textLayout.endLayout(); - + + int iTransX, iTransY = iTransX = 0; + int iHeight = lLines.count() * lineSpacing; + if (didElide) iHeight += lineSpacing; + + //Compute lines translation with alignment + if (alignment() & Qt::AlignTop) + iTransY = 0; + if (alignment() & Qt::AlignBottom) + iTransY = cr.height() - iHeight; + if (alignment() & Qt::AlignVCenter) + iTransY = (cr.height() - iHeight) / 2; + + QPair pair; + QPoint lastPos(-1,-1); + //Now we know how many lines to redraw at good position + foreach (pair, lLines){ + lastPos = pair.second + QPoint(0, iTransY); + pair.first.draw(&painter, lastPos); + } + + //Print last elided line + if (didElide) { + int width = fontMetrics.width(elidedLastLine); + if (lastPos.y() == -1){ + y = iTransY;// Only one line + } else { + y = lastPos.y() + lineSpacing; + } + if (width < cr.width()){ + //Text don't taking all line (with line break), so align it + if (alignment() & Qt::AlignLeft) + iTransX = 0; + if (alignment() & Qt::AlignRight) + iTransX = cr.width() - width; + if (alignment() & Qt::AlignHCenter) + iTransX = (cr.width() - width) / 2; + if (alignment() & Qt::AlignJustify) + iTransX = 0; + } + + painter.drawText(QPoint(iTransX, y + fontMetrics.ascent()), elidedLastLine); + //Draw button to get ToolTip + mRectElision = QRect(iTransX + width - fontMetrics.width(ellipsisChar) + , y + , fontMetrics.width(ellipsisChar) + , fontMetrics.height() - 1); + painter.drawRoundRect(mRectElision); + } else { + mRectElision = QRect(); + } + + //Send signal if changed if (didElide != mElided) { mElided = didElide; emit elisionChanged(didElide); } } + +void ElidedLabel::mousePressEvent(QMouseEvent *ev) +{ + if (mElided && (ev->buttons()==Qt::LeftButton) && (mRectElision.contains(ev->pos()))){ + QToolTip::showText(mapToGlobal(QPoint(0, 0)),QString("") + mContent + QString("")); + } +} diff --git a/retroshare-gui/src/gui/common/ElidedLabel.h b/retroshare-gui/src/gui/common/ElidedLabel.h index 3015209a8..db51aef79 100644 --- a/retroshare-gui/src/gui/common/ElidedLabel.h +++ b/retroshare-gui/src/gui/common/ElidedLabel.h @@ -52,6 +52,7 @@ class ElidedLabel : public QLabel Q_OBJECT Q_PROPERTY(QString text READ text WRITE setText) Q_PROPERTY(bool isElided READ isElided) + Q_PROPERTY(bool isOnlyPlainText READ isOnlyPlainText WRITE setOnlyPlainText) public: ElidedLabel(const QString &text, QWidget *parent = 0); @@ -59,20 +60,25 @@ public: const QString & text() const { return mContent; } bool isElided() const { return mElided; } + bool isOnlyPlainText() const { return mOnlyPlainText; } public slots: void setText(const QString &text); + void setOnlyPlainText(const bool &value); void clear(); protected: void paintEvent(QPaintEvent *event); + void mousePressEvent(QMouseEvent *ev); signals: void elisionChanged(bool elided); private: bool mElided; + bool mOnlyPlainText; QString mContent; + QRect mRectElision; }; #endif // ELIDEDLABEL_H From d9fd60ee75a64537a8394991f48303ce51e9957a Mon Sep 17 00:00:00 2001 From: defnax Date: Sun, 30 Aug 2015 03:48:45 +0200 Subject: [PATCH 133/165] Moved Id Chooser to Tool Menu Added a place holder text. --- retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp | 13 ++++++++++--- retroshare-gui/src/gui/chat/ChatLobbyDialog.h | 4 +++- retroshare-gui/src/gui/chat/CreateLobbyDialog.ui | 6 +++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp index b695cc62e..7bc1e8c1f 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "ChatLobbyDialog.h" #include "gui/ChatLobbyWidget.h" @@ -81,8 +82,8 @@ ChatLobbyDialog::ChatLobbyDialog(const ChatLobbyId& lid, QWidget *parent, Qt::Wi // Add a button to invite friends. // inviteFriendsButton = new QToolButton ; - inviteFriendsButton->setMinimumSize(QSize(2*S,2*S)) ; - inviteFriendsButton->setMaximumSize(QSize(2*S,2*S)) ; + inviteFriendsButton->setMinimumSize(QSize(2*S,2*S)) ; + inviteFriendsButton->setMaximumSize(QSize(2*S,2*S)) ; inviteFriendsButton->setText(QString()) ; inviteFriendsButton->setAutoRaise(true) ; inviteFriendsButton->setToolTip(tr("Invite friends to this lobby")); @@ -106,8 +107,14 @@ ChatLobbyDialog::ChatLobbyDialog(const ChatLobbyId& lid, QWidget *parent, Qt::Wi ownIdChooser = new GxsIdChooser() ; ownIdChooser->loadIds(IDCHOOSER_ID_REQUIRED,current_id) ; + + QWidgetAction *checkableAction = new QWidgetAction(this); + checkableAction->setDefaultWidget(ownIdChooser); + + ui.chatWidget->addToolsAction(checkableAction); + //getChatWidget()->addChatBarWidget(ownIdChooser); + - getChatWidget()->addChatBarWidget(ownIdChooser) ; connect(ownIdChooser,SIGNAL(currentIndexChanged(int)),this,SLOT(changeNickname())) ; diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.h b/retroshare-gui/src/gui/chat/ChatLobbyDialog.h index 1aa742573..7729abba8 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.h +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.h @@ -29,6 +29,7 @@ class GxsIdChooser ; class QToolButton; +class QWidgetAction; class ChatLobbyDialog: public ChatDialog { @@ -55,7 +56,7 @@ private slots: signals: void lobbyLeave(ChatLobbyId) ; void typingEventReceived(ChatLobbyId) ; - void messageReceived(bool incoming, ChatLobbyId lobby_id, QDateTime time, QString senderName, QString msg) ; + void messageReceived(bool incoming, ChatLobbyId lobby_id, QDateTime time, QString senderName, QString msg) ; void peerJoined(ChatLobbyId) ; void peerLeft(ChatLobbyId) ; @@ -102,6 +103,7 @@ private: QAction *muteAct; QAction *distantChatAct; + QWidgetAction *checkableAction; GxsIdChooser *ownIdChooser ; }; diff --git a/retroshare-gui/src/gui/chat/CreateLobbyDialog.ui b/retroshare-gui/src/gui/chat/CreateLobbyDialog.ui index 1d2340e08..4877a5f71 100644 --- a/retroshare-gui/src/gui/chat/CreateLobbyDialog.ui +++ b/retroshare-gui/src/gui/chat/CreateLobbyDialog.ui @@ -71,7 +71,11 @@ - + + + Set a descriptive topic here + + From 68918bf9c1a6bd7841e5d2e99762607e1d918aea Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 29 Aug 2015 21:48:58 -0400 Subject: [PATCH 134/165] added variable bitrate and attempt to control it. --- plugins/VOIP/gui/AudioInputConfig.ui | 2 +- plugins/VOIP/gui/QVideoDevice.cpp | 2 +- plugins/VOIP/gui/VideoProcessor.cpp | 52 ++++++++++++++++++++++------ plugins/VOIP/gui/VideoProcessor.h | 8 ++--- 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/plugins/VOIP/gui/AudioInputConfig.ui b/plugins/VOIP/gui/AudioInputConfig.ui index 71ed06569..62e8c98a6 100644 --- a/plugins/VOIP/gui/AudioInputConfig.ui +++ b/plugins/VOIP/gui/AudioInputConfig.ui @@ -412,7 +412,7 @@ 1 - 5.000000000000000 + 2.000000000000000 200.000000000000000 diff --git a/plugins/VOIP/gui/QVideoDevice.cpp b/plugins/VOIP/gui/QVideoDevice.cpp index 516933807..3a0cc4aa9 100644 --- a/plugins/VOIP/gui/QVideoDevice.cpp +++ b/plugins/VOIP/gui/QVideoDevice.cpp @@ -77,7 +77,7 @@ void QVideoInputDevice::grabFrame() if(_video_processor != NULL) { - _video_processor->processImage(image,0) ; + _video_processor->processImage(image) ; emit networkPacketReady() ; } diff --git a/plugins/VOIP/gui/VideoProcessor.cpp b/plugins/VOIP/gui/VideoProcessor.cpp index ef10b63a5..7da37fbbe 100644 --- a/plugins/VOIP/gui/VideoProcessor.cpp +++ b/plugins/VOIP/gui/VideoProcessor.cpp @@ -36,7 +36,7 @@ VideoProcessor::VideoProcessor() _estimated_bandwidth_in = 0 ; _estimated_bandwidth_out = 0 ; - _target_bandwidth_out = 0 ; + _target_bandwidth_out = 30*1024 ; // 30 KB/s _total_encoded_size_in = 0 ; _total_encoded_size_out = 0 ; @@ -58,7 +58,7 @@ VideoProcessor::~VideoProcessor() } } -bool VideoProcessor::processImage(const QImage& img,uint32_t size_hint) +bool VideoProcessor::processImage(const QImage& img) { VideoCodec *codec ; @@ -80,7 +80,7 @@ bool VideoProcessor::processImage(const QImage& img,uint32_t size_hint) { RsVOIPDataChunk chunk ; - if(codec->encodeData(img.scaled(_encoded_frame_size,Qt::IgnoreAspectRatio,Qt::SmoothTransformation),size_hint,chunk) && chunk.size > 0) + if(codec->encodeData(img.scaled(_encoded_frame_size,Qt::IgnoreAspectRatio,Qt::SmoothTransformation),_target_bandwidth_out,chunk) && chunk.size > 0) { RS_STACK_MUTEX(vpMtx) ; _encoded_out_queue.push_back(chunk) ; @@ -318,7 +318,7 @@ bool JPEGVideo::encodeData(const QImage& image,uint32_t /* size_hint */,RsVOIPDa } -bool WaveletVideo::encodeData(const QImage& image,uint32_t size_hint,RsVOIPDataChunk& voip_chunk) +bool WaveletVideo::encodeData(const QImage& image, uint32_t target_encoding_bitrate, RsVOIPDataChunk& voip_chunk) { static const int WAVELET_IMG_SIZE = 128 ; static const float W_THRESHOLD = 0.005 ; // low quality @@ -568,7 +568,28 @@ FFmpegVideo::FFmpegVideo() if (!encoding_context) throw std::runtime_error("AV: Could not allocate video codec encoding context"); /* put sample parameters */ - encoding_context->bit_rate = 200000; + encoding_context->bit_rate = 30*1024 ; // default bitrate is 30KB/s + encoding_context->bit_rate_tolerance = encoding_context->bit_rate ; + encoding_context->rc_min_rate = 0; + encoding_context->rc_max_rate = 81920; + encoding_context->rc_buffer_size = 1024*1024; + encoding_context->flags |= CODEC_FLAG_PSNR; + //encoding_context->partitions = X264_PART_I4X4 | X264_PART_I8X8 | X264_PART_P8X8 | X264_PART_P4X4 | X264_PART_B8X8; + //encoding_context->crf = 0.0f; + //encoding_context->cqp = 26; + encoding_context->i_quant_factor = 0.769f; + encoding_context->b_quant_factor = 1.4f; + encoding_context->rc_initial_buffer_occupancy = (int) ( 0.9 * encoding_context->rc_buffer_size); + encoding_context->rc_max_available_vbv_use = 0.9; + encoding_context->rc_min_vbv_overflow_use = 0.1; + encoding_context->time_base.num = 1; + encoding_context->time_base.den = 15;//framesPerSecond; + //encoding_context->me_method = ME_HEX; + encoding_context->qmin = 10; + encoding_context->qmax = 51; + encoding_context->max_qdiff = 4; + encoding_context->max_b_frames = 4; + /* resolution must be a multiple of two */ encoding_context->width = 352;//176; encoding_context->height = 288;//144; @@ -580,10 +601,9 @@ FFmpegVideo::FFmpegVideo() * then gop_size is ignored and the output of encoder * will always be I frame irrespective to gop_size */ - encoding_context->gop_size = 10; + encoding_context->gop_size = 250; encoding_context->max_b_frames = 1; - //context->pix_fmt = AV_PIX_FMT_RGB24; - encoding_context->pix_fmt = AV_PIX_FMT_YUV420P; + encoding_context->pix_fmt = AV_PIX_FMT_YUV420P; //context->pix_fmt = AV_PIX_FMT_RGB24; if (codec_id == AV_CODEC_ID_H264) av_opt_set(encoding_context->priv_data, "preset", "slow", 0); @@ -664,13 +684,22 @@ FFmpegVideo::~FFmpegVideo() free(decoding_frame_buffer); } +#define MAX_FFMPEG_ENCODING_BITRATE 81920 -bool FFmpegVideo::encodeData(const QImage& image,uint32_t size_hint,RsVOIPDataChunk& voip_chunk) +bool FFmpegVideo::encodeData(const QImage& image, uint32_t target_encoding_bitrate, RsVOIPDataChunk& voip_chunk) { #ifdef DEBUG_MPEG_VIDEO std::cerr << "Encoding frame of size " << image.width() << "x" << image.height() << ", resized to " << encoding_frame_buffer->width << "x" << encoding_frame_buffer->height << " : "; #endif QImage input ; + + if(target_encoding_bitrate > MAX_FFMPEG_ENCODING_BITRATE) + { + std::cerr << "Max encodign bitrate eexceeded. Capping to " << MAX_FFMPEG_ENCODING_BITRATE << std::endl; + target_encoding_bitrate = MAX_FFMPEG_ENCODING_BITRATE ; + } + encoding_context->bit_rate = target_encoding_bitrate; + encoding_context->bit_rate_tolerance = target_encoding_bitrate; if(image.width() != encoding_frame_buffer->width || image.height() != encoding_frame_buffer->height) input = image.scaled(QSize(encoding_frame_buffer->width,encoding_frame_buffer->height),Qt::IgnoreAspectRatio,Qt::SmoothTransformation) ; @@ -775,6 +804,7 @@ bool FFmpegVideo::encodeData(const QImage& image,uint32_t size_hint,RsVOIPDataCh } } + bool FFmpegVideo::decodeData(const RsVOIPDataChunk& chunk,QImage& image) { #ifdef DEBUG_MPEG_VIDEO @@ -843,9 +873,9 @@ bool FFmpegVideo::decodeData(const RsVOIPDataChunk& chunk,QImage& image) int U = decoding_frame_buffer->data[1][(y/2) * decoding_frame_buffer->linesize[1] + x/2] ; int V = decoding_frame_buffer->data[2][(y/2) * decoding_frame_buffer->linesize[2] + x/2] ; - int R = std::min(255,std::max(0,(int)(1.164*(Y - 16) + 1.596*(V - 128)))) ; + int B = std::min(255,std::max(0,(int)(1.164*(Y - 16) + 1.596*(V - 128)))) ; int G = std::min(255,std::max(0,(int)(1.164*(Y - 16) - 0.813*(V - 128) - 0.391*(U - 128)))) ; - int B = std::min(255,std::max(0,(int)(1.164*(Y - 16) + 2.018*(U - 128)))) ; + int R = std::min(255,std::max(0,(int)(1.164*(Y - 16) + 2.018*(U - 128)))) ; image.setPixel(QPoint(x,y),QRgb( 0xff000000 + (R << 16) + (G << 8) + B)) ; } diff --git a/plugins/VOIP/gui/VideoProcessor.h b/plugins/VOIP/gui/VideoProcessor.h index a36598649..85ecae7df 100644 --- a/plugins/VOIP/gui/VideoProcessor.h +++ b/plugins/VOIP/gui/VideoProcessor.h @@ -29,7 +29,7 @@ public: JPEGVideo() ; protected: - virtual bool encodeData(const QImage& Image, uint32_t size_hint, RsVOIPDataChunk& chunk) ; + virtual bool encodeData(const QImage& Image, uint32_t target_encoding_bitrate, RsVOIPDataChunk& chunk) ; virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) ; static const uint32_t JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME = 0x0001 ; @@ -47,7 +47,7 @@ public: WaveletVideo() {} protected: - virtual bool encodeData(const QImage& Image, uint32_t size_hint, RsVOIPDataChunk& chunk) ; + virtual bool encodeData(const QImage& Image, uint32_t target_encoding_bitrate, RsVOIPDataChunk& chunk) ; virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) ; private: @@ -73,7 +73,7 @@ public: ~FFmpegVideo() ; protected: - virtual bool encodeData(const QImage& Image, uint32_t size_hint, RsVOIPDataChunk& chunk) ; + virtual bool encodeData(const QImage& Image, uint32_t target_encoding_bitrate, RsVOIPDataChunk& chunk) ; virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) ; private: @@ -130,7 +130,7 @@ class VideoProcessor public: // Takes the next image to be encoded. // - bool processImage(const QImage& Image, uint32_t size_hint) ; + bool processImage(const QImage& Image) ; bool encodedPacketReady() const { return !_encoded_out_queue.empty() ; } bool nextEncodedPacket(RsVOIPDataChunk& ) ; From acc3e4bb62397e14d6972ea7a6283fcf31f54888 Mon Sep 17 00:00:00 2001 From: hunbernd Date: Sat, 29 Aug 2015 21:31:01 +0200 Subject: [PATCH 135/165] Replaced Q_WS_ --> Q_OS_ Q_WS macros are not available in Qt5 Restores some functions in Options->General dialog that were not available under Qt5 --- retroshare-gui/src/gui/AboutDialog.cpp | 6 ++--- retroshare-gui/src/gui/GetStartedDialog.cpp | 6 ++--- retroshare-gui/src/gui/NetworkDialog.cpp | 4 ---- .../src/gui/PhotoShare/PhotoDialog.cpp | 2 +- .../src/gui/PhotoShare/PhotoSlideShow.cpp | 2 +- retroshare-gui/src/gui/QuickStartWizard.cpp | 6 ++--- retroshare-gui/src/gui/SearchDialog.cpp | 4 ---- retroshare-gui/src/gui/common/Emoticons.cpp | 2 +- .../src/gui/common/RSGraphWidget.cpp | 2 +- .../src/gui/connect/ConnectFriendWizard.cpp | 4 ++-- .../src/gui/help/browser/helpbrowser.cpp | 4 ++-- .../src/gui/settings/GeneralPage.cpp | 6 ++--- .../src/gui/settings/rsharesettings.cpp | 24 +++++++++---------- .../gui/statistics/BandwidthGraphWindow.cpp | 10 ++++---- retroshare-gui/src/rshare.cpp | 2 +- retroshare-gui/src/util/printpreview.cpp | 2 +- 16 files changed, 39 insertions(+), 47 deletions(-) diff --git a/retroshare-gui/src/gui/AboutDialog.cpp b/retroshare-gui/src/gui/AboutDialog.cpp index 003253443..7d1a047d6 100644 --- a/retroshare-gui/src/gui/AboutDialog.cpp +++ b/retroshare-gui/src/gui/AboutDialog.cpp @@ -761,13 +761,13 @@ void AboutDialog::on_copy_button_clicked() verInfo+=QSysInfo::prettyProductName(); #endif #else - #ifdef Q_WS_X11 + #ifdef Q_OS_LINUX verInfo+="Linux"; #endif - #ifdef Q_WS_WIN + #ifdef Q_OS_WIN verInfo+="Windows"; #endif - #ifdef Q_WS_MACX + #ifdef Q_OS_MAC verInfo+="Mac"; #endif #endif diff --git a/retroshare-gui/src/gui/GetStartedDialog.cpp b/retroshare-gui/src/gui/GetStartedDialog.cpp index 6d4f88d5a..6cf6b2593 100644 --- a/retroshare-gui/src/gui/GetStartedDialog.cpp +++ b/retroshare-gui/src/gui/GetStartedDialog.cpp @@ -189,7 +189,7 @@ void GetStartedDialog::tickFirewallChanged() static void sendMail(const QString &address, const QString &subject, QString body) { /* Only under windows do we need to do this! */ -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN /* search and replace the end of lines with: "%0D%0A" */ body.replace("\n", "%0D%0A"); #endif @@ -343,7 +343,7 @@ void GetStartedDialog::emailSupport() #ifdef __APPLE__ - #ifdef Q_WS_MAC + #ifdef Q_OS_MAC switch(QSysInfo::MacintoshVersion) { case QSysInfo::MV_9: @@ -383,7 +383,7 @@ void GetStartedDialog::emailSupport() #else #if defined(_WIN32) || defined(__MINGW32__) // Windows - #ifdef Q_WS_WIN + #ifdef Q_OS_WIN switch(QSysInfo::windowsVersion()) { case QSysInfo::WV_32s: diff --git a/retroshare-gui/src/gui/NetworkDialog.cpp b/retroshare-gui/src/gui/NetworkDialog.cpp index d15d50f5a..16ee66b0d 100644 --- a/retroshare-gui/src/gui/NetworkDialog.cpp +++ b/retroshare-gui/src/gui/NetworkDialog.cpp @@ -169,10 +169,6 @@ NetworkDialog::NetworkDialog(QWidget *parent) //updateNetworkStatus(); //loadtabsettings(); - /* Hide platform specific features */ -#ifdef Q_WS_WIN - -#endif } void NetworkDialog::changeEvent(QEvent *e) diff --git a/retroshare-gui/src/gui/PhotoShare/PhotoDialog.cpp b/retroshare-gui/src/gui/PhotoShare/PhotoDialog.cpp index c0091de74..cb338091a 100644 --- a/retroshare-gui/src/gui/PhotoShare/PhotoDialog.cpp +++ b/retroshare-gui/src/gui/PhotoShare/PhotoDialog.cpp @@ -220,7 +220,7 @@ void PhotoDialog::setFullScreen() if (!isFullScreen()) { // hide menu & toolbars -#ifdef Q_WS_X11 +#ifdef Q_OS_LINUX show(); raise(); setWindowState( windowState() | Qt::WindowFullScreen ); diff --git a/retroshare-gui/src/gui/PhotoShare/PhotoSlideShow.cpp b/retroshare-gui/src/gui/PhotoShare/PhotoSlideShow.cpp index fee31fd71..fa21d07bc 100644 --- a/retroshare-gui/src/gui/PhotoShare/PhotoSlideShow.cpp +++ b/retroshare-gui/src/gui/PhotoShare/PhotoSlideShow.cpp @@ -299,7 +299,7 @@ void PhotoSlideShow::setFullScreen() if (!isFullScreen()) { // hide menu & toolbars -#ifdef Q_WS_X11 +#ifdef Q_OS_LINUX show(); raise(); setWindowState( windowState() | Qt::WindowFullScreen ); diff --git a/retroshare-gui/src/gui/QuickStartWizard.cpp b/retroshare-gui/src/gui/QuickStartWizard.cpp index 297030509..bc684b7bf 100644 --- a/retroshare-gui/src/gui/QuickStartWizard.cpp +++ b/retroshare-gui/src/gui/QuickStartWizard.cpp @@ -66,7 +66,7 @@ QuickStartWizard::QuickStartWizard(QWidget *parent) : ui.shareddirList->horizontalHeader()->setStretchLastSection(false); /* Hide platform specific features */ -#ifndef Q_WS_WIN +#ifndef Q_OS_WIN ui.checkBoxRunRetroshareAtSystemStartup->setVisible(false); ui.chkRunRetroshareAtSystemStartupMinimized->setVisible(false); #endif @@ -192,7 +192,7 @@ void QuickStartWizard::on_pushButtonSystemFinish_clicked() { Settings->setStartMinimized(ui.checkBoxStartMinimized->isChecked()); Settings->setValue("doQuit", ui.checkBoxQuit->isChecked()); -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN Settings->setRunRetroshareOnBoot(ui.checkBoxRunRetroshareAtSystemStartup->isChecked(), ui.chkRunRetroshareAtSystemStartupMinimized->isChecked()); #endif @@ -381,7 +381,7 @@ bool QuickStartWizard::messageBoxOk(QString msg) void QuickStartWizard::loadGeneral() { -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN bool minimized; ui.checkBoxRunRetroshareAtSystemStartup->setChecked(Settings->runRetroshareOnBoot(minimized)); ui.chkRunRetroshareAtSystemStartupMinimized->setChecked(minimized); diff --git a/retroshare-gui/src/gui/SearchDialog.cpp b/retroshare-gui/src/gui/SearchDialog.cpp index ef813d8f7..ea2a7d933 100644 --- a/retroshare-gui/src/gui/SearchDialog.cpp +++ b/retroshare-gui/src/gui/SearchDialog.cpp @@ -213,10 +213,6 @@ SearchDialog::SearchDialog(QWidget *parent) checkText(ui.lineEdit->text()); -/* Hide platform specific features */ -#ifdef Q_WS_WIN - -#endif } SearchDialog::~SearchDialog() diff --git a/retroshare-gui/src/gui/common/Emoticons.cpp b/retroshare-gui/src/gui/common/Emoticons.cpp index 8b2041e27..9ba3b1501 100644 --- a/retroshare-gui/src/gui/common/Emoticons.cpp +++ b/retroshare-gui/src/gui/common/Emoticons.cpp @@ -40,7 +40,7 @@ void Emoticons::load() QString sm_codes; bool internalEmoticons = true; -#if defined(Q_OS_WIN32) +#if defined(Q_OS_WIN) // first try external emoticons QFile sm_file(QApplication::applicationDirPath() + "/emoticons/emotes.acs"); if(sm_file.open(QIODevice::ReadOnly)) diff --git a/retroshare-gui/src/gui/common/RSGraphWidget.cpp b/retroshare-gui/src/gui/common/RSGraphWidget.cpp index 2f0e83d65..6d92166a4 100644 --- a/retroshare-gui/src/gui/common/RSGraphWidget.cpp +++ b/retroshare-gui/src/gui/common/RSGraphWidget.cpp @@ -518,7 +518,7 @@ void RSGraphWidget::paintTotals() int x = SCALE_WIDTH*fact + FS, y = 0; int rowHeight = FS; -#if !defined(Q_WS_MAC) +#if !defined(Q_OS_MAC) /* On Mac, we don't need vertical spacing between the text rows. */ rowHeight += 5; #endif diff --git a/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp b/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp index fa4515af4..80aaf7698 100755 --- a/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp +++ b/retroshare-gui/src/gui/connect/ConnectFriendWizard.cpp @@ -77,7 +77,7 @@ ConnectFriendWizard::ConnectFriendWizard(QWidget *parent) : mTitleFontWeight = 0; // Standard // this define comes from Qt example. I don't have mac, so it wasn't tested -#ifndef Q_WS_MAC +#ifndef Q_OS_MAC setWizardStyle(ModernStyle); #endif @@ -568,7 +568,7 @@ void ConnectFriendWizard::initializePage(int id) static void sendMail(QString sAddress, QString sSubject, QString sBody) { -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN /* search and replace the end of lines with: "%0D%0A" */ sBody.replace("\n", "%0D%0A"); #endif diff --git a/retroshare-gui/src/gui/help/browser/helpbrowser.cpp b/retroshare-gui/src/gui/help/browser/helpbrowser.cpp index 333a80f69..46f88da3c 100644 --- a/retroshare-gui/src/gui/help/browser/helpbrowser.cpp +++ b/retroshare-gui/src/gui/help/browser/helpbrowser.cpp @@ -58,10 +58,10 @@ HelpBrowser::HelpBrowser(QWidget *parent) { /* Invoke Qt Designer generated QObject setup routine */ ui.setupUi(this); -#if defined(Q_WS_MAC) +#if defined(Q_OS_MAC) ui.actionHome->setShortcut(QString("Shift+Ctrl+H")); #endif -#if !defined(Q_WS_WIN) +#if !defined(Q_OS_WIN) ui.actionClose->setShortcut(QString("Ctrl+W")); #endif diff --git a/retroshare-gui/src/gui/settings/GeneralPage.cpp b/retroshare-gui/src/gui/settings/GeneralPage.cpp index cbe3ecda0..3eea9c701 100755 --- a/retroshare-gui/src/gui/settings/GeneralPage.cpp +++ b/retroshare-gui/src/gui/settings/GeneralPage.cpp @@ -42,7 +42,7 @@ GeneralPage::GeneralPage(QWidget * parent, Qt::WindowFlags flags) connect(ui.runStartWizard_PB,SIGNAL(clicked()), this,SLOT(runStartWizard())) ; /* Hide platform specific features */ -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN #ifdef QT_DEBUG ui.chkRunRetroshareAtSystemStartup->setEnabled(false); @@ -79,7 +79,7 @@ bool GeneralPage::save(QString &/*errmsg*/) Settings->setValue("doQuit", ui.checkQuit->isChecked()); Settings->setCloseToTray(ui.checkCloseToTray->isChecked()); -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN #ifndef QT_DEBUG Settings->setRunRetroshareOnBoot(ui.chkRunRetroshareAtSystemStartup->isChecked(), ui.chkRunRetroshareAtSystemStartupMinimized->isChecked()); @@ -117,7 +117,7 @@ bool GeneralPage::save(QString &/*errmsg*/) /** Loads the settings for this page */ void GeneralPage::load() { -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN bool minimized; ui.chkRunRetroshareAtSystemStartup->setChecked(Settings->runRetroshareOnBoot(minimized)); ui.chkRunRetroshareAtSystemStartupMinimized->setChecked(minimized); diff --git a/retroshare-gui/src/gui/settings/rsharesettings.cpp b/retroshare-gui/src/gui/settings/rsharesettings.cpp index c803872d6..83fbf0563 100644 --- a/retroshare-gui/src/gui/settings/rsharesettings.cpp +++ b/retroshare-gui/src/gui/settings/rsharesettings.cpp @@ -33,7 +33,7 @@ #include #include -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) #include #endif @@ -60,7 +60,7 @@ /* Default Retroshare Settings */ #define DEFAULT_OPACITY 100 -#if defined(Q_OS_WIN32) +#if defined(Q_OS_WIN) #define STARTUP_REG_KEY "Software\\Microsoft\\Windows\\CurrentVersion\\Run" #define RETROSHARE_REG_KEY "RetroShare" #endif @@ -104,11 +104,11 @@ void RshareSettings::initSettings() // use GTK as default style on ubuntu setDefault(SETTING_STYLE, "GTK+"); #else -#if defined(Q_WS_MAC) +#if defined(Q_OS_MAC) setDefault(SETTING_STYLE, "macintosh (aqua)"); #else static QStringList styles = QStyleFactory::keys(); -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) if (styles.contains("windowsvista", Qt::CaseInsensitive)) setDefault(SETTING_STYLE, "windowsvista"); else if (styles.contains("windowsxp", Qt::CaseInsensitive)) @@ -710,7 +710,7 @@ RshareSettings::runRetroshareOnBoot(bool &minimized) { minimized = false; -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) QString value = win32_registry_get_key_value(STARTUP_REG_KEY, RETROSHARE_REG_KEY); if (!value.isEmpty()) { @@ -729,9 +729,9 @@ RshareSettings::runRetroshareOnBoot(bool &minimized) void RshareSettings::setRunRetroshareOnBoot(bool run, bool minimized) { -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) if (run) { - QString value = "\"" + QDir::convertSeparators(QCoreApplication::applicationFilePath()) + "\""; + QString value = "\"" + QDir::toNativeSeparators(QCoreApplication::applicationFilePath()) + "\""; if (minimized) { value += " -m"; @@ -748,17 +748,17 @@ RshareSettings::setRunRetroshareOnBoot(bool run, bool minimized) #endif } -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) static QString getAppPathForProtocol() { - return "\"" + QDir::convertSeparators(QCoreApplication::applicationFilePath()) + "\" -r \"%1\""; + return "\"" + QDir::toNativeSeparators(QCoreApplication::applicationFilePath()) + "\" -r \"%1\""; } #endif /** Returns true if retroshare:// is registered as protocol */ bool RshareSettings::getRetroShareProtocol() { -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) /* Check key */ QSettings retroshare("HKEY_CLASSES_ROOT\\retroshare", QSettings::NativeFormat); if (retroshare.contains("Default")) { @@ -780,7 +780,7 @@ bool RshareSettings::getRetroShareProtocol() /** Returns true if the user can set retroshare as protocol */ bool RshareSettings::canSetRetroShareProtocol() { -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) QSettings retroshare("HKEY_CLASSES_ROOT\\retroshare", QSettings::NativeFormat); return retroshare.isWritable(); #else @@ -791,7 +791,7 @@ bool RshareSettings::canSetRetroShareProtocol() /** Register retroshare:// as protocol */ bool RshareSettings::setRetroShareProtocol(bool value) { -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) if (value) { QSettings retroshare("HKEY_CLASSES_ROOT\\retroshare", QSettings::NativeFormat); retroshare.setValue("Default", "URL: RetroShare protocol"); diff --git a/retroshare-gui/src/gui/statistics/BandwidthGraphWindow.cpp b/retroshare-gui/src/gui/statistics/BandwidthGraphWindow.cpp index bc8c0c1bd..cd01dd25d 100644 --- a/retroshare-gui/src/gui/statistics/BandwidthGraphWindow.cpp +++ b/retroshare-gui/src/gui/statistics/BandwidthGraphWindow.cpp @@ -57,7 +57,7 @@ BandwidthGraph::BandwidthGraph(QWidget *parent, Qt::WindowFlags flags) { /* Invoke Qt Designer generated QObject setup routine */ ui.setupUi(this); -#if defined(Q_WS_WIN) +#if defined(Q_OS_WIN) setShortcut("Esc", SLOT(close())); #else setShortcut("Ctrl+W", SLOT(close())); @@ -78,13 +78,13 @@ BandwidthGraph::BandwidthGraph(QWidget *parent, Qt::WindowFlags flags) loadSettings(); /* Turn off opacity group on unsupported platforms */ - #if defined(Q_WS_WIN) + #if defined(Q_OS_WIN) if(!(QSysInfo::WV_2000 <= QSysInfo::WindowsVersion && QSysInfo::WindowsVersion <= QSysInfo::WV_2003)) { ui.frmOpacity->setVisible(false); } #endif - #if defined(Q_WS_X11) + #if defined(Q_OS_LINUX) ui.frmOpacity->setVisible(false); #endif } @@ -236,10 +236,10 @@ void BandwidthGraph::setOpacity(int value) qreal newValue = value / 100.0; /* Opacity only supported by Mac and Win32 */ -#if defined(Q_WS_MAC) +#if defined(Q_OS_MAC) this->setWindowOpacity(newValue); ui.lblPercentOpacity->setText(QString::number(value)); -#elif defined(Q_WS_WIN) +#elif defined(Q_OS_WIN) if(QSysInfo::WV_2000 <= QSysInfo::WindowsVersion && QSysInfo::WindowsVersion <= QSysInfo::WV_2003) { this->setWindowOpacity(newValue); ui.lblPercentOpacity->setText(QString::number(value)); diff --git a/retroshare-gui/src/rshare.cpp b/retroshare-gui/src/rshare.cpp index 8c049b3c5..4528215d4 100644 --- a/retroshare-gui/src/rshare.cpp +++ b/retroshare-gui/src/rshare.cpp @@ -613,7 +613,7 @@ Rshare::dataDirectory() QString Rshare::defaultDataDirectory() { -#if defined(Q_OS_WIN32) +#if defined(Q_OS_WIN) return (win32_app_data_folder() + "\\RetroShare"); #else return (QDir::homePath() + "/.RetroShare"); diff --git a/retroshare-gui/src/util/printpreview.cpp b/retroshare-gui/src/util/printpreview.cpp index 8e920417e..73bc09ca4 100644 --- a/retroshare-gui/src/util/printpreview.cpp +++ b/retroshare-gui/src/util/printpreview.cpp @@ -54,7 +54,7 @@ #include #include -#ifdef Q_WS_MAC +#ifdef Q_OS_MAC const QString rsrcPath = ":/images/mac"; #else const QString rsrcPath = ":/images/win"; From bd3f7f6d38b3cc4952905420c3ebabe2036cf7ce Mon Sep 17 00:00:00 2001 From: hunbernd Date: Sat, 29 Aug 2015 21:45:30 +0200 Subject: [PATCH 136/165] Removed limit on opacity setting with recent windows versions on BandwidthGraphDialog Conflicts: retroshare-gui/src/gui/statistics/BandwidthGraphWindow.cpp --- retroshare-gui/src/gui/statistics/BandwidthGraphWindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/statistics/BandwidthGraphWindow.cpp b/retroshare-gui/src/gui/statistics/BandwidthGraphWindow.cpp index cd01dd25d..27bd8bb4b 100644 --- a/retroshare-gui/src/gui/statistics/BandwidthGraphWindow.cpp +++ b/retroshare-gui/src/gui/statistics/BandwidthGraphWindow.cpp @@ -79,7 +79,7 @@ BandwidthGraph::BandwidthGraph(QWidget *parent, Qt::WindowFlags flags) /* Turn off opacity group on unsupported platforms */ #if defined(Q_OS_WIN) - if(!(QSysInfo::WV_2000 <= QSysInfo::WindowsVersion && QSysInfo::WindowsVersion <= QSysInfo::WV_2003)) { + if(!(QSysInfo::WV_2000 <= QSysInfo::WindowsVersion)) { ui.frmOpacity->setVisible(false); } #endif @@ -240,7 +240,7 @@ void BandwidthGraph::setOpacity(int value) this->setWindowOpacity(newValue); ui.lblPercentOpacity->setText(QString::number(value)); #elif defined(Q_OS_WIN) - if(QSysInfo::WV_2000 <= QSysInfo::WindowsVersion && QSysInfo::WindowsVersion <= QSysInfo::WV_2003) { + if(QSysInfo::WV_2000 <= QSysInfo::WindowsVersion) { this->setWindowOpacity(newValue); ui.lblPercentOpacity->setText(QString::number(value)); } From 5f81d8efc8105d3c01e4510fbc5380a13854fcad Mon Sep 17 00:00:00 2001 From: AsamK Date: Mon, 31 Aug 2015 01:38:09 +0200 Subject: [PATCH 137/165] Remove nick from anchor names, causes problems - Nicknames that contain " could break the formatting - Nicknames containing chars like < or > were converted to html entities by the QTextBrowser so the anchor was no longer identical with the anchor stored in the _listMsg list --- retroshare-gui/src/gui/chat/ChatLobbyUserNotify.cpp | 3 +-- retroshare-gui/src/gui/chat/ChatWidget.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/retroshare-gui/src/gui/chat/ChatLobbyUserNotify.cpp b/retroshare-gui/src/gui/chat/ChatLobbyUserNotify.cpp index 68c31417b..2f0054f7b 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyUserNotify.cpp +++ b/retroshare-gui/src/gui/chat/ChatLobbyUserNotify.cpp @@ -257,9 +257,8 @@ void ChatLobbyUserNotify::chatLobbyNewMessage(ChatLobbyId lobby_id, QDateTime ti if ((bGetNickName || bFoundTextToNotify || _bCountUnRead)){ QString strAnchor = time.toString(Qt::ISODate); - strAnchor.append("_").append(senderName); MsgData msgData; - msgData.text=msg; + msgData.text=senderName + ": " + msg; msgData.unread=!(bGetNickName || bFoundTextToNotify); _listMsg[lobby_id][strAnchor]=msgData; diff --git a/retroshare-gui/src/gui/chat/ChatWidget.cpp b/retroshare-gui/src/gui/chat/ChatWidget.cpp index b5adf84d7..ac6a66152 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.cpp +++ b/retroshare-gui/src/gui/chat/ChatWidget.cpp @@ -902,7 +902,7 @@ void ChatWidget::addChatMsg(bool incoming, const QString &name, const QDateTime QString formatMsg = chatStyle.formatMessage(type, name, dtTimestamp, formattedMessage, formatFlag); QString timeStamp = dtTimestamp.toString(Qt::ISODate); - formatMsg.prepend(QString("").arg(timeStamp).arg(name)); + formatMsg.prepend(QString("").arg(timeStamp)); //To call this anchor do: ui->textBrowser->scrollToAnchor(QString("%1_%2").arg(timeStamp).arg(name)); QTextCursor textCursor = QTextCursor(ui->textBrowser->textCursor()); textCursor.movePosition(QTextCursor::End); From bd6bb8996be14f89a16eede7c5c05fb06de7be6d Mon Sep 17 00:00:00 2001 From: AsamK Date: Mon, 31 Aug 2015 02:09:55 +0200 Subject: [PATCH 138/165] Improve performance of eventFilter in chat lobbies - Only check the anchors if the visible content has actually changed by saving lastUpdateCursorPos and End - Check notify first, before doing any work - Simplify regexp as the anchors have a fixed format - Remove unnecessary conversion to utf8 and back --- retroshare-gui/src/gui/chat/ChatWidget.cpp | 28 ++++++++++------------ retroshare-gui/src/gui/chat/ChatWidget.h | 3 +++ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/retroshare-gui/src/gui/chat/ChatWidget.cpp b/retroshare-gui/src/gui/chat/ChatWidget.cpp index ac6a66152..42344c4c8 100644 --- a/retroshare-gui/src/gui/chat/ChatWidget.cpp +++ b/retroshare-gui/src/gui/chat/ChatWidget.cpp @@ -448,7 +448,7 @@ bool ChatWidget::eventFilter(QObject *obj, QEvent *event) } } - if (chatType() == CHATTYPE_LOBBY) { + if (notify && chatType() == CHATTYPE_LOBBY) { if ((event->type() == QEvent::KeyPress) || (event->type() == QEvent::MouseMove) || (event->type() == QEvent::Enter) @@ -460,9 +460,11 @@ bool ChatWidget::eventFilter(QObject *obj, QEvent *event) QPoint bottom_right(ui->textBrowser->viewport()->width() - 1, ui->textBrowser->viewport()->height() - 1); int end_pos = ui->textBrowser->cursorForPosition(bottom_right).position(); cursor.setPosition(end_pos, QTextCursor::KeepAnchor); - - if (!cursor.selectedText().isEmpty()){ - QRegExp rx("toUtf8(); - std::string stdString=std::string(bytArray.begin(),bytArray.end()); - if (notify) notify->chatLobbyCleared(chatId.toLobbyId() - ,QString::fromUtf8(stdString.c_str()) - ,obj != ui->textBrowser && obj != ui->textBrowser->viewport());//, true); + notify->chatLobbyCleared(chatId.toLobbyId(), *it); } - } + } } } } @@ -490,11 +488,11 @@ bool ChatWidget::eventFilter(QObject *obj, QEvent *event) QKeyEvent *keyEvent = static_cast(event); if (keyEvent) { - if (keyEvent->key() == Qt::Key_Delete ) { + if (notify && keyEvent->key() == Qt::Key_Delete) { // Delete key pressed if (ui->textBrowser->textCursor().selectedText().length() > 0) { if (chatType() == CHATTYPE_LOBBY) { - QRegExp rx("textBrowser->textCursor().selection().toHtml(); QStringList anchors; @@ -505,9 +503,7 @@ bool ChatWidget::eventFilter(QObject *obj, QEvent *event) } for (QStringList::iterator it=anchors.begin();it!=anchors.end();++it) { - QByteArray bytArray=it->toUtf8(); - std::string stdString=std::string(bytArray.begin(),bytArray.end()); - if (notify) notify->chatLobbyCleared(chatId.toLobbyId(), QString::fromUtf8(stdString.c_str())); + notify->chatLobbyCleared(chatId.toLobbyId(), *it); } } @@ -529,7 +525,7 @@ bool ChatWidget::eventFilter(QObject *obj, QEvent *event) cursor.select(QTextCursor::WordUnderCursor); QString toolTipText = ""; if (!cursor.selectedText().isEmpty()){ - QRegExp rx(" Date: Mon, 31 Aug 2015 16:38:28 +0200 Subject: [PATCH 139/165] Escape name before inserting in name changed message and in anchor info --- retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp | 2 +- retroshare-gui/src/gui/chat/ChatLobbyUserNotify.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp index 7bc1e8c1f..a72c72bae 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp @@ -671,7 +671,7 @@ void ChatLobbyDialog::displayLobbyEvent(int event_type, const RsGxsId& gxs_id, c ui.chatWidget->addChatMsg(true, tr("Lobby management"), QDateTime::currentDateTime(), QDateTime::currentDateTime(), - tr("%1 changed his name to: %2").arg(name).arg(newname), + tr("%1 changed his name to: %2").arg(RsHtml::plainText(name)).arg(RsHtml::plainText(newname)), ChatWidget::MSGTYPE_SYSTEM); // TODO if a user was muted and changed his name, update mute list, but only, when the muted peer, dont change his name to a other peer in your chat lobby diff --git a/retroshare-gui/src/gui/chat/ChatLobbyUserNotify.cpp b/retroshare-gui/src/gui/chat/ChatLobbyUserNotify.cpp index 2f0054f7b..bed476b7f 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyUserNotify.cpp +++ b/retroshare-gui/src/gui/chat/ChatLobbyUserNotify.cpp @@ -28,6 +28,7 @@ #include "gui/settings/rsharesettings.h" #include "util/DateTime.h" #include +#include ChatLobbyUserNotify::ChatLobbyUserNotify(QObject *parent) : UserNotify(parent) @@ -258,7 +259,7 @@ void ChatLobbyUserNotify::chatLobbyNewMessage(ChatLobbyId lobby_id, QDateTime ti if ((bGetNickName || bFoundTextToNotify || _bCountUnRead)){ QString strAnchor = time.toString(Qt::ISODate); MsgData msgData; - msgData.text=senderName + ": " + msg; + msgData.text=RsHtml::plainText(senderName) + ": " + msg; msgData.unread=!(bGetNickName || bFoundTextToNotify); _listMsg[lobby_id][strAnchor]=msgData; From 5d4e94c6718cdcbf32d70de02c757cfef33e989f Mon Sep 17 00:00:00 2001 From: electron128 Date: Mon, 31 Aug 2015 19:44:15 +0200 Subject: [PATCH 140/165] libresapi: add basic forum read api (patch from Chozabu) close #32 --- libresapi/src/api/ApiServer.cpp | 4 + libresapi/src/api/ApiServer.h | 1 + libresapi/src/api/ForumHandler.cpp | 148 +++++++++++++++++++++++++++++ libresapi/src/api/ForumHandler.h | 20 ++++ libresapi/src/libresapi.pro | 2 + 5 files changed, 175 insertions(+) create mode 100644 libresapi/src/api/ForumHandler.cpp create mode 100644 libresapi/src/api/ForumHandler.h diff --git a/libresapi/src/api/ApiServer.cpp b/libresapi/src/api/ApiServer.cpp index 994df8a75..842308e2b 100644 --- a/libresapi/src/api/ApiServer.cpp +++ b/libresapi/src/api/ApiServer.cpp @@ -225,6 +225,7 @@ public: ApiServerMainModules(ResourceRouter& router, StateTokenServer* sts, const RsPlugInInterfaces &ifaces): mPeersHandler(sts, ifaces.mNotify, ifaces.mPeers, ifaces.mMsgs), mIdentityHandler(ifaces.mIdentity), + mForumHandler(ifaces.mGxsForums), mServiceControlHandler(rsServiceControl), // TODO: don't use global variable here mFileSearchHandler(sts, ifaces.mNotify, ifaces.mTurtle, ifaces.mFiles), mTransfersHandler(sts, ifaces.mFiles), @@ -238,6 +239,8 @@ public: &PeersHandler::handleRequest); router.addResourceHandler("identity", dynamic_cast(&mIdentityHandler), &IdentityHandler::handleRequest); + router.addResourceHandler("forums", dynamic_cast(&mForumHandler), + &ForumHandler::handleRequest); router.addResourceHandler("servicecontrol", dynamic_cast(&mServiceControlHandler), &ServiceControlHandler::handleRequest); router.addResourceHandler("filesearch", dynamic_cast(&mFileSearchHandler), @@ -250,6 +253,7 @@ public: PeersHandler mPeersHandler; IdentityHandler mIdentityHandler; + ForumHandler mForumHandler; ServiceControlHandler mServiceControlHandler; FileSearchHandler mFileSearchHandler; TransfersHandler mTransfersHandler; diff --git a/libresapi/src/api/ApiServer.h b/libresapi/src/api/ApiServer.h index becb21641..10b4c92b0 100644 --- a/libresapi/src/api/ApiServer.h +++ b/libresapi/src/api/ApiServer.h @@ -5,6 +5,7 @@ #include "ApiTypes.h" #include "PeersHandler.h" #include "IdentityHandler.h" +#include "ForumHandler.h" #include "ServiceControlHandler.h" #include "StateTokenServer.h" #include "FileSearchHandler.h" diff --git a/libresapi/src/api/ForumHandler.cpp b/libresapi/src/api/ForumHandler.cpp new file mode 100644 index 000000000..6d312958f --- /dev/null +++ b/libresapi/src/api/ForumHandler.cpp @@ -0,0 +1,148 @@ +#include "ForumHandler.h" + +#include +#include + +#include "Operators.h" +#include "ApiTypes.h" +#include "GxsResponseTask.h" +#ifndef WINDOWS_SYS +#include "unistd.h" +#endif + +namespace resource_api +{ +ForumHandler::ForumHandler(RsGxsForums* forums): + mRsGxsForums(forums) +{ + addResourceHandler("*", this, &ForumHandler::handleWildcard); +} + +void ForumHandler::handleWildcard(Request &req, Response &resp) +{ + bool ok = true; + if(!req.mPath.empty()) + { + std::string str = req.mPath.top(); + req.mPath.pop(); + if(str != "") + { + //assume we have a groupID + RsGxsGroupId grpId(str); + std::list groupIds; + groupIds.push_back(grpId); + + uint32_t token; + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA; + mRsGxsForums->getTokenService()->requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, groupIds); + + time_t start = time(NULL); + while((mRsGxsForums->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + &&(mRsGxsForums->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + &&((time(NULL) < (start+10))) + ) + { + #ifdef WINDOWS_SYS + Sleep(500); + #else + usleep(500*1000) ; + #endif + } + + if(mRsGxsForums->getTokenService()->requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + { + std::vector grps; + ok &= mRsGxsForums->getMsgData(token, grps); + for(std::vector::iterator vit = grps.begin(); vit != grps.end(); vit++) + { + RsGxsForumMsg& grp = *vit; + KeyValueReference group_id("group_id", grp.mMeta.mGroupId); + resp.mDataStream.getStreamToMember() + << group_id + << makeKeyValueReference("name", grp.mMeta.mMsgName) + << makeKeyValueReference("id", grp.mMeta.mMsgId) + << makeKeyValueReference("parent_id", grp.mMeta.mParentId) + << makeKeyValueReference("author_id", grp.mMeta.mAuthorId) + << makeKeyValueReference("orig_msg_id", grp.mMeta.mOrigMsgId) + << makeKeyValueReference("thread_id", grp.mMeta.mThreadId) + << makeKeyValueReference("message", grp.mMsg); + } + } + else + { + ok = false; + } + + } + + } + else + { + // no more path element + RsTokReqOptions opts; + opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA; + uint32_t token; + mRsGxsForums->getTokenService()->requestGroupInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts); + + time_t start = time(NULL); + while((mRsGxsForums->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + &&(mRsGxsForums->getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED) + &&((time(NULL) < (start+10))) + ) + { + #ifdef WINDOWS_SYS + Sleep(500); + #else + usleep(500*1000) ; + #endif + } + if(mRsGxsForums->getTokenService()->requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE) + { + std::vector grps; + ok &= mRsGxsForums->getGroupData(token, grps); + for(std::vector::iterator vit = grps.begin(); vit != grps.end(); vit++) + { + RsGxsForumGroup& grp = *vit; + KeyValueReference id("id", grp.mMeta.mGroupId); + KeyValueReference vis_msg("visible_msg_count", grp.mMeta.mVisibleMsgCount); + //KeyValueReference pgp_id("pgp_id",grp.mPgpId ); + // not very happy about this, i think the flags should stay hidden in rsidentities + bool own = (grp.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN); + bool pgp_linked = (grp.mMeta.mGroupFlags & RSGXSID_GROUPFLAG_REALID); + bool subscribed = IS_GROUP_SUBSCRIBED(grp.mMeta.mSubscribeFlags); + resp.mDataStream.getStreamToMember() + << id + //<< pgp_id + << makeKeyValueReference("name", grp.mMeta.mGroupName) + //<< makeKeyValueReference("last_post", grp.mMeta.mLastPost) + << makeKeyValueReference("pop", grp.mMeta.mPop) + //<< makeKeyValueReference("publish_ts", grp.mMeta.mPublishTs) + << vis_msg + << makeKeyValueReference("group_status", grp.mMeta.mGroupStatus) + << makeKeyValueReference("author_id", grp.mMeta.mAuthorId) + << makeKeyValueReference("parent_grp_id", grp.mMeta.mParentGrpId) + << makeKeyValueReference("description", grp.mDescription) + << makeKeyValueReference("own", own) + << makeKeyValueReference("subscribed", subscribed) + << makeKeyValueReference("pgp_linked", pgp_linked); + } + } + else + { + ok = false; + } + } + + + if(ok) + { + resp.setOk(); + } + else + { + resp.setFail(); + } +} + +} // namespace resource_api diff --git a/libresapi/src/api/ForumHandler.h b/libresapi/src/api/ForumHandler.h new file mode 100644 index 000000000..e44b19818 --- /dev/null +++ b/libresapi/src/api/ForumHandler.h @@ -0,0 +1,20 @@ +#ifndef FORUMHANDLER_H +#define FORUMHANDLER_H + +#include "ResourceRouter.h" + +class RsGxsForums; + +namespace resource_api +{ + +class ForumHandler : public ResourceRouter +{ +public: + ForumHandler(RsGxsForums* forums); +private: + RsGxsForums* mRsGxsForums; + void handleWildcard(Request& req, Response& resp); +}; +} // namespace resource_api +#endif // FORUMHANDLER_H diff --git a/libresapi/src/libresapi.pro b/libresapi/src/libresapi.pro index b71f50f24..a7a081701 100644 --- a/libresapi/src/libresapi.pro +++ b/libresapi/src/libresapi.pro @@ -29,6 +29,7 @@ SOURCES += \ api/PeersHandler.cpp \ api/Operators.cpp \ api/IdentityHandler.cpp \ + api/ForumHandler.cpp \ api/ServiceControlHandler.cpp \ api/StateTokenServer.cpp \ api/GxsResponseTask.cpp \ @@ -49,6 +50,7 @@ HEADERS += \ api/PeersHandler.h \ api/Operators.h \ api/IdentityHandler.h \ + api/ForumHandler.h \ api/ServiceControlHandler.h \ api/GxsMetaOperators.h \ api/StateTokenServer.h \ From e135e3441cde7b2fd18ae5735feb172c599df224 Mon Sep 17 00:00:00 2001 From: AsamK Date: Mon, 31 Aug 2015 17:55:30 +0200 Subject: [PATCH 141/165] Create retroshare.pri for common configurations in .pro files So far it only contains the default values for installation paths --- RetroShare.pro | 7 ++----- libbitdht/src/libbitdht.pro | 2 ++ libresapi/src/libresapi.pro | 2 ++ libretroshare/src/libretroshare.pro | 7 ++----- openpgpsdk/src/openpgpsdk.pro | 2 ++ plugins/Common/retroshare_plugin.pri | 5 ++--- retroshare-gui/src/retroshare-gui.pro | 5 ++--- retroshare-nogui/src/retroshare-nogui.pro | 4 ++-- retroshare.pri | 6 ++++++ 9 files changed, 22 insertions(+), 18 deletions(-) create mode 100644 retroshare.pri diff --git a/RetroShare.pro b/RetroShare.pro index b6df6e491..aaa1bbfde 100644 --- a/RetroShare.pro +++ b/RetroShare.pro @@ -1,3 +1,5 @@ +!include("retroshare.pri"): error("Could not include file retroshare.pri") + TEMPLATE = subdirs SUBDIRS += \ @@ -32,11 +34,6 @@ plugins.file = plugins/plugins.pro plugins.depends = retroshare_gui unix { - isEmpty(PREFIX) { PREFIX = /usr } - isEmpty(INC_DIR) { INC_DIR = "$${PREFIX}/include/retroshare06" } - isEmpty(LIB_DIR) { LIB_DIR = "$${PREFIX}/lib" } - isEmpty(DATA_DIR) { DATA_DIR = "$${PREFIX}/share/RetroShare06" } - icon_files.path = "$${PREFIX}/share/icons/hicolor" icon_files.files = data/24x24 icon_files.files += data/48x48 diff --git a/libbitdht/src/libbitdht.pro b/libbitdht/src/libbitdht.pro index 6f705fa7d..ed576a700 100644 --- a/libbitdht/src/libbitdht.pro +++ b/libbitdht/src/libbitdht.pro @@ -1,3 +1,5 @@ +!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") + TEMPLATE = lib CONFIG += staticlib CONFIG -= qt diff --git a/libresapi/src/libresapi.pro b/libresapi/src/libresapi.pro index a7a081701..cc12e1503 100644 --- a/libresapi/src/libresapi.pro +++ b/libresapi/src/libresapi.pro @@ -1,3 +1,5 @@ +!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") + TEMPLATE = lib CONFIG += staticlib CONFIG -= qt diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index dca32bcd1..ba29fa605 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -1,3 +1,5 @@ +!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") + TEMPLATE = lib CONFIG += staticlib bitdht CONFIG -= qt @@ -168,11 +170,6 @@ linux-* { } unix { - isEmpty(PREFIX) { PREFIX = /usr } - isEmpty(INC_DIR) { INC_DIR = "$${PREFIX}/include/retroshare06" } - isEmpty(LIB_DIR) { LIB_DIR = "$${PREFIX}/lib" } - isEmpty(DATA_DIR) { DATA_DIR = "$${PREFIX}/share/RetroShare06" } - DEFINES *= LIB_DIR=\"\\\"$${LIB_DIR}\\\"\" DEFINES *= DATA_DIR=\"\\\"$${DATA_DIR}\\\"\" diff --git a/openpgpsdk/src/openpgpsdk.pro b/openpgpsdk/src/openpgpsdk.pro index c0f741857..786ee5819 100644 --- a/openpgpsdk/src/openpgpsdk.pro +++ b/openpgpsdk/src/openpgpsdk.pro @@ -1,3 +1,5 @@ +!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") + TEMPLATE = lib win32 { CONFIG += staticlib diff --git a/plugins/Common/retroshare_plugin.pri b/plugins/Common/retroshare_plugin.pri index e77626dc6..d20c1baa4 100644 --- a/plugins/Common/retroshare_plugin.pri +++ b/plugins/Common/retroshare_plugin.pri @@ -1,3 +1,5 @@ +!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") + TEMPLATE = lib CONFIG *= plugin @@ -5,9 +7,6 @@ DEPENDPATH += ../../libretroshare/src/ ../../retroshare-gui/src/ INCLUDEPATH += ../../libretroshare/src/ ../../retroshare-gui/src/ unix { - isEmpty(PREFIX) { PREFIX = /usr } - isEmpty(LIB_DIR) { LIB_DIR = "$${PREFIX}/lib" } - target.path = "$${LIB_DIR}/retroshare/extensions6" INSTALLS += target } diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 6e61a81e2..6632c871f 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -1,3 +1,5 @@ +!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") + QT += network xml script CONFIG += qt gui uic qrc resources idle bitdht @@ -110,9 +112,6 @@ linux-* { } unix { - isEmpty(PREFIX) { PREFIX = /usr } - isEmpty(DATA_DIR) { DATA_DIR = "$${PREFIX}/share/RetroShare06" } - target.path = "$${PREFIX}/bin" INSTALLS += target diff --git a/retroshare-nogui/src/retroshare-nogui.pro b/retroshare-nogui/src/retroshare-nogui.pro index 9d590efba..52dde1f02 100644 --- a/retroshare-nogui/src/retroshare-nogui.pro +++ b/retroshare-nogui/src/retroshare-nogui.pro @@ -1,3 +1,5 @@ +!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") + TEMPLATE = app TARGET = RetroShare06-nogui CONFIG += bitdht @@ -56,8 +58,6 @@ linux-* { } unix { - isEmpty(PREFIX) { PREFIX = /usr } - target.path = "$${PREFIX}/bin" INSTALLS += target } diff --git a/retroshare.pri b/retroshare.pri new file mode 100644 index 000000000..fb20b1984 --- /dev/null +++ b/retroshare.pri @@ -0,0 +1,6 @@ +unix { + isEmpty(PREFIX) { PREFIX = "/usr" } + isEmpty(INC_DIR) { INC_DIR = "$${PREFIX}/include/retroshare06" } + isEmpty(LIB_DIR) { LIB_DIR = "$${PREFIX}/lib" } + isEmpty(DATA_DIR) { DATA_DIR = "$${PREFIX}/share/RetroShare06" } +} From b66f466c7a6bd2acb2fc7cf6ac5df868a463021a Mon Sep 17 00:00:00 2001 From: AsamK Date: Mon, 31 Aug 2015 18:01:18 +0200 Subject: [PATCH 142/165] Move all INSTALLS to the subproject they belong to Allows installation of for example only retroshare-nogui, without installing files only relevant for gui $ qmake $ make retroshare-nogui $ make retroshare-nogui-install_subtargets --- RetroShare.pro | 32 +++------------------------ libbitdht/src/libbitdht.pro | 7 ++++++ libresapi/src/libresapi.pro | 10 +++++++++ retroshare-gui/src/retroshare-gui.pro | 16 ++++++++++++++ 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/RetroShare.pro b/RetroShare.pro index aaa1bbfde..4a1be6b49 100644 --- a/RetroShare.pro +++ b/RetroShare.pro @@ -26,38 +26,12 @@ pegmarkdown.file = supportlibs/pegmarkdown/pegmarkdown.pro retroshare_gui.file = retroshare-gui/src/retroshare-gui.pro retroshare_gui.depends = libretroshare libresapi pegmarkdown +retroshare_gui.target = retroshare-gui retroshare_nogui.file = retroshare-nogui/src/retroshare-nogui.pro retroshare_nogui.depends = libretroshare libresapi +retroshare_nogui.target = retroshare-nogui plugins.file = plugins/plugins.pro plugins.depends = retroshare_gui - -unix { - icon_files.path = "$${PREFIX}/share/icons/hicolor" - icon_files.files = data/24x24 - icon_files.files += data/48x48 - icon_files.files += data/64x64 - icon_files.files += data/128x128 - INSTALLS += icon_files - - desktop_files.path = "$${PREFIX}/share/applications" - desktop_files.files = data/retroshare06.desktop - INSTALLS += desktop_files - - pixmap_files.path = "$${PREFIX}/share/pixmaps" - pixmap_files.files = data/retroshare06.xpm - INSTALLS += pixmap_files - - data_files.path = "$${DATA_DIR}" - data_files.files = libbitdht/src/bitdht/bdboot.txt - INSTALLS += data_files - - webui_files.path = "$${DATA_DIR}/webui" - webui_files.files = libresapi/src/webfiles/* - INSTALLS += webui_files - - webui_img_files.path = "$${DATA_DIR}/webui/img" - webui_img_files.files = retroshare-gui/src/gui/images/logo/logo_splash.png - INSTALLS += webui_img_files -} +plugins.target = plugins diff --git a/libbitdht/src/libbitdht.pro b/libbitdht/src/libbitdht.pro index ed576a700..7d6dca1d6 100644 --- a/libbitdht/src/libbitdht.pro +++ b/libbitdht/src/libbitdht.pro @@ -39,6 +39,13 @@ linux-g++-64 { OBJECTS_DIR = temp/linux-g++-64/obj } +unix { + data_files.path = "$${DATA_DIR}" + data_files.files = bitdht/bdboot.txt + INSTALLS += data_files +} + + #################### Cross compilation for windows under Linux #################### win32-x-g++ { diff --git a/libresapi/src/libresapi.pro b/libresapi/src/libresapi.pro index cc12e1503..a45255e45 100644 --- a/libresapi/src/libresapi.pro +++ b/libresapi/src/libresapi.pro @@ -10,6 +10,16 @@ CONFIG += libmicrohttpd INCLUDEPATH += ../../libretroshare/src +unix { + webui_files.path = "$${DATA_DIR}/webui" + webui_files.files = webfiles/* + INSTALLS += webui_files + + webui_img_files.path = "$${DATA_DIR}/webui/img" + webui_img_files.files = ../../retroshare-gui/src/gui/images/logo/logo_splash.png + INSTALLS += webui_img_files +} + win32{ DEFINES *= WINDOWS_SYS INCLUDEPATH += $$PWD/../../../libs/include diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 6632c871f..57a8a88d8 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -122,6 +122,22 @@ unix { style_files.path="$${DATA_DIR}/stylesheets" style_files.files=gui/qss/chat/Bubble gui/qss/chat/Bubble_Compact INSTALLS += style_files + + icon_files.path = "$${PREFIX}/share/icons/hicolor" + icon_files.files = ../../data/24x24 + icon_files.files += ../../data/48x48 + icon_files.files += ../../data/64x64 + icon_files.files += ../../data/128x128 + INSTALLS += icon_files + + desktop_files.path = "$${PREFIX}/share/applications" + desktop_files.files = ../../data/retroshare06.desktop + INSTALLS += desktop_files + + pixmap_files.path = "$${PREFIX}/share/pixmaps" + pixmap_files.files = ../../data/retroshare06.xpm + INSTALLS += pixmap_files + } linux-g++ { From b9c174ba8f1f156d788191a75a8b8a9d4c273ea7 Mon Sep 17 00:00:00 2001 From: AsamK Date: Mon, 31 Aug 2015 18:01:55 +0200 Subject: [PATCH 143/165] Add BIN_DIR variable to allow packagers to override it --- retroshare-gui/src/retroshare-gui.pro | 2 +- retroshare-nogui/src/retroshare-nogui.pro | 2 +- retroshare.pri | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 57a8a88d8..ec967c51a 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -112,7 +112,7 @@ linux-* { } unix { - target.path = "$${PREFIX}/bin" + target.path = "$${BIN_DIR}" INSTALLS += target data_files.path="$${DATA_DIR}/" diff --git a/retroshare-nogui/src/retroshare-nogui.pro b/retroshare-nogui/src/retroshare-nogui.pro index 52dde1f02..9b8136942 100644 --- a/retroshare-nogui/src/retroshare-nogui.pro +++ b/retroshare-nogui/src/retroshare-nogui.pro @@ -58,7 +58,7 @@ linux-* { } unix { - target.path = "$${PREFIX}/bin" + target.path = "$${BIN_DIR}" INSTALLS += target } diff --git a/retroshare.pri b/retroshare.pri index fb20b1984..b85b40cbc 100644 --- a/retroshare.pri +++ b/retroshare.pri @@ -1,5 +1,6 @@ unix { isEmpty(PREFIX) { PREFIX = "/usr" } + isEmpty(BIN_DIR) { BIN_DIR = "$${PREFIX}/bin" } isEmpty(INC_DIR) { INC_DIR = "$${PREFIX}/include/retroshare06" } isEmpty(LIB_DIR) { LIB_DIR = "$${PREFIX}/lib" } isEmpty(DATA_DIR) { DATA_DIR = "$${PREFIX}/share/RetroShare06" } From dca295143aee6c8e39f12b6de3f5d75eb49d268f Mon Sep 17 00:00:00 2001 From: AsamK Date: Mon, 31 Aug 2015 19:20:52 +0200 Subject: [PATCH 144/165] Use CONFIG+=create_prl for libretroshare Allows to specify all LIBS in libretroshare.pro so they don't also have to be specified in gui/nogui.pro --- libretroshare/src/libretroshare.pro | 1 + retroshare-gui/src/retroshare-gui.pro | 1 + retroshare-nogui/src/retroshare-nogui.pro | 1 + 3 files changed, 3 insertions(+) diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index ba29fa605..433c49b73 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -2,6 +2,7 @@ TEMPLATE = lib CONFIG += staticlib bitdht +CONFIG += create_prl CONFIG -= qt TARGET = retroshare diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index ec967c51a..00fd3a5e4 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -2,6 +2,7 @@ QT += network xml script CONFIG += qt gui uic qrc resources idle bitdht +CONFIG += link_prl # Plz never commit the .pro with these flags enabled. # Use this flag when developping new features only. diff --git a/retroshare-nogui/src/retroshare-nogui.pro b/retroshare-nogui/src/retroshare-nogui.pro index 9b8136942..fe5c7d6a6 100644 --- a/retroshare-nogui/src/retroshare-nogui.pro +++ b/retroshare-nogui/src/retroshare-nogui.pro @@ -8,6 +8,7 @@ CONFIG += bitdht # webinterface, requires libmicrohttpd CONFIG += webui CONFIG -= qt xml gui +CONFIG += link_prl # if you are linking against the libretroshare with gxs. # this option links against the required sqlite library. From b43e0ab2e0c4910f06da2364af6565a0d79bc4ac Mon Sep 17 00:00:00 2001 From: AsamK Date: Mon, 31 Aug 2015 23:38:50 +0200 Subject: [PATCH 145/165] Fix compile with qt < 4.7 Reenable placeholder text for lobby name, not sure why it was disabled --- retroshare-gui/src/gui/chat/CreateLobbyDialog.cpp | 9 ++++----- retroshare-gui/src/gui/chat/CreateLobbyDialog.ui | 6 +----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/retroshare-gui/src/gui/chat/CreateLobbyDialog.cpp b/retroshare-gui/src/gui/chat/CreateLobbyDialog.cpp index 05a7684f2..2d1a75829 100644 --- a/retroshare-gui/src/gui/chat/CreateLobbyDialog.cpp +++ b/retroshare-gui/src/gui/chat/CreateLobbyDialog.cpp @@ -47,11 +47,10 @@ CreateLobbyDialog::CreateLobbyDialog(const std::set& peer_list, int pr ui->idChooser_CB->loadIds(IDCHOOSER_ID_REQUIRED, default_identity); -//#if QT_VERSION >= 0x040700 -// ui->lobbyName_LE->setPlaceholderText(tr("Put a sensible lobby name here")) ; -// ui->nickName_LE->setPlaceholderText(tr("Your nickname for this lobby (Change default name in options->chat)")) ; -//#endif -// ui->nickName_LE->setText(QString::fromUtf8(default_nick.c_str())) ; +#if QT_VERSION >= 0x040700 + ui->lobbyName_LE->setPlaceholderText(tr("Put a sensible lobby name here")); + ui->lobbyTopic_LE->setPlaceholderText(tr("Set a descriptive topic here")); +#endif connect( ui->buttonBox, SIGNAL(accepted()), this, SLOT(createLobby())); connect( ui->buttonBox, SIGNAL(rejected()), this, SLOT(close())); diff --git a/retroshare-gui/src/gui/chat/CreateLobbyDialog.ui b/retroshare-gui/src/gui/chat/CreateLobbyDialog.ui index 4877a5f71..1d2340e08 100644 --- a/retroshare-gui/src/gui/chat/CreateLobbyDialog.ui +++ b/retroshare-gui/src/gui/chat/CreateLobbyDialog.ui @@ -71,11 +71,7 @@ - - - Set a descriptive topic here - - + From 3d9e3e8b7cb06fd1e7c0110e5e423cbec1c019fa Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 31 Aug 2015 22:41:38 -0400 Subject: [PATCH 146/165] attempt to setup variable bitrate. Improved codec params --- plugins/VOIP/gui/VideoProcessor.cpp | 61 +++++++++++++++++------------ 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/plugins/VOIP/gui/VideoProcessor.cpp b/plugins/VOIP/gui/VideoProcessor.cpp index 7da37fbbe..26fa74a53 100644 --- a/plugins/VOIP/gui/VideoProcessor.cpp +++ b/plugins/VOIP/gui/VideoProcessor.cpp @@ -26,7 +26,7 @@ extern "C" { //#define DEBUG_MPEG_VIDEO 1 VideoProcessor::VideoProcessor() - :_encoded_frame_size(176,144) , vpMtx("VideoProcessor") + :_encoded_frame_size(640,480) , vpMtx("VideoProcessor") { _decoded_output_device = NULL ; @@ -554,7 +554,8 @@ FFmpegVideo::FFmpegVideo() encoding_context = NULL ; //AVCodecID codec_id = AV_CODEC_ID_H264 ; - AVCodecID codec_id = AV_CODEC_ID_MPEG1VIDEO; + //AVCodecID codec_id = AV_CODEC_ID_MPEG2VIDEO; + AVCodecID codec_id = AV_CODEC_ID_MPEG4; uint8_t endcode[] = { 0, 0, 1, 0xb7 }; @@ -568,31 +569,42 @@ FFmpegVideo::FFmpegVideo() if (!encoding_context) throw std::runtime_error("AV: Could not allocate video codec encoding context"); /* put sample parameters */ - encoding_context->bit_rate = 30*1024 ; // default bitrate is 30KB/s + encoding_context->bit_rate = 10*1024 ; // default bitrate is 30KB/s encoding_context->bit_rate_tolerance = encoding_context->bit_rate ; + +#ifdef USE_VARIABLE_BITRATE encoding_context->rc_min_rate = 0; - encoding_context->rc_max_rate = 81920; - encoding_context->rc_buffer_size = 1024*1024; + encoding_context->rc_max_rate = 10*1024;//encoding_context->bit_rate; + encoding_context->rc_buffer_size = 10*1024*1024; + encoding_context->rc_initial_buffer_occupancy = (int) ( 0.9 * encoding_context->rc_buffer_size); + encoding_context->rc_max_available_vbv_use = 1.0; + encoding_context->rc_min_vbv_overflow_use = 0.0; +#else + encoding_context->rc_min_rate = 0; + encoding_context->rc_max_rate = 0; + encoding_context->rc_buffer_size = 0; +#endif encoding_context->flags |= CODEC_FLAG_PSNR; + encoding_context->flags |= CODEC_FLAG_TRUNCATED; + encoding_context->flags |= CODEC_CAP_PARAM_CHANGE; + encoding_context->i_quant_factor = 0.769f; + encoding_context->b_quant_factor = 1.4f; + encoding_context->time_base.num = 1; + encoding_context->time_base.den = 15;//framesPerSecond; + encoding_context->qmin = 1; + encoding_context->qmax = 51; + encoding_context->max_qdiff = 4; + + //encoding_context->me_method = ME_HEX; + //encoding_context->max_b_frames = 4; + //encoding_context->flags |= CODEC_FLAG_LOW_DELAY; // MPEG2 only //encoding_context->partitions = X264_PART_I4X4 | X264_PART_I8X8 | X264_PART_P8X8 | X264_PART_P4X4 | X264_PART_B8X8; //encoding_context->crf = 0.0f; //encoding_context->cqp = 26; - encoding_context->i_quant_factor = 0.769f; - encoding_context->b_quant_factor = 1.4f; - encoding_context->rc_initial_buffer_occupancy = (int) ( 0.9 * encoding_context->rc_buffer_size); - encoding_context->rc_max_available_vbv_use = 0.9; - encoding_context->rc_min_vbv_overflow_use = 0.1; - encoding_context->time_base.num = 1; - encoding_context->time_base.den = 15;//framesPerSecond; - //encoding_context->me_method = ME_HEX; - encoding_context->qmin = 10; - encoding_context->qmax = 51; - encoding_context->max_qdiff = 4; - encoding_context->max_b_frames = 4; - + /* resolution must be a multiple of two */ - encoding_context->width = 352;//176; - encoding_context->height = 288;//144; + encoding_context->width = 640;//176; + encoding_context->height = 480;//144; /* frames per second */ encoding_context->time_base = (AVRational){1,25}; /* emit one intra frame every ten frames @@ -601,8 +613,8 @@ FFmpegVideo::FFmpegVideo() * then gop_size is ignored and the output of encoder * will always be I frame irrespective to gop_size */ - encoding_context->gop_size = 250; - encoding_context->max_b_frames = 1; + encoding_context->gop_size = 100; + //encoding_context->max_b_frames = 1; encoding_context->pix_fmt = AV_PIX_FMT_YUV420P; //context->pix_fmt = AV_PIX_FMT_RGB24; if (codec_id == AV_CODEC_ID_H264) @@ -698,8 +710,9 @@ bool FFmpegVideo::encodeData(const QImage& image, uint32_t target_encoding_bitra std::cerr << "Max encodign bitrate eexceeded. Capping to " << MAX_FFMPEG_ENCODING_BITRATE << std::endl; target_encoding_bitrate = MAX_FFMPEG_ENCODING_BITRATE ; } - encoding_context->bit_rate = target_encoding_bitrate; - encoding_context->bit_rate_tolerance = target_encoding_bitrate; + //encoding_context->bit_rate = target_encoding_bitrate; + encoding_context->rc_max_rate = target_encoding_bitrate; + //encoding_context->bit_rate_tolerance = target_encoding_bitrate; if(image.width() != encoding_frame_buffer->width || image.height() != encoding_frame_buffer->height) input = image.scaled(QSize(encoding_frame_buffer->width,encoding_frame_buffer->height),Qt::IgnoreAspectRatio,Qt::SmoothTransformation) ; From c5cd701d4c516fa6e51887b9a83f2aaf1a35db2e Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 31 Aug 2015 22:44:34 -0400 Subject: [PATCH 147/165] removed experimental wavelet codec --- plugins/VOIP/gui/DaubechyWavelets.h | 267 ---------------------------- plugins/VOIP/gui/VideoProcessor.cpp | 234 ------------------------ plugins/VOIP/gui/VideoProcessor.h | 21 --- 3 files changed, 522 deletions(-) delete mode 100644 plugins/VOIP/gui/DaubechyWavelets.h diff --git a/plugins/VOIP/gui/DaubechyWavelets.h b/plugins/VOIP/gui/DaubechyWavelets.h deleted file mode 100644 index c69f025b0..000000000 --- a/plugins/VOIP/gui/DaubechyWavelets.h +++ /dev/null @@ -1,267 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#ifdef USE_SSE_INSTRUCTIONS -#include -#endif - -template class DaubechyWavelets -{ - public: - typedef enum { DWT_DAUB02=2, DWT_DAUB04=4, DWT_DAUB12=12, DWT_DAUB20=20 } WaveletType ; - typedef enum { DWT_FORWARD=1, DWT_BACKWARD=0 } TransformType ; - - static void DWT2D(FLOAT *data,unsigned long int W,unsigned long int H,WaveletType type,TransformType tr) - { - unsigned long int nn[2] = {W,H} ; - wtn(&data[-1], &nn[-1],2, tr, waveletFilter(type), pwt) ; - } - static void DWT1D(FLOAT *data,unsigned long int W,WaveletType type,TransformType tr) - { - unsigned long int nn[1] = {W} ; - wtn(&data[-1], &nn[-1],1, tr, waveletFilter(type), pwt) ; - } - - - private: - class wavefilt - { - public: - wavefilt(int n) - { - int k; - FLOAT sig = -1.0; - static const FLOAT c2[5]={ 0.0, sqrt(2.0)/2.0, sqrt(2.0)/2.0, 0.0, 0.0 }; - - static const FLOAT c4[5]={ 0.0, 0.4829629131445341, 0.8365163037378079, 0.2241438680420134,-0.1294095225512604 }; - - static const FLOAT c12[13]={0.0,0.111540743350, 0.494623890398, 0.751133908021, - 0.315250351709,-0.226264693965,-0.129766867567, - 0.097501605587, 0.027522865530,-0.031582039318, - 0.000553842201, 0.004777257511,-0.001077301085}; - - static const FLOAT c20[21]={0.0,0.026670057901, 0.188176800078, 0.527201188932, - 0.688459039454, 0.281172343661,-0.249846424327, - -0.195946274377, 0.127369340336, 0.093057364604, - -0.071394147166,-0.029457536822, 0.033212674059, - 0.003606553567,-0.010733175483, 0.001395351747, - 0.001992405295,-0.000685856695,-0.000116466855, - 0.000093588670,-0.000013264203 }; - - ncof= (n==2)?4:n; - const FLOAT *tmpcc ; - cc.resize(ncof+1) ; - cr.resize(ncof+1) ; - - if (n == 2) - { - tmpcc=c2; - cc[1] = tmpcc[1] ; - cc[2] = tmpcc[2] ; - cc[3] = 0.0f ; - cc[4] = 0.0f ; - cr[1] = tmpcc[1] ; - cr[2] =-tmpcc[2] ; - cr[3] = 0.0f ; - cr[4] = 0.0f ; - - ioff = joff = -1 ; - } - else - { - if (n == 4) - tmpcc=c4; - else if (n == 12) - tmpcc=c12; - else if (n == 20) - tmpcc=c20; - else - throw std::runtime_error("unimplemented value n in pwtset"); - - for (k=1;k<=n;k++) - { - cc[k] = tmpcc[k] ; - cr[ncof+1-k]=sig*tmpcc[k]; - sig = -sig; - } - ioff = joff = -(n >> 1); - } - } - - ~wavefilt() {} - - int ncof,ioff,joff; - std::vector cc; - std::vector cr; - } ; - - static const wavefilt& waveletFilter(WaveletType type) - { - static wavefilt *daub02filt = NULL ; - static wavefilt *daub04filt = NULL ; - static wavefilt *daub12filt = NULL ; - static wavefilt *daub20filt = NULL ; - - switch(type) - { - case DWT_DAUB02: if(daub02filt == NULL) - daub02filt = new wavefilt(2) ; - return *daub02filt ; - - case DWT_DAUB04: if(daub04filt == NULL) - daub04filt = new wavefilt(4) ; - return *daub04filt ; - - case DWT_DAUB12: if(daub12filt == NULL) - daub12filt = new wavefilt(12) ; - return *daub12filt ; - - case DWT_DAUB20: if(daub20filt == NULL) - daub20filt = new wavefilt(20) ; - return *daub20filt ; - - default: - throw std::runtime_error("Unknown wavelet type.") ; - } - } - - static void pwt(FLOAT a[], unsigned long n, int isign,const wavefilt& wfilt) - { -/********************** BEGIN SIGNED PART *************************/ -/** md5sum = 2b9e1e38ac690f50806873cdb4a061ea **/ -/** Validation date = 08/10/10 **/ -/******************************************************************/ - unsigned long i,ii,ni,nj ; - - if (n < 4) - return; - - FLOAT *wksp=new FLOAT[n+1];//vector(1,n); - FLOAT ai,ai1 ; - unsigned long int nmod=wfilt.ncof*n; - unsigned long int n1=n-1; - unsigned long int nh=n >> 1; - - memset(wksp,0,(n+1)*sizeof(FLOAT)) ; - - if (isign == DWT_FORWARD) - for (ii=1,i=1;i<=n;i+=2,ii++) - { - ni=i+nmod+wfilt.ioff; - nj=i+nmod+wfilt.joff; - -#ifdef USE_SSE_INSTRUCTIONS -#warning Using SSE2 Instruction set for wavelet internal loops - for (int k=1;k<=wfilt.ncof;k+=4) - { - int jf=ni+k; - int jr=nj+k; - - sse_block w1(wfilt.cc[k],wfilt.cc[k+1],wfilt.cc[k+2],wfilt.cc[k+3]) ; - sse_block w2(wfilt.cr[k],wfilt.cr[k+1],wfilt.cr[k+2],wfilt.cr[k+3]) ; - - sse_block a1( a[1+((jf+0)&n1)], a[1+((jf+1)&n1)], a[1+((jf+2)&n1)], a[1+((jf+3)&n1)]) ; - sse_block a2( a[1+((jr+0)&n1)], a[1+((jr+1)&n1)], a[1+((jr+2)&n1)], a[1+((jr+3)&n1)]) ; - - sse_block wk1( w1*a1 ) ; - sse_block wk2( w2*a2 ) ; - - wksp[ii ] += wk1.sum() ; - wksp[ii+nh] += wk2.sum() ; - } -#else - for (int k=1;k<=wfilt.ncof;k++) - { - int jf=n1 & (ni+k); - int jr=n1 & (nj+k); - wksp[ii] += wfilt.cc[k]*a[jf+1]; - wksp[ii+nh] += wfilt.cr[k]*a[jr+1]; - } -#endif - } - else - for (ii=1,i=1;i<=n;i+=2,ii++) - { - ai=a[ii]; - ai1=a[ii+nh]; - ni=i+nmod+wfilt.ioff; - nj=i+nmod+wfilt.joff; - -#ifdef USE_SSE_INSTRUCTIONS - sse_block ai_sse( ai,ai,ai,ai ) ; - sse_block ai1_sse( ai1,ai1,ai1,ai1 ) ; - - for (int k=1;k<=wfilt.ncof;k+=4) - { - int jf=ni+k ; - int jr=nj+k ; // in fact we have jf==jr, so the code is simpler. - - sse_block w1(wksp[1+((jf+0) & n1)],wksp[1+((jf+1) & n1)],wksp[1+((jf+2) & n1)],wksp[1+((jf+3) & n1)]) ; - - w1 += sse_block(wfilt.cc[k+0],wfilt.cc[k+1],wfilt.cc[k+2],wfilt.cc[k+3]) * ai_sse ; - w1 += sse_block(wfilt.cr[k+0],wfilt.cr[k+1],wfilt.cr[k+2],wfilt.cr[k+3]) * ai1_sse ; - - wksp[1+((jr+0) & n1)] = w1[0] ; - wksp[1+((jr+1) & n1)] = w1[1] ; - wksp[1+((jr+2) & n1)] = w1[2] ; - wksp[1+((jr+3) & n1)] = w1[3] ; - } -#else - for (int k=1;k<=wfilt.ncof;++k) - { - wksp[(n1 & (ni+k))+1] += wfilt.cc[k]*ai; - wksp[(n1 & (nj+k))+1] += wfilt.cr[k]*ai1; - } -#endif - } - - for (uint j=1;j<=n;j++) - a[j]=wksp[j]; - - delete[] wksp ;//free_vector(wksp,1,n); -/********************** END SIGNED PART *************************/ - } - - static void wtn(FLOAT a[], unsigned long nn[], int ndim, int isign, const wavefilt& w,void (*wtstep)(FLOAT [], unsigned long, int,const wavefilt&)) - { - unsigned long i1,i2,i3,k,n,nnew,nprev=1,nt,ntot=1; - int idim; - FLOAT *wksp; - - for (idim=1;idim<=ndim;idim++) - ntot *= nn[idim]; - - wksp=new FLOAT[ntot+1] ; //vector(1,ntot); - - for (idim=1;idim<=ndim;idim++) - { - n=nn[idim]; - nnew=n*nprev; - - if (n > 4) - for (i2=0;i2=4;nt >>= 1) - (*wtstep)(wksp,nt,isign,w); - else - for(nt=4;nt<=n;nt <<= 1) - (*wtstep)(wksp,nt,isign,w); - - for (i3=i1+i2,k=1;k<=n;k++,i3+=nprev) a[i3]=wksp[k]; - } - - nprev=nnew; - } - delete[] wksp ;//free_vector(wksp,1,ntot); - } -}; - diff --git a/plugins/VOIP/gui/VideoProcessor.cpp b/plugins/VOIP/gui/VideoProcessor.cpp index 26fa74a53..a0084ea18 100644 --- a/plugins/VOIP/gui/VideoProcessor.cpp +++ b/plugins/VOIP/gui/VideoProcessor.cpp @@ -8,7 +8,6 @@ #include "VideoProcessor.h" #include "QVideoDevice.h" -#include "DaubechyWavelets.h" #include @@ -31,7 +30,6 @@ VideoProcessor::VideoProcessor() _decoded_output_device = NULL ; //_encoding_current_codec = VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO; - //_encoding_current_codec = VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO; _encoding_current_codec = VIDEO_PROCESSOR_CODEC_ID_MPEG_VIDEO; _estimated_bandwidth_in = 0 ; @@ -66,8 +64,6 @@ bool VideoProcessor::processImage(const QImage& img) { case VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO: codec = &_jpeg_video_codec ; break ; - case VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO: codec = &_ddwt_video_codec ; - break ; case VIDEO_PROCESSOR_CODEC_ID_MPEG_VIDEO: codec = &_mpeg_video_codec ; break ; default: @@ -159,8 +155,6 @@ void VideoProcessor::receiveEncodedData(const RsVOIPDataChunk& chunk) { case VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO: codec = &_jpeg_video_codec ; break ; - case VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO: codec = &_ddwt_video_codec ; - break ; case VIDEO_PROCESSOR_CODEC_ID_MPEG_VIDEO: codec = &_mpeg_video_codec ; break ; default: @@ -317,234 +311,6 @@ bool JPEGVideo::encodeData(const QImage& image,uint32_t /* size_hint */,RsVOIPDa return true ; } - -bool WaveletVideo::encodeData(const QImage& image, uint32_t target_encoding_bitrate, RsVOIPDataChunk& voip_chunk) -{ - static const int WAVELET_IMG_SIZE = 128 ; - static const float W_THRESHOLD = 0.005 ; // low quality - //static const float W_THRESHOLD = 0.0001; // high quality - //static const float W_THRESHOLD = 0.0005; // medium quality - - static const int W2 = WAVELET_IMG_SIZE ; - static const int H2 = WAVELET_IMG_SIZE ; - - assert(image.width() == W2) ; - assert(image.height() == H2) ; - - float *temp = new float[W2*H2] ; - - std::cerr << " codec type: wavelets." << std::endl; - - // We should perform some interpolation here ;-) - // - for(int i=0;i::DWT2D(temp,W2,H2,DaubechyWavelets::DWT_DAUB12,DaubechyWavelets::DWT_FORWARD) ; - - // Now estimate the max energy in the W coefs, and only keep the largest. - - float mx = 0.0f ; - for(int i=0;i compressed_values ; - compressed_values.reserve(W2*H2) ; - - for(int i=0;i= W_THRESHOLD*mx) // This needs to be improved. Wavelets do not all have the same visual impact. - { - // add one value, using 16 bits for coordinates and 16 bits for the value. - - compressed_values.push_back((uint16_t)i) ; - compressed_values.push_back(quantize_16b(temp[i],mx)) ; - - //float f2 = from_quantized_16b(quantize_16b(temp[i],mx),mx) ; - - //if(fabs(f2 - temp[i]) >= 0.01*(fabs(temp[i])+fabs(f2))) - //std::cerr << " before: " << temp[i] << ", quantised=" << quantize_16b(temp[i],mx)<< ", after: " << f2 << std::endl; - } - delete[] temp ; - - // Serialise all values into a memory buffer. This needs to be taken care of because of endian issues. - - int compressed_size = 4 + compressed_values.size()*2 ; - - std::cerr << " threshold : " << W_THRESHOLD << std::endl; - std::cerr << " values kept: " << compressed_values.size()/2 << std::endl; - std::cerr << " compression: " << compressed_size/float(W2*H2*3)*100 << " %" << std::endl; - - voip_chunk.data = malloc(HEADER_SIZE + compressed_size) ; - - // build header - uint32_t flags = 0 ; - - ((unsigned char *)voip_chunk.data)[0] = VideoProcessor::VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO & 0xff ; - ((unsigned char *)voip_chunk.data)[1] = (VideoProcessor::VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO >> 8) & 0xff ; - ((unsigned char *)voip_chunk.data)[2] = flags & 0xff ; - ((unsigned char *)voip_chunk.data)[3] = (flags >> 8) & 0xff ; - - unsigned char *compressed_mem = &((unsigned char *)voip_chunk.data)[HEADER_SIZE] ; - serialise_ufloat(compressed_mem,mx) ; - - for(uint32_t i=0;i> 8 ; - } - - voip_chunk.type = RsVOIPDataChunk::RS_VOIP_DATA_TYPE_VIDEO ; - voip_chunk.size = HEADER_SIZE + compressed_size ; - - return true ; -} - -bool WaveletVideo::decodeData(const RsVOIPDataChunk& chunk,QImage& image) -{ - static const int WAVELET_IMG_SIZE = 128 ; - - static const int W2 = WAVELET_IMG_SIZE ; - static const int H2 = WAVELET_IMG_SIZE ; - - float *temp = new float[W2*H2] ; - - const unsigned char *compressed_mem = &static_cast(chunk.data)[HEADER_SIZE] ; - int compressed_size = chunk.size - HEADER_SIZE; - - memset(temp,0,W2*H2*sizeof(float)) ; - float M = deserialise_ufloat(compressed_mem); - -#ifdef VOIP_CODEC_DEBUG - std::cerr << " codec type: wavelets." << std::endl; - std::cerr << " max coef: " << M << std::endl; -#endif - - for(int i=4;i::DWT2D(temp,W2,H2,DaubechyWavelets::DWT_DAUB12,DaubechyWavelets::DWT_BACKWARD) ; - -#ifdef VOIP_CODEC_DEBUG - std::cerr << " resizing image to: " << w << "x" << h << std::endl; -#endif - - image = QImage(W2,H2,QImage::Format_RGB32) ; - - int indx = 0 ; - - for(int j=0;j1023), and p is coded on 6 bits (0->63). - // Packing [mp] into a 16bit uint16_t. M is the maximum coefficient over the quantization - // process. - // - // So this represents numbers from M * 1 * 2^{-73} to M - // - // All calculatoins are performed on x/M*2^10 - // - static const float LOG2 = log(2.0f) ; - - int m,p ; - - if(fabs(x) < 1e-8*M) - { - m = 0 ; - p = 0 ; - } - else - { - float log2f = log(fabsf(x)/M)/LOG2 ; - int mexp = (int)floor(MANTISSE_BITS - log2f) ; - - m = (int)floor(pow(2.0f,mexp+log2f)) ; - p = mexp ; - - if(p > (1<> EXPONENT_BITS ; - - if(p > 10) - return M * m / 1024.0f / (float)(1 << (p-10)) ; - else - return M * m / (float)(1 << p) ; -} - -void WaveletVideo::serialise_ufloat(unsigned char *mem, float f) -{ - if(f < 0.0f) - { - std::cerr << "(EE) Cannot serialise invalid negative float value " << f << " in " << __PRETTY_FUNCTION__ << std::endl; - return ; - } - // This serialisation is quite accurate. The max relative error is approx. - // 0.01% and most of the time less than 1e-05% The error is well distributed - // over numbers also. - // - uint32_t n = (f < 1e-7)?(~(uint32_t)0): ((uint32_t)( (1.0f/(1.0f+f) * (~(uint32_t)0)))) ; - - mem[0] = n & 0xff ; n >>= 8 ; - mem[1] = n & 0xff ; n >>= 8 ; - mem[2] = n & 0xff ; n >>= 8 ; - mem[3] = n & 0xff ; -} -float WaveletVideo::deserialise_ufloat(const unsigned char *mem) -{ - uint32_t n = mem[3] ; - n = (n << 8) + mem[2] ; - n = (n << 8) + mem[1] ; - n = (n << 8) + mem[0] ; - - return 1.0f/ ( n/(float)(~(uint32_t)0)) - 1.0f ; -} - FFmpegVideo::FFmpegVideo() { // Encoding diff --git a/plugins/VOIP/gui/VideoProcessor.h b/plugins/VOIP/gui/VideoProcessor.h index 85ecae7df..a3869dc5e 100644 --- a/plugins/VOIP/gui/VideoProcessor.h +++ b/plugins/VOIP/gui/VideoProcessor.h @@ -41,26 +41,6 @@ private: uint32_t _encoded_ref_frame_count ; }; -class WaveletVideo: public VideoCodec -{ -public: - WaveletVideo() {} - -protected: - virtual bool encodeData(const QImage& Image, uint32_t target_encoding_bitrate, RsVOIPDataChunk& chunk) ; - virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) ; -private: - - static const int MANTISSE_BITS = 9 ; - static const int EXPONENT_BITS = 6 ; - - static void serialise_ufloat(unsigned char *mem, float f); - static float deserialise_ufloat(const unsigned char *mem); - - static float from_quantized_16b(uint16_t n, float M); - static uint16_t quantize_16b(float x, float M); -}; - struct AVCodec ; struct AVCodecContext ; struct AVFrame ; @@ -152,7 +132,6 @@ class VideoProcessor // ===================================================================================== JPEGVideo _jpeg_video_codec ; - WaveletVideo _ddwt_video_codec ; FFmpegVideo _mpeg_video_codec ; uint16_t _encoding_current_codec ; From b1572c29243203f56a1d66b50af14abd3345c1cb Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 31 Aug 2015 22:50:20 -0400 Subject: [PATCH 148/165] added missing deps for avcodec --- build_scripts/Debian+Ubuntu/control.precise | 2 +- build_scripts/Debian+Ubuntu/control.squeeze_bubba3 | 2 +- build_scripts/Debian+Ubuntu/control.ubuntu_lucid | 2 +- build_scripts/Debian+Ubuntu/debian/control | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build_scripts/Debian+Ubuntu/control.precise b/build_scripts/Debian+Ubuntu/control.precise index b008cf5fa..70d77ea50 100644 --- a/build_scripts/Debian+Ubuntu/control.precise +++ b/build_scripts/Debian+Ubuntu/control.precise @@ -2,7 +2,7 @@ Source: retroshare06 Section: devel Priority: standard Maintainer: Cyril Soler -Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, qt4-dev-tools, libqt4-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libqt4-opengl-dev, libqtmultimediakit1, qtmobility-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libcv-dev, libopencv-core-dev, libopencv-contrib-dev, libhighgui-dev, tcl8.5, libsqlcipher-dev, libmicrohttpd-dev +Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, qt4-dev-tools, libqt4-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libqt4-opengl-dev, libqtmultimediakit1, qtmobility-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libcv-dev, libopencv-core-dev, libopencv-contrib-dev, libhighgui-dev, tcl8.5, libsqlcipher-dev, libmicrohttpd-dev, libavcodec-dev Standards-Version: 3.9.3 Homepage: http://retroshare.sourceforge.net diff --git a/build_scripts/Debian+Ubuntu/control.squeeze_bubba3 b/build_scripts/Debian+Ubuntu/control.squeeze_bubba3 index 244bdb2a0..c72507d0f 100644 --- a/build_scripts/Debian+Ubuntu/control.squeeze_bubba3 +++ b/build_scripts/Debian+Ubuntu/control.squeeze_bubba3 @@ -2,7 +2,7 @@ Source: retroshare06 Section: devel Priority: standard Maintainer: Cyril Soler -Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, qt4-dev-tools, libqt4-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libqt4-opengl-dev, libqt4-multimedia, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libcv-dev, libcvaux-dev, libhighgui-dev, tcl8.5, libmicrohttpd-dev, libsqlite3-dev +Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, qt4-dev-tools, libqt4-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libqt4-opengl-dev, libqt4-multimedia, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libcv-dev, libcvaux-dev, libhighgui-dev, tcl8.5, libmicrohttpd-dev, libsqlite3-dev, libavcodec-dev Standards-Version: 3.9.3 Homepage: http://retroshare.sourceforge.net diff --git a/build_scripts/Debian+Ubuntu/control.ubuntu_lucid b/build_scripts/Debian+Ubuntu/control.ubuntu_lucid index 1188ca8a0..ae12f4247 100644 --- a/build_scripts/Debian+Ubuntu/control.ubuntu_lucid +++ b/build_scripts/Debian+Ubuntu/control.ubuntu_lucid @@ -2,7 +2,7 @@ Source: retroshare Section: devel Priority: standard Maintainer: Cyril Soler -Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, qt4-dev-tools, libqt4-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libqt4-opengl-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, libprotobuf-dev, protobuf-compiler, cmake, libcurl4-openssl-dev +Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, qt4-dev-tools, libqt4-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libqt4-opengl-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, libprotobuf-dev, protobuf-compiler, cmake, libcurl4-openssl-dev, libavcodec-dev Standards-Version: 3.9.1 Homepage: http://retroshare.sourceforge.net diff --git a/build_scripts/Debian+Ubuntu/debian/control b/build_scripts/Debian+Ubuntu/debian/control index 357150da5..b251bb923 100644 --- a/build_scripts/Debian+Ubuntu/debian/control +++ b/build_scripts/Debian+Ubuntu/debian/control @@ -2,7 +2,7 @@ Source: retroshare06 Section: devel Priority: standard Maintainer: Cyril Soler -Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, qt4-dev-tools, libqt4-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libqt4-opengl-dev, libqtmultimediakit1, qtmobility-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libopencv-dev, tcl8.5, libsqlcipher-dev, libmicrohttpd-dev +Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, qt4-dev-tools, libqt4-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libqt4-opengl-dev, libqtmultimediakit1, qtmobility-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libopencv-dev, tcl8.5, libsqlcipher-dev, libmicrohttpd-dev, libavcodec-dev Standards-Version: 3.9.3 Homepage: http://retroshare.sourceforge.net From 846f7d02044f5802412349f2f8d09685c01c5ec1 Mon Sep 17 00:00:00 2001 From: AsamK Date: Mon, 31 Aug 2015 19:25:10 +0200 Subject: [PATCH 149/165] Make usage of sqlcipher explicit at compile time Either the build fails if it is not available, or the user specifies CONFIG+=NO_SQLCIPHER to build without it, even if it exists in the system. --- libretroshare/src/libretroshare.pro | 23 +++++++++++++++-------- retroshare-gui/src/retroshare-gui.pro | 21 --------------------- retroshare-nogui/src/retroshare-nogui.pro | 21 --------------------- 3 files changed, 15 insertions(+), 50 deletions(-) diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 433c49b73..6b731a608 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -138,15 +138,22 @@ linux-* { DEPENDPATH += . $${SSL_DIR} $${UPNP_DIR} INCLUDEPATH += . $${SSL_DIR} $${UPNP_DIR} - SQLCIPHER_OK = $$system(pkg-config --exists sqlcipher && echo yes) - isEmpty(SQLCIPHER_OK) { -# We need a explicit path here, to force using the home version of sqlite3 that really encrypts the database. - !exists(../../../lib/sqlcipher/.libs/libsqlcipher.a) { - message(libsqlcipher.a not found. Compilation will not use SQLCIPER. Database will be unencrypted.) - DEFINES *= NO_SQLCIPHER + contains(CONFIG, NO_SQLCIPHER) { + DEFINES *= NO_SQLCIPHER + LIBS *= -lsqlite3 + } else { + SQLCIPHER_OK = $$system(pkg-config --exists sqlcipher && echo yes) + isEmpty(SQLCIPHER_OK) { + # We need a explicit path here, to force using the home version of sqlite3 that really encrypts the database. + exists(../../../lib/sqlcipher/.libs/libsqlcipher.a) { + LIBS += ../../../lib/sqlcipher/.libs/libsqlcipher.a + DEPENDPATH += ../../../lib/ + INCLUDEPATH += ../../../lib/ + } else { + error("libsqlcipher is not installed and libsqlcipher.a not found. SQLCIPHER is necessary for encrypted database, to build with unencrypted database, run: qmake CONFIG+=NO_SQLCIPHER") + } } else { - DEPENDPATH += ../../../lib/ - INCLUDEPATH += ../../../lib/ + LIBS *= -lsqlcipher } } diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 00fd3a5e4..9ee2a2ca8 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -85,27 +85,6 @@ linux-* { LIBS += ../../supportlibs/pegmarkdown/lib/libpegmarkdown.a - SQLCIPHER_OK = $$system(pkg-config --exists sqlcipher && echo yes) - isEmpty(SQLCIPHER_OK) { -# We need a explicit path here, to force using the home version of sqlite3 that really encrypts the database. - - exists(../../../lib/sqlcipher/.libs/libsqlcipher.a) { - - LIBS += ../../../lib/sqlcipher/.libs/libsqlcipher.a - DEPENDPATH += ../../../lib/sqlcipher/src/ - INCLUDEPATH += ../../../lib/sqlcipher/src/ - DEPENDPATH += ../../../lib/sqlcipher/tsrc/ - INCLUDEPATH += ../../../lib/sqlcipher/tsrc/ - } else { - message(libsqlcipher.a not found. Compilation will not use SQLCIPHER. Database will be unencrypted.) - DEFINES *= NO_SQLCIPHER - LIBS *= -lsqlite3 - } - - } else { - LIBS += -lsqlcipher - } - LIBS *= -lglib-2.0 LIBS *= -rdynamic DEFINES *= HAVE_XSS # for idle time, libx screensaver extensions diff --git a/retroshare-nogui/src/retroshare-nogui.pro b/retroshare-nogui/src/retroshare-nogui.pro index fe5c7d6a6..dc18270ba 100644 --- a/retroshare-nogui/src/retroshare-nogui.pro +++ b/retroshare-nogui/src/retroshare-nogui.pro @@ -35,27 +35,6 @@ linux-* { LIBS += -lssl -lupnp -lixml -lgnome-keyring LIBS *= -lcrypto -ldl -lz -lpthread LIBS *= -rdynamic - - gxs { - SQLCIPHER_OK = $$system(pkg-config --exists sqlcipher && echo yes) - isEmpty(SQLCIPHER_OK) { -# We need a explicit path here, to force using the home version of sqlite3 that really encrypts the database. - - exists(../../../lib/sqlcipher/.libs/libsqlcipher.a) { - - LIBS += ../../../lib/sqlcipher/.libs/libsqlcipher.a - DEPENDPATH += ../../../lib/sqlcipher/src/ - INCLUDEPATH += ../../../lib/sqlcipher/src/ - } else { - message(libsqlcipher.a not found. Compilation will not use SQLCIPHER. Database will be unencrypted.) - DEFINES *= NO_SQLCIPHER - LIBS *= -lsqlite3 - } - - } else { - LIBS *= -lsqlcipher - } - } } unix { From 829c2f396eb19cde5acb1f92a7ebeb310f63d949 Mon Sep 17 00:00:00 2001 From: AsamK Date: Mon, 31 Aug 2015 20:57:11 +0200 Subject: [PATCH 150/165] Move LIBS from gui/nogui linux section to libretroshare remove -lglib-2.0 it's not needed: was added in d8e327afcc8677579568ad03e4ce040019c5750d to compile for arch, but it compiles on arch now also without this --- libretroshare/src/libretroshare.pro | 6 ++++++ retroshare-gui/src/retroshare-gui.pro | 14 +++----------- retroshare-nogui/src/retroshare-nogui.pro | 10 +--------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 6b731a608..c3fea45cd 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -83,6 +83,8 @@ SOURCES += tcponudp/udppeer.cc \ # The next line is for compliance with debian packages. Keep it! INCLUDEPATH += ../libbitdht DEFINES *= RS_USE_BITDHT + PRE_TARGETDEPS *= ../../libbitdht/src/lib/libbitdht.a + LIBS += ../../libbitdht/src/lib/libbitdht.a } @@ -175,6 +177,10 @@ linux-* { DEFINES *= UBUNTU INCLUDEPATH += /usr/include/glib-2.0/ /usr/lib/glib-2.0/include LIBS *= -lgnome-keyring + LIBS *= ../../openpgpsdk/src/lib/libops.a -lbz2 + PRE_TARGETDEPS *= ../../openpgpsdk/src/lib/libops.a + LIBS *= -lssl -lupnp -lixml + LIBS *= -lcrypto -lz -lpthread } unix { diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 9ee2a2ca8..fcb7d333c 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -76,17 +76,14 @@ linux-* { QMAKE_CXXFLAGS *= -D_FILE_OFFSET_BITS=64 PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a - PRE_TARGETDEPS *= ../../openpgpsdk/src/lib/libops.a LIBS += ../../libretroshare/src/lib/libretroshare.a - LIBS += ../../openpgpsdk/src/lib/libops.a -lbz2 - LIBS += -lssl -lupnp -lixml -lXss -lgnome-keyring - LIBS *= -lcrypto -ldl -lX11 -lz + LIBS *= -lX11 -lXss LIBS += ../../supportlibs/pegmarkdown/lib/libpegmarkdown.a - LIBS *= -lglib-2.0 - LIBS *= -rdynamic + #LIBS *= -lglib-2.0 + LIBS *= -rdynamic -ldl DEFINES *= HAVE_XSS # for idle time, libx screensaver extensions DEFINES *= UBUNTU } @@ -306,11 +303,6 @@ openbsd-* { # ########################################### -bitdht { - LIBS += ../../libbitdht/src/lib/libbitdht.a - PRE_TARGETDEPS *= ../../libbitdht/src/lib/libbitdht.a -} - DEPENDPATH += . ../../libretroshare/src/ INCLUDEPATH += ../../libretroshare/src/ diff --git a/retroshare-nogui/src/retroshare-nogui.pro b/retroshare-nogui/src/retroshare-nogui.pro index dc18270ba..c8f2f0ca1 100644 --- a/retroshare-nogui/src/retroshare-nogui.pro +++ b/retroshare-nogui/src/retroshare-nogui.pro @@ -31,10 +31,7 @@ linux-* { QMAKE_CXXFLAGS *= -D_FILE_OFFSET_BITS=64 LIBS += ../../libretroshare/src/lib/libretroshare.a - LIBS += ../../openpgpsdk/src/lib/libops.a -lbz2 - LIBS += -lssl -lupnp -lixml -lgnome-keyring - LIBS *= -lcrypto -ldl -lz -lpthread - LIBS *= -rdynamic + LIBS *= -rdynamic -ldl } unix { @@ -166,11 +163,6 @@ openbsd-* { ############################## Common stuff ###################################### -# bitdht config -bitdht { - LIBS += ../../libbitdht/src/lib/libbitdht.a -} - DEPENDPATH += . ../../libretroshare/src INCLUDEPATH += . ../../libretroshare/src From 2be400e33ede80c1eb90a1f2829da425c6416af5 Mon Sep 17 00:00:00 2001 From: AsamK Date: Mon, 31 Aug 2015 21:40:52 +0200 Subject: [PATCH 151/165] =?UTF-8?q?CONFIG=20shouldn't=20be=20reset=20at=20?= =?UTF-8?q?qmake=20call,=20use=20CONFIG+=3D=E2=80=A6=20instead?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With CONFIG=…, the default values of CONFIG are cleared, with qt4 this doesn't seem to be a problem, but with qt5 the build fails. CONFIG=staticlib in openpgpsdk.pro was added in 3caeb0ab7f6912a983dd52934883995d3ea80a92 for OS X, but is not necessary on linux --- README.md | 4 ++-- build_scripts/Debian+Ubuntu/debian/rules | 2 +- build_scripts/RedHat+Fedora/retroshare06.spec | 2 +- openpgpsdk/src/openpgpsdk.pro | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 617794d77..88d1c5a87 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Compilation on Linux 3. Compile ```bash cd trunk - qmake CONFIG=debug + qmake CONFIG+=debug make ``` @@ -55,7 +55,7 @@ For packagers ------------- Packagers can use PREFIX and LIB\_DIR to customize the installation paths: ```bash -qmake PREFIX=/usr LIB_DIR=/usr/lib64 +qmake PREFIX=/usr LIB_DIR=/usr/lib64 "CONFIG-=debug" "CONFIG+=release" make make INSTALL_ROOT=${PKGDIR} install ``` diff --git a/build_scripts/Debian+Ubuntu/debian/rules b/build_scripts/Debian+Ubuntu/debian/rules index a0d66eb32..69487e51a 100755 --- a/build_scripts/Debian+Ubuntu/debian/rules +++ b/build_scripts/Debian+Ubuntu/debian/rules @@ -3,7 +3,7 @@ configure: configure-stamp configure-stamp: dh_testdir - cd src && qmake-qt4 CONFIG=release PREFIX=/usr LIB_DIR=/usr/lib RetroShare.pro + cd src && qmake-qt4 "CONFIG-=debug" "CONFIG+=release" PREFIX=/usr LIB_DIR=/usr/lib RetroShare.pro touch $@ diff --git a/build_scripts/RedHat+Fedora/retroshare06.spec b/build_scripts/RedHat+Fedora/retroshare06.spec index bb8339330..d6ef0ff9f 100644 --- a/build_scripts/RedHat+Fedora/retroshare06.spec +++ b/build_scripts/RedHat+Fedora/retroshare06.spec @@ -56,7 +56,7 @@ cd lib/sqlcipher make cd - cd src -qmake-qt4 CONFIG=release PREFIX=%{_prefix} LIB_DIR=%{_libdir} RetroShare.pro +qmake-qt4 "CONFIG-=debug" "CONFIG+=release" PREFIX=%{_prefix} LIB_DIR=%{_libdir} RetroShare.pro make cd - diff --git a/openpgpsdk/src/openpgpsdk.pro b/openpgpsdk/src/openpgpsdk.pro index 786ee5819..f54f5d7f8 100644 --- a/openpgpsdk/src/openpgpsdk.pro +++ b/openpgpsdk/src/openpgpsdk.pro @@ -1,10 +1,10 @@ !include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") TEMPLATE = lib -win32 { - CONFIG += staticlib -} else { +macx { CONFIG = staticlib +} else { + CONFIG += staticlib } DEFINES *= OPENSSL_NO_IDEA From 30d7aa3be33b8f575773e5c88a14bca5d1eeee34 Mon Sep 17 00:00:00 2001 From: AsamK Date: Mon, 31 Aug 2015 22:08:09 +0200 Subject: [PATCH 152/165] Remove dependency on qt script, it's unused --- retroshare-gui/src/retroshare-gui.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index fcb7d333c..8e3cff862 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -1,6 +1,6 @@ !include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") -QT += network xml script +QT += network xml CONFIG += qt gui uic qrc resources idle bitdht CONFIG += link_prl From d116f40d6ea9a7c992b0deda0f472f6ac6b27eb2 Mon Sep 17 00:00:00 2001 From: AsamK Date: Mon, 31 Aug 2015 23:06:31 +0200 Subject: [PATCH 153/165] Move openpgpsdk to common section of libretroshare.pro It is the same for all platforms --- libretroshare/src/libretroshare.pro | 6 ++++-- retroshare-gui/src/retroshare-gui.pro | 5 ----- retroshare-nogui/src/retroshare-nogui.pro | 5 ----- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index c3fea45cd..92c8127d2 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -177,8 +177,6 @@ linux-* { DEFINES *= UBUNTU INCLUDEPATH += /usr/include/glib-2.0/ /usr/lib/glib-2.0/include LIBS *= -lgnome-keyring - LIBS *= ../../openpgpsdk/src/lib/libops.a -lbz2 - PRE_TARGETDEPS *= ../../openpgpsdk/src/lib/libops.a LIBS *= -lssl -lupnp -lixml LIBS *= -lcrypto -lz -lpthread } @@ -341,6 +339,10 @@ openbsd-* { ################################### COMMON stuff ################################## +# openpgpsdk +PRE_TARGETDEPS *= ../../openpgpsdk/src/lib/libops.a +LIBS *= ../../openpgpsdk/src/lib/libops.a -lbz2 + HEADERS += dbase/cachestrapper.h \ dbase/fimonitor.h \ dbase/findex.h \ diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 8e3cff862..0108fb7f6 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -190,12 +190,10 @@ win32 { #QTPLUGIN += qjpeg PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a - PRE_TARGETDEPS *= ../../openpgpsdk/src/lib/libops.a LIBS_DIR = $$PWD/../../../libs LIBS += ../../libretroshare/src/lib/libretroshare.a - LIBS += ../../openpgpsdk/src/lib/libops.a -lbz2 LIBS += -L"$$LIBS_DIR/lib" LIBS += ../../supportlibs/pegmarkdown/lib/libpegmarkdown.a @@ -240,7 +238,6 @@ macx { CONFIG += version_detail_bash_script LIBS += ../../libretroshare/src/lib/libretroshare.a - LIBS += ../../openpgpsdk/src/lib/libops.a -lbz2 LIBS += -lssl -lcrypto -lz #LIBS += -lssl -lcrypto -lz -lgpgme -lgpg-error -lassuan LIBS += ../../../miniupnpc-1.0/libminiupnpc.a @@ -278,10 +275,8 @@ openbsd-* { INCLUDEPATH *= /usr/local/include PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a - PRE_TARGETDEPS *= ../../openpgpsdk/src/lib/libops.a LIBS *= ../../libretroshare/src/lib/libretroshare.a - LIBS *= ../../openpgpsdk/src/lib/libops.a -lbz2 LIBS *= -lssl -lcrypto LIBS *= -lgpgme LIBS *= -lupnp diff --git a/retroshare-nogui/src/retroshare-nogui.pro b/retroshare-nogui/src/retroshare-nogui.pro index c8f2f0ca1..d5438515c 100644 --- a/retroshare-nogui/src/retroshare-nogui.pro +++ b/retroshare-nogui/src/retroshare-nogui.pro @@ -76,12 +76,10 @@ win32 { MOC_DIR = temp/moc PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a - PRE_TARGETDEPS *= ../../openpgpsdk/src/lib/libops.a LIBS_DIR = $$PWD/../../../libs LIBS += ../../libretroshare/src/lib/libretroshare.a - LIBS += ../../openpgpsdk/src/lib/libops.a -lbz2 LIBS += -L"$$LIBS_DIR/lib" LIBS += -lssl -lcrypto -lpthread -lminiupnpc -lz # added after bitdht @@ -111,7 +109,6 @@ macx { LIBS += -Wl,-search_paths_first LIBS += ../../libretroshare/src/lib/libretroshare.a - LIBS += ../../openpgpsdk/src/lib/libops.a -lbz2 LIBS += -lssl -lcrypto -lz LIBS += ../../../miniupnpc-1.0/libminiupnpc.a LIBS += -framework CoreFoundation @@ -150,13 +147,11 @@ openbsd-* { INCLUDEPATH *= /usr/local/include QMAKE_CXXFLAGS *= -Dfseeko64=fseeko -Dftello64=ftello -Dstat64=stat -Dstatvfs64=statvfs -Dfopen64=fopen LIBS *= ../../libretroshare/src/lib/libretroshare.a - LIBS *= ../../openpgpsdk/src/lib/libops.a -lbz2 LIBS *= -lssl -lcrypto LIBS *= -lgpgme LIBS *= -lupnp LIBS *= -lgnome-keyring PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a - PRE_TARGETDEPS *= ../../openpgpsdk/src/lib/libops.a LIBS *= -rdynamic } From 069b112135bb8418f5169bbc0ad359c66049f825 Mon Sep 17 00:00:00 2001 From: AsamK Date: Mon, 31 Aug 2015 23:15:17 +0200 Subject: [PATCH 154/165] Update README.md --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 88d1c5a87..4072f6a3f 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,17 @@ Compilation on Linux /usr/bin/RetroShare06 /usr/bin/RetroShare06-nogui +Compile only retroshare-nogui +----------------------------- +If you want to run RetroShare on a server and don’t need the gui and plugins, +you can run the following commands to only compile/install the nogui version: + +```bash +qmake +make retroshare-nogui +sudo make retroshare-nogui-install_subtargets +``` + For packagers ------------- Packagers can use PREFIX and LIB\_DIR to customize the installation paths: From dda8a49ef51226aee4738287045dded75bb731c3 Mon Sep 17 00:00:00 2001 From: AsamK Date: Tue, 1 Sep 2015 14:50:55 +0200 Subject: [PATCH 155/165] Add CONFIG+=NO_SQLCIPHER to travis config --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6759fd515..aecd47c39 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,12 +27,12 @@ addons: project: name: "RetroShare/RetroShare" description: "RetroShare Build submitted via Travis CI" - build_command_prepend: "qmake; make clean" + build_command_prepend: "qmake CONFIG+=NO_SQLCIPHER; make clean" build_command: "make -j 4" branch_pattern: coverity_scan before_script: - - qmake + - qmake CONFIG+=NO_SQLCIPHER #script: make script: if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then make ; fi From c3fff396249abd85d7f0fd0efe3e294dca473675 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Tue, 1 Sep 2015 22:49:08 +0200 Subject: [PATCH 156/165] Fixed Windows compile --- libresapi/src/api/ForumHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libresapi/src/api/ForumHandler.cpp b/libresapi/src/api/ForumHandler.cpp index 6d312958f..3a628a5a5 100644 --- a/libresapi/src/api/ForumHandler.cpp +++ b/libresapi/src/api/ForumHandler.cpp @@ -105,7 +105,7 @@ void ForumHandler::handleWildcard(Request &req, Response &resp) { RsGxsForumGroup& grp = *vit; KeyValueReference id("id", grp.mMeta.mGroupId); - KeyValueReference vis_msg("visible_msg_count", grp.mMeta.mVisibleMsgCount); + KeyValueReference vis_msg("visible_msg_count", grp.mMeta.mVisibleMsgCount); //KeyValueReference pgp_id("pgp_id",grp.mPgpId ); // not very happy about this, i think the flags should stay hidden in rsidentities bool own = (grp.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN); From 3e6874199410925b05cb18ba88ee0d479f83a2a7 Mon Sep 17 00:00:00 2001 From: Phenom Date: Tue, 1 Sep 2015 22:49:15 +0200 Subject: [PATCH 157/165] Fix Windows compilation of libresapi with error: \libresapi\src\api\ForumHandler.cpp:108: erreur : 'u_int32_t' was not declared in this scope KeyValueReference vis_msg("visible_msg_count", grp.mMeta.mVisibleMsgCount); ^ --- libresapi/src/api/ForumHandler.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libresapi/src/api/ForumHandler.cpp b/libresapi/src/api/ForumHandler.cpp index 6d312958f..1a3a9c5c0 100644 --- a/libresapi/src/api/ForumHandler.cpp +++ b/libresapi/src/api/ForumHandler.cpp @@ -8,6 +8,9 @@ #include "GxsResponseTask.h" #ifndef WINDOWS_SYS #include "unistd.h" +#else +#include "stdint.h" +typedef uint32_t u_int32_t; #endif namespace resource_api From 3cfe69787f0c7b59ce0ee42aa246c9c02233ec42 Mon Sep 17 00:00:00 2001 From: AsamK Date: Wed, 2 Sep 2015 02:03:46 +0200 Subject: [PATCH 158/165] Fix subtle bug in tlv deserialization of TLV_TYPE_KEYSIGNATURETYPE When using -O2, the variable currType is optimized out, so the signature is added with the wrong sign type. Then when verifying the data the signature is not found and verification fails. The main sympton of this bug was receiving no more forum/channel posts. Wit debug builds (-O0) this worked, that's why not every one was affected by this. This bug was introduced in 2012 (19e856c2a8eb56c5e43e977aac27a3dbc79ab2d0) --- libretroshare/src/serialiser/rstlvkeys.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/libretroshare/src/serialiser/rstlvkeys.cc b/libretroshare/src/serialiser/rstlvkeys.cc index eb90fff52..968b09d83 100644 --- a/libretroshare/src/serialiser/rstlvkeys.cc +++ b/libretroshare/src/serialiser/rstlvkeys.cc @@ -649,7 +649,6 @@ bool RsTlvKeySignatureSet::GetTlv(void *data, uint32_t size, uint32_t *offset) /* get the next type */ uint16_t tlvsubtype = GetTlvType( &(((uint8_t *) data)[*offset]) ); - SignType currType; switch(tlvsubtype) { @@ -659,16 +658,13 @@ bool RsTlvKeySignatureSet::GetTlv(void *data, uint32_t size, uint32_t *offset) ok &= sign.GetTlv(data, size, offset); if (ok) { - keySignSet[currType] = sign; + keySignSet[sign_type] = sign; } } break; case TLV_TYPE_KEYSIGNATURETYPE: { ok = GetTlvUInt32(data, size, offset, TLV_TYPE_KEYSIGNATURETYPE, &sign_type); - - if(ok) - currType = sign_type; } break; default: From 6af57f3aeac5171782cba5d11b2ac9e39931a6c2 Mon Sep 17 00:00:00 2001 From: Cyril Soler Date: Tue, 1 Sep 2015 21:03:23 -0400 Subject: [PATCH 159/165] Revert "Fix Windows compilation of libresapi with error:" --- libresapi/src/api/ForumHandler.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libresapi/src/api/ForumHandler.cpp b/libresapi/src/api/ForumHandler.cpp index 144a61057..3a628a5a5 100644 --- a/libresapi/src/api/ForumHandler.cpp +++ b/libresapi/src/api/ForumHandler.cpp @@ -8,9 +8,6 @@ #include "GxsResponseTask.h" #ifndef WINDOWS_SYS #include "unistd.h" -#else -#include "stdint.h" -typedef uint32_t u_int32_t; #endif namespace resource_api From 11d54b8c0ba2222ac26e2fa8fe012afc034fbcf9 Mon Sep 17 00:00:00 2001 From: Chozabu Date: Wed, 2 Sep 2015 22:37:34 +0100 Subject: [PATCH 160/165] added more details to travis IRC output --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index aecd47c39..d2d2c2781 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,6 +53,8 @@ notifications: - "chat.freenode.net#retroshare" template: - "%{repository}/%{branch} (%{commit} - %{author}): %{build_url}: %{message}" + - "Message: %{commit_message}" + - "Commit details: %{compare_url}" # webhooks: # urls: # - https://webhooks.gitter.im/e/9502afd22ca6c8e85fb3 From feafb1e2914f5d2d3ed6422fd7ab0b6f0470238a Mon Sep 17 00:00:00 2001 From: AsamK Date: Thu, 3 Sep 2015 00:27:14 +0200 Subject: [PATCH 161/165] Add "Paste as plain text" to context menu of RS text edits Useful for example when pasting from a website --- retroshare-gui/src/gui/common/MimeTextEdit.cpp | 8 ++++++++ retroshare-gui/src/gui/common/MimeTextEdit.h | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/retroshare-gui/src/gui/common/MimeTextEdit.cpp b/retroshare-gui/src/gui/common/MimeTextEdit.cpp index 1c51980c4..9513703d6 100644 --- a/retroshare-gui/src/gui/common/MimeTextEdit.cpp +++ b/retroshare-gui/src/gui/common/MimeTextEdit.cpp @@ -19,6 +19,8 @@ * Boston, MA 02110-1301, USA. ****************************************************************/ +#include +#include #include #include #include @@ -228,6 +230,7 @@ void MimeTextEdit::contextMenuEvent(QContextMenuEvent *e) QMenu *contextMenu = createStandardContextMenu(e->pos()); /* Add actions for pasting links */ + contextMenu->addAction( tr("Paste as plain text"), this, SLOT(pastePlainText())); contextMenu->addSeparator(); QAction *pasteLinkAction = contextMenu->addAction(QIcon(":/images/pasterslink.png"), tr("Paste RetroShare Link"), this, SLOT(pasteLink())); contextMenu->addAction(QIcon(":/images/pasterslink.png"), tr("Paste my certificate link"), this, SLOT(pasteOwnCertificateLink())); @@ -260,3 +263,8 @@ void MimeTextEdit::pasteOwnCertificateLink() insertHtml(link.toHtml() + " "); } } + +void MimeTextEdit::pastePlainText() +{ + insertPlainText(QApplication::clipboard()->text()); +} diff --git a/retroshare-gui/src/gui/common/MimeTextEdit.h b/retroshare-gui/src/gui/common/MimeTextEdit.h index 5ef5d6a5f..d28bb2c6e 100644 --- a/retroshare-gui/src/gui/common/MimeTextEdit.h +++ b/retroshare-gui/src/gui/common/MimeTextEdit.h @@ -58,7 +58,7 @@ private slots: void insertCompletion(const QString &completion); void pasteLink(); void pasteOwnCertificateLink(); - + void pastePlainText(); private: QString textUnderCursor() const; From 77c0d562fb5c450937de0f9054c39add4f67f5ae Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 2 Sep 2015 22:14:04 -0400 Subject: [PATCH 162/165] fixed deleting/stopping video devices --- plugins/VOIP/gui/AudioInputConfig.cpp | 10 +++++++--- plugins/VOIP/gui/QVideoDevice.cpp | 14 +++++++++++++- plugins/VOIP/gui/QVideoDevice.h | 4 ++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/plugins/VOIP/gui/AudioInputConfig.cpp b/plugins/VOIP/gui/AudioInputConfig.cpp index 6ef39bce5..ea0f2e129 100644 --- a/plugins/VOIP/gui/AudioInputConfig.cpp +++ b/plugins/VOIP/gui/AudioInputConfig.cpp @@ -157,6 +157,8 @@ void AudioInputConfig::togglePreview(bool b) AudioInputConfig::~AudioInputConfig() { + disconnect( qtTick, SIGNAL( timeout ( ) ), this, SLOT( on_Tick_timeout() ) ); + graph_source->stop() ; graph_source->setVideoInput(NULL) ; @@ -350,8 +352,10 @@ void AudioInputConfig::on_qcbTransmit_currentIndexChanged(int v) { } -void AudioInputConfig::on_Tick_timeout() { - if (!inputAudioProcessor) { +void AudioInputConfig::on_Tick_timeout() +{ + if (!inputAudioProcessor) + { inputAudioProcessor = new QtSpeex::SpeexInputProcessor(); inputAudioProcessor->open(QIODevice::WriteOnly | QIODevice::Unbuffered); @@ -376,7 +380,7 @@ void AudioInputConfig::on_Tick_timeout() { // also transmit encoded video RsVOIPDataChunk chunk ; - while(videoInput->getNextEncodedPacket(chunk)) + while((!videoInput->stopped()) && videoInput->getNextEncodedPacket(chunk)) { videoProcessor->receiveEncodedData(chunk) ; chunk.clear() ; diff --git a/plugins/VOIP/gui/QVideoDevice.cpp b/plugins/VOIP/gui/QVideoDevice.cpp index 3a0cc4aa9..b81b7b79c 100644 --- a/plugins/VOIP/gui/QVideoDevice.cpp +++ b/plugins/VOIP/gui/QVideoDevice.cpp @@ -15,6 +15,11 @@ QVideoInputDevice::QVideoInputDevice(QWidget *parent) _echo_output_device = NULL ; } +bool QVideoInputDevice::stopped() +{ + return _timer == NULL ; +} + void QVideoInputDevice::stop() { if(_timer != NULL) @@ -54,6 +59,9 @@ void QVideoInputDevice::start() void QVideoInputDevice::grabFrame() { + if(!_timer) + return ; + IplImage *img=cvQueryFrame(_capture_device); if(img == NULL) @@ -87,6 +95,9 @@ void QVideoInputDevice::grabFrame() bool QVideoInputDevice::getNextEncodedPacket(RsVOIPDataChunk& chunk) { + if(!_timer) + return false ; + if(_video_processor) return _video_processor->nextEncodedPacket(chunk) ; else @@ -100,7 +111,8 @@ uint32_t QVideoInputDevice::currentBandwidth() const QVideoInputDevice::~QVideoInputDevice() { - stop() ; + stop() ; + _video_processor = NULL ; } diff --git a/plugins/VOIP/gui/QVideoDevice.h b/plugins/VOIP/gui/QVideoDevice.h index 20a837446..cc92302a2 100644 --- a/plugins/VOIP/gui/QVideoDevice.h +++ b/plugins/VOIP/gui/QVideoDevice.h @@ -51,8 +51,8 @@ class QVideoInputDevice: public QObject void start() ; void stop() ; - - protected slots: + bool stopped(); +protected slots: void grabFrame() ; signals: From b1b2de617a7e1c4693eafe495c6b2c42562c1130 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Thu, 3 Sep 2015 13:11:12 +0200 Subject: [PATCH 163/165] Fixed Windows compile. - Set name for prl file in libretroshare.pro - Use "QMAKE_LFLAGS += -Wl,--start-group" to solve link issue --- libretroshare/src/libretroshare.pro | 1 + retroshare-gui/src/retroshare-gui.pro | 12 ++++-------- retroshare-nogui/src/retroshare-nogui.pro | 10 ++++------ 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/libretroshare/src/libretroshare.pro b/libretroshare/src/libretroshare.pro index 92c8127d2..18ded24a5 100644 --- a/libretroshare/src/libretroshare.pro +++ b/libretroshare/src/libretroshare.pro @@ -5,6 +5,7 @@ CONFIG += staticlib bitdht CONFIG += create_prl CONFIG -= qt TARGET = retroshare +TARGET_PRL = libretroshare #GXS Stuff. diff --git a/retroshare-gui/src/retroshare-gui.pro b/retroshare-gui/src/retroshare-gui.pro index 0108fb7f6..9727227e1 100644 --- a/retroshare-gui/src/retroshare-gui.pro +++ b/retroshare-gui/src/retroshare-gui.pro @@ -175,6 +175,9 @@ win32 { QMAKE_CFLAGS += -Wextra QMAKE_CXXFLAGS += -Wextra + # solve linker warnings because of the order of the libraries + QMAKE_LFLAGS += -Wl,--start-group + # Switch off optimization for release version QMAKE_CXXFLAGS_RELEASE -= -O2 QMAKE_CXXFLAGS_RELEASE += -O0 @@ -199,9 +202,7 @@ win32 { LIBS += ../../supportlibs/pegmarkdown/lib/libpegmarkdown.a LIBS += -lsqlcipher - LIBS += -lssl -lcrypto -lpthread -lminiupnpc -lz -# added after bitdht -# LIBS += -lws2_32 + LIBS += -lssl -lcrypto -lpthread -lminiupnpc -lz -lws2_32 LIBS += -luuid -lole32 -liphlpapi -lcrypt32 -lgdi32 LIBS += -lole32 -lwinmm RC_FILE = gui/images/retroshare_win.rc @@ -307,11 +308,6 @@ INCLUDEPATH += ../../libresapi/src PRE_TARGETDEPS *= ../../libresapi/src/lib/libresapi.a LIBS += ../../libresapi/src/lib/libresapi.a -lmicrohttpd -win32 { -# must be added after bitdht - LIBS += -lws2_32 -} - # Input HEADERS += rshare.h \ retroshare-gui/configpage.h \ diff --git a/retroshare-nogui/src/retroshare-nogui.pro b/retroshare-nogui/src/retroshare-nogui.pro index d5438515c..a15cb1bb2 100644 --- a/retroshare-nogui/src/retroshare-nogui.pro +++ b/retroshare-nogui/src/retroshare-nogui.pro @@ -75,6 +75,9 @@ win32 { UI_DIR = temp/ui MOC_DIR = temp/moc + # solve linker warnings because of the order of the libraries + QMAKE_LFLAGS += -Wl,--start-group + PRE_TARGETDEPS *= ../../libretroshare/src/lib/libretroshare.a LIBS_DIR = $$PWD/../../../libs @@ -82,8 +85,7 @@ win32 { LIBS += ../../libretroshare/src/lib/libretroshare.a LIBS += -L"$$LIBS_DIR/lib" LIBS += -lssl -lcrypto -lpthread -lminiupnpc -lz -# added after bitdht -# LIBS += -lcrypto -lws2_32 -lgdi32 + LIBS += -lcrypto -lws2_32 -lgdi32 LIBS += -luuid -lole32 -liphlpapi -lcrypt32 LIBS += -lole32 -lwinmm @@ -353,7 +355,3 @@ protorpc { INCLUDEPATH += $${PROTOPATH}/src } } -win32 { -# must be added after ssh - LIBS += -lcrypto -lws2_32 -lgdi32 -} From 9bbdefa48aa56b4777eadeee05ad177c9eedd433 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Thu, 3 Sep 2015 16:24:57 +0200 Subject: [PATCH 164/165] Added "QMAKE_LFLAGS += -Wl,--start-group" to pluigns for Windows compile. --- plugins/Common/retroshare_plugin.pri | 3 +++ plugins/FeedReader/FeedReader.pro | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/Common/retroshare_plugin.pri b/plugins/Common/retroshare_plugin.pri index d20c1baa4..3c9644c55 100644 --- a/plugins/Common/retroshare_plugin.pri +++ b/plugins/Common/retroshare_plugin.pri @@ -28,6 +28,9 @@ win32 { QMAKE_CFLAGS += -Wextra QMAKE_CXXFLAGS += -Wextra + # solve linker warnings because of the order of the libraries + QMAKE_LFLAGS += -Wl,--start-group + OBJECTS_DIR = temp/obj MOC_DIR = temp/moc RCC_DIR = temp/qrc diff --git a/plugins/FeedReader/FeedReader.pro b/plugins/FeedReader/FeedReader.pro index acc3b4e4c..4cebc5f48 100644 --- a/plugins/FeedReader/FeedReader.pro +++ b/plugins/FeedReader/FeedReader.pro @@ -92,8 +92,7 @@ linux-* { win32 { DEFINES += CURL_STATICLIB LIBXML_STATIC LIBXSLT_STATIC LIBEXSLT_STATIC - # Change order of the libraries - LIBS = -lcurl -lxml2 -lz -lxslt -lws2_32 -lwldap32 -lssl -lcrypto -lgdi32 -lwsock32 $${LIBS} + LIBS += -lcurl -lxml2 -lz -lxslt -lws2_32 -lwldap32 -lssl -lcrypto } openbsd-* { From 738dadadc9055698b4159c407d5ad779104326ff Mon Sep 17 00:00:00 2001 From: thunder2 Date: Thu, 3 Sep 2015 16:33:50 +0200 Subject: [PATCH 165/165] Fixed Windows compile of VOIP. --- plugins/VOIP/VOIP.pro | 3 +++ plugins/VOIP/gui/VideoProcessor.cpp | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/plugins/VOIP/VOIP.pro b/plugins/VOIP/VOIP.pro index 86a716309..e560a8501 100644 --- a/plugins/VOIP/VOIP.pro +++ b/plugins/VOIP/VOIP.pro @@ -24,6 +24,9 @@ linux-* { } win32 { + # ffmpeg + QMAKE_CXXFLAGS += -D__STDC_CONSTANT_MACROS + LIBS_DIR = $$PWD/../../../libs LIBS += -L"$$LIBS_DIR/lib/opencv" diff --git a/plugins/VOIP/gui/VideoProcessor.cpp b/plugins/VOIP/gui/VideoProcessor.cpp index a0084ea18..20aca0410 100644 --- a/plugins/VOIP/gui/VideoProcessor.cpp +++ b/plugins/VOIP/gui/VideoProcessor.cpp @@ -10,7 +10,11 @@ #include "QVideoDevice.h" #include +#include +#if defined(__MINGW32__) +#define memalign _aligned_malloc +#endif //MINGW extern "C" { #include