mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Merge branch 'master' into chatlog_v3_1
Conflicts: qtox.pro res.qrc src/widget/form/chatform.cpp src/widget/form/chatform.h src/widget/form/genericchatform.cpp src/widget/tool/chatactions/chataction.h src/widget/tool/chatactions/messageaction.cpp src/widget/widget.cpp ui/chatArea/innerStyle.css
This commit is contained in:
commit
52f220c9e4
39
INSTALL.md
39
INSTALL.md
|
@ -230,45 +230,18 @@ The following steps assume that MinGW is installed at "C:\MinGW". If you decided
|
|||
|
||||
###Setting up Path
|
||||
|
||||
Add MinGW/MSYS binaries to the system path to make them globally accessible.
|
||||
Add MinGW/MSYS/CMake binaries to the system path to make them globally accessible.
|
||||
Open Control Panel -> System and Security -> System -> Advanced system settings -> Environment Variables...
|
||||
In the second box search for the PATH variable and press Edit...
|
||||
The input box "Variable value:" should already contain some directories. Each directory is separated with a semicolon.
|
||||
Extend the input box by adding ";C:\MinGW\bin;C:\MinGW\msys\1.0\bin". The very first semicolon must only be added if it is missing.
|
||||
Extend the input box by adding ";C:\MinGW\bin;C:\MinGW\msys\1.0\bin;C:\Program Files (x86)\CMake 2.8\bin".
|
||||
The very first semicolon must only be added if it is missing. CMake may be added by installer automatically.
|
||||
|
||||
###Cloning the Repository
|
||||
|
||||
Clone the repository (https://github.com/tux3/qTox.git) with your preferred Git client. [SmartGit](http://www.syntevo.com/smartgit/) is very nice for this task.
|
||||
The following steps assume that you cloned the repository at "C:\qTox". If you decided to choose another location, replace corresponding parts.
|
||||
|
||||
###Tox Core
|
||||
|
||||
[jenkins.libtoxcore.so](http://jenkins.libtoxcore.so/job/libtoxcore-win32-i686/lastSuccessfulBuild/artifact/libtoxcore-win32-i686.zip)
|
||||
provides a prebuild package of Tox Core. Download this package and extract its content to "C:\qTox\libs". You may have to create the directory "libs".
|
||||
If you prefer to compile Tox Core on your own follow the instructions at https://github.com/irungentoo/toxcore/blob/master/INSTALL.md#windows
|
||||
|
||||
###OpenCV
|
||||
|
||||
Unfortunately there are no prebuild packages for OpenCV compiled with MinGW. Thus, you have to create your own.
|
||||
First of all download and install the most recent version of CMake from
|
||||
[cmake.org](http://www.cmake.org/cmake/resources/software.html).
|
||||
Afterwards download OpenCV in version 2.4.9 from [sourceforge.net](http://sourceforge.net/projects/opencvlibrary/files/opencv-unix/2.4.9/opencv-2.4.9.zip/download) and extract the content of the source archive to "C:\qTox\libs". Furthermore, create a new directory named "opencv-build" in "C:\qTox\libs".
|
||||
Now you should have the two directories "opencv-2.4.9" and "opencv-build" inside your "C:\qTox\libs" directory.
|
||||
|
||||
Run CMake (cmake-gui) and set up the input boxes "Where is the source code:" and "Where to build the binaries" with "C:\qTox\libs\opencv-2.4.9" and "C:\qTox\libs\opencv-build". Press configure and choose "MSYS Makefiles" in the drop down menu with "Use default native compilers". To start initial configuration press Finish. Given that qTox only needs some components of OpenCV it's recommended to disable not required modules. Furthermore, this will decrease compilation time of OpenCV dramatically. Each module begins with "BUILD_opencv_" and can be disabled by deselecting its entry. Use the "Search" input box for convenience. Disable all modules except of "core", "highgui" and "imgproc" (highgui depends on imgproc and will automatically be disabled if imgproc is disabled). For maximum performance search for "CMAKE_BUILD_TYPE" and set this value to "Release". Finally, make sure "CMAKE_INSTALL_PREFIX" points to "C:\qTox\libs\opencv-build\install" (should be by default). To update the configuration press Configure again. To generate the Makefiles press Generate.
|
||||
|
||||
Open a new command prompt within "C:\qTox\libs\opencv-build" (HINT: Use shift + right click -> "Open command window here" on the directory within Windows Explorer). Compile and install OpenCV with the following command. It's not recommended to use -j for multicore compilation, because it freezes the terminal from time to time.
|
||||
```bash
|
||||
make
|
||||
make install
|
||||
```
|
||||
|
||||
After OpenCV was successfully installed to "C:\qTox\libs\opencv-build\install" copy the dlls "libopencv_core249.dll", "libopencv_highgui249.dll" and "libopencv_imgproc249.dll" located at "C:\qTox\libs\opencv-build\install\x86\mingw\bin" to "C:\qTox\libs\lib". Afterwards copy the content of the directory "C:\qTox\libs\opencv-build\install\include" to "C:\qTox\libs\include". Finally, you have to patch the file "C:\qTox\libs\include\opencv2\opencv.hpp" because it includes all modules of OpenCV regardless of your configuration. Open this file with your preferred text editor and remove all includes except of "opencv2/core/core_c.h", "opencv2/core/core.hpp", "opencv2/imgproc/imgproc_c.h", "opencv2/imgproc/imgproc.hpp", "opencv2/highgui/highgui_c.h" and "opencv2/highgui/highgui.hpp". OpenCV is now ready to use. Feel free to delete the directories "opencv-2.4.9" and "opencv-build", but you don't need to.
|
||||
|
||||
###OpenAL Soft
|
||||
As for OpenCV there are no prebuild packages of OpenAL Softe compiled with MinGW, but the installation process is very similar to OpenCV. Download the most recent source archive of OpenAL Soft from [http://kcat.strangesoft.net](http://kcat.strangesoft.net/openal.html#download). Extract its content to "C:\qTox\libs". Besides the source folder itself you'll find the file "pax_global_header". It is not required and can be deleted. Create the directory "openal-build" next to source folder. Now you should have the two directories "openal-soft-x.y.z" where x.y.z is the version of OpenAL and "openal-build" inside your "C:\qTox\libs" directory. Run CMake (cmake-gui) and setup the source and build location. Run the initial configuration and use "MSYS Makefiles" with "Use default native compilers". The only thing you need to configure is "CMAKE_INSTALL_PREFIX" which does not point to "C:\qTox\libs\openal-build\install" by default. Configure the project and generate the Makefiles. Compile and install OpenAL Soft with:
|
||||
```bash
|
||||
make
|
||||
make install
|
||||
```
|
||||
Copy the dll "OpenAL32.dll" located at "C:\qTox\libs\openal-build\install\bin" to "C:\qTox\libs\lib". Finally, copy the directory "AL" located at "C:\qTox\libs\openal-build\install\include" to "C:\qTox\libs\include". Unlike OpenCV you don't need to patch any files. Feel free to delete the directories "openal-soft-x.y.z" and "openal-build", but you don't need to.
|
||||
### Getting dependencies
|
||||
Run bootstrap.bat in cloned C:\qTox directory
|
||||
Script will download rest of dependencies compile them and put to appropriate directories.
|
||||
|
|
11
README.md
11
README.md
|
@ -20,9 +20,10 @@ qTox is a powerful Tox client that tries to follow the Tox design guidelines whi
|
|||
|
||||
This client runs on Windows, Linux and Mac natively.<br/>
|
||||
|
||||
<a href="http://207.12.89.155:8080/job/qTox-win64-nsis/lastSuccessfulBuild/artifact/setup-qtox64.exe">Windows 64 bit download</a><br/>
|
||||
<a href="http://207.12.89.155:8080/job/qTox-win32-nsis/lastSuccessfulBuild/artifact/setup-qtox32.exe">Windows 32 bit download (for older hardware)</a><br/>
|
||||
<a href="https://dist-build.tox.im/qtox.dmg">Mac OS X download </a><br/>
|
||||
|
||||
<a href="https://tux3-dev.tox.im/jenkins/job/qTox-win64-nsis/lastSuccessfulBuild/artifact/setup-qtox64.exe">Windows 64 bit download</a><br/>
|
||||
<a href="https://tux3-dev.tox.im/jenkins/job/qTox-win32-nsis/lastSuccessfulBuild/artifact/setup-qtox32.exe">Windows 32 bit download (for older hardware)</a><br/>
|
||||
<a href="https://jenkins.libtoxcore.so/job/qTox%20OS%20X/lastSuccessfulBuild/artifact/qtox.dmg">Mac OS X download </a><br/>
|
||||
<a href="https://jenkins.libtoxcore.so/job/qTox-linux-amd64/lastSuccessfulBuild/artifact/qt/qtox.xz">Linux binary download</a><br/>
|
||||
<a href="https://jenkins.libtoxcore.so/user/tux3/my-views/view/qTox/job/qTox-Linux-pkg/lastSuccessfulBuild/artifact/">Linux packages</a><br/>
|
||||
|
||||
|
@ -37,6 +38,6 @@ This client runs on Windows, Linux and Mac natively.<br/>
|
|||
|
||||
##Developer overview:
|
||||
|
||||
[GitStats](http://104.219.184.93/index.html)<br/>
|
||||
[GitStats](https://tux3-dev.tox.im/)<br/>
|
||||
[Mac & Linux jenkins](https://jenkins.libtoxcore.so/user/tux3/my-views/view/qTox/)<br/>
|
||||
[Windows jenkins](http://104.219.184.93:8080)<br/>
|
||||
[Windows jenkins](https://tux3-dev.tox.im/jenkins)<br/>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@mkdir %~dp0libs
|
||||
%~dp0tools\wget --no-check-certificate http://jenkins.libtoxcore.so/job/libtoxcore-win32-i686/lastSuccessfulBuild/artifact/libtoxcore-win32-i686.zip -O %~dp0libs\libtoxcore-latest.zip
|
||||
%~dp0tools\unzip -o %~dp0libs\libtoxcore-latest.zip -d %~dp0libs\
|
||||
@del %~dp0libs\libtoxcore-latest.zip
|
||||
@echo off
|
||||
|
||||
sh bootstrap.sh
|
||||
@pause
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
WINDOWS_VERSION=$(cmd.exe /c ver 2>/dev/null | grep "Microsoft Windows")
|
||||
if [ ! -z "$WINDOWS_VERSION" ]; then
|
||||
cd windows
|
||||
./bootstrap.sh
|
||||
exit $?
|
||||
fi
|
||||
|
||||
################ parameters ################
|
||||
# directory where the script is located
|
||||
SCRIPT_DIR=$( cd $(dirname $0); pwd -P)
|
||||
|
@ -67,7 +74,7 @@ while [ $# -ge 1 ] ; do
|
|||
echo ""
|
||||
fi
|
||||
|
||||
# print help
|
||||
# print help
|
||||
echo "Use this script to install/update libsodium and libtoxcore in ${INSTALL_DIR}"
|
||||
echo ""
|
||||
echo "usage:"
|
||||
|
|
|
@ -14,6 +14,17 @@ else
|
|||
INCLUDE_DIR="$2/include/"
|
||||
fi
|
||||
|
||||
WINDOWS_VERSION=$(cmd.exe /c ver 2>/dev/null | grep "Microsoft Windows")
|
||||
if [ ! -z "$WINDOWS_VERSION" ]; then
|
||||
EXT="dll"
|
||||
BIN_DIR="$2/bin/"
|
||||
STATIC_EXT="$EXT.a"
|
||||
else
|
||||
BIN_DIR=$LIB_DIR
|
||||
EXT="so"
|
||||
STATIC_EXT="a"
|
||||
fi
|
||||
|
||||
echo "Cloning filter_audio from GitHub.com"
|
||||
git clone https://github.com/irungentoo/filter_audio.git $SOURCE_DIR
|
||||
|
||||
|
@ -22,16 +33,21 @@ cd $SOURCE_DIR
|
|||
gcc -c -fPIC filter_audio.c aec/*.c agc/*.c ns/*.c other/*.c -lm -lpthread
|
||||
|
||||
echo "Creating shared object file"
|
||||
gcc *.o -shared -o libfilteraudio.so
|
||||
gcc *.o -shared -o libfilteraudio.$EXT -Wl,--out-implib,libfilteraudio.$STATIC_EXT
|
||||
|
||||
echo "Cleaning up"
|
||||
rm *.o
|
||||
|
||||
muhcmd="cp libfilteraudio.so $LIB_DIR"
|
||||
muhcmd="cp libfilteraudio.$EXT $BIN_DIR"
|
||||
[ -z "$2" ] && muhcmd="sudo $muhcmd"
|
||||
echo "Installing libfilteraudio.so with $muhcmd"
|
||||
$muhcmd
|
||||
|
||||
muhcmd="cp libfilteraudio.$STATIC_EXT $LIB_DIR"
|
||||
[ -z "$2" ] && muhcmd="sudo $muhcmd"
|
||||
echo "Installing libfilteraudio.$STATIC_EXT with $muhcmd"
|
||||
$muhcmd
|
||||
|
||||
muhcmd="cp *.h $INCLUDE_DIR"
|
||||
[ -z "$2" ] && muhcmd="sudo $muhcmd"
|
||||
echo "Installing include files with $muhcmd"
|
||||
|
|
31
qtox.pro
31
qtox.pro
|
@ -54,6 +54,23 @@ TIMESTAMP = $$system($1 2>null||echo 0||a;rm null;date +%s||echo 0) # I'm so sor
|
|||
DEFINES += TIMESTAMP=$$TIMESTAMP
|
||||
DEFINES += LOG_TO_FILE
|
||||
|
||||
contains(ENABLE_SYSTRAY_UNITY_BACKEND, YES) {
|
||||
DEFINES += ENABLE_SYSTRAY_UNITY_BACKEND
|
||||
|
||||
INCLUDEPATH += "/usr/include/libappindicator-0.1"
|
||||
INCLUDEPATH += "/usr/include/gtk-2.0"
|
||||
INCLUDEPATH += "/usr/include/glib-2.0"
|
||||
INCLUDEPATH += "/usr/lib/x86_64-linux-gnu/glib-2.0/include"
|
||||
INCLUDEPATH += "/usr/include/cairo"
|
||||
INCLUDEPATH += "/usr/include/pango-1.0"
|
||||
INCLUDEPATH += "/usr/lib/x86_64-linux-gnu/gtk-2.0/include"
|
||||
INCLUDEPATH += "/usr/include/gdk-pixbuf-2.0"
|
||||
INCLUDEPATH += "/usr/include/atk-1.0"
|
||||
INCLUDEPATH += "/usr/include/libdbusmenu-glib-0.4"
|
||||
|
||||
LIBS += -lgobject-2.0 -lappindicator -lgtk-x11-2.0
|
||||
}
|
||||
|
||||
contains(DISABLE_PLATFORM_EXT, YES) {
|
||||
|
||||
} else {
|
||||
|
@ -75,9 +92,9 @@ contains(JENKINS,YES) {
|
|||
# Rules for Windows, Mac OSX, and Linux
|
||||
win32 {
|
||||
RC_FILE = windows/qtox.rc
|
||||
LIBS += -liphlpapi -L$$PWD/libs/lib -lsodium -ltoxav -ltoxcore -ltoxencryptsave -ltoxdns -lvpx -lpthread
|
||||
LIBS += -L$$PWD/libs/lib -lopencv_core248 -lopencv_highgui248 -lopencv_imgproc248 -lOpenAL32 -lopus
|
||||
LIBS += -lopengl32 -lole32 -loleaut32 -luuid -lvfw32 -ljpeg -ltiff -lpng -ljasper -lIlmImf -lHalf -lws2_32 -lz
|
||||
LIBS += -L$$PWD/libs/lib -ltoxav -ltoxcore -ltoxencryptsave -ltoxdns -lsodium -lvpx -lpthread
|
||||
LIBS += -L$$PWD/libs/lib -lopencv_core249 -lopencv_highgui249 -lopencv_imgproc249 -lOpenAL32 -lopus
|
||||
LIBS += -lopengl32 -lole32 -loleaut32 -luuid -lvfw32 -lws2_32 -liphlpapi -lz
|
||||
|
||||
contains(DEFINES, QTOX_FILTER_AUDIO) {
|
||||
contains(STATICPKG, YES) {
|
||||
|
@ -195,7 +212,9 @@ HEADERS += src/widget/form/addfriendform.h \
|
|||
src/chatlog/content/notificationicon.h \
|
||||
src/chatlog/content/timestamp.h \
|
||||
src/chatlog/documentcache.h \
|
||||
src/chatlog/pixmapcache.h
|
||||
src/chatlog/pixmapcache.h \
|
||||
src/widget/callconfirmwidget.h \
|
||||
src/widget/systemtrayicon.h \
|
||||
|
||||
SOURCES += \
|
||||
src/widget/form/addfriendform.cpp \
|
||||
|
@ -268,7 +287,9 @@ SOURCES += \
|
|||
src/chatlog/content/notificationicon.cpp \
|
||||
src/chatlog/content/timestamp.cpp \
|
||||
src/chatlog/documentcache.cpp \
|
||||
src/chatlog/pixmapcache.cpp
|
||||
src/chatlog/pixmapcache.cpp \
|
||||
src/widget/callconfirmwidget.cpp \
|
||||
src/widget/systemtrayicon.cpp
|
||||
|
||||
contains(DEFINES, QTOX_FILTER_AUDIO) {
|
||||
HEADERS += src/audiofilterer.h
|
||||
|
|
4
res.qrc
4
res.qrc
|
@ -124,6 +124,7 @@
|
|||
<file>translations/fi.qm</file>
|
||||
<file>translations/fr.qm</file>
|
||||
<file>translations/it.qm</file>
|
||||
<file>translations/lt.qm</file>
|
||||
<file>translations/mannol.qm</file>
|
||||
<file>translations/pirate.qm</file>
|
||||
<file>translations/pl.qm</file>
|
||||
|
@ -226,5 +227,8 @@
|
|||
<file>ui/fileTransferInstance/arrow_white.svg</file>
|
||||
<file>ui/fileTransferInstance/browse.svg</file>
|
||||
<file>ui/fileTransferInstance/filetransferWidget.css</file>
|
||||
<file>ui/acceptCall/acceptCall.png</file>
|
||||
<file>ui/rejectCall/rejectCall.png</file>
|
||||
<file>ui/volButton/volButtonDisabled.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -6,8 +6,8 @@ if which apt-get; then
|
|||
elif which pacman; then
|
||||
sudo pacman -S --needed base-devel qt5 opencv openal opus libvpx libxss
|
||||
elif which yum; then
|
||||
yum groupinstall "Development Tools"
|
||||
yum install qt-devel qt-doc qt-creator opencv-devel openal-soft-devel libtool autoconf automake check check-devel libXScrnSaver-devel
|
||||
sudo yum groupinstall "Development Tools"
|
||||
sudo yum install qt-devel qt-doc qt-creator opencv-devel openal-soft-devel libtool autoconf automake check check-devel libXScrnSaver-devel
|
||||
else
|
||||
echo "Unknown package manager, attempting to compile anyways"
|
||||
fi
|
||||
|
|
|
@ -41,6 +41,7 @@ ALCdevice* Audio::alInDev{nullptr};
|
|||
ALCdevice* Audio::alOutDev{nullptr};
|
||||
ALCcontext* Audio::alContext{nullptr};
|
||||
ALuint Audio::alMainSource{0};
|
||||
float Audio::outputVolume{1.0};
|
||||
|
||||
void audioDebugLog(QString msg)
|
||||
{
|
||||
|
@ -64,6 +65,18 @@ Audio& Audio::getInstance()
|
|||
return *instance;
|
||||
}
|
||||
|
||||
Audio::~Audio()
|
||||
{
|
||||
qDebug() << "Deleting Audio";
|
||||
audioThread->exit(0);
|
||||
audioThread->wait();
|
||||
if (audioThread->isRunning())
|
||||
audioThread->terminate();
|
||||
delete audioThread;
|
||||
delete audioInLock;
|
||||
delete audioOutLock;
|
||||
}
|
||||
|
||||
void Audio::suscribeInput()
|
||||
{
|
||||
if (!alInDev)
|
||||
|
@ -249,7 +262,10 @@ void Audio::playGroupAudio(int group, int peer, const int16_t* data,
|
|||
return;
|
||||
|
||||
if (!call.alSources.contains(peer))
|
||||
{
|
||||
alGenSources(1, &call.alSources[peer]);
|
||||
alSourcef(call.alSources[peer], AL_GAIN, outputVolume);
|
||||
}
|
||||
|
||||
playAudioBuffer(call.alSources[peer], data, samples, channels, sample_rate);
|
||||
}
|
||||
|
@ -289,6 +305,7 @@ void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, u
|
|||
|
||||
ALint state;
|
||||
alGetSourcei(alSource, AL_SOURCE_STATE, &state);
|
||||
alSourcef(alSource, AL_GAIN, outputVolume);
|
||||
if (state != AL_PLAYING)
|
||||
alSourcePlay(alSource);
|
||||
}
|
||||
|
|
|
@ -73,9 +73,11 @@ public:
|
|||
static QThread* audioThread;
|
||||
static ALCcontext* alContext;
|
||||
static ALuint alMainSource;
|
||||
static float outputVolume;
|
||||
|
||||
private:
|
||||
explicit Audio()=default;
|
||||
~Audio();
|
||||
static void playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate);
|
||||
|
||||
private:
|
||||
|
|
|
@ -65,9 +65,13 @@ const QString AutoUpdater::checkURI = AutoUpdater::updateServer+"/qtox/"+AutoUpd
|
|||
const QString AutoUpdater::flistURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/flist";
|
||||
const QString AutoUpdater::filesURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/files/";
|
||||
bool AutoUpdater::abortFlag{false};
|
||||
std::atomic_bool AutoUpdater::isDownloadingUpdate{false};
|
||||
|
||||
bool AutoUpdater::isUpdateAvailable()
|
||||
{
|
||||
if (isDownloadingUpdate)
|
||||
return false;
|
||||
|
||||
VersionInfo newVersion = getUpdateVersion();
|
||||
if (newVersion.timestamp <= TIMESTAMP
|
||||
|| newVersion.versionString.isEmpty() || newVersion.versionString == GIT_VERSION)
|
||||
|
@ -280,26 +284,33 @@ bool AutoUpdater::downloadUpdate()
|
|||
if (platform.isEmpty())
|
||||
return false;
|
||||
|
||||
bool expectFalse = false;
|
||||
if (!isDownloadingUpdate.compare_exchange_strong(expectFalse,true))
|
||||
return false;
|
||||
|
||||
// Get a list of files to update
|
||||
QByteArray newFlistData = getUpdateFlist();
|
||||
QList<UpdateFileMeta> newFlist = parseFlist(newFlistData);
|
||||
QList<UpdateFileMeta> diff = genUpdateDiff(newFlist);
|
||||
|
||||
if (abortFlag)
|
||||
{
|
||||
isDownloadingUpdate = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << "AutoUpdater: Need to update "<<diff.size()<<" files";
|
||||
|
||||
// Create an empty directory to download updates into
|
||||
QString updateDirStr = Settings::getInstance().getSettingsDirPath() + "/update/";
|
||||
QDir updateDir(updateDirStr);
|
||||
if (updateDir.exists())
|
||||
updateDir.removeRecursively();
|
||||
QDir().mkdir(updateDirStr);
|
||||
if (!updateDir.exists())
|
||||
QDir().mkdir(updateDirStr);
|
||||
updateDir = QDir(updateDirStr);
|
||||
if (!updateDir.exists())
|
||||
{
|
||||
qWarning() << "AutoUpdater::downloadUpdate: Can't create update directory, aborting...";
|
||||
isDownloadingUpdate = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -308,6 +319,7 @@ bool AutoUpdater::downloadUpdate()
|
|||
if (!newFlistFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
|
||||
{
|
||||
qWarning() << "AutoUpdater::downloadUpdate: Can't save new flist file, aborting...";
|
||||
isDownloadingUpdate = false;
|
||||
return false;
|
||||
}
|
||||
newFlistFile.write(newFlistData);
|
||||
|
@ -317,7 +329,19 @@ bool AutoUpdater::downloadUpdate()
|
|||
for (UpdateFileMeta fileMeta : diff)
|
||||
{
|
||||
if (abortFlag)
|
||||
{
|
||||
isDownloadingUpdate = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip files we already have
|
||||
QFile fileFile(updateDirStr+fileMeta.installpath);
|
||||
if (fileFile.open(QIODevice::ReadOnly) && fileFile.size() == (qint64)fileMeta.size)
|
||||
{
|
||||
qDebug() << "AutoUpdater: Skipping already downloaded file '"+fileMeta.installpath+"'";
|
||||
fileFile.close();
|
||||
continue;
|
||||
}
|
||||
|
||||
qDebug() << "AutoUpdater: Downloading '"+fileMeta.installpath+"' ...";
|
||||
|
||||
|
@ -329,10 +353,14 @@ bool AutoUpdater::downloadUpdate()
|
|||
// Download
|
||||
UpdateFile file = getUpdateFile(fileMeta);
|
||||
if (abortFlag)
|
||||
{
|
||||
isDownloadingUpdate = false;
|
||||
return false;
|
||||
}
|
||||
if (file.data.isNull())
|
||||
{
|
||||
qWarning() << "AutoUpdater::downloadUpdate: Error downloading a file, aborting...";
|
||||
isDownloadingUpdate = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -341,20 +369,24 @@ bool AutoUpdater::downloadUpdate()
|
|||
file.data.size(), key) != 0)
|
||||
{
|
||||
qCritical() << "AutoUpdater: downloadUpdate: RECEIVED FORGED FILE, aborting...";
|
||||
isDownloadingUpdate = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save
|
||||
QFile fileFile(updateDirStr+fileMeta.installpath);
|
||||
if (!fileFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
|
||||
{
|
||||
qWarning() << "AutoUpdater::downloadUpdate: Can't save new update file, aborting...";
|
||||
isDownloadingUpdate = false;
|
||||
return false;
|
||||
}
|
||||
fileFile.write(file.data);
|
||||
fileFile.close();
|
||||
}
|
||||
|
||||
qDebug() << "AutoUpdater::downloadUpdate: The update is ready, it'll be installed on the next restart";
|
||||
|
||||
isDownloadingUpdate = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -364,6 +396,9 @@ bool AutoUpdater::isLocalUpdateReady()
|
|||
if (platform.isEmpty())
|
||||
return false;
|
||||
|
||||
if (isDownloadingUpdate)
|
||||
return false;
|
||||
|
||||
// Check that there's an update dir in the first place, valid or not
|
||||
QString updateDirStr = Settings::getInstance().getSettingsDirPath() + "/update/";
|
||||
QDir updateDir(updateDirStr);
|
||||
|
@ -380,22 +415,15 @@ bool AutoUpdater::isLocalUpdateReady()
|
|||
QList<UpdateFileMeta> updateFlist = parseFlist(updateFlistData);
|
||||
QList<UpdateFileMeta> diff = genUpdateDiff(updateFlist);
|
||||
|
||||
// If the update wasn't downloaded correctly, redownload it
|
||||
// We don't check signatures to not block qTox too long, the updater will do it anyway
|
||||
// Check that we have every file
|
||||
for (UpdateFileMeta fileMeta : diff)
|
||||
{
|
||||
if (!QFile::exists(updateDirStr+fileMeta.installpath))
|
||||
{
|
||||
QtConcurrent::run(&AutoUpdater::downloadUpdate);
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile f(updateDirStr+fileMeta.installpath);
|
||||
if (f.size() != (int64_t)fileMeta.size)
|
||||
{
|
||||
QtConcurrent::run(&AutoUpdater::downloadUpdate);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -446,6 +474,9 @@ fail:
|
|||
|
||||
void AutoUpdater::checkUpdatesAsyncInteractive()
|
||||
{
|
||||
if (isDownloadingUpdate)
|
||||
return;
|
||||
|
||||
QtConcurrent::run(&AutoUpdater::checkUpdatesAsyncInteractiveWorker);
|
||||
}
|
||||
|
||||
|
@ -454,7 +485,12 @@ void AutoUpdater::checkUpdatesAsyncInteractiveWorker()
|
|||
if (!isUpdateAvailable())
|
||||
return;
|
||||
|
||||
if (Widget::getInstance()->askMsgboxQuestion(QObject::tr("Update", "The title of a message box"),
|
||||
// If there's already an update dir, resume updating, otherwise ask the user
|
||||
QString updateDirStr = Settings::getInstance().getSettingsDirPath() + "/update/";
|
||||
QDir updateDir(updateDirStr);
|
||||
|
||||
if ((updateDir.exists() && QFile(updateDirStr+"flist").exists())
|
||||
|| Widget::getInstance()->askMsgboxQuestion(QObject::tr("Update", "The title of a message box"),
|
||||
QObject::tr("An update is available, do you want to download it now?\nIt will be installed when qTox restarts.")))
|
||||
{
|
||||
downloadUpdate();
|
||||
|
@ -464,4 +500,5 @@ void AutoUpdater::checkUpdatesAsyncInteractiveWorker()
|
|||
void AutoUpdater::abortUpdates()
|
||||
{
|
||||
abortFlag = true;
|
||||
isDownloadingUpdate = false;
|
||||
}
|
||||
|
|
|
@ -21,9 +21,10 @@
|
|||
#include <QString>
|
||||
#include <QList>
|
||||
#include <sodium.h>
|
||||
#include <atomic>
|
||||
|
||||
/// For now we only support auto updates on Windows, although extending it is not a technical issue.
|
||||
/// Linux and Mac users are expected to use their package managers or update manually through official channels.
|
||||
/// For now we only support auto updates on Windows and OS X, although extending it is not a technical issue.
|
||||
/// Linux users are expected to use their package managers or update manually through official channels.
|
||||
#ifdef Q_OS_WIN
|
||||
#define AUTOUPDATE_ENABLED 1
|
||||
#elif defined(Q_OS_OSX)
|
||||
|
@ -122,6 +123,7 @@ private:
|
|||
static const QString updaterBin; ///< Path to the qtox-updater binary
|
||||
static unsigned char key[];
|
||||
static bool abortFlag; ///< If true, try to abort everything.
|
||||
static std::atomic_bool isDownloadingUpdate; ///< We'll pretend there's no new update available if we're already updating
|
||||
};
|
||||
|
||||
#endif // AUTOUPDATE_H
|
||||
|
|
54
src/core.cpp
54
src/core.cpp
|
@ -84,7 +84,7 @@ Core::Core(Camera* cam, QThread *CoreThread, QString loadPath) :
|
|||
}
|
||||
|
||||
// OpenAL init
|
||||
QString outDevDescr = Settings::getInstance().getOutDev(); ;
|
||||
QString outDevDescr = Settings::getInstance().getOutDev();
|
||||
Audio::openOutput(outDevDescr);
|
||||
QString inDevDescr = Settings::getInstance().getInDev();
|
||||
Audio::openInput(inDevDescr);
|
||||
|
@ -92,9 +92,19 @@ Core::Core(Camera* cam, QThread *CoreThread, QString loadPath) :
|
|||
|
||||
Core::~Core()
|
||||
{
|
||||
qDebug() << "Deleting Core";
|
||||
|
||||
clearPassword(Core::ptMain);
|
||||
clearPassword(Core::ptHistory);
|
||||
|
||||
toxTimer->stop();
|
||||
coreThread->exit(0);
|
||||
while (coreThread->isRunning())
|
||||
{
|
||||
qApp->processEvents();
|
||||
coreThread->wait(500);
|
||||
}
|
||||
|
||||
if (tox)
|
||||
{
|
||||
toxav_kill(toxav);
|
||||
|
@ -355,7 +365,7 @@ void Core::bootstrapDht()
|
|||
}
|
||||
static int j = qrand() % listSize;
|
||||
|
||||
qDebug() << "Core: Bootstraping to the DHT ...";
|
||||
qDebug() << "Core: Bootstrapping to the DHT ...";
|
||||
|
||||
int i=0;
|
||||
while (i < 2) // i think the more we bootstrap, the more we jitter because the more we overwrite nodes
|
||||
|
@ -363,10 +373,10 @@ void Core::bootstrapDht()
|
|||
const Settings::DhtServer& dhtServer = dhtServerList[j % listSize];
|
||||
if (tox_bootstrap_from_address(tox, dhtServer.address.toLatin1().data(),
|
||||
dhtServer.port, CUserId(dhtServer.userId).data()) == 1)
|
||||
qDebug() << QString("Core: Bootstraping from ")+dhtServer.name+QString(", addr ")+dhtServer.address.toLatin1().data()
|
||||
qDebug() << QString("Core: Bootstrapping from ")+dhtServer.name+QString(", addr ")+dhtServer.address.toLatin1().data()
|
||||
+QString(", port ")+QString().setNum(dhtServer.port);
|
||||
else
|
||||
qDebug() << "Core: Error bootstraping from "+dhtServer.name;
|
||||
qDebug() << "Core: Error bootstrapping from "+dhtServer.name;
|
||||
|
||||
j++;
|
||||
i++;
|
||||
|
@ -731,7 +741,7 @@ void Core::acceptFriendRequest(const QString& userId)
|
|||
|
||||
void Core::requestFriendship(const QString& friendAddress, const QString& message)
|
||||
{
|
||||
const QString userId = friendAddress.mid(0, TOX_CLIENT_ID_SIZE * 2);
|
||||
const QString userId = friendAddress.mid(0, TOX_PUBLIC_KEY_SIZE * 2);
|
||||
|
||||
if (hasFriendWithAddress(friendAddress))
|
||||
{
|
||||
|
@ -1240,8 +1250,6 @@ bool Core::loadConfiguration(QString path)
|
|||
// tox core is already decrypted
|
||||
if (Settings::getInstance().getEnableLogging() && Settings::getInstance().getEncryptLogs())
|
||||
{
|
||||
bool error = true;
|
||||
|
||||
// get salt
|
||||
QFile file(HistoryKeeper::getHistoryPath());
|
||||
file.open(QIODevice::ReadOnly);
|
||||
|
@ -1255,6 +1263,7 @@ bool Core::loadConfiguration(QString path)
|
|||
}
|
||||
else
|
||||
{
|
||||
bool error = true;
|
||||
do
|
||||
{
|
||||
while (!pwsaltedkeys[ptHistory])
|
||||
|
@ -1294,6 +1303,9 @@ bool Core::loadConfiguration(QString path)
|
|||
|
||||
void Core::saveConfiguration()
|
||||
{
|
||||
if (QThread::currentThread() != coreThread)
|
||||
return (void) QMetaObject::invokeMethod(this, "saveConfiguration");
|
||||
|
||||
QString dir = Settings::getSettingsDirPath();
|
||||
QDir directory(dir);
|
||||
if (!directory.exists() && !directory.mkpath(directory.absolutePath())) {
|
||||
|
@ -1320,6 +1332,9 @@ void Core::saveConfiguration()
|
|||
|
||||
void Core::saveConfiguration(const QString& path)
|
||||
{
|
||||
if (QThread::currentThread() != coreThread)
|
||||
return (void) QMetaObject::invokeMethod(this, "saveConfiguration", Q_ARG(const QString&, path));
|
||||
|
||||
if (!tox)
|
||||
{
|
||||
qWarning() << "Core::saveConfiguration: Tox not started, aborting!";
|
||||
|
@ -1329,27 +1344,28 @@ void Core::saveConfiguration(const QString& path)
|
|||
Settings::getInstance().save();
|
||||
|
||||
QSaveFile configurationFile(path);
|
||||
if (!configurationFile.open(QIODevice::WriteOnly)) {
|
||||
if (!configurationFile.open(QIODevice::WriteOnly))
|
||||
{
|
||||
qCritical() << "File " << path << " cannot be opened";
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Core: writing tox_save to " << path;
|
||||
|
||||
uint32_t fileSize; bool encrypt = Settings::getInstance().getEncryptTox();
|
||||
uint32_t fileSize;
|
||||
bool encrypt = Settings::getInstance().getEncryptTox();
|
||||
if (encrypt)
|
||||
fileSize = tox_encrypted_size(tox);
|
||||
else
|
||||
fileSize = tox_size(tox);
|
||||
|
||||
if (fileSize > 0 && fileSize <= INT32_MAX) {
|
||||
if (fileSize > 0 && fileSize <= INT32_MAX)
|
||||
{
|
||||
uint8_t *data = new uint8_t[fileSize];
|
||||
|
||||
if (encrypt)
|
||||
{
|
||||
if (!pwsaltedkeys[ptMain])
|
||||
{
|
||||
// probably zero chance event
|
||||
Widget::getInstance()->showWarningMsgBox(tr("NO Password"), tr("Will be saved without encryption!"));
|
||||
tox_save(tox, data);
|
||||
}
|
||||
|
@ -1364,7 +1380,9 @@ void Core::saveConfiguration(const QString& path)
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tox_save(tox, data);
|
||||
}
|
||||
|
||||
configurationFile.write(reinterpret_cast<char *>(data), fileSize);
|
||||
configurationFile.commit();
|
||||
|
@ -1420,7 +1438,7 @@ void Core::loadFriends()
|
|||
// assuming there are not that many friends to fill up the whole stack
|
||||
int32_t *ids = new int32_t[friendCount];
|
||||
tox_get_friendlist(tox, ids, friendCount);
|
||||
uint8_t clientId[TOX_CLIENT_ID_SIZE];
|
||||
uint8_t clientId[TOX_PUBLIC_KEY_SIZE];
|
||||
for (int32_t i = 0; i < static_cast<int32_t>(friendCount); ++i) {
|
||||
if (tox_get_client_id(tox, ids[i], clientId) == 0) {
|
||||
emit friendAdded(ids[i], CUserId::toString(clientId));
|
||||
|
@ -1481,7 +1499,7 @@ ToxID Core::getGroupPeerToxID(int groupId, int peerId) const
|
|||
{
|
||||
ToxID peerToxID;
|
||||
|
||||
uint8_t rawID[TOX_CLIENT_ID_SIZE];
|
||||
uint8_t rawID[TOX_PUBLIC_KEY_SIZE];
|
||||
int res = tox_group_peer_pubkey(tox, groupId, peerId, rawID);
|
||||
if (res == -1)
|
||||
{
|
||||
|
@ -1687,14 +1705,14 @@ bool Core::hasFriendWithAddress(const QString &addr) const
|
|||
return false;
|
||||
}
|
||||
|
||||
QString pubkey = addr.left(TOX_CLIENT_ID_SIZE * 2);
|
||||
QString pubkey = addr.left(TOX_PUBLIC_KEY_SIZE * 2);
|
||||
return hasFriendWithPublicKey(pubkey);
|
||||
}
|
||||
|
||||
bool Core::hasFriendWithPublicKey(const QString &pubkey) const
|
||||
{
|
||||
// Valid length check
|
||||
if (pubkey.length() != (TOX_CLIENT_ID_SIZE * 2))
|
||||
if (pubkey.length() != (TOX_PUBLIC_KEY_SIZE * 2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1727,9 +1745,9 @@ bool Core::hasFriendWithPublicKey(const QString &pubkey) const
|
|||
QString Core::getFriendAddress(int friendNumber) const
|
||||
{
|
||||
// If we don't know the full address of the client, return just the id, otherwise get the full address
|
||||
uint8_t rawid[TOX_CLIENT_ID_SIZE];
|
||||
uint8_t rawid[TOX_PUBLIC_KEY_SIZE];
|
||||
tox_get_client_id(tox, friendNumber, rawid);
|
||||
QByteArray data((char*)rawid,TOX_CLIENT_ID_SIZE);
|
||||
QByteArray data((char*)rawid,TOX_PUBLIC_KEY_SIZE);
|
||||
QString id = data.toHex().toUpper();
|
||||
|
||||
QString addr = Settings::getInstance().getFriendAdress(id);
|
||||
|
|
|
@ -64,9 +64,6 @@ public:
|
|||
bool hasFriendWithPublicKey(const QString &pubkey) const; ///< Check if we have a friend by public key
|
||||
int joinGroupchat(int32_t friendNumber, uint8_t type, const uint8_t* pubkey,uint16_t length) const; ///< Accept a groupchat invite
|
||||
void quitGroupChat(int groupId) const; ///< Quit a groupchat
|
||||
|
||||
void saveConfiguration();
|
||||
void saveConfiguration(const QString& path);
|
||||
|
||||
QString getIDString() const; ///< Get the 12 first characters of our Tox ID
|
||||
|
||||
|
@ -88,6 +85,9 @@ public slots:
|
|||
void bootstrapDht(); ///< Connects us to the Tox network
|
||||
void switchConfiguration(const QString& profile); ///< Load a different profile and restart the core
|
||||
|
||||
void saveConfiguration();
|
||||
void saveConfiguration(const QString& path);
|
||||
|
||||
void acceptFriendRequest(const QString& userId);
|
||||
void requestFriendship(const QString& friendAddress, const QString& message);
|
||||
void groupInviteFriend(int friendId, int groupId);
|
||||
|
@ -117,6 +117,7 @@ public slots:
|
|||
void pauseResumeFileRecv(int friendId, int fileNum);
|
||||
|
||||
void answerCall(int callId);
|
||||
void rejectCall(int callId);
|
||||
void hangupCall(int callId);
|
||||
void startCall(int friendId, bool video=false);
|
||||
void cancelCall(int callId, int friendId);
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
ToxCall Core::calls[TOXAV_MAX_CALLS];
|
||||
#ifdef QTOX_FILTER_AUDIO
|
||||
AudioFilterer * Core::filterer[TOXAV_MAX_CALLS] { nullptr};
|
||||
AudioFilterer * Core::filterer[TOXAV_MAX_CALLS] {nullptr};
|
||||
#endif
|
||||
const int Core::videobufsize{TOXAV_MAX_VIDEO_WIDTH * TOXAV_MAX_VIDEO_HEIGHT * 4};
|
||||
uint8_t* Core::videobuf;
|
||||
|
@ -159,6 +159,13 @@ void Core::hangupCall(int callId)
|
|||
toxav_hangup(toxav, callId);
|
||||
}
|
||||
|
||||
void Core::rejectCall(int callId)
|
||||
{
|
||||
qDebug() << QString("Core: rejecting call %1").arg(callId);
|
||||
calls[callId].active = false;
|
||||
toxav_reject(toxav, callId, nullptr);
|
||||
}
|
||||
|
||||
void Core::startCall(int friendId, bool video)
|
||||
{
|
||||
int callId;
|
||||
|
@ -201,7 +208,7 @@ void Core::cancelCall(int callId, int friendId)
|
|||
{
|
||||
qDebug() << QString("Core: Cancelling call with %1").arg(friendId);
|
||||
calls[callId].active = false;
|
||||
toxav_cancel(toxav, callId, friendId, 0);
|
||||
toxav_cancel(toxav, callId, friendId, nullptr);
|
||||
}
|
||||
|
||||
void Core::cleanupCall(int callId)
|
||||
|
@ -245,10 +252,11 @@ void Core::sendCallAudio(int callId, ToxAv* toxav)
|
|||
|
||||
const int framesize = (calls[callId].codecSettings.audio_frame_duration * calls[callId].codecSettings.audio_sample_rate) / 1000 * av_DefaultSettings.audio_channels;
|
||||
const int bufsize = framesize * 2 * av_DefaultSettings.audio_channels;
|
||||
uint8_t buf[bufsize], dest[bufsize];
|
||||
uint8_t buf[bufsize];
|
||||
|
||||
if (Audio::tryCaptureSamples(buf, framesize))
|
||||
{
|
||||
uint8_t dest[bufsize];
|
||||
int r;
|
||||
if ((r = toxav_prepare_audio_frame(toxav, callId, dest, framesize*2, (int16_t*)buf, framesize)) < 0)
|
||||
{
|
||||
|
@ -551,6 +559,7 @@ void Core::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, un
|
|||
|
||||
ALint state;
|
||||
alGetSourcei(alSource, AL_SOURCE_STATE, &state);
|
||||
alSourcef(alSource, AL_GAIN, Audio::outputVolume);
|
||||
if (state != AL_PLAYING)
|
||||
{
|
||||
alSourcePlay(alSource);
|
||||
|
@ -618,9 +627,8 @@ void Core::sendGroupCallAudio(int groupId, ToxAv* toxav)
|
|||
|
||||
if (Audio::tryCaptureSamples(buf, framesize))
|
||||
{
|
||||
int r;
|
||||
if ((r = toxav_group_send_audio(toxav_get_tox(toxav), groupId, (int16_t*)buf,
|
||||
framesize, av_DefaultSettings.audio_channels, av_DefaultSettings.audio_sample_rate)) < 0)
|
||||
if (toxav_group_send_audio(toxav_get_tox(toxav), groupId, (int16_t*)buf,
|
||||
framesize, av_DefaultSettings.audio_channels, av_DefaultSettings.audio_sample_rate) < 0)
|
||||
{
|
||||
qDebug() << "Core: toxav_group_send_audio error";
|
||||
groupCalls[groupId].sendAudioTimer->start();
|
||||
|
|
|
@ -33,6 +33,13 @@ bool ToxFile::open(bool write)
|
|||
return write ? file->open(QIODevice::ReadWrite) : file->open(QIODevice::ReadOnly);
|
||||
}
|
||||
|
||||
ToxID::ToxID(const ToxID& other)
|
||||
{
|
||||
publicKey = other.publicKey;
|
||||
noSpam = other.noSpam;
|
||||
checkSum = other.checkSum;
|
||||
}
|
||||
|
||||
QString ToxID::toString() const
|
||||
{
|
||||
return publicKey + noSpam + checkSum;
|
||||
|
|
|
@ -16,6 +16,9 @@ enum class Status : int {Online = 0, Away, Busy, Offline};
|
|||
|
||||
struct ToxID
|
||||
{
|
||||
ToxID()=default;
|
||||
ToxID(const ToxID& other);
|
||||
|
||||
QString publicKey;
|
||||
QString noSpam;
|
||||
QString checkSum;
|
||||
|
|
|
@ -23,12 +23,11 @@
|
|||
#include "src/misc/settings.h"
|
||||
|
||||
Friend::Friend(int FriendId, const ToxID &UserId)
|
||||
: friendId(FriendId)
|
||||
: userName{Core::getInstance()->getPeerName(UserId)},
|
||||
userID{UserId}, friendId{FriendId}
|
||||
{
|
||||
hasNewEvents = 0;
|
||||
friendStatus = Status::Offline;
|
||||
userID = UserId;
|
||||
userName = Core::getInstance()->getPeerName(UserId);
|
||||
if (userName.size() == 0)
|
||||
userName = UserId.publicKey;
|
||||
|
||||
|
|
|
@ -27,7 +27,9 @@ struct Friend
|
|||
{
|
||||
public:
|
||||
Friend(int FriendId, const ToxID &UserId);
|
||||
Friend(const Friend& other)=delete;
|
||||
~Friend();
|
||||
Friend& operator=(const Friend& other)=delete;
|
||||
|
||||
void setName(QString name);
|
||||
void setAlias(QString name);
|
||||
|
|
|
@ -63,10 +63,10 @@ private:
|
|||
void updateAliases();
|
||||
QPair<int, ChatType> getChatID(const QString &id_str, ChatType ct);
|
||||
int getAliasID(const QString &id_str);
|
||||
QString wrapMessage(const QString &str);
|
||||
QString unWrapMessage(const QString &str);
|
||||
|
||||
ChatType convertToChatType(int);
|
||||
static QString wrapMessage(const QString &str);
|
||||
static QString unWrapMessage(const QString &str);
|
||||
static ChatType convertToChatType(int);
|
||||
|
||||
GenericDdInterface *db;
|
||||
QMap<QString, int> aliases;
|
||||
|
|
23
src/main.cpp
23
src/main.cpp
|
@ -66,12 +66,24 @@ int main(int argc, char *argv[])
|
|||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
parser.addPositionalArgument("uri", QObject::tr("Tox URI to parse"));
|
||||
parser.addOption(QCommandLineOption("P", QObject::tr("Starts new instance and loads specified profile."), QObject::tr("profile")));
|
||||
parser.addOption(QCommandLineOption("p", QObject::tr("Starts new instance and loads specified profile."), QObject::tr("profile")));
|
||||
parser.process(a);
|
||||
|
||||
Settings::getInstance(); // Build our Settings singleton as soon as QApplication is ready, not before
|
||||
if (parser.isSet("P"))
|
||||
Settings::getInstance().setCurrentProfile(parser.value("P"));
|
||||
if (parser.isSet("p"))
|
||||
{
|
||||
QString profile = parser.value("p");
|
||||
if (QDir(Settings::getSettingsDirPath()).exists(profile + ".tox"))
|
||||
{
|
||||
qDebug() << "Setting profile to" << profile;
|
||||
Settings::getInstance().setCurrentProfile(profile);
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "Error: -p profile" << profile + ".tox" << "doesn't exist";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
sodium_init(); // For the auto-updater
|
||||
|
||||
|
@ -82,7 +94,7 @@ int main(int argc, char *argv[])
|
|||
if (logfile.open(QIODevice::Append))
|
||||
{
|
||||
logFile->setDevice(&logfile);
|
||||
*logFile << QDateTime::currentDateTime().toString("\nyyyy-dd-MM HH:mm:ss' file logger starting\n'");
|
||||
*logFile << QDateTime::currentDateTime().toString("\nyyyy-MM-dd HH:mm:ss' file logger starting\n'");
|
||||
qInstallMessageHandler(myMessageHandler);
|
||||
}
|
||||
else
|
||||
|
@ -156,7 +168,7 @@ int main(int argc, char *argv[])
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
else if (!ipc.isCurrentOwner() && !parser.isSet("P"))
|
||||
else if (!ipc.isCurrentOwner() && !parser.isSet("p"))
|
||||
{
|
||||
time_t event = ipc.postEvent("$activate");
|
||||
ipc.waitUntilProcessed(event);
|
||||
|
@ -165,6 +177,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
// Run
|
||||
a.setQuitOnLastWindowClosed(false);
|
||||
Widget* w = Widget::getInstance();
|
||||
int errorcode = a.exec();
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ uint8_t* CData::data()
|
|||
return cData;
|
||||
}
|
||||
|
||||
uint16_t CData::size()
|
||||
uint16_t CData::size() const
|
||||
{
|
||||
return cDataSize;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ uint16_t CData::fromString(const QString& data, uint8_t* cData)
|
|||
|
||||
// CUserId
|
||||
|
||||
const uint16_t CUserId::SIZE{TOX_CLIENT_ID_SIZE};
|
||||
const uint16_t CUserId::SIZE{TOX_PUBLIC_KEY_SIZE};
|
||||
|
||||
CUserId::CUserId(const QString &userId) :
|
||||
CData(userId, SIZE < userId.size() ? userId.size() : SIZE)
|
||||
|
|
|
@ -24,11 +24,13 @@ class CData
|
|||
{
|
||||
public:
|
||||
uint8_t* data();
|
||||
uint16_t size();
|
||||
uint16_t size() const;
|
||||
|
||||
protected:
|
||||
explicit CData(const QString& data, uint16_t byteSize);
|
||||
CData(const CData& other)=delete;
|
||||
virtual ~CData();
|
||||
CData& operator=(const CData& other)=delete;
|
||||
|
||||
static QString toString(const uint8_t* cData, const uint16_t cDataSize);
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ uint8_t* CString::data()
|
|||
return cString;
|
||||
}
|
||||
|
||||
uint16_t CString::size()
|
||||
uint16_t CString::size() const
|
||||
{
|
||||
return cStringSize;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
~CString();
|
||||
|
||||
uint8_t* data();
|
||||
uint16_t size();
|
||||
uint16_t size() const;
|
||||
|
||||
static QString toString(const uint8_t* cMessage, const uint16_t cMessageSize);
|
||||
static uint16_t fromString(const QString& message, uint8_t* cMessage);
|
||||
|
|
|
@ -29,12 +29,7 @@
|
|||
#include <QList>
|
||||
#include <QStyleFactory>
|
||||
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#define SHOW_SYSTEM_TRAY_DEFAULT (bool) false
|
||||
#else // OS is not linux
|
||||
#define SHOW_SYSTEM_TRAY_DEFAULT (bool) true
|
||||
#endif
|
||||
|
||||
const QString Settings::OLDFILENAME = "settings.ini";
|
||||
const QString Settings::FILENAME = "qtox.ini";
|
||||
|
@ -136,12 +131,15 @@ void Settings::load()
|
|||
currentProfile = s.value("currentProfile", "").toString();
|
||||
autoAwayTime = s.value("autoAwayTime", 10).toInt();
|
||||
checkUpdates = s.value("checkUpdates", false).toBool();
|
||||
showWindow = s.value("showWindow", true).toBool();
|
||||
showInFront = s.value("showInFront", false).toBool();
|
||||
groupAlwaysNotify = s.value("groupAlwaysNotify", false).toBool();
|
||||
fauxOfflineMessaging = s.value("fauxOfflineMessaging", true).toBool();
|
||||
autoSaveEnabled = s.value("autoSaveEnabled", false).toBool();
|
||||
globalAutoAcceptDir = s.value("globalAutoAcceptDir",
|
||||
QStandardPaths::locate(QStandardPaths::HomeLocation, QString(), QStandardPaths::LocateDirectory)
|
||||
).toString();
|
||||
compactLayout = s.value("compactLayout", false).toBool();
|
||||
s.endGroup();
|
||||
|
||||
s.beginGroup("Advanced");
|
||||
|
@ -201,6 +199,10 @@ void Settings::load()
|
|||
filterAudio = s.value("filterAudio", false).toBool();
|
||||
s.endGroup();
|
||||
|
||||
s.beginGroup("Video");
|
||||
camVideoRes = s.value("camVideoRes",QSize()).toSize();
|
||||
s.endGroup();
|
||||
|
||||
// Read the embedded DHT bootsrap nodes list if needed
|
||||
if (dhtServerList.isEmpty())
|
||||
{
|
||||
|
@ -289,8 +291,11 @@ void Settings::save(QString path, bool writeFriends)
|
|||
s.setValue("currentProfile", currentProfile);
|
||||
s.setValue("autoAwayTime", autoAwayTime);
|
||||
s.setValue("checkUpdates", checkUpdates);
|
||||
s.setValue("showWindow", showWindow);
|
||||
s.setValue("showInFront", showInFront);
|
||||
s.setValue("groupAlwaysNotify", groupAlwaysNotify);
|
||||
s.setValue("fauxOfflineMessaging", fauxOfflineMessaging);
|
||||
s.setValue("compactLayout", compactLayout);
|
||||
s.setValue("autoSaveEnabled", autoSaveEnabled);
|
||||
s.setValue("globalAutoAcceptDir", globalAutoAcceptDir);
|
||||
s.endGroup();
|
||||
|
@ -344,6 +349,10 @@ void Settings::save(QString path, bool writeFriends)
|
|||
s.setValue("filterAudio", filterAudio);
|
||||
s.endGroup();
|
||||
|
||||
s.beginGroup("Video");
|
||||
s.setValue("camVideoRes",camVideoRes);
|
||||
s.endGroup();
|
||||
|
||||
if (!writeFriends || currentProfile.isEmpty()) // Core::switchConfiguration
|
||||
return;
|
||||
|
||||
|
@ -561,7 +570,17 @@ bool Settings::getShowInFront() const
|
|||
|
||||
void Settings::setShowInFront(bool newValue)
|
||||
{
|
||||
showInFront = newValue;
|
||||
showInFront = newValue;
|
||||
}
|
||||
|
||||
bool Settings::getGroupAlwaysNotify() const
|
||||
{
|
||||
return groupAlwaysNotify;
|
||||
}
|
||||
|
||||
void Settings::setGroupAlwaysNotify(bool newValue)
|
||||
{
|
||||
groupAlwaysNotify = newValue;
|
||||
}
|
||||
|
||||
QString Settings::getTranslation() const
|
||||
|
@ -854,6 +873,16 @@ void Settings::setCheckUpdates(bool newValue)
|
|||
checkUpdates = newValue;
|
||||
}
|
||||
|
||||
bool Settings::getShowWindow() const
|
||||
{
|
||||
return showWindow;
|
||||
}
|
||||
|
||||
void Settings::setShowWindow(bool newValue)
|
||||
{
|
||||
showWindow = newValue;
|
||||
}
|
||||
|
||||
QByteArray Settings::getSplitterState() const
|
||||
{
|
||||
return splitterState;
|
||||
|
@ -914,6 +943,16 @@ void Settings::setFilterAudio(bool newValue)
|
|||
filterAudio = newValue;
|
||||
}
|
||||
|
||||
QSize Settings::getCamVideoRes() const
|
||||
{
|
||||
return camVideoRes;
|
||||
}
|
||||
|
||||
void Settings::setCamVideoRes(QSize newValue)
|
||||
{
|
||||
camVideoRes = newValue;
|
||||
}
|
||||
|
||||
QString Settings::getFriendAdress(const QString &publicKey) const
|
||||
{
|
||||
QString key = ToxID::fromString(publicKey).publicKey;
|
||||
|
@ -986,6 +1025,17 @@ void Settings::setFauxOfflineMessaging(bool value)
|
|||
fauxOfflineMessaging = value;
|
||||
}
|
||||
|
||||
bool Settings::getCompactLayout() const
|
||||
{
|
||||
return compactLayout;
|
||||
}
|
||||
|
||||
void Settings::setCompactLayout(bool value)
|
||||
{
|
||||
compactLayout = value;
|
||||
emit compactLayoutChanged();
|
||||
}
|
||||
|
||||
int Settings::getThemeColor() const
|
||||
{
|
||||
return themeColor;
|
||||
|
|
|
@ -115,9 +115,15 @@ public:
|
|||
bool getCheckUpdates() const;
|
||||
void setCheckUpdates(bool newValue);
|
||||
|
||||
bool getShowWindow() const;
|
||||
void setShowWindow(bool newValue);
|
||||
|
||||
bool getShowInFront() const;
|
||||
void setShowInFront(bool newValue);
|
||||
|
||||
bool getGroupAlwaysNotify() const;
|
||||
void setGroupAlwaysNotify(bool newValue);
|
||||
|
||||
QPixmap getSavedAvatar(const QString& ownerId);
|
||||
void saveAvatar(QPixmap& pic, const QString& ownerId);
|
||||
|
||||
|
@ -133,6 +139,9 @@ public:
|
|||
bool getFilterAudio() const;
|
||||
void setFilterAudio(bool newValue);
|
||||
|
||||
QSize getCamVideoRes() const;
|
||||
void setCamVideoRes(QSize newValue);
|
||||
|
||||
// Assume all widgets have unique names
|
||||
// Don't use it to save every single thing you want to save, use it
|
||||
// for some general purpose widgets, such as MainWindows or Splitters,
|
||||
|
@ -223,6 +232,9 @@ public:
|
|||
bool getFauxOfflineMessaging() const;
|
||||
void setFauxOfflineMessaging(bool value);
|
||||
|
||||
bool getCompactLayout() const;
|
||||
void setCompactLayout(bool compact);
|
||||
|
||||
public:
|
||||
void save(bool writeFriends = true);
|
||||
void save(QString path, bool writeFriends = true);
|
||||
|
@ -246,6 +258,7 @@ private:
|
|||
bool dontShowDhtDialog;
|
||||
|
||||
bool fauxOfflineMessaging;
|
||||
bool compactLayout;
|
||||
bool enableIPv6;
|
||||
QString translation;
|
||||
static bool makeToxPortable;
|
||||
|
@ -255,7 +268,9 @@ private:
|
|||
bool lightTrayIcon;
|
||||
bool useEmoticons;
|
||||
bool checkUpdates;
|
||||
bool showWindow;
|
||||
bool showInFront;
|
||||
bool groupAlwaysNotify;
|
||||
|
||||
bool forceTCP;
|
||||
|
||||
|
@ -305,6 +320,9 @@ private:
|
|||
QString outDev;
|
||||
bool filterAudio;
|
||||
|
||||
// Video
|
||||
QSize camVideoRes;
|
||||
|
||||
struct friendProp
|
||||
{
|
||||
QString alias;
|
||||
|
@ -323,6 +341,7 @@ signals:
|
|||
void smileyPackChanged();
|
||||
void emojiFontChanged();
|
||||
void timestampFormatChanged();
|
||||
void compactLayoutChanged();
|
||||
};
|
||||
|
||||
#endif // SETTINGS_HPP
|
||||
|
|
|
@ -130,7 +130,8 @@ bool SmileyPack::load(const QString& filename)
|
|||
|
||||
while (!stringElement.isNull())
|
||||
{
|
||||
QString emoticon = stringElement.text();
|
||||
QString emoticon = stringElement.text()
|
||||
.replace("<","<").replace(">",">");
|
||||
filenameTable.insert(emoticon, file);
|
||||
|
||||
cacheSmiley(file); // preload all smileys
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
uint32_t Platform::getIdleTime()
|
||||
{
|
||||
LASTINPUTINFO info = { 0 };
|
||||
LASTINPUTINFO info = { 0, 0 };
|
||||
info.cbSize = sizeof(info);
|
||||
if (GetLastInputInfo(&info))
|
||||
return GetTickCount() - info.dwTime;
|
||||
|
|
|
@ -221,8 +221,8 @@ fallbackOnTox1:
|
|||
toxIdStr = queryTox1(record, silent);
|
||||
#elif TOX1_ASK_FALLBACK
|
||||
QMessageBox::StandardButton btn = QMessageBox::warning(nullptr, "qTox", tr("It appears that qTox has to use the old tox1 protocol.\n\
|
||||
Unfortunately tox1 is not secure. Should it be used anyway?"), QMessageBox::Ok|QMessageBox::No, QMessageBox::No);
|
||||
if (btn == QMessageBox::Ok)
|
||||
Unfortunately tox1 is not secure. Should it be used anyway?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
|
||||
if (btn == QMessageBox::Yes)
|
||||
queryTox1(record, silent);
|
||||
#endif
|
||||
return toxIdStr;
|
||||
|
|
|
@ -99,7 +99,7 @@ double Camera::getProp(Camera::Prop prop)
|
|||
return worker->getProp(int(prop));
|
||||
}
|
||||
|
||||
void Camera::onNewFrameAvailable(const VideoFrame frame)
|
||||
void Camera::onNewFrameAvailable(const VideoFrame &frame)
|
||||
{
|
||||
emit frameAvailable(frame);
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <QList>
|
||||
#include <QMutex>
|
||||
#include "vpx/vpx_image.h"
|
||||
#include "opencv2/opencv.hpp"
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
#include "src/video/videosource.h"
|
||||
|
||||
class CameraWorker;
|
||||
|
@ -79,7 +79,7 @@ private:
|
|||
CameraWorker* worker;
|
||||
|
||||
private slots:
|
||||
void onNewFrameAvailable(const VideoFrame frame);
|
||||
void onNewFrameAvailable(const VideoFrame& frame);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -29,6 +29,12 @@ CameraWorker::CameraWorker(int index)
|
|||
qRegisterMetaType<QList<QSize>>();
|
||||
}
|
||||
|
||||
CameraWorker::~CameraWorker()
|
||||
{
|
||||
if (clock)
|
||||
delete clock;
|
||||
}
|
||||
|
||||
void CameraWorker::onStart()
|
||||
{
|
||||
clock = new QTimer(this);
|
||||
|
@ -112,7 +118,7 @@ void CameraWorker::_probeResolutions()
|
|||
|
||||
//qDebug() << "PROBING:" << res << " got " << w << h;
|
||||
|
||||
if (!resolutions.contains(QSize(w,h)))
|
||||
if (w>0 && h>0 && !resolutions.contains(QSize(w,h)))
|
||||
resolutions.append(QSize(w,h));
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include <QQueue>
|
||||
#include <QSize>
|
||||
|
||||
#include "opencv2/opencv.hpp"
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
#include "videosource.h"
|
||||
|
||||
class QTimer;
|
||||
|
@ -34,6 +34,7 @@ class CameraWorker : public QObject
|
|||
Q_OBJECT
|
||||
public:
|
||||
CameraWorker(int index);
|
||||
~CameraWorker();
|
||||
void doWork();
|
||||
|
||||
void suspend();
|
||||
|
@ -48,7 +49,7 @@ public slots:
|
|||
|
||||
signals:
|
||||
void started();
|
||||
void newFrameAvailable(const VideoFrame frame);
|
||||
void newFrameAvailable(const VideoFrame& frame);
|
||||
void resProbingFinished(QList<QSize> res);
|
||||
void propProbingFinished(int prop, double val);
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#include "videosource.h"
|
||||
|
||||
class vpx_image;
|
||||
struct vpx_image;
|
||||
|
||||
class NetVideoSource : public VideoSource
|
||||
{
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
virtual void unsubscribe() = 0;
|
||||
|
||||
signals:
|
||||
void frameAvailable(const VideoFrame frame);
|
||||
void frameAvailable(const VideoFrame& frame);
|
||||
|
||||
};
|
||||
|
||||
|
|
93
src/widget/callconfirmwidget.cpp
Normal file
93
src/widget/callconfirmwidget.cpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
#include "callconfirmwidget.h"
|
||||
#include "widget.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPainter>
|
||||
#include <QPaintEvent>
|
||||
#include <QRect>
|
||||
#include <QPalette>
|
||||
|
||||
CallConfirmWidget::CallConfirmWidget(const QWidget *Anchor) :
|
||||
QWidget(Widget::getInstance()), anchor(Anchor),
|
||||
rectW{120}, rectH{85},
|
||||
spikeW{30}, spikeH{15},
|
||||
roundedFactor{20},
|
||||
rectRatio{static_cast<qreal>(rectH)/static_cast<qreal>(rectW)}
|
||||
{
|
||||
setWindowFlags(Qt::SubWindow);
|
||||
|
||||
QPalette palette;
|
||||
palette.setColor(QPalette::WindowText, Qt::white);
|
||||
setPalette(palette);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
QLabel *callLabel = new QLabel(QObject::tr("Incoming call..."), this);
|
||||
callLabel->setAlignment(Qt::AlignHCenter);
|
||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal, this);
|
||||
QPushButton *accept = new QPushButton(this), *reject = new QPushButton(this);
|
||||
accept->setFlat(true);
|
||||
reject->setFlat(true);
|
||||
accept->setStyleSheet("QPushButton{border:none;}");
|
||||
reject->setStyleSheet("QPushButton{border:none;}");
|
||||
accept->setIcon(QIcon(":/ui/acceptCall/acceptCall.png"));
|
||||
reject->setIcon(QIcon(":/ui/rejectCall/rejectCall.png"));
|
||||
accept->setIconSize(accept->size());
|
||||
reject->setIconSize(reject->size());
|
||||
|
||||
buttonBox->addButton(accept, QDialogButtonBox::AcceptRole);
|
||||
buttonBox->addButton(reject, QDialogButtonBox::RejectRole);
|
||||
|
||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &CallConfirmWidget::accepted);
|
||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &CallConfirmWidget::rejected);
|
||||
|
||||
connect(Widget::getInstance(), &Widget::resized, this, &CallConfirmWidget::reposition);
|
||||
|
||||
layout->setMargin(12);
|
||||
layout->addSpacing(spikeH);
|
||||
layout->addWidget(callLabel);
|
||||
layout->addWidget(buttonBox);
|
||||
|
||||
setFixedSize(rectW,rectH+spikeH);
|
||||
reposition();
|
||||
}
|
||||
|
||||
void CallConfirmWidget::reposition()
|
||||
{
|
||||
Widget* w = Widget::getInstance();
|
||||
QPoint pos = anchor->mapToGlobal({(anchor->width()-rectW)/2,anchor->height()})-w->mapToGlobal({0,0});
|
||||
|
||||
// We don't want the widget to overflow past the right of the screen
|
||||
int xOverflow=0;
|
||||
if (pos.x() + rectW > w->width())
|
||||
xOverflow = pos.x() + rectW - w->width();
|
||||
pos.rx() -= xOverflow;
|
||||
|
||||
mainRect = {0,spikeH,rectW,rectH};
|
||||
brush = QBrush(QColor(65,65,65));
|
||||
spikePoly = QPolygon({{(rectW-spikeW)/2+xOverflow,spikeH},
|
||||
{rectW/2+xOverflow,0},
|
||||
{(rectW+spikeW)/2+xOverflow,spikeH}});
|
||||
|
||||
move(pos);
|
||||
update();
|
||||
}
|
||||
|
||||
void CallConfirmWidget::paintEvent(QPaintEvent*)
|
||||
{
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setBrush(brush);
|
||||
painter.setPen(Qt::NoPen);
|
||||
|
||||
painter.drawRoundRect(mainRect, roundedFactor*rectRatio, roundedFactor);
|
||||
painter.drawPolygon(spikePoly);
|
||||
}
|
||||
|
||||
void CallConfirmWidget::showEvent(QShowEvent*)
|
||||
{
|
||||
reposition();
|
||||
update();
|
||||
}
|
45
src/widget/callconfirmwidget.h
Normal file
45
src/widget/callconfirmwidget.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#ifndef CALLCONFIRMWIDGET_H
|
||||
#define CALLCONFIRMWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QRect>
|
||||
#include <QPolygon>
|
||||
#include <QBrush>
|
||||
|
||||
class QPaintEvent;
|
||||
class QShowEvent;
|
||||
|
||||
/// This is a widget with dialog buttons to accept/reject a call
|
||||
/// It tracks the position of another widget called the anchor
|
||||
/// and looks like a bubble at the bottom of that widget.
|
||||
class CallConfirmWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CallConfirmWidget(const QWidget *Anchor);
|
||||
|
||||
signals:
|
||||
void accepted();
|
||||
void rejected();
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent* event) override;
|
||||
virtual void showEvent(QShowEvent * event) override;
|
||||
|
||||
protected slots:
|
||||
void reposition(); ///< Recalculate our positions to track the anchor
|
||||
|
||||
private:
|
||||
const QWidget* anchor; ///< The widget we're going to be tracking
|
||||
|
||||
QRect mainRect;
|
||||
QPolygon spikePoly;
|
||||
QBrush brush;
|
||||
|
||||
const int rectW, rectH;
|
||||
const int spikeW, spikeH;
|
||||
const int roundedFactor; ///< By how much are the corners of the main rect rounded
|
||||
const qreal rectRatio; ///< Used to correct the rounding factors on non-square rects
|
||||
};
|
||||
|
||||
#endif // CALLCONFIRMWIDGET_H
|
|
@ -98,8 +98,8 @@ void AddFriendForm::onSendTriggered()
|
|||
if (Settings::getInstance().getProxyType() != ProxyType::ptNone)
|
||||
{
|
||||
QMessageBox::StandardButton btn = QMessageBox::warning(main, "qTox", tr("qTox needs to use the Tox DNS, but can't do it through a proxy.\n\
|
||||
Ignore the proxy and connect to the Internet directly?"), QMessageBox::Ok|QMessageBox::No, QMessageBox::No);
|
||||
if (btn != QMessageBox::Ok)
|
||||
Ignore the proxy and connect to the Internet directly?"), QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
|
||||
if (btn != QMessageBox::Yes)
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,13 +24,20 @@
|
|||
#include <QDragEnterEvent>
|
||||
#include <QBitmap>
|
||||
#include "chatform.h"
|
||||
#include "src/historykeeper.h"
|
||||
#include "src/widget/form/loadhistorydialog.h"
|
||||
#include "src/core.h"
|
||||
#include "src/friend.h"
|
||||
#include "src/filetransferinstance.h"
|
||||
#include "src/historykeeper.h"
|
||||
#include "src/misc/style.h"
|
||||
#include "src/misc/settings.h"
|
||||
#include "src/misc/cstring.h"
|
||||
#include "src/widget/callconfirmwidget.h"
|
||||
#include "src/widget/friendwidget.h"
|
||||
#include "src/widget/netcamview.h"
|
||||
#include "src/widget/chatareawidget.h"
|
||||
#include "src/widget/form/loadhistorydialog.h"
|
||||
#include "src/widget/tool/chattextedit.h"
|
||||
#include "src/core.h"
|
||||
#include "src/widget/tool/chatactions/filetransferaction.h"
|
||||
#include "src/widget/widget.h"
|
||||
#include "src/widget/maskablepixmapwidget.h"
|
||||
#include "src/widget/croppinglabel.h"
|
||||
|
@ -56,8 +63,13 @@ ChatForm::ChatForm(Friend* chatFriend)
|
|||
statusMessageLabel->setFont(Style::getFont(Style::Medium));
|
||||
statusMessageLabel->setMinimumHeight(Style::getFont(Style::Medium).pixelSize());
|
||||
|
||||
callConfirm = nullptr;
|
||||
|
||||
typingTimer.setSingleShot(true);
|
||||
|
||||
netcam = new NetCamView();
|
||||
timer = nullptr;
|
||||
callDurationTimer = nullptr;
|
||||
disableCallButtonsTimer = nullptr;
|
||||
|
||||
chatWidget->setTypingNotification(ChatMessage::createTypingNotification());
|
||||
|
||||
|
@ -80,6 +92,7 @@ ChatForm::ChatForm(Friend* chatFriend)
|
|||
connect(volButton, SIGNAL(clicked()), this, SLOT(onVolMuteToggle()));
|
||||
connect(Core::getInstance(), &Core::fileSendFailed, this, &ChatForm::onFileSendFailed);
|
||||
connect(this, SIGNAL(chatAreaCleared()), this, SLOT(clearReciepts()));
|
||||
connect(&typingTimer, &QTimer::timeout, this, [=]{Core::getInstance()->sendTyping(f->getFriendID(), false);});
|
||||
connect(nameLabel, &CroppingLabel::textChanged, this, [=](QString text, QString orig) {
|
||||
if (text != orig) emit aliasChanged(text);
|
||||
} );
|
||||
|
@ -90,6 +103,7 @@ ChatForm::ChatForm(Friend* chatFriend)
|
|||
ChatForm::~ChatForm()
|
||||
{
|
||||
delete netcam;
|
||||
delete callConfirm;
|
||||
}
|
||||
|
||||
void ChatForm::setStatusMessage(QString newMessage)
|
||||
|
@ -132,6 +146,8 @@ void ChatForm::onSendTriggered()
|
|||
rec = Core::getInstance()->sendMessage(f->getFriendID(), qt_msg);
|
||||
|
||||
registerReceipt(rec, id, ma);
|
||||
|
||||
msgEdit->setLastMessage(msg); //set last message only when sending it
|
||||
}
|
||||
|
||||
msgEdit->clear();
|
||||
|
@ -145,11 +161,10 @@ void ChatForm::onTextEditChanged()
|
|||
else
|
||||
isNowTyping = msgEdit->toPlainText().length() > 0;
|
||||
|
||||
if (isTyping != isNowTyping)
|
||||
{
|
||||
isTyping = isNowTyping;
|
||||
Core::getInstance()->sendTyping(f->getFriendID(), isTyping);
|
||||
}
|
||||
if (isNowTyping)
|
||||
typingTimer.start(3000);
|
||||
|
||||
Core::getInstance()->sendTyping(f->getFriendID(), isNowTyping);
|
||||
}
|
||||
|
||||
void ChatForm::onAttachClicked()
|
||||
|
@ -245,20 +260,30 @@ void ChatForm::onAvInvite(int FriendId, int CallId, bool video)
|
|||
videoButton->disconnect();
|
||||
if (video)
|
||||
{
|
||||
callConfirm = new CallConfirmWidget(videoButton);
|
||||
if (isVisible())
|
||||
callConfirm->show();
|
||||
connect(callConfirm, &CallConfirmWidget::accepted, this, &ChatForm::onAnswerCallTriggered);
|
||||
connect(callConfirm, &CallConfirmWidget::rejected, this, &ChatForm::onRejectCallTriggered);
|
||||
|
||||
callButton->setObjectName("grey");
|
||||
callButton->style()->polish(callButton);
|
||||
videoButton->setObjectName("yellow");
|
||||
videoButton->style()->polish(videoButton);
|
||||
connect(videoButton, SIGNAL(clicked()), this, SLOT(onAnswerCallTriggered()));
|
||||
connect(videoButton, &QPushButton::clicked, this, &ChatForm::onAnswerCallTriggered);
|
||||
}
|
||||
else
|
||||
{
|
||||
callConfirm = new CallConfirmWidget(callButton);
|
||||
if (isVisible())
|
||||
callConfirm->show();
|
||||
connect(callConfirm, &CallConfirmWidget::accepted, this, &ChatForm::onAnswerCallTriggered);
|
||||
connect(callConfirm, &CallConfirmWidget::rejected, this, &ChatForm::onRejectCallTriggered);
|
||||
|
||||
callButton->setObjectName("yellow");
|
||||
callButton->style()->polish(callButton);
|
||||
videoButton->setObjectName("grey");
|
||||
videoButton->style()->polish(videoButton);
|
||||
connect(callButton, SIGNAL(clicked()), this, SLOT(onAnswerCallTriggered()));
|
||||
connect(callButton, &QPushButton::clicked, this, &ChatForm::onAnswerCallTriggered);
|
||||
}
|
||||
callButton->style()->polish(callButton);
|
||||
videoButton->style()->polish(videoButton);
|
||||
|
||||
insertChatMessage(ChatMessage::createChatInfoMessage(tr("%1 calling").arg(f->getDisplayedName()), ChatMessage::INFO, QDateTime::currentDateTime()));
|
||||
|
||||
|
@ -287,49 +312,38 @@ void ChatForm::onAvStart(int FriendId, int CallId, bool video)
|
|||
if (video)
|
||||
{
|
||||
callButton->setObjectName("grey");
|
||||
callButton->style()->polish(callButton);
|
||||
videoButton->setObjectName("red");
|
||||
videoButton->style()->polish(videoButton);
|
||||
connect(videoButton, SIGNAL(clicked()), this, SLOT(onHangupCallTriggered()));
|
||||
connect(videoButton, SIGNAL(clicked()),
|
||||
this, SLOT(onHangupCallTriggered()));
|
||||
|
||||
netcam->show(Core::getInstance()->getVideoSourceFromCall(CallId), f->getDisplayedName());
|
||||
}
|
||||
else
|
||||
{
|
||||
callButton->setObjectName("red");
|
||||
callButton->style()->polish(callButton);
|
||||
videoButton->setObjectName("grey");
|
||||
videoButton->style()->polish(videoButton);
|
||||
connect(callButton, SIGNAL(clicked()), this, SLOT(onHangupCallTriggered()));
|
||||
connect(callButton, SIGNAL(clicked()),
|
||||
this, SLOT(onHangupCallTriggered()));
|
||||
}
|
||||
callButton->style()->polish(callButton);
|
||||
videoButton->style()->polish(videoButton);
|
||||
|
||||
startCounter();
|
||||
}
|
||||
|
||||
void ChatForm::onAvCancel(int FriendId, int)
|
||||
{
|
||||
|
||||
if (FriendId != f->getFriendID())
|
||||
return;
|
||||
|
||||
qDebug() << "onAvCancel";
|
||||
|
||||
delete callConfirm;
|
||||
callConfirm = nullptr;
|
||||
|
||||
stopCounter();
|
||||
|
||||
audioInputFlag = false;
|
||||
audioOutputFlag = false;
|
||||
micButton->setObjectName("green");
|
||||
micButton->style()->polish(micButton);
|
||||
volButton->setObjectName("green");
|
||||
volButton->style()->polish(volButton);
|
||||
callButton->disconnect();
|
||||
videoButton->disconnect();
|
||||
callButton->setObjectName("green");
|
||||
callButton->style()->polish(callButton);
|
||||
videoButton->setObjectName("green");
|
||||
videoButton->style()->polish(videoButton);
|
||||
connect(callButton, SIGNAL(clicked()), this, SLOT(onCallTriggered()));
|
||||
connect(videoButton, SIGNAL(clicked()), this, SLOT(onVideoCallTriggered()));
|
||||
enableCallButtons();
|
||||
|
||||
netcam->hide();
|
||||
|
||||
|
@ -343,21 +357,11 @@ void ChatForm::onAvEnd(int FriendId, int)
|
|||
|
||||
qDebug() << "onAvEnd";
|
||||
|
||||
audioInputFlag = false;
|
||||
audioOutputFlag = false;
|
||||
micButton->setObjectName("green");
|
||||
micButton->style()->polish(micButton);
|
||||
volButton->setObjectName("green");
|
||||
volButton->style()->polish(volButton);
|
||||
callButton->disconnect();
|
||||
videoButton->disconnect();
|
||||
callButton->setObjectName("green");
|
||||
callButton->style()->polish(callButton);
|
||||
videoButton->setObjectName("green");
|
||||
videoButton->style()->polish(videoButton);
|
||||
connect(callButton, SIGNAL(clicked()), this, SLOT(onCallTriggered()));
|
||||
connect(videoButton, SIGNAL(clicked()), this, SLOT(onVideoCallTriggered()));
|
||||
delete callConfirm;
|
||||
callConfirm = nullptr;
|
||||
|
||||
enableCallButtons();
|
||||
|
||||
netcam->hide();
|
||||
|
||||
stopCounter();
|
||||
|
@ -379,7 +383,8 @@ void ChatForm::onAvRinging(int FriendId, int CallId, bool video)
|
|||
callButton->style()->polish(callButton);
|
||||
videoButton->setObjectName("yellow");
|
||||
videoButton->style()->polish(videoButton);
|
||||
connect(videoButton, SIGNAL(clicked()), this, SLOT(onCancelCallTriggered()));
|
||||
connect(videoButton, SIGNAL(clicked()),
|
||||
this, SLOT(onCancelCallTriggered()));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -387,7 +392,8 @@ void ChatForm::onAvRinging(int FriendId, int CallId, bool video)
|
|||
callButton->style()->polish(callButton);
|
||||
videoButton->setObjectName("grey");
|
||||
videoButton->style()->polish(videoButton);
|
||||
connect(callButton, SIGNAL(clicked()), this, SLOT(onCancelCallTriggered()));
|
||||
connect(callButton, SIGNAL(clicked()),
|
||||
this, SLOT(onCancelCallTriggered()));
|
||||
}
|
||||
|
||||
addSystemInfoMessage(tr("Calling to %1").arg(f->getDisplayedName()), ChatMessage::INFO, QDateTime::currentDateTime());
|
||||
|
@ -431,22 +437,10 @@ void ChatForm::onAvEnding(int FriendId, int)
|
|||
|
||||
qDebug() << "onAvEnding";
|
||||
|
||||
audioInputFlag = false;
|
||||
audioOutputFlag = false;
|
||||
micButton->setObjectName("green");
|
||||
micButton->style()->polish(micButton);
|
||||
volButton->setObjectName("green");
|
||||
volButton->style()->polish(volButton);
|
||||
callButton->disconnect();
|
||||
videoButton->disconnect();
|
||||
callButton->setObjectName("green");
|
||||
callButton->style()->polish(callButton);
|
||||
callButton->disconnect();
|
||||
videoButton->setObjectName("green");
|
||||
videoButton->style()->polish(videoButton);
|
||||
videoButton->disconnect();
|
||||
connect(callButton, SIGNAL(clicked()), this, SLOT(onCallTriggered()));
|
||||
connect(videoButton, SIGNAL(clicked()), this, SLOT(onVideoCallTriggered()));
|
||||
delete callConfirm;
|
||||
callConfirm = nullptr;
|
||||
|
||||
enableCallButtons();
|
||||
|
||||
netcam->hide();
|
||||
|
||||
|
@ -460,23 +454,11 @@ void ChatForm::onAvRequestTimeout(int FriendId, int)
|
|||
|
||||
qDebug() << "onAvRequestTimeout";
|
||||
|
||||
audioInputFlag = false;
|
||||
audioOutputFlag = false;
|
||||
micButton->setObjectName("green");
|
||||
micButton->style()->polish(micButton);
|
||||
volButton->setObjectName("green");
|
||||
volButton->style()->polish(volButton);
|
||||
callButton->disconnect();
|
||||
videoButton->disconnect();
|
||||
callButton->setObjectName("green");
|
||||
callButton->style()->polish(callButton);
|
||||
callButton->disconnect();
|
||||
videoButton->setObjectName("green");
|
||||
videoButton->style()->polish(videoButton);
|
||||
videoButton->disconnect();
|
||||
connect(callButton, SIGNAL(clicked()), this, SLOT(onCallTriggered()));
|
||||
connect(videoButton, SIGNAL(clicked()), this, SLOT(onVideoCallTriggered()));
|
||||
delete callConfirm;
|
||||
callConfirm = nullptr;
|
||||
|
||||
enableCallButtons();
|
||||
|
||||
netcam->hide();
|
||||
}
|
||||
|
||||
|
@ -487,22 +469,10 @@ void ChatForm::onAvPeerTimeout(int FriendId, int)
|
|||
|
||||
qDebug() << "onAvPeerTimeout";
|
||||
|
||||
audioInputFlag = false;
|
||||
audioOutputFlag = false;
|
||||
micButton->setObjectName("green");
|
||||
micButton->style()->polish(micButton);
|
||||
volButton->setObjectName("green");
|
||||
volButton->style()->polish(volButton);
|
||||
callButton->disconnect();
|
||||
videoButton->disconnect();
|
||||
callButton->setObjectName("green");
|
||||
callButton->style()->polish(callButton);
|
||||
callButton->disconnect();
|
||||
videoButton->setObjectName("green");
|
||||
videoButton->style()->polish(videoButton);
|
||||
videoButton->disconnect();
|
||||
connect(callButton, SIGNAL(clicked()), this, SLOT(onCallTriggered()));
|
||||
connect(videoButton, SIGNAL(clicked()), this, SLOT(onVideoCallTriggered()));
|
||||
delete callConfirm;
|
||||
callConfirm = nullptr;
|
||||
|
||||
enableCallButtons();
|
||||
|
||||
netcam->hide();
|
||||
}
|
||||
|
@ -514,22 +484,10 @@ void ChatForm::onAvRejected(int FriendId, int)
|
|||
|
||||
qDebug() << "onAvRejected";
|
||||
|
||||
audioInputFlag = false;
|
||||
audioOutputFlag = false;
|
||||
micButton->setObjectName("green");
|
||||
micButton->style()->polish(micButton);
|
||||
volButton->setObjectName("green");
|
||||
volButton->style()->polish(volButton);
|
||||
callButton->disconnect();
|
||||
videoButton->disconnect();
|
||||
callButton->setObjectName("green");
|
||||
callButton->style()->polish(callButton);
|
||||
callButton->disconnect();
|
||||
videoButton->setObjectName("green");
|
||||
videoButton->style()->polish(videoButton);
|
||||
videoButton->disconnect();
|
||||
connect(callButton, SIGNAL(clicked()), this, SLOT(onCallTriggered()));
|
||||
connect(videoButton, SIGNAL(clicked()), this, SLOT(onVideoCallTriggered()));
|
||||
delete callConfirm;
|
||||
callConfirm = nullptr;
|
||||
|
||||
enableCallButtons();
|
||||
|
||||
insertChatMessage(ChatMessage::createChatInfoMessage(tr("Call rejected"), ChatMessage::INFO, QDateTime::currentDateTime()));
|
||||
|
||||
|
@ -557,6 +515,12 @@ void ChatForm::onAnswerCallTriggered()
|
|||
{
|
||||
qDebug() << "onAnswerCallTriggered";
|
||||
|
||||
if (callConfirm)
|
||||
{
|
||||
delete callConfirm;
|
||||
callConfirm = nullptr;
|
||||
}
|
||||
|
||||
audioInputFlag = true;
|
||||
audioOutputFlag = true;
|
||||
emit answerCall(callId);
|
||||
|
@ -569,16 +533,32 @@ void ChatForm::onHangupCallTriggered()
|
|||
audioInputFlag = false;
|
||||
audioOutputFlag = false;
|
||||
emit hangupCall(callId);
|
||||
micButton->setObjectName("green");
|
||||
micButton->style()->polish(micButton);
|
||||
volButton->setObjectName("green");
|
||||
volButton->style()->polish(volButton);
|
||||
|
||||
enableCallButtons();
|
||||
}
|
||||
|
||||
void ChatForm::onRejectCallTriggered()
|
||||
{
|
||||
qDebug() << "onRejectCallTriggered";
|
||||
|
||||
if (callConfirm)
|
||||
{
|
||||
delete callConfirm;
|
||||
callConfirm = nullptr;
|
||||
}
|
||||
|
||||
audioInputFlag = false;
|
||||
audioOutputFlag = false;
|
||||
emit rejectCall(callId);
|
||||
|
||||
enableCallButtons();
|
||||
|
||||
}
|
||||
|
||||
void ChatForm::onCallTriggered()
|
||||
{
|
||||
qDebug() << "onCallTriggered";
|
||||
|
||||
|
||||
audioInputFlag = true;
|
||||
audioOutputFlag = true;
|
||||
callButton->disconnect();
|
||||
|
@ -589,7 +569,7 @@ void ChatForm::onCallTriggered()
|
|||
void ChatForm::onVideoCallTriggered()
|
||||
{
|
||||
qDebug() << "onVideoCallTriggered";
|
||||
|
||||
|
||||
audioInputFlag = true;
|
||||
audioOutputFlag = true;
|
||||
callButton->disconnect();
|
||||
|
@ -604,37 +584,80 @@ void ChatForm::onAvCallFailed(int FriendId)
|
|||
|
||||
qDebug() << "onAvCallFailed";
|
||||
|
||||
audioInputFlag = false;
|
||||
audioOutputFlag = false;
|
||||
callButton->disconnect();
|
||||
videoButton->disconnect();
|
||||
connect(callButton, SIGNAL(clicked()), this, SLOT(onCallTriggered()));
|
||||
connect(videoButton, SIGNAL(clicked()), this, SLOT(onVideoCallTriggered()));
|
||||
delete callConfirm;
|
||||
callConfirm = nullptr;
|
||||
|
||||
enableCallButtons();
|
||||
}
|
||||
|
||||
void ChatForm::onCancelCallTriggered()
|
||||
{
|
||||
qDebug() << "onCancelCallTriggered";
|
||||
|
||||
enableCallButtons();
|
||||
|
||||
netcam->hide();
|
||||
emit cancelCall(callId, f->getFriendID());
|
||||
}
|
||||
|
||||
void ChatForm::enableCallButtons()
|
||||
{
|
||||
qDebug() << "enableCallButtons";
|
||||
|
||||
audioInputFlag = false;
|
||||
audioOutputFlag = false;
|
||||
|
||||
micButton->setObjectName("grey");
|
||||
micButton->style()->polish(micButton);
|
||||
micButton->disconnect();
|
||||
volButton->setObjectName("grey");
|
||||
volButton->style()->polish(volButton);
|
||||
volButton->disconnect();
|
||||
|
||||
callButton->setObjectName("grey");
|
||||
callButton->style()->polish(callButton);
|
||||
callButton->disconnect();
|
||||
videoButton->setObjectName("grey");
|
||||
videoButton->style()->polish(videoButton);
|
||||
videoButton->disconnect();
|
||||
|
||||
if(disableCallButtonsTimer == nullptr)
|
||||
{
|
||||
disableCallButtonsTimer = new QTimer();
|
||||
connect(disableCallButtonsTimer, SIGNAL(timeout()),
|
||||
this, SLOT(onEnableCallButtons()));
|
||||
disableCallButtonsTimer->start(1500); // 1.5sec
|
||||
qDebug() << "timer started!!";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ChatForm::onEnableCallButtons()
|
||||
{
|
||||
qDebug() << "onEnableCallButtons";
|
||||
audioInputFlag = false;
|
||||
audioOutputFlag = false;
|
||||
micButton->setObjectName("green");
|
||||
micButton->style()->polish(micButton);
|
||||
volButton->setObjectName("green");
|
||||
volButton->style()->polish(volButton);
|
||||
callButton->disconnect();
|
||||
videoButton->disconnect();
|
||||
callButton->setObjectName("green");
|
||||
callButton->style()->polish(callButton);
|
||||
callButton->disconnect();
|
||||
videoButton->setObjectName("green");
|
||||
videoButton->style()->polish(videoButton);
|
||||
videoButton->disconnect();
|
||||
connect(callButton, SIGNAL(clicked()), this, SLOT(onCallTriggered()));
|
||||
connect(videoButton, SIGNAL(clicked()), this, SLOT(onVideoCallTriggered()));
|
||||
|
||||
netcam->hide();
|
||||
emit cancelCall(callId, f->getFriendID());
|
||||
|
||||
connect(callButton, SIGNAL(clicked()),
|
||||
this, SLOT(onCallTriggered()));
|
||||
connect(videoButton, SIGNAL(clicked()),
|
||||
this, SLOT(onVideoCallTriggered()));
|
||||
connect(micButton, SIGNAL(clicked()),
|
||||
this, SLOT(onMicMuteToggle()));
|
||||
connect(volButton, SIGNAL(clicked()),
|
||||
this, SLOT(onVolMuteToggle()));
|
||||
|
||||
disableCallButtonsTimer->stop();
|
||||
delete disableCallButtonsTimer;
|
||||
disableCallButtonsTimer = nullptr;
|
||||
}
|
||||
|
||||
void ChatForm::onMicMuteToggle()
|
||||
|
@ -695,6 +718,20 @@ void ChatForm::dropEvent(QDropEvent *ev)
|
|||
{
|
||||
QFileInfo info(url.path());
|
||||
|
||||
QFile file(info.absoluteFilePath());
|
||||
if (!file.exists() || !file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
QMessageBox::warning(this, tr("File not read"), tr("qTox wasn't able to open %1").arg(info.fileName()));
|
||||
continue;
|
||||
}
|
||||
if (file.isSequential())
|
||||
{
|
||||
QMessageBox::critical(0, tr("Bad Idea"), tr("You're trying to send a special (sequential) file, that's not going to work!"));
|
||||
file.close();
|
||||
continue;
|
||||
}
|
||||
file.close();
|
||||
|
||||
if (info.exists())
|
||||
Core::getInstance()->sendFile(f->getFriendID(), info.fileName(), info.absoluteFilePath(), info.size());
|
||||
}
|
||||
|
@ -805,11 +842,11 @@ void ChatForm::onLoadHistory()
|
|||
|
||||
void ChatForm::startCounter()
|
||||
{
|
||||
if (!timer)
|
||||
if (!callDurationTimer)
|
||||
{
|
||||
timer = new QTimer();
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(updateTime()));
|
||||
timer->start(1000);
|
||||
callDurationTimer = new QTimer();
|
||||
connect(callDurationTimer, SIGNAL(timeout()), this, SLOT(onUpdateTime()));
|
||||
callDurationTimer->start(1000);
|
||||
timeElapsed.start();
|
||||
callDuration->show();
|
||||
}
|
||||
|
@ -817,19 +854,20 @@ void ChatForm::startCounter()
|
|||
|
||||
void ChatForm::stopCounter()
|
||||
{
|
||||
if (timer)
|
||||
if (callDurationTimer)
|
||||
{
|
||||
addSystemInfoMessage(tr("Call with %1 ended. %2").arg(f->getDisplayedName(),secondsToDHMS(timeElapsed.elapsed()/1000)),
|
||||
ChatMessage::INFO, QDateTime::currentDateTime());
|
||||
timer->stop();
|
||||
callDurationTimer->stop();
|
||||
callDuration->setText("");
|
||||
callDuration->hide();
|
||||
timer = nullptr;
|
||||
delete timer;
|
||||
|
||||
delete callDurationTimer;
|
||||
callDurationTimer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ChatForm::updateTime()
|
||||
void ChatForm::onUpdateTime()
|
||||
{
|
||||
callDuration->setText(secondsToDHMS(timeElapsed.elapsed()/1000));
|
||||
}
|
||||
|
@ -915,3 +953,17 @@ void ChatForm::deliverOfflineMsgs()
|
|||
registerReceipt(rec, iter.key(), iter.value());
|
||||
}
|
||||
}
|
||||
|
||||
void ChatForm::show(Ui::MainWindow &ui)
|
||||
{
|
||||
GenericChatForm::show(ui);
|
||||
|
||||
if (callConfirm)
|
||||
callConfirm->show();
|
||||
}
|
||||
|
||||
void ChatForm::hideEvent(QHideEvent*)
|
||||
{
|
||||
if (callConfirm)
|
||||
callConfirm->hide();
|
||||
}
|
||||
|
|
|
@ -19,15 +19,19 @@
|
|||
|
||||
#include "genericchatform.h"
|
||||
#include "src/corestructs.h"
|
||||
#include <QSet>
|
||||
#include <QLabel>
|
||||
#include <QTimer>
|
||||
#include <QElapsedTimer>
|
||||
#include <QSet>
|
||||
|
||||
|
||||
struct Friend;
|
||||
class FileTransferInstance;
|
||||
class NetCamView;
|
||||
class QPixmap;
|
||||
class CallConfirmWidget;
|
||||
class QHideEvent;
|
||||
class QMoveEvent;
|
||||
|
||||
class ChatForm : public GenericChatForm
|
||||
{
|
||||
|
@ -41,6 +45,8 @@ public:
|
|||
void dischargeReceipt(int receipt);
|
||||
void setFriendTyping(bool isTyping);
|
||||
|
||||
virtual void show(Ui::MainWindow &ui);
|
||||
|
||||
signals:
|
||||
void sendFile(int32_t friendId, QString, QString, long long);
|
||||
void startCall(int friendId);
|
||||
|
@ -48,6 +54,7 @@ signals:
|
|||
void answerCall(int callId);
|
||||
void hangupCall(int callId);
|
||||
void cancelCall(int callId, int friendId);
|
||||
void rejectCall(int callId);
|
||||
void micMuteToggle(int callId);
|
||||
void volMuteToggle(int callId);
|
||||
void aliasChanged(const QString& alias);
|
||||
|
@ -83,15 +90,18 @@ private slots:
|
|||
void onAnswerCallTriggered();
|
||||
void onHangupCallTriggered();
|
||||
void onCancelCallTriggered();
|
||||
void onRejectCallTriggered();
|
||||
void onFileSendFailed(int FriendId, const QString &fname);
|
||||
void onLoadHistory();
|
||||
void updateTime();
|
||||
void onUpdateTime();
|
||||
void onEnableCallButtons();
|
||||
|
||||
protected:
|
||||
// drag & drop
|
||||
void dragEnterEvent(QDragEnterEvent* ev);
|
||||
void dropEvent(QDropEvent* ev);
|
||||
void registerReceipt(int receipt, int messageID, ChatMessage::Ptr msg);
|
||||
virtual void hideEvent(QHideEvent* event);
|
||||
|
||||
private:
|
||||
Friend* f;
|
||||
|
@ -99,7 +109,9 @@ private:
|
|||
NetCamView* netcam;
|
||||
int callId;
|
||||
QLabel *callDuration;
|
||||
QTimer *timer;
|
||||
QTimer *callDurationTimer;
|
||||
QTimer typingTimer;
|
||||
QTimer *disableCallButtonsTimer;
|
||||
QElapsedTimer timeElapsed;
|
||||
|
||||
QHash<uint, FileTransferInstance*> ftransWidgets;
|
||||
|
@ -109,6 +121,8 @@ private:
|
|||
QHash<int, int> receipts;
|
||||
QMap<int, ChatMessage::Ptr> undeliveredMsgs;
|
||||
bool isTyping;
|
||||
CallConfirmWidget *callConfirm;
|
||||
void enableCallButtons();
|
||||
};
|
||||
|
||||
#endif // CHATFORM_H
|
||||
|
|
|
@ -55,9 +55,12 @@ GenericChatForm::GenericChatForm(QWidget *parent)
|
|||
*mainFootLayout = new QHBoxLayout();
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(),
|
||||
*footButtonsSmall = new QVBoxLayout(),
|
||||
*volMicLayout = new QVBoxLayout();
|
||||
headTextLayout = new QVBoxLayout();
|
||||
*footButtonsSmall = new QVBoxLayout(),
|
||||
*micButtonsLayout = new QVBoxLayout();
|
||||
|
||||
QGridLayout *buttonsLayout = new QGridLayout();
|
||||
|
||||
headTextLayout = new QVBoxLayout();
|
||||
|
||||
chatWidget = new ChatLog(this);
|
||||
chatWidget->setBusyNotification(ChatMessage::createBusyNotification());
|
||||
|
@ -123,28 +126,37 @@ GenericChatForm::GenericChatForm(QWidget *parent)
|
|||
mainFootLayout->addWidget(sendButton);
|
||||
mainFootLayout->setSpacing(0);
|
||||
|
||||
headTextLayout->addStretch();
|
||||
headTextLayout->addStretch();
|
||||
headTextLayout->addWidget(nameLabel);
|
||||
|
||||
volMicLayout->addWidget(micButton, Qt::AlignTop);
|
||||
volMicLayout->addSpacing(2);
|
||||
volMicLayout->addWidget(volButton, Qt::AlignBottom);
|
||||
headTextLayout->addStretch();
|
||||
|
||||
micButtonsLayout->setSpacing(0);
|
||||
micButtonsLayout->addWidget(micButton, Qt::AlignTop | Qt::AlignRight);
|
||||
micButtonsLayout->addSpacing(4);
|
||||
micButtonsLayout->addWidget(volButton, Qt::AlignTop | Qt::AlignRight);
|
||||
|
||||
buttonsLayout->addLayout(micButtonsLayout, 0, 0, 2, 1, Qt::AlignTop | Qt::AlignRight);
|
||||
buttonsLayout->addWidget(callButton, 0, 1, 2, 1, Qt::AlignTop);
|
||||
buttonsLayout->addWidget(videoButton, 0, 2, 2, 1, Qt::AlignTop);
|
||||
buttonsLayout->setVerticalSpacing(0);
|
||||
buttonsLayout->setHorizontalSpacing(4);
|
||||
|
||||
headLayout->addWidget(avatar, Qt::AlignTop | Qt::AlignLeft);
|
||||
headLayout->addSpacing(5);
|
||||
headLayout->addLayout(headTextLayout, Qt::AlignTop | Qt::AlignAbsolute);
|
||||
headLayout->addLayout(buttonsLayout, Qt::AlignTop | Qt::AlignRight);
|
||||
|
||||
headWidget->setLayout(headLayout);
|
||||
headLayout->addWidget(avatar);
|
||||
headLayout->addSpacing(5);
|
||||
headLayout->addLayout(headTextLayout);
|
||||
headLayout->addLayout(volMicLayout);
|
||||
headLayout->addWidget(callButton);
|
||||
headLayout->addSpacing(3);
|
||||
headLayout->addWidget(videoButton);
|
||||
headLayout->setSpacing(0);
|
||||
|
||||
|
||||
//Fix for incorrect layouts on OS X as per
|
||||
//https://bugreports.qt-project.org/browse/QTBUG-14591
|
||||
sendButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||
fileButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||
emoteButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||
micButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||
volButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||
callButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||
videoButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||
|
||||
menu.addActions(chatWidget->actions());
|
||||
menu.addSeparator();
|
||||
|
|
|
@ -30,6 +30,7 @@ AdvancedForm::AdvancedForm() :
|
|||
bodyUI->dbLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
bodyUI->dbLabel->setOpenExternalLinks(true);
|
||||
|
||||
bodyUI->cbMakeToxPortable->setChecked(Settings::getInstance().getMakeToxPortable());
|
||||
bodyUI->syncTypeComboBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
|
||||
bodyUI->syncTypeComboBox->addItems({tr("FULL - very safe, slowest (recommended)"),
|
||||
tr("NORMAL - almost as safe as FULL, about 20% faster than FULL"),
|
||||
|
@ -38,6 +39,7 @@ AdvancedForm::AdvancedForm() :
|
|||
int index = 2 - static_cast<int>(Settings::getInstance().getDbSyncType());
|
||||
bodyUI->syncTypeComboBox->setCurrentIndex(index);
|
||||
|
||||
connect(bodyUI->cbMakeToxPortable, &QCheckBox::stateChanged, this, &AdvancedForm::onMakeToxPortableUpdated);
|
||||
connect(bodyUI->syncTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onDbSyncTypeUpdated()));
|
||||
connect(bodyUI->resetButton, SIGNAL(clicked()), this, SLOT(resetToDefault()));
|
||||
}
|
||||
|
@ -47,6 +49,11 @@ AdvancedForm::~AdvancedForm()
|
|||
delete bodyUI;
|
||||
}
|
||||
|
||||
void AdvancedForm::onMakeToxPortableUpdated()
|
||||
{
|
||||
Settings::getInstance().setMakeToxPortable(bodyUI->cbMakeToxPortable->isChecked());
|
||||
}
|
||||
|
||||
void AdvancedForm::onDbSyncTypeUpdated()
|
||||
{
|
||||
int index = 2 - bodyUI->syncTypeComboBox->currentIndex();
|
||||
|
|
|
@ -33,6 +33,7 @@ public:
|
|||
virtual ~AdvancedForm();
|
||||
|
||||
private slots:
|
||||
void onMakeToxPortableUpdated();
|
||||
void onDbSyncTypeUpdated();
|
||||
void resetToDefault();
|
||||
|
||||
|
|
|
@ -29,6 +29,16 @@
|
|||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbMakeToxPortable">
|
||||
<property name="toolTip">
|
||||
<string extracomment="describes makeToxPortable checkbox">Save settings to the working directory instead of the usual conf dir</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Make Tox portable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="warningLabel">
|
||||
<property name="text">
|
||||
|
|
|
@ -47,6 +47,7 @@ AVForm::AVForm() :
|
|||
connect(bodyUI->outDevCombobox, qcomboboxIndexChanged, this, &AVForm::onOutDevChanged);
|
||||
connect(bodyUI->filterAudio, SIGNAL(toggled(bool)), this, SLOT(onFilterAudioToggled(bool)));
|
||||
connect(bodyUI->rescanButton, &QPushButton::clicked, this, [=](){getAudioInDevices(); getAudioOutDevices();});
|
||||
bodyUI->playbackSlider->setValue(100);
|
||||
}
|
||||
|
||||
AVForm::~AVForm()
|
||||
|
@ -67,6 +68,10 @@ void AVForm::present()
|
|||
Camera::getInstance()->probeProp(Camera::HUE);
|
||||
|
||||
Camera::getInstance()->probeResolutions();
|
||||
|
||||
bodyUI->videoModescomboBox->blockSignals(true);
|
||||
bodyUI->videoModescomboBox->addItem(tr("Initializing Camera..."));
|
||||
bodyUI->videoModescomboBox->blockSignals(false);
|
||||
}
|
||||
|
||||
void AVForm::on_ContrastSlider_sliderMoved(int position)
|
||||
|
@ -89,9 +94,11 @@ void AVForm::on_HueSlider_sliderMoved(int position)
|
|||
Camera::getInstance()->setProp(Camera::HUE, position / 100.0);
|
||||
}
|
||||
|
||||
void AVForm::on_videoModescomboBox_activated(int index)
|
||||
void AVForm::on_videoModescomboBox_currentIndexChanged(int index)
|
||||
{
|
||||
Camera::getInstance()->setResolution(bodyUI->videoModescomboBox->itemData(index).toSize());
|
||||
QSize res = bodyUI->videoModescomboBox->itemData(index).toSize();
|
||||
Settings::getInstance().setCamVideoRes(res);
|
||||
Camera::getInstance()->setResolution(res);
|
||||
}
|
||||
|
||||
void AVForm::onPropProbingFinished(Camera::Prop prop, double val)
|
||||
|
@ -117,11 +124,25 @@ void AVForm::onPropProbingFinished(Camera::Prop prop, double val)
|
|||
|
||||
void AVForm::onResProbingFinished(QList<QSize> res)
|
||||
{
|
||||
QSize savedRes = Settings::getInstance().getCamVideoRes();
|
||||
int savedResIndex = -1;
|
||||
bodyUI->videoModescomboBox->clear();
|
||||
for (QSize r : res)
|
||||
bodyUI->videoModescomboBox->blockSignals(true);
|
||||
for (int i=0; i<res.size(); ++i)
|
||||
{
|
||||
QSize& r = res[i];
|
||||
bodyUI->videoModescomboBox->addItem(QString("%1x%2").arg(QString::number(r.width()),QString::number(r.height())), r);
|
||||
if (r == savedRes)
|
||||
savedResIndex = i;
|
||||
}
|
||||
//reset index, otherwise cameras with only one resolution won't get initialized
|
||||
bodyUI->videoModescomboBox->setCurrentIndex(-1);
|
||||
bodyUI->videoModescomboBox->blockSignals(false);
|
||||
|
||||
bodyUI->videoModescomboBox->setCurrentIndex(bodyUI->videoModescomboBox->count()-1);
|
||||
if (savedResIndex != -1)
|
||||
bodyUI->videoModescomboBox->setCurrentIndex(savedResIndex);
|
||||
else
|
||||
bodyUI->videoModescomboBox->setCurrentIndex(bodyUI->videoModescomboBox->count()-1);
|
||||
}
|
||||
|
||||
void AVForm::hideEvent(QHideEvent *)
|
||||
|
@ -129,36 +150,47 @@ void AVForm::hideEvent(QHideEvent *)
|
|||
bodyUI->CamVideoSurface->setSource(nullptr);
|
||||
}
|
||||
|
||||
void AVForm::showEvent(QShowEvent *)
|
||||
{
|
||||
bodyUI->CamVideoSurface->setSource(Camera::getInstance());
|
||||
}
|
||||
|
||||
void AVForm::getAudioInDevices()
|
||||
{
|
||||
QString settingsInDev = Settings::getInstance().getInDev();
|
||||
bool inDevFound = false;
|
||||
int inDevIndex = 0;
|
||||
bodyUI->inDevCombobox->clear();
|
||||
const ALchar *pDeviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
|
||||
if (pDeviceList)
|
||||
{
|
||||
//prevent currentIndexChanged to be fired while adding items
|
||||
bodyUI->inDevCombobox->blockSignals(true);
|
||||
while (*pDeviceList)
|
||||
{
|
||||
int len = strlen(pDeviceList);
|
||||
QString inDev = QString::fromLocal8Bit(pDeviceList,len);
|
||||
#ifdef Q_OS_WIN32
|
||||
QString inDev = QString::fromUtf8(pDeviceList,len);
|
||||
#else
|
||||
QString inDev = QString::fromLocal8Bit(pDeviceList,len);
|
||||
#endif
|
||||
bodyUI->inDevCombobox->addItem(inDev);
|
||||
if (settingsInDev == inDev)
|
||||
{
|
||||
bodyUI->inDevCombobox->setCurrentIndex(bodyUI->inDevCombobox->count()-1);
|
||||
inDevFound = true;
|
||||
inDevIndex = bodyUI->inDevCombobox->count()-1;
|
||||
}
|
||||
pDeviceList += len+1;
|
||||
}
|
||||
//addItem changes currentIndex -> reset
|
||||
bodyUI->inDevCombobox->setCurrentIndex(-1);
|
||||
bodyUI->inDevCombobox->blockSignals(false);
|
||||
}
|
||||
|
||||
if (!inDevFound)
|
||||
Settings::getInstance().setInDev(bodyUI->inDevCombobox->itemText(0));
|
||||
bodyUI->inDevCombobox->setCurrentIndex(inDevIndex);
|
||||
}
|
||||
|
||||
void AVForm::getAudioOutDevices()
|
||||
{
|
||||
QString settingsOutDev = Settings::getInstance().getOutDev();
|
||||
bool outDevFound = false;
|
||||
int outDevIndex = 0;
|
||||
bodyUI->outDevCombobox->clear();
|
||||
const ALchar *pDeviceList;
|
||||
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
|
||||
|
@ -167,22 +199,28 @@ void AVForm::getAudioOutDevices()
|
|||
pDeviceList = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
|
||||
if (pDeviceList)
|
||||
{
|
||||
//prevent currentIndexChanged to be fired while adding items
|
||||
bodyUI->outDevCombobox->blockSignals(true);
|
||||
while (*pDeviceList)
|
||||
{
|
||||
int len = strlen(pDeviceList);
|
||||
QString outDev = QString::fromLocal8Bit(pDeviceList,len);
|
||||
#ifdef Q_OS_WIN32
|
||||
QString outDev = QString::fromUtf8(pDeviceList,len);
|
||||
#else
|
||||
QString outDev = QString::fromLocal8Bit(pDeviceList,len);
|
||||
#endif
|
||||
bodyUI->outDevCombobox->addItem(outDev);
|
||||
if (settingsOutDev == outDev)
|
||||
{
|
||||
bodyUI->outDevCombobox->setCurrentIndex(bodyUI->outDevCombobox->count()-1);
|
||||
outDevFound = true;
|
||||
outDevIndex = bodyUI->outDevCombobox->count()-1;
|
||||
}
|
||||
pDeviceList += len+1;
|
||||
}
|
||||
//addItem changes currentIndex -> reset
|
||||
bodyUI->outDevCombobox->setCurrentIndex(-1);
|
||||
bodyUI->outDevCombobox->blockSignals(false);
|
||||
}
|
||||
|
||||
if (!outDevFound)
|
||||
Settings::getInstance().setOutDev(bodyUI->outDevCombobox->itemText(0));
|
||||
bodyUI->outDevCombobox->setCurrentIndex(outDevIndex);
|
||||
}
|
||||
|
||||
void AVForm::onInDevChanged(const QString &deviceDescriptor)
|
||||
|
@ -201,3 +239,28 @@ void AVForm::onFilterAudioToggled(bool filterAudio)
|
|||
{
|
||||
Settings::getInstance().setFilterAudio(filterAudio);
|
||||
}
|
||||
|
||||
void AVForm::on_HueSlider_valueChanged(int value)
|
||||
{
|
||||
Camera::getInstance()->setProp(Camera::HUE, value / 100.0);
|
||||
}
|
||||
|
||||
void AVForm::on_BrightnessSlider_valueChanged(int value)
|
||||
{
|
||||
Camera::getInstance()->setProp(Camera::BRIGHTNESS, value / 100.0);
|
||||
}
|
||||
|
||||
void AVForm::on_SaturationSlider_valueChanged(int value)
|
||||
{
|
||||
Camera::getInstance()->setProp(Camera::SATURATION, value / 100.0);
|
||||
}
|
||||
|
||||
void AVForm::on_ContrastSlider_valueChanged(int value)
|
||||
{
|
||||
Camera::getInstance()->setProp(Camera::CONTRAST, value / 100.0);
|
||||
}
|
||||
|
||||
void AVForm::on_playbackSlider_valueChanged(int value)
|
||||
{
|
||||
Audio::getInstance().outputVolume = value / 100.0;
|
||||
}
|
||||
|
|
|
@ -47,18 +47,28 @@ private slots:
|
|||
void on_SaturationSlider_sliderMoved(int position);
|
||||
void on_BrightnessSlider_sliderMoved(int position);
|
||||
void on_HueSlider_sliderMoved(int position);
|
||||
void on_videoModescomboBox_activated(int index);
|
||||
void on_videoModescomboBox_currentIndexChanged(int index);
|
||||
|
||||
// audio
|
||||
void onInDevChanged(const QString& deviceDescriptor);
|
||||
void onOutDevChanged(const QString& deviceDescriptor);
|
||||
void onFilterAudioToggled(bool filterAudio);
|
||||
void on_playbackSlider_valueChanged(int value);
|
||||
|
||||
// camera
|
||||
void onPropProbingFinished(Camera::Prop prop, double val);
|
||||
void onResProbingFinished(QList<QSize> res);
|
||||
|
||||
virtual void hideEvent(QHideEvent*);
|
||||
virtual void showEvent(QShowEvent*);
|
||||
|
||||
void on_HueSlider_valueChanged(int value);
|
||||
|
||||
void on_BrightnessSlider_valueChanged(int value);
|
||||
|
||||
void on_SaturationSlider_valueChanged(int value);
|
||||
|
||||
void on_ContrastSlider_valueChanged(int value);
|
||||
|
||||
private:
|
||||
Ui::AVSettings *bodyUI;
|
||||
|
|
|
@ -60,6 +60,9 @@
|
|||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Use slider to set volume of your speakers.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
|
@ -67,6 +70,10 @@
|
|||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Use slider to set volume of your microphone.
|
||||
WARNING: slider is not supposed to work yet.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
|
@ -101,6 +108,9 @@
|
|||
<property name="text">
|
||||
<string>Filter audio</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Filter sound from your microphone, so that people hearing you would get better sound.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -122,6 +132,13 @@
|
|||
<property name="text">
|
||||
<string>Resolution</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Set resolution of your camera.
|
||||
The higher values, the better video quality your friends may get.
|
||||
Note though that with better video quality there is needed better internet connection.
|
||||
Sometimes your connection may not be good enough to handle higher video quality,
|
||||
which may lead to problems with video calls.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
|
@ -132,6 +149,13 @@
|
|||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Set resolution of your camera.
|
||||
The higher values, the better video quality your friends may get.
|
||||
Note though that with better video quality there is needed better internet connection.
|
||||
Sometimes your connection may not be good enough to handle higher video quality,
|
||||
which may lead to problems with video calls.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
|
||||
#include "src/autoupdate.h"
|
||||
|
||||
static QStringList locales = {"bg", "de", "en", "es", "fr", "it", "mannol", "pirate", "pl", "pt", "ru", "fi", "sv", "uk"};
|
||||
static QStringList langs = {"Български", "Deutsch", "English", "Español", "Français", "Italiano", "mannol", "Pirate", "Polski", "Português", "Русский", "Suomi", "Svenska", "Українська"};
|
||||
static QStringList locales = {"bg", "de", "en", "es", "fr", "it", "lt", "mannol", "pirate", "pl", "pt", "ru", "fi", "sv", "uk"};
|
||||
static QStringList langs = {"Български", "Deutsch", "English", "Español", "Français", "Italiano", "Lietuvių", "mannol", "Pirate", "Polski", "Português", "Русский", "Suomi", "Svenska", "Українська"};
|
||||
|
||||
static QStringList timeFormats = {"hh:mm AP", "hh:mm", "hh:mm:ss AP", "hh:mm:ss"};
|
||||
|
||||
|
@ -45,16 +45,14 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
|
|||
|
||||
bodyUI->checkUpdates->setVisible(AUTOUPDATE_ENABLED);
|
||||
bodyUI->checkUpdates->setChecked(Settings::getInstance().getCheckUpdates());
|
||||
bodyUI->trayBehavior->addStretch();
|
||||
|
||||
bodyUI->cbEnableIPv6->setChecked(Settings::getInstance().getEnableIPv6());
|
||||
for (int i = 0; i < langs.size(); i++)
|
||||
bodyUI->transComboBox->insertItem(i, langs[i]);
|
||||
bodyUI->transComboBox->setCurrentIndex(locales.indexOf(Settings::getInstance().getTranslation()));
|
||||
bodyUI->cbMakeToxPortable->setChecked(Settings::getInstance().getMakeToxPortable());
|
||||
|
||||
bool showSystemTray = Settings::getInstance().getShowSystemTray();
|
||||
|
||||
|
||||
bodyUI->showSystemTray->setChecked(showSystemTray);
|
||||
bodyUI->startInTray->setChecked(Settings::getInstance().getAutostartInTray());
|
||||
bodyUI->startInTray->setEnabled(showSystemTray);
|
||||
|
@ -68,8 +66,11 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
|
|||
bodyUI->useEmoticons->setChecked(Settings::getInstance().getUseEmoticons());
|
||||
bodyUI->autoacceptFiles->setChecked(Settings::getInstance().getAutoSaveEnabled());
|
||||
bodyUI->autoSaveFilesDir->setText(Settings::getInstance().getGlobalAutoAcceptDir());
|
||||
bodyUI->showWindow->setChecked(Settings::getInstance().getShowWindow());
|
||||
bodyUI->showInFront->setChecked(Settings::getInstance().getShowInFront());
|
||||
bodyUI->groupAlwaysNotify->setChecked(Settings::getInstance().getGroupAlwaysNotify());
|
||||
bodyUI->cbFauxOfflineMessaging->setChecked(Settings::getInstance().getFauxOfflineMessaging());
|
||||
bodyUI->cbCompactLayout->setChecked(Settings::getInstance().getCompactLayout());
|
||||
|
||||
for (auto entry : SmileyPack::listSmileyPacks())
|
||||
{
|
||||
|
@ -117,7 +118,6 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
|
|||
//general
|
||||
connect(bodyUI->checkUpdates, &QCheckBox::stateChanged, this, &GeneralForm::onCheckUpdateChanged);
|
||||
connect(bodyUI->transComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onTranslationUpdated()));
|
||||
connect(bodyUI->cbMakeToxPortable, &QCheckBox::stateChanged, this, &GeneralForm::onMakeToxPortableUpdated);
|
||||
connect(bodyUI->showSystemTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetShowSystemTray);
|
||||
connect(bodyUI->startInTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetAutostartInTray);
|
||||
connect(bodyUI->closeToTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetCloseToTray);
|
||||
|
@ -125,7 +125,9 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
|
|||
connect(bodyUI->lightTrayIcon, &QCheckBox::stateChanged, this, &GeneralForm::onSetLightTrayIcon);
|
||||
connect(bodyUI->statusChanges, &QCheckBox::stateChanged, this, &GeneralForm::onSetStatusChange);
|
||||
connect(bodyUI->autoAwaySpinBox, SIGNAL(editingFinished()), this, SLOT(onAutoAwayChanged()));
|
||||
connect(bodyUI->showWindow, &QCheckBox::stateChanged, this, &GeneralForm::onShowWindowChanged);
|
||||
connect(bodyUI->showInFront, &QCheckBox::stateChanged, this, &GeneralForm::onSetShowInFront);
|
||||
connect(bodyUI->groupAlwaysNotify, &QCheckBox::stateChanged, this, &GeneralForm::onSetGroupAlwaysNotify);
|
||||
connect(bodyUI->autoacceptFiles, &QCheckBox::stateChanged, this, &GeneralForm::onAutoAcceptFileChange);
|
||||
if (bodyUI->autoacceptFiles->isChecked())
|
||||
connect(bodyUI->autoSaveFilesDir, SIGNAL(clicked()), this, SLOT(onAutoSaveDirChange()));
|
||||
|
@ -144,6 +146,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
|
|||
connect(bodyUI->proxyPort, SIGNAL(valueChanged(int)), this, SLOT(onProxyPortEdited(int)));
|
||||
connect(bodyUI->reconnectButton, &QPushButton::clicked, this, &GeneralForm::onReconnectClicked);
|
||||
connect(bodyUI->cbFauxOfflineMessaging, &QCheckBox::stateChanged, this, &GeneralForm::onFauxOfflineMessaging);
|
||||
connect(bodyUI->cbCompactLayout, &QCheckBox::stateChanged, this, &GeneralForm::onCompactLayout);
|
||||
|
||||
#ifndef QTOX_PLATFORM_EXT
|
||||
bodyUI->autoAwayLabel->setEnabled(false); // these don't seem to change the appearance of the widgets,
|
||||
|
@ -167,11 +170,6 @@ void GeneralForm::onTranslationUpdated()
|
|||
Widget::getInstance()->setTranslation();
|
||||
}
|
||||
|
||||
void GeneralForm::onMakeToxPortableUpdated()
|
||||
{
|
||||
Settings::getInstance().setMakeToxPortable(bodyUI->cbMakeToxPortable->isChecked());
|
||||
}
|
||||
|
||||
void GeneralForm::onSetShowSystemTray()
|
||||
{
|
||||
Settings::getInstance().setShowSystemTray(bodyUI->showSystemTray->isChecked());
|
||||
|
@ -330,9 +328,19 @@ void GeneralForm::onCheckUpdateChanged()
|
|||
Settings::getInstance().setCheckUpdates(bodyUI->checkUpdates->isChecked());
|
||||
}
|
||||
|
||||
void GeneralForm::onShowWindowChanged()
|
||||
{
|
||||
Settings::getInstance().setShowWindow(bodyUI->showWindow->isChecked());
|
||||
}
|
||||
|
||||
void GeneralForm::onSetShowInFront()
|
||||
{
|
||||
Settings::getInstance().setShowInFront(bodyUI->showInFront->isChecked());
|
||||
Settings::getInstance().setShowInFront(bodyUI->showInFront->isChecked());
|
||||
}
|
||||
|
||||
void GeneralForm::onSetGroupAlwaysNotify()
|
||||
{
|
||||
Settings::getInstance().setGroupAlwaysNotify(bodyUI->groupAlwaysNotify->isChecked());
|
||||
}
|
||||
|
||||
void GeneralForm::onFauxOfflineMessaging()
|
||||
|
@ -340,6 +348,12 @@ void GeneralForm::onFauxOfflineMessaging()
|
|||
Settings::getInstance().setFauxOfflineMessaging(bodyUI->cbFauxOfflineMessaging->isChecked());
|
||||
}
|
||||
|
||||
void GeneralForm::onCompactLayout()
|
||||
{
|
||||
Settings::getInstance().setCompactLayout(bodyUI->cbCompactLayout->isChecked());
|
||||
emit parent->compactToggled(bodyUI->cbCompactLayout->isChecked());
|
||||
}
|
||||
|
||||
void GeneralForm::onThemeColorChanged(int)
|
||||
{
|
||||
int index = bodyUI->themeColorCBox->currentIndex();
|
||||
|
|
|
@ -33,7 +33,6 @@ public:
|
|||
private slots:
|
||||
void onEnableIPv6Updated();
|
||||
void onTranslationUpdated();
|
||||
void onMakeToxPortableUpdated();
|
||||
void onSetShowSystemTray();
|
||||
void onSetAutostartInTray();
|
||||
void onSetCloseToTray();
|
||||
|
@ -54,8 +53,11 @@ private slots:
|
|||
void onAutoAcceptFileChange();
|
||||
void onAutoSaveDirChange();
|
||||
void onCheckUpdateChanged();
|
||||
void onShowWindowChanged();
|
||||
void onSetShowInFront();
|
||||
void onSetGroupAlwaysNotify();
|
||||
void onFauxOfflineMessaging();
|
||||
void onCompactLayout();
|
||||
void onThemeColorChanged(int);
|
||||
|
||||
private:
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>545</width>
|
||||
<width>573</width>
|
||||
<height>644</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -34,16 +34,16 @@
|
|||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents_2">
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>-173</y>
|
||||
<width>511</width>
|
||||
<height>797</height>
|
||||
<y>0</y>
|
||||
<width>544</width>
|
||||
<height>785</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0,0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0,0,1">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
|
@ -57,14 +57,14 @@
|
|||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="transLayout">
|
||||
<layout class="QHBoxLayout" name="generalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="transLabel">
|
||||
<property name="toolTip">
|
||||
<string>The translation may not load until qTox restarts.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Translation</string>
|
||||
<string>Language:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -81,27 +81,30 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="generalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbMakeToxPortable">
|
||||
<property name="toolTip">
|
||||
<string extracomment="describes makeToxPortable checkbox">Save settings to the working directory instead of the usual conf dir</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Make Tox portable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="trayGroup">
|
||||
<property name="title">
|
||||
<string>System tray integration</string>
|
||||
<string>System tray</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="showSystemTray">
|
||||
<property name="text">
|
||||
|
@ -109,103 +112,131 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="trayBehavior">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="startInTray">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start in tray</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="closeToTray">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Close to tray</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="minimizeToTray">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Minimize to tray</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="lightTrayIcon">
|
||||
<property name="text">
|
||||
<string>Light icon</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string comment="toolTip for light icon setting">Enable light tray icon.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="startInTray">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start in tray</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string comment="toolTip for Start in tray setting">qTox will start minimized in tray.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="closeToTray">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Close to tray</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string comment="toolTip for close to tray setting">After pressing close (X) qTox will minimize to tray,
|
||||
instead of closing itself.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QCheckBox" name="minimizeToTray">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Minimize to tray</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string comment="toolTip for minimize to tray setting">After pressing minimize (_) qTox will minimize itself to tray,
|
||||
instead of system taskbar.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<spacer name="traySpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="statusChanges">
|
||||
<property name="text">
|
||||
<string>Show contacts' status changes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkUpdates">
|
||||
<property name="text">
|
||||
<string>Check for updates on startup (unstable)</string>
|
||||
<string>Check for updates on startup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showInFront">
|
||||
<property name="text">
|
||||
<string>Focus qTox when a message is received</string>
|
||||
<layout class="QGridLayout" name="autoLayout">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbFauxOfflineMessaging">
|
||||
<property name="text">
|
||||
<string>Faux offline messaging</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item alignment="Qt::AlignLeft">
|
||||
<widget class="QLabel" name="autoAwayLabel">
|
||||
<property name="toolTip">
|
||||
<string>Provided in minutes</string>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="autoSaveFilesDirLabel">
|
||||
<property name="text">
|
||||
<string>Auto away after (0 to disable)</string>
|
||||
<string>Save to:</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Set where files will be saved.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="autoacceptFiles">
|
||||
<property name="toolTip">
|
||||
<string comment="autoaccept cb tooltip">You can set this on a per-friend basis by right clicking them.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Autoaccept files</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="autoSaveFilesDir">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Set where files will be saved.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QSpinBox" name="autoAwaySpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
|
@ -230,46 +261,116 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="fileLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoacceptFiles">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="autoAwayLabel">
|
||||
<property name="toolTip">
|
||||
<string comment="autoaccept cb tooltip">You can set this on a per-friend basis by right clicking them.</string>
|
||||
<string>Your status is changed to Away after set period of inactivity.</string>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Autoaccept files</string>
|
||||
<string>Auto away after (0 to disable):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="chatGroupBox">
|
||||
<property name="title">
|
||||
<string>Chat</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0">
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="groupAlwaysNotify">
|
||||
<property name="toolTip">
|
||||
<string comment="toolTip for Group chat always notify">Always notify about new messages in groupchats.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Group chats always notify</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="statusChanges">
|
||||
<property name="text">
|
||||
<string>Show contacts' status changes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>On new message:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="onMessageLayout">
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showWindow">
|
||||
<property name="toolTip">
|
||||
<string comment="tooltip for Show window setting">Show qTox's window when you receive new message.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show window</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="saveFilesHLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="autoSaveFilesDirLabel">
|
||||
<property name="text">
|
||||
<string>Save files in</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="autoSaveFilesDir">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<widget class="QCheckBox" name="showInFront">
|
||||
<property name="toolTip">
|
||||
<string comment="toolTip for Focus window setting">Focus qTox when you receive message.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Focus window</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<spacer name="chatSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="cbFauxOfflineMessaging">
|
||||
<property name="toolTip">
|
||||
<string comment="toolTip for Faux offline messaging setting">Messages you are trying to send to your friends when they are not online
|
||||
will be sent to them when they will appear online to you.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Faux offline messaging</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="cbCompactLayout">
|
||||
<property name="toolTip">
|
||||
<string comment="toolTip for compact layout setting">Your contact list will be shown in compact mode.
|
||||
qTox's restart needed.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Compact contact list</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -306,7 +407,7 @@
|
|||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="smileyPackLabel">
|
||||
<property name="text">
|
||||
<string extracomment="Text on smiley pack label">Smiley Pack</string>
|
||||
<string extracomment="Text on smiley pack label">Smiley Pack:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -378,47 +479,13 @@
|
|||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="styleLabel">
|
||||
<widget class="QLabel" name="emoticonSizeLabel">
|
||||
<property name="text">
|
||||
<string>Style</string>
|
||||
<string>Emoticon size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="styleBrowser">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="themeColorLabel">
|
||||
<property name="text">
|
||||
<string>Theme color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="themeColorCBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="emoticonSizeLabel">
|
||||
<property name="text">
|
||||
<string>Emoticon size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QSpinBox" name="emoticonSize">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
|
@ -443,10 +510,44 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="styleLabel">
|
||||
<property name="text">
|
||||
<string>Style:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="styleBrowser">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="themeColorLabel">
|
||||
<property name="text">
|
||||
<string>Theme color:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="themeColorCBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="timestampLabel">
|
||||
<property name="text">
|
||||
<string>Timestamp format</string>
|
||||
<string>Timestamp format:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -478,32 +579,76 @@
|
|||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbEnableIPv6">
|
||||
<property name="text">
|
||||
<string extracomment="Text on a checkbox to enable IPv6">Enable IPv6 (recommended)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbEnableUDP">
|
||||
<property name="toolTip">
|
||||
<string extracomment="force tcp checkbox tooltip">Disabling this allows, e.g., toxing over Tor. It adds load to the Tox network however, so uncheck only when necessary.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string extracomment="Text on checkbox to disable UDP">Enable UDP (recommended)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="proxyLayout_2">
|
||||
<layout class="QHBoxLayout" name="coreProtocolLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<widget class="QCheckBox" name="cbEnableUDP">
|
||||
<property name="toolTip">
|
||||
<string extracomment="force tcp checkbox tooltip">Disabling this allows, e.g., toxing over Tor. It adds load to the Tox network however, so uncheck only when necessary.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Proxy type</string>
|
||||
<string extracomment="Text on checkbox to disable UDP">Enable UDP (recommended)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbEnableIPv6">
|
||||
<property name="text">
|
||||
<string extracomment="Text on a checkbox to enable IPv6">Enable IPv6 (recommended)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="protocolSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="proxyLayout">
|
||||
<item row="2" column="3">
|
||||
<widget class="QSpinBox" name="proxyPort">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="proxyTypeLabel">
|
||||
<property name="text">
|
||||
<string>Proxy type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="proxyAddrLabel">
|
||||
<property name="text">
|
||||
<string extracomment="Text on proxy addr label">Address:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="proxyAddr"/>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="proxyPortLabel">
|
||||
<property name="text">
|
||||
<string extracomment="Text on proxy port label">Port</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="3">
|
||||
<widget class="QComboBox" name="proxyType">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
|
@ -530,40 +675,6 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="proxyLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="proxyAddrLabel">
|
||||
<property name="text">
|
||||
<string extracomment="Text on proxy addr label">Address</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="proxyAddr"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="proxyPortLabel">
|
||||
<property name="text">
|
||||
<string extracomment="Text on proxy port label">Port</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="proxyPort">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="reconnectButton">
|
||||
<property name="text">
|
||||
|
@ -630,5 +741,21 @@
|
|||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>showWindow</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>showInFront</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>329</x>
|
||||
<y>349</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>451</x>
|
||||
<y>349</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
|
|
@ -46,9 +46,9 @@ IdentityForm::IdentityForm() :
|
|||
|
||||
bodyUI->toxGroup->layout()->addWidget(toxId);
|
||||
|
||||
timer.setInterval(1000);
|
||||
timer.setInterval(750);
|
||||
timer.setSingleShot(true);
|
||||
connect(&timer, &QTimer::timeout, this, [=]() {bodyUI->toxIdLabel->setText(bodyUI->toxIdLabel->text().replace(" ✔", ""));});
|
||||
connect(&timer, &QTimer::timeout, this, [=]() {bodyUI->toxIdLabel->setText(bodyUI->toxIdLabel->text().replace(" ✔", "")); hasCheck = false;});
|
||||
|
||||
connect(bodyUI->toxIdLabel, SIGNAL(clicked()), this, SLOT(copyIdClicked()));
|
||||
connect(toxId, SIGNAL(clicked()), this, SLOT(copyIdClicked()));
|
||||
|
@ -89,7 +89,11 @@ void IdentityForm::copyIdClicked()
|
|||
QApplication::clipboard()->setText(txt);
|
||||
toxId->setCursorPosition(0);
|
||||
|
||||
bodyUI->toxIdLabel->setText(bodyUI->toxIdLabel->text() + " ✔");
|
||||
if (!hasCheck)
|
||||
{
|
||||
bodyUI->toxIdLabel->setText(bodyUI->toxIdLabel->text() + " ✔");
|
||||
hasCheck = true;
|
||||
}
|
||||
timer.start();
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ private:
|
|||
Ui::IdentitySettings* bodyUI;
|
||||
Core* core;
|
||||
QTimer timer;
|
||||
bool hasCheck = false;
|
||||
|
||||
ClickableTE* toxId;
|
||||
};
|
||||
|
|
|
@ -81,6 +81,10 @@
|
|||
<property name="title">
|
||||
<string>Tox ID</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string comment="Tox ID tooltip">This bunch of characters tells other Tox clients how to contact you.
|
||||
Share it with your friends to communicate.</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="CroppingLabel" name="toxIdLabel">
|
||||
|
@ -109,6 +113,9 @@
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="profiles">
|
||||
<property name="toolTip">
|
||||
<string comment="toolTip for currently set profile">Currently selected profile.</string>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
|
@ -124,7 +131,7 @@
|
|||
<item>
|
||||
<widget class="QPushButton" name="loadButton">
|
||||
<property name="toolTip">
|
||||
<string comment="tooltip">Switching profiles is disabled during calls</string>
|
||||
<string comment="tooltip for loading profile button">Load selected profile and switch to it.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string comment="load profile button">Load</string>
|
||||
|
@ -136,6 +143,9 @@
|
|||
<property name="text">
|
||||
<string comment="rename profile button">Rename</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string comment="tooltip for renaming profile button">Rename selected profile.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -143,12 +153,16 @@
|
|||
<property name="text">
|
||||
<string comment="export profile button">Export</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string comment="tooltip for profile exporting button">Allows you to export your Tox profile to a file.
|
||||
Profile does not contain your history.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="deleteButton">
|
||||
<property name="toolTip">
|
||||
<string comment="delete profile button tooltip">This is useful to remain safe on public computers</string>
|
||||
<string comment="delete profile button tooltip">Delete selected profile.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string comment="delete profile button">Delete</string>
|
||||
|
@ -164,12 +178,15 @@
|
|||
<property name="text">
|
||||
<string comment="import profile button">Import a profile</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string comment="tooltip for importing profile button">Import Tox profile from a .tox file.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="newButton">
|
||||
<property name="toolTip">
|
||||
<string comment="tooltip">Switching profiles is disabled during calls</string>
|
||||
<string comment="tooltip for creating new Tox ID button">Create new Tox ID and switch to it.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string comment="new profile button">New Tox ID</string>
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
<item>
|
||||
<widget class="QCheckBox" name="cbTypingNotification">
|
||||
<property name="toolTip">
|
||||
<string extracomment="Your friends will be able to see when you are typing."/>
|
||||
<string comment="tooltip for typing notifications setting">Your friends will be able to see when you are typing.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Send Typing Notifications</string>
|
||||
|
@ -54,7 +54,8 @@
|
|||
<item>
|
||||
<widget class="QCheckBox" name="cbKeepHistory">
|
||||
<property name="toolTip">
|
||||
<string extracomment="History keeping still under developing. Log format changin is possible."/>
|
||||
<string comment="toolTip for Keep History setting">History keeping is still in development.
|
||||
Save format changes are possible, which may result in data loss.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Keep History (unstable)</string>
|
||||
|
@ -101,6 +102,12 @@
|
|||
<property name="title">
|
||||
<string>Nospam</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string comment="toolTip for nospam">Nospam is part of your Tox ID.
|
||||
It is there to help you change your Tox ID when you feel like you are getting too much spam friend requests.
|
||||
When you change nospam, your current contacts still can communicate with you,
|
||||
but new contacts need to know your new Tox ID to be able to add you.</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
|
|
|
@ -42,15 +42,15 @@ public:
|
|||
void show(Ui::MainWindow &ui);
|
||||
void setBodyHeadStyle(QString style);
|
||||
|
||||
signals:
|
||||
void setShowSystemTray(bool newValue);
|
||||
void compactToggled(bool compact);
|
||||
|
||||
private slots:
|
||||
void onTabChanged(int);
|
||||
|
||||
signals:
|
||||
void setShowSystemTray(bool newValue);
|
||||
|
||||
private:
|
||||
QWidget *head, *body; // keep the others private
|
||||
IdentityForm *ifrm;
|
||||
QWidget *head, *body;
|
||||
QTabWidget *settingsWidgets;
|
||||
QLabel *nameLabel, *imgLabel;
|
||||
};
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
const QString TabCompleter::nickSuffix = QString(": ");
|
||||
|
||||
TabCompleter::TabCompleter(ChatTextEdit* msgEdit, Group* group)
|
||||
: QObject(msgEdit), msgEdit(msgEdit), group(group), enabled(false)
|
||||
: QObject{msgEdit}, msgEdit{msgEdit}, group{group},
|
||||
enabled{false}, lastCompletionLength{0}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -70,9 +71,11 @@ void TabCompleter::complete()
|
|||
|
||||
if (nextCompletion != completionMap.end()) {
|
||||
// clear previous completion
|
||||
for (int i = 0; i < lastCompletionLength; i++) {
|
||||
msgEdit->keyPressEvent(new QKeyEvent(QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier));
|
||||
}
|
||||
auto cur = msgEdit->textCursor();
|
||||
cur.setPosition(cur.selectionEnd());
|
||||
msgEdit->setTextCursor(cur);
|
||||
for (int i = 0; i < lastCompletionLength; i++)
|
||||
msgEdit->textCursor().deletePreviousChar();
|
||||
|
||||
// insert completion
|
||||
msgEdit->insertPlainText(*nextCompletion);
|
||||
|
@ -95,7 +98,6 @@ void TabCompleter::complete()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void TabCompleter::reset()
|
||||
{
|
||||
enabled = false;
|
||||
|
|
|
@ -40,7 +40,7 @@ public slots:
|
|||
|
||||
private:
|
||||
struct SortableString {
|
||||
inline SortableString(const QString &n) { contents = n; }
|
||||
inline SortableString(const QString &n) : contents{n} {}
|
||||
bool operator<(const SortableString &other) const;
|
||||
QString contents;
|
||||
};
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "genericchatroomwidget.h"
|
||||
#include "src/misc/style.h"
|
||||
#include "src/misc/settings.h"
|
||||
#include "maskablepixmapwidget.h"
|
||||
#include "croppinglabel.h"
|
||||
#include <QMouseEvent>
|
||||
|
@ -24,17 +25,17 @@
|
|||
GenericChatroomWidget::GenericChatroomWidget(QWidget *parent)
|
||||
: QFrame(parent)
|
||||
{
|
||||
setFixedHeight(55);
|
||||
|
||||
setLayout(&layout);
|
||||
layout.setSpacing(0);
|
||||
layout.setMargin(0);
|
||||
textLayout.setSpacing(0);
|
||||
textLayout.setMargin(0);
|
||||
setLayoutDirection(Qt::LeftToRight); // parent might have set Qt::RightToLeft
|
||||
setProperty("compact", Settings::getInstance().getCompactLayout());
|
||||
|
||||
// avatar
|
||||
avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png");
|
||||
if (property("compact").toBool())
|
||||
{
|
||||
avatar = new MaskablePixmapWidget(this, QSize(20,20), ":/img/avatar_mask.png");
|
||||
}
|
||||
else
|
||||
{
|
||||
avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png");
|
||||
}
|
||||
|
||||
// status text
|
||||
statusMessageLabel = new CroppingLabel(this);
|
||||
|
@ -44,24 +45,65 @@ GenericChatroomWidget::GenericChatroomWidget(QWidget *parent)
|
|||
nameLabel = new CroppingLabel(this);
|
||||
nameLabel->setObjectName("name");
|
||||
|
||||
textLayout.addStretch();
|
||||
textLayout.addWidget(nameLabel);
|
||||
textLayout.addWidget(statusMessageLabel);
|
||||
textLayout.addStretch();
|
||||
|
||||
layout.addSpacing(20);
|
||||
layout.addWidget(avatar);
|
||||
layout.addSpacing(10);
|
||||
layout.addLayout(&textLayout);
|
||||
layout.addSpacing(10);
|
||||
layout.addWidget(&statusPic);
|
||||
layout.addSpacing(10);
|
||||
layout.activate();
|
||||
onCompactChanged(property("compact").toBool());
|
||||
|
||||
setProperty("active", false);
|
||||
setStyleSheet(Style::getStylesheet(":/ui/chatroomWidgets/genericChatroomWidget.css"));
|
||||
}
|
||||
|
||||
void GenericChatroomWidget::onCompactChanged(bool _compact)
|
||||
{
|
||||
delete textLayout; // has to be first, deleted by layout
|
||||
delete layout;
|
||||
|
||||
setProperty("compact", _compact);
|
||||
|
||||
layout = new QHBoxLayout;
|
||||
textLayout = new QVBoxLayout;
|
||||
|
||||
setLayout(layout);
|
||||
layout->setSpacing(0);
|
||||
layout->setMargin(0);
|
||||
textLayout->setSpacing(0);
|
||||
textLayout->setMargin(0);
|
||||
setLayoutDirection(Qt::LeftToRight); // parent might have set Qt::RightToLeft
|
||||
|
||||
// avatar
|
||||
if (property("compact").toBool())
|
||||
{
|
||||
setFixedHeight(25);
|
||||
avatar->setSize(QSize(20,20));
|
||||
layout->addSpacing(18);
|
||||
layout->addWidget(avatar);
|
||||
layout->addSpacing(5);
|
||||
layout->addWidget(nameLabel);
|
||||
layout->addWidget(statusMessageLabel);
|
||||
layout->addSpacing(5);
|
||||
layout->addWidget(&statusPic);
|
||||
layout->addSpacing(5);
|
||||
layout->activate();
|
||||
}
|
||||
else
|
||||
{
|
||||
setFixedHeight(55);
|
||||
avatar->setSize(QSize(40,40));
|
||||
textLayout->addStretch();
|
||||
textLayout->addWidget(nameLabel);
|
||||
textLayout->addWidget(statusMessageLabel);
|
||||
textLayout->addStretch();
|
||||
layout->addSpacing(20);
|
||||
layout->addWidget(avatar);
|
||||
layout->addSpacing(10);
|
||||
layout->addLayout(textLayout);
|
||||
layout->addSpacing(10);
|
||||
layout->addWidget(&statusPic);
|
||||
layout->addSpacing(10);
|
||||
layout->activate();
|
||||
}
|
||||
|
||||
Style::repolish(this);
|
||||
}
|
||||
|
||||
bool GenericChatroomWidget::isActive()
|
||||
{
|
||||
return property("active").toBool();
|
||||
|
@ -102,3 +144,14 @@ void GenericChatroomWidget::reloadTheme()
|
|||
{
|
||||
setStyleSheet(Style::getStylesheet(":/ui/chatroomWidgets/genericChatroomWidget.css"));
|
||||
}
|
||||
|
||||
bool GenericChatroomWidget::isCompact() const
|
||||
{
|
||||
return compact;
|
||||
}
|
||||
|
||||
void GenericChatroomWidget::setCompact(bool compact)
|
||||
{
|
||||
this->compact = compact;
|
||||
Style::repolish(this);
|
||||
}
|
||||
|
|
|
@ -53,18 +53,25 @@ public:
|
|||
|
||||
void reloadTheme();
|
||||
|
||||
bool isCompact() const;
|
||||
void setCompact(bool compact);
|
||||
|
||||
Q_PROPERTY(bool compact READ isCompact WRITE setCompact)
|
||||
|
||||
signals:
|
||||
void chatroomWidgetClicked(GenericChatroomWidget* widget);
|
||||
|
||||
public slots:
|
||||
void onCompactChanged(bool compact);
|
||||
|
||||
protected:
|
||||
QColor lastColor;
|
||||
QHBoxLayout layout;
|
||||
QVBoxLayout textLayout;
|
||||
QHBoxLayout* layout = nullptr;
|
||||
QVBoxLayout* textLayout = nullptr;
|
||||
MaskablePixmapWidget* avatar;
|
||||
QLabel statusPic;
|
||||
CroppingLabel *nameLabel, *statusMessageLabel;
|
||||
CroppingLabel* nameLabel, * statusMessageLabel;
|
||||
bool compact;
|
||||
|
||||
friend class Style; ///< To update our stylesheets
|
||||
};
|
||||
|
|
|
@ -99,16 +99,9 @@ void GroupWidget::updateStatusLight()
|
|||
Group *g = GroupList::findGroup(groupId);
|
||||
|
||||
if (!g->getEventFlag())
|
||||
{
|
||||
statusPic.setPixmap(QPixmap(":img/status/dot_online.png"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!g->getMentionedFlag())
|
||||
statusPic.setPixmap(QPixmap(":img/status/dot_online_notification.png"));
|
||||
else
|
||||
statusPic.setPixmap(QPixmap(":img/status/dot_online_notification.png"));
|
||||
}
|
||||
statusPic.setPixmap(QPixmap(":img/status/dot_online_notification.png"));
|
||||
}
|
||||
|
||||
void GroupWidget::setChatForm(Ui::MainWindow &ui)
|
||||
|
|
|
@ -19,16 +19,11 @@
|
|||
|
||||
MaskablePixmapWidget::MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName)
|
||||
: QWidget(parent)
|
||||
, renderTarget(size)
|
||||
, maskName(maskName)
|
||||
, backgroundColor(Qt::white)
|
||||
, clickable(false)
|
||||
{
|
||||
setFixedSize(size);
|
||||
|
||||
QPixmap pmapMask = QPixmap(maskName);
|
||||
|
||||
if (!pmapMask.isNull())
|
||||
mask = QPixmap(maskName).scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
setSize(size);
|
||||
}
|
||||
|
||||
void MaskablePixmapWidget::autopickBackground()
|
||||
|
@ -63,16 +58,11 @@ void MaskablePixmapWidget::autopickBackground()
|
|||
|
||||
QColor color = QColor::fromRgb(r,g,b);
|
||||
backgroundColor = QColor::fromRgb(0xFFFFFF ^ color.rgb());
|
||||
manualColor = false;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void MaskablePixmapWidget::setBackground(QColor color)
|
||||
{
|
||||
backgroundColor = color;
|
||||
update();
|
||||
}
|
||||
|
||||
void MaskablePixmapWidget::setClickable(bool clickable)
|
||||
{
|
||||
this->clickable = clickable;
|
||||
|
@ -87,9 +77,10 @@ void MaskablePixmapWidget::setPixmap(const QPixmap &pmap, QColor background)
|
|||
{
|
||||
if (!pmap.isNull())
|
||||
{
|
||||
unscaled = pmap;
|
||||
pixmap = pmap.scaled(width(), height(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
backgroundColor = background;
|
||||
|
||||
manualColor = true;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
@ -98,25 +89,44 @@ void MaskablePixmapWidget::setPixmap(const QPixmap &pmap)
|
|||
{
|
||||
if (!pmap.isNull())
|
||||
{
|
||||
unscaled = pmap;
|
||||
pixmap = pmap.scaled(width(), height(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
autopickBackground();
|
||||
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
QPixmap MaskablePixmapWidget::getPixmap() const
|
||||
{
|
||||
return renderTarget;
|
||||
return *renderTarget;
|
||||
}
|
||||
|
||||
void MaskablePixmapWidget::setSize(QSize size)
|
||||
{
|
||||
setFixedSize(size);
|
||||
delete renderTarget;
|
||||
renderTarget = new QPixmap(size);
|
||||
|
||||
QPixmap pmapMask = QPixmap(maskName);
|
||||
if (!pmapMask.isNull())
|
||||
mask = pmapMask.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
|
||||
if (!unscaled.isNull())
|
||||
{
|
||||
pixmap = unscaled.scaled(width(), height(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
if (!manualColor)
|
||||
autopickBackground();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void MaskablePixmapWidget::paintEvent(QPaintEvent *)
|
||||
{
|
||||
renderTarget.fill(Qt::transparent);
|
||||
renderTarget->fill(Qt::transparent);
|
||||
|
||||
QPoint offset((width() - pixmap.size().width())/2,(height() - pixmap.size().height())/2); // centering the pixmap
|
||||
|
||||
QPainter painter(&renderTarget);
|
||||
QPainter painter(renderTarget);
|
||||
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
painter.fillRect(0,0,width(),height(),backgroundColor);
|
||||
painter.drawPixmap(offset,pixmap);
|
||||
|
@ -125,7 +135,7 @@ void MaskablePixmapWidget::paintEvent(QPaintEvent *)
|
|||
painter.end();
|
||||
|
||||
painter.begin(this);
|
||||
painter.drawPixmap(0,0,renderTarget);
|
||||
painter.drawPixmap(0,0,*renderTarget);
|
||||
}
|
||||
|
||||
void MaskablePixmapWidget::mousePressEvent(QMouseEvent*)
|
||||
|
|
|
@ -26,11 +26,11 @@ public:
|
|||
MaskablePixmapWidget(QWidget *parent, QSize size, QString maskName = QString());
|
||||
|
||||
void autopickBackground();
|
||||
void setBackground(QColor color);
|
||||
void setClickable(bool clickable);
|
||||
void setPixmap(const QPixmap &pmap, QColor background);
|
||||
void setPixmap(const QPixmap &pmap);
|
||||
QPixmap getPixmap() const;
|
||||
void setSize(QSize size);
|
||||
|
||||
signals:
|
||||
void clicked();
|
||||
|
@ -40,13 +40,12 @@ protected:
|
|||
virtual void mousePressEvent(QMouseEvent *);
|
||||
|
||||
private:
|
||||
QPixmap pixmap;
|
||||
QPixmap mask;
|
||||
QPixmap renderTarget;
|
||||
QPixmap pixmap, mask, unscaled; // a lot of memory...
|
||||
QPixmap* renderTarget = nullptr; // pointer to dynamically call the constructor
|
||||
QSize size;
|
||||
QString maskName;
|
||||
QColor backgroundColor;
|
||||
bool clickable;
|
||||
bool clickable, manualColor = false;
|
||||
};
|
||||
|
||||
#endif // MASKABLEPIXMAPWIDGET_H
|
||||
|
|
162
src/widget/systemtrayicon.cpp
Normal file
162
src/widget/systemtrayicon.cpp
Normal file
|
@ -0,0 +1,162 @@
|
|||
#include "systemtrayicon.h"
|
||||
#include <QString>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QMenu>
|
||||
#include <QFile>
|
||||
#include <QDebug>
|
||||
#include "src/misc/settings.h"
|
||||
|
||||
SystemTrayIcon::SystemTrayIcon()
|
||||
{
|
||||
QString desktop = getenv("XDG_CURRENT_DESKTOP");
|
||||
if (false);
|
||||
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND
|
||||
else if (desktop.toLower() == "unity")
|
||||
{
|
||||
QString settingsDir = Settings::getSettingsDirPath();
|
||||
QFile iconFile(settingsDir+"/icon.png");
|
||||
if (iconFile.open(QIODevice::Truncate | QIODevice::WriteOnly))
|
||||
{
|
||||
QFile resIconFile(":/img/icon.png");
|
||||
if (resIconFile.open(QIODevice::ReadOnly))
|
||||
iconFile.write(resIconFile.readAll());
|
||||
resIconFile.close();
|
||||
iconFile.close();
|
||||
}
|
||||
backendType = SystrayBackendType::Unity;
|
||||
unityMenu = gtk_menu_new();
|
||||
unityIndicator = app_indicator_new_with_path(
|
||||
"qTox",
|
||||
"icon",
|
||||
APP_INDICATOR_CATEGORY_APPLICATION_STATUS,
|
||||
settingsDir.toStdString().c_str()
|
||||
);
|
||||
app_indicator_set_menu(unityIndicator, GTK_MENU(unityMenu));
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
qtIcon = new QSystemTrayIcon;
|
||||
backendType = SystrayBackendType::Qt;
|
||||
connect(qtIcon, &QSystemTrayIcon::activated, this, &SystemTrayIcon::activated);
|
||||
}
|
||||
}
|
||||
|
||||
QString SystemTrayIcon::extractIconToFile(QIcon icon, QString name)
|
||||
{
|
||||
QString iconPath;
|
||||
(void) icon;
|
||||
(void) name;
|
||||
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND
|
||||
iconPath = Settings::getSettingsDirPath()+"/"+name+".png";
|
||||
QSize iconSize = icon.actualSize(QSize{64,64});
|
||||
icon.pixmap(iconSize).save(iconPath);
|
||||
#endif
|
||||
return iconPath;
|
||||
}
|
||||
|
||||
void SystemTrayIcon::setContextMenu(QMenu* menu)
|
||||
{
|
||||
if (false);
|
||||
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND
|
||||
else if (backendType == SystrayBackendType::Unity)
|
||||
{
|
||||
for (QAction* a : menu->actions())
|
||||
{
|
||||
gtk_image_menu_item_new();
|
||||
QString aText = a->text().replace('&',"");
|
||||
GtkWidget* item;
|
||||
if (a->isSeparator())
|
||||
item = gtk_menu_item_new();
|
||||
else if (a->icon().isNull())
|
||||
item = gtk_menu_item_new_with_label(aText.toStdString().c_str());
|
||||
else
|
||||
{
|
||||
QString iconPath = extractIconToFile(a->icon(),"iconmenu"+a->icon().name());
|
||||
GtkWidget* image = gtk_image_new_from_file(iconPath.toStdString().c_str());
|
||||
item = gtk_image_menu_item_new_with_label(aText.toStdString().c_str());
|
||||
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
|
||||
gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM(item),TRUE);
|
||||
}
|
||||
gtk_menu_shell_append(GTK_MENU_SHELL(unityMenu), item);
|
||||
void (*callback)(GtkMenu*, gpointer data) = [](GtkMenu*, gpointer a)
|
||||
{
|
||||
((QAction*)a)->activate(QAction::Trigger);
|
||||
};
|
||||
g_signal_connect(item, "activate", G_CALLBACK(callback), a);
|
||||
gtk_widget_show(item);
|
||||
}
|
||||
app_indicator_set_menu(unityIndicator, GTK_MENU(unityMenu));
|
||||
DbusmenuServer *menuServer;
|
||||
DbusmenuMenuitem *rootMenuItem;
|
||||
g_object_get(unityIndicator, "dbus-menu-server", &menuServer, NULL);
|
||||
g_object_get(menuServer, "root-node", &rootMenuItem, NULL);
|
||||
void (*callback)(DbusmenuMenuitem *, gpointer) =
|
||||
[](DbusmenuMenuitem *, gpointer data)
|
||||
{
|
||||
((SystemTrayIcon*)data)->activated(QSystemTrayIcon::Unknown);
|
||||
};
|
||||
g_signal_connect(rootMenuItem, "about-to-show", G_CALLBACK(callback), this);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
qtIcon->setContextMenu(menu);
|
||||
}
|
||||
}
|
||||
|
||||
void SystemTrayIcon::show()
|
||||
{
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
void SystemTrayIcon::hide()
|
||||
{
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
void SystemTrayIcon::setVisible(bool newState)
|
||||
{
|
||||
if (false);
|
||||
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND
|
||||
else if (backendType == SystrayBackendType::Unity)
|
||||
{
|
||||
if (newState)
|
||||
app_indicator_set_status(unityIndicator, APP_INDICATOR_STATUS_ACTIVE);
|
||||
else
|
||||
app_indicator_set_status(unityIndicator, APP_INDICATOR_STATUS_PASSIVE);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
if (newState)
|
||||
qtIcon->show();
|
||||
else
|
||||
qtIcon->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void SystemTrayIcon::setIcon(QIcon &&icon)
|
||||
{
|
||||
if (false);
|
||||
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND
|
||||
else if (backendType == SystrayBackendType::Unity)
|
||||
{
|
||||
// Alternate file names or appindicator will not reload the icon
|
||||
if (app_indicator_get_icon(unityIndicator) == QString("icon2"))
|
||||
{
|
||||
extractIconToFile(icon,"icon");
|
||||
app_indicator_set_icon_full(unityIndicator, "icon","qtox");
|
||||
}
|
||||
else
|
||||
{
|
||||
extractIconToFile(icon,"icon2");
|
||||
app_indicator_set_icon_full(unityIndicator, "icon2","qtox");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
qtIcon->setIcon(icon);
|
||||
}
|
||||
}
|
36
src/widget/systemtrayicon.h
Normal file
36
src/widget/systemtrayicon.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#ifndef SYSTEMTRAYICON_H
|
||||
#define SYSTEMTRAYICON_H
|
||||
|
||||
#include "systemtrayicon_private.h"
|
||||
#include <QObject>
|
||||
|
||||
class QSystemTrayIcon;
|
||||
class QMenu;
|
||||
|
||||
class SystemTrayIcon : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SystemTrayIcon();
|
||||
void setContextMenu(QMenu* menu);
|
||||
void show();
|
||||
void hide();
|
||||
void setVisible(bool);
|
||||
void setIcon(QIcon&& icon);
|
||||
|
||||
signals:
|
||||
void activated(QSystemTrayIcon::ActivationReason);
|
||||
|
||||
private:
|
||||
QString extractIconToFile(QIcon icon, QString name="icon");
|
||||
|
||||
private:
|
||||
SystrayBackendType backendType;
|
||||
QSystemTrayIcon* qtIcon;
|
||||
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND
|
||||
AppIndicator *unityIndicator;
|
||||
GtkWidget *unityMenu;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // SYSTEMTRAYICON_H
|
35
src/widget/systemtrayicon_private.h
Normal file
35
src/widget/systemtrayicon_private.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef SYSTEMTRAYICON_PRIVATE_H
|
||||
#define SYSTEMTRAYICON_PRIVATE_H
|
||||
|
||||
#include <QSystemTrayIcon>
|
||||
|
||||
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND
|
||||
#ifdef signals
|
||||
#undef signals
|
||||
#endif
|
||||
extern "C" {
|
||||
#include <libappindicator/app-indicator.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <libdbusmenu-glib/server.h>
|
||||
}
|
||||
#define signals public
|
||||
#endif
|
||||
|
||||
enum class SystrayBackendType
|
||||
{
|
||||
Qt,
|
||||
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND
|
||||
Unity
|
||||
#endif
|
||||
};
|
||||
|
||||
union SystrayBackend
|
||||
{
|
||||
QSystemTrayIcon *qt;
|
||||
#ifdef ENABLE_SYSTRAY_UNITY_BACKEND
|
||||
AppIndicator *unity;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#endif // SYSTEMTRAYICON_PRIVATE_H
|
|
@ -25,17 +25,26 @@ ChatTextEdit::ChatTextEdit(QWidget *parent) :
|
|||
}
|
||||
|
||||
void ChatTextEdit::keyPressEvent(QKeyEvent * event)
|
||||
{
|
||||
{
|
||||
int key = event->key();
|
||||
if ((key == Qt::Key_Enter || key == Qt::Key_Return) && !(event->modifiers() && Qt::ShiftModifier))
|
||||
if ((key == Qt::Key_Enter || key == Qt::Key_Return) && !(event->modifiers() & Qt::ShiftModifier))
|
||||
emit enterPressed();
|
||||
else if (key == Qt::Key_Tab)
|
||||
emit tabPressed();
|
||||
else if (key == Qt::Key_Backspace) // because of the backspace() hack in tabber, we can't emit on these
|
||||
QTextEdit::keyPressEvent(event);
|
||||
else if (key == Qt::Key_Up && this->toPlainText().isEmpty())
|
||||
{
|
||||
this->setText(lastMessage);
|
||||
this->setFocus();
|
||||
this->moveCursor(QTextCursor::MoveOperation::End,QTextCursor::MoveMode::MoveAnchor);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit keyPressed();
|
||||
QTextEdit::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatTextEdit::setLastMessage(QString lm)
|
||||
{
|
||||
lastMessage = lm;
|
||||
}
|
||||
|
|
|
@ -25,14 +25,15 @@ class ChatTextEdit : public QTextEdit
|
|||
public:
|
||||
explicit ChatTextEdit(QWidget *parent = 0);
|
||||
virtual void keyPressEvent(QKeyEvent * event) override;
|
||||
|
||||
void setLastMessage(QString lm);
|
||||
|
||||
signals:
|
||||
void enterPressed();
|
||||
void tabPressed();
|
||||
void keyPressed();
|
||||
|
||||
public slots:
|
||||
|
||||
private:
|
||||
QString lastMessage;
|
||||
};
|
||||
|
||||
#endif // CHATTEXTEDIT_H
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
FriendRequestDialog::FriendRequestDialog(QWidget *parent, const QString &userId, const QString &message) :
|
||||
QDialog(parent)
|
||||
{
|
||||
setAttribute(Qt::WA_QuitOnClose, false);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setWindowTitle(tr("Friend request","Title of the window to aceept/deny a friend request"));
|
||||
|
||||
|
|
|
@ -22,15 +22,17 @@
|
|||
#include <QDebug>
|
||||
|
||||
VideoSurface::VideoSurface(QWidget* parent)
|
||||
: QGLWidget(QGLFormat(QGL::SampleBuffers | QGL::SingleBuffer), parent)
|
||||
, source(nullptr)
|
||||
: QGLWidget(QGLFormat(QGL::SingleBuffer), parent)
|
||||
, source{nullptr}
|
||||
, pbo{nullptr, nullptr}
|
||||
, textureId(0)
|
||||
, pboAllocSize(0)
|
||||
, hasSubscribed(false)
|
||||
, pboIndex(0)
|
||||
, bgrProgramm{nullptr}
|
||||
, yuvProgramm{nullptr}
|
||||
, textureId{0}
|
||||
, pboAllocSize{0}
|
||||
, hasSubscribed{false}
|
||||
, pboIndex{0}
|
||||
{
|
||||
setAutoBufferSwap(false);
|
||||
|
||||
}
|
||||
|
||||
VideoSurface::VideoSurface(VideoSource *source, QWidget* parent)
|
||||
|
@ -65,8 +67,8 @@ void VideoSurface::setSource(VideoSource *src)
|
|||
|
||||
void VideoSurface::initializeGL()
|
||||
{
|
||||
QGLWidget::initializeGL();
|
||||
qDebug() << "VideoSurface: Init";
|
||||
|
||||
// pbo
|
||||
pbo[0] = new QOpenGLBuffer(QOpenGLBuffer::PixelUnpackBuffer);
|
||||
pbo[0]->setUsagePattern(QOpenGLBuffer::StreamDraw);
|
||||
|
@ -180,14 +182,6 @@ void VideoSurface::paintGL()
|
|||
pbo[nextPboIndex]->release();
|
||||
}
|
||||
|
||||
// render pbo
|
||||
static float values[] = {
|
||||
-1, -1,
|
||||
1, -1,
|
||||
-1, 1,
|
||||
1, 1
|
||||
};
|
||||
|
||||
// background
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
@ -220,6 +214,14 @@ void VideoSurface::paintGL()
|
|||
|
||||
if (programm)
|
||||
{
|
||||
// render pbo
|
||||
static float values[] = {
|
||||
-1, -1,
|
||||
1, -1,
|
||||
-1, 1,
|
||||
1, 1
|
||||
};
|
||||
|
||||
programm->bind();
|
||||
programm->setAttributeArray(0, GL_FLOAT, values, 2);
|
||||
programm->enableAttributeArray(0);
|
||||
|
@ -259,7 +261,7 @@ void VideoSurface::unsubscribe()
|
|||
}
|
||||
}
|
||||
|
||||
void VideoSurface::onNewFrameAvailable(const VideoFrame newFrame)
|
||||
void VideoSurface::onNewFrameAvailable(const VideoFrame& newFrame)
|
||||
{
|
||||
mutex.lock();
|
||||
frame = newFrame;
|
||||
|
|
|
@ -44,7 +44,7 @@ protected:
|
|||
void unsubscribe();
|
||||
|
||||
private slots:
|
||||
void onNewFrameAvailable(const VideoFrame newFrame);
|
||||
void onNewFrameAvailable(const VideoFrame &newFrame);
|
||||
|
||||
private:
|
||||
VideoSource* source;
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "src/autoupdate.h"
|
||||
#include "src/audio.h"
|
||||
#include "src/platform/timer.h"
|
||||
#include "systemtrayicon.h"
|
||||
#include <QMessageBox>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
|
@ -56,8 +57,7 @@ void toxActivateEventHandler(const QByteArray& data)
|
|||
{
|
||||
if (data != "$activate")
|
||||
return;
|
||||
Widget::getInstance()->show();
|
||||
Widget::getInstance()->activateWindow();
|
||||
Widget::getInstance()->forceShow();
|
||||
}
|
||||
|
||||
Widget *Widget::instance{nullptr};
|
||||
|
@ -85,7 +85,7 @@ void Widget::init()
|
|||
|
||||
if (QSystemTrayIcon::isSystemTrayAvailable())
|
||||
{
|
||||
icon = new QSystemTrayIcon(this);
|
||||
icon = new SystemTrayIcon;
|
||||
updateTrayIcon();
|
||||
trayMenu = new QMenu;
|
||||
|
||||
|
@ -113,7 +113,8 @@ void Widget::init()
|
|||
this,
|
||||
SLOT(onIconClick(QSystemTrayIcon::ActivationReason)));
|
||||
|
||||
if (Settings::getInstance().getShowSystemTray()){
|
||||
if (Settings::getInstance().getShowSystemTray())
|
||||
{
|
||||
icon->show();
|
||||
if (Settings::getInstance().getAutostartInTray() == false)
|
||||
this->show();
|
||||
|
@ -214,7 +215,7 @@ void Widget::init()
|
|||
addFriendForm = new AddFriendForm;
|
||||
settingsWidget = new SettingsWidget();
|
||||
|
||||
connect(settingsWidget, SIGNAL(setShowSystemTray(bool)), this, SLOT(onSetShowSystemTray(bool)));
|
||||
connect(settingsWidget, &SettingsWidget::setShowSystemTray, this, &Widget::onSetShowSystemTray);
|
||||
|
||||
connect(core, &Core::connected, this, &Widget::onConnected);
|
||||
connect(core, &Core::disconnected, this, &Widget::onDisconnected);
|
||||
|
@ -314,16 +315,16 @@ void Widget::updateTrayIcon()
|
|||
|
||||
Widget::~Widget()
|
||||
{
|
||||
qDebug() << "Deleting Widget";
|
||||
core->saveConfiguration();
|
||||
coreThread->exit();
|
||||
coreThread->wait(500); // In case of deadlock (can happen with QtAudio/PA bugs)
|
||||
if (!coreThread->isFinished())
|
||||
coreThread->terminate();
|
||||
AutoUpdater::abortUpdates();
|
||||
delete core;
|
||||
icon->hide();
|
||||
hideMainForms();
|
||||
delete settingsWidget;
|
||||
delete addFriendForm;
|
||||
delete filesForm;
|
||||
delete idleTimer;
|
||||
|
||||
FriendList::clear();
|
||||
GroupList::clear();
|
||||
|
@ -359,6 +360,7 @@ void Widget::closeEvent(QCloseEvent *event)
|
|||
{
|
||||
saveWindowGeometry();
|
||||
saveSplitterGeometry();
|
||||
qApp->exit(0);
|
||||
QWidget::closeEvent(event);
|
||||
}
|
||||
}
|
||||
|
@ -378,6 +380,8 @@ void Widget::resizeEvent(QResizeEvent *event)
|
|||
{
|
||||
Q_UNUSED(event);
|
||||
saveWindowGeometry();
|
||||
|
||||
emit resized();
|
||||
}
|
||||
|
||||
QString Widget::detectProfile()
|
||||
|
@ -569,6 +573,13 @@ void Widget::setWindowTitle(const QString& title)
|
|||
QMainWindow::setWindowTitle("qTox - " + title);
|
||||
}
|
||||
|
||||
void Widget::forceShow()
|
||||
{
|
||||
hide(); // Workaround to force minimized window to be restored
|
||||
show();
|
||||
activateWindow();
|
||||
}
|
||||
|
||||
void Widget::onAddClicked()
|
||||
{
|
||||
hideMainForms();
|
||||
|
@ -591,21 +602,38 @@ void Widget::onTransferClicked()
|
|||
|
||||
void Widget::onIconClick(QSystemTrayIcon::ActivationReason reason)
|
||||
{
|
||||
switch (reason) {
|
||||
switch (reason)
|
||||
{
|
||||
case QSystemTrayIcon::Trigger:
|
||||
if (this->isHidden() == true)
|
||||
{
|
||||
this->show();
|
||||
this->activateWindow();
|
||||
if (isHidden())
|
||||
{
|
||||
show();
|
||||
activateWindow();
|
||||
}
|
||||
else if (isMinimized())
|
||||
{
|
||||
forceShow();
|
||||
}
|
||||
else
|
||||
{
|
||||
hide();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
this->hide();
|
||||
case QSystemTrayIcon::DoubleClick:
|
||||
case QSystemTrayIcon::DoubleClick:
|
||||
forceShow();
|
||||
break;
|
||||
case QSystemTrayIcon::MiddleClick:
|
||||
hide();
|
||||
break;
|
||||
case QSystemTrayIcon::Unknown:
|
||||
if (isHidden())
|
||||
forceShow();
|
||||
break;
|
||||
default:
|
||||
;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -633,15 +661,18 @@ void Widget::hideMainForms()
|
|||
|
||||
void Widget::onUsernameChanged(const QString& newUsername, const QString& oldUsername)
|
||||
{
|
||||
ui->nameLabel->setText(oldUsername); // restore old username until Core tells us to set it
|
||||
ui->nameLabel->setToolTip(oldUsername); // for overlength names
|
||||
setUsername(oldUsername); // restore old username until Core tells us to set it
|
||||
core->setUsername(newUsername);
|
||||
}
|
||||
|
||||
void Widget::setUsername(const QString& username)
|
||||
{
|
||||
ui->nameLabel->setText(username);
|
||||
ui->nameLabel->setToolTip(username); // for overlength names
|
||||
ui->nameLabel->setToolTip(username); // for overlength names
|
||||
QString sanename = username;
|
||||
sanename.remove(QRegExp("[\\t\\n\\v\\f\\r\\x0000]"));
|
||||
nameMention = QRegExp("\\b" + QRegExp::escape(username) + "\\b", Qt::CaseInsensitive);
|
||||
sanitizedNameMention = QRegExp("\\b" + QRegExp::escape(sanename) + "\\b", Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
void Widget::onStatusMessageChanged(const QString& newStatusMessage, const QString& oldStatusMessage)
|
||||
|
@ -665,6 +696,10 @@ void Widget::addFriend(int friendId, const QString &userId)
|
|||
QLayout* layout = contactListWidget->getFriendLayout(Status::Offline);
|
||||
layout->addWidget(newfriend->getFriendWidget());
|
||||
|
||||
if (Settings::getInstance().getEnableLogging())
|
||||
newfriend->getChatForm()->loadHistory(QDateTime::currentDateTime().addDays(-7), true);
|
||||
|
||||
connect(settingsWidget, &SettingsWidget::compactToggled, newfriend->getFriendWidget(), &GenericChatroomWidget::onCompactChanged);
|
||||
connect(newfriend->getFriendWidget(), SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), this, SLOT(onChatroomWidgetClicked(GenericChatroomWidget*)));
|
||||
connect(newfriend->getFriendWidget(), SIGNAL(removeFriend(int)), this, SLOT(removeFriend(int)));
|
||||
connect(newfriend->getFriendWidget(), SIGNAL(copyFriendIdToClipboard(int)), this, SLOT(copyFriendIdToClipboard(int)));
|
||||
|
@ -674,6 +709,7 @@ void Widget::addFriend(int friendId, const QString &userId)
|
|||
connect(newfriend->getChatForm(), SIGNAL(sendFile(int32_t, QString, QString, long long)), core, SLOT(sendFile(int32_t, QString, QString, long long)));
|
||||
connect(newfriend->getChatForm(), SIGNAL(answerCall(int)), core, SLOT(answerCall(int)));
|
||||
connect(newfriend->getChatForm(), SIGNAL(hangupCall(int)), core, SLOT(hangupCall(int)));
|
||||
connect(newfriend->getChatForm(), SIGNAL(rejectCall(int)), core, SLOT(rejectCall(int)));
|
||||
connect(newfriend->getChatForm(), SIGNAL(startCall(int)), core, SLOT(startCall(int)));
|
||||
connect(newfriend->getChatForm(), SIGNAL(startVideoCall(int,bool)), core, SLOT(startCall(int,bool)));
|
||||
connect(newfriend->getChatForm(), SIGNAL(cancelCall(int,int)), core, SLOT(cancelCall(int,int)));
|
||||
|
@ -803,25 +839,11 @@ void Widget::onFriendMessageReceived(int friendId, const QString& message, bool
|
|||
QDateTime timestamp = QDateTime::currentDateTime();
|
||||
f->getChatForm()->addMessage(f->getToxID(), message, isAction, timestamp, true);
|
||||
|
||||
if (isAction)
|
||||
HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, "/me " + message, f->getToxID().publicKey, timestamp, true);
|
||||
else
|
||||
HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, message, f->getToxID().publicKey, timestamp, true);
|
||||
|
||||
if (activeChatroomWidget != nullptr)
|
||||
{
|
||||
if ((static_cast<GenericChatroomWidget*>(f->getFriendWidget()) != activeChatroomWidget) || isMinimized() || !isActiveWindow())
|
||||
{
|
||||
f->setEventFlag(true);
|
||||
newMessageAlert(f->getFriendWidget());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
f->setEventFlag(true);
|
||||
newMessageAlert(f->getFriendWidget());
|
||||
}
|
||||
HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, isAction ? "/me " + message : message,
|
||||
f->getToxID().publicKey, timestamp, true);
|
||||
|
||||
f->setEventFlag(static_cast<GenericChatroomWidget*>(f->getFriendWidget()) != activeChatroomWidget);
|
||||
newMessageAlert(f->getFriendWidget());
|
||||
f->getFriendWidget()->updateStatusLight();
|
||||
}
|
||||
|
||||
|
@ -836,17 +858,22 @@ void Widget::onReceiptRecieved(int friendId, int receipt)
|
|||
|
||||
void Widget::newMessageAlert(GenericChatroomWidget* chat)
|
||||
{
|
||||
bool inactiveWindow = isMinimized() || !isActiveWindow();
|
||||
if (!inactiveWindow && activeChatroomWidget != nullptr && chat == activeChatroomWidget)
|
||||
return;
|
||||
|
||||
QApplication::alert(this);
|
||||
|
||||
static QFile sndFile(":audio/notification.pcm");
|
||||
if ((isMinimized() || !isActiveWindow()) && Settings::getInstance().getShowInFront())
|
||||
if (Settings::getInstance().getShowWindow())
|
||||
{
|
||||
this->show();
|
||||
showNormal();
|
||||
activateWindow();
|
||||
emit chat->chatroomWidgetClicked(chat);
|
||||
show();
|
||||
if (inactiveWindow && Settings::getInstance().getShowInFront())
|
||||
setWindowState(Qt::WindowActive);
|
||||
}
|
||||
|
||||
static QFile sndFile(":audio/notification.pcm");
|
||||
static QByteArray sndData;
|
||||
|
||||
if (sndData.isEmpty())
|
||||
{
|
||||
sndFile.open(QIODevice::ReadOnly);
|
||||
|
@ -950,24 +977,21 @@ void Widget::onGroupMessageReceived(int groupnumber, int peernumber, const QStri
|
|||
return;
|
||||
|
||||
ToxID author = Core::getInstance()->getGroupPeerToxID(groupnumber, peernumber);
|
||||
QString name = core->getUsername();
|
||||
|
||||
bool targeted = (!author.isMine()) && message.contains(name, Qt::CaseInsensitive);
|
||||
bool targeted = !author.isMine() && (message.contains(nameMention) || message.contains(sanitizedNameMention));
|
||||
if (targeted && !isAction)
|
||||
g->getChatForm()->addAlertMessage(author, message, QDateTime::currentDateTime());
|
||||
else
|
||||
g->getChatForm()->addMessage(author, message, isAction, QDateTime::currentDateTime(), true);
|
||||
|
||||
if ((static_cast<GenericChatroomWidget*>(g->getGroupWidget()) != activeChatroomWidget) || isMinimized() || !isActiveWindow())
|
||||
{
|
||||
g->setEventFlag(true);
|
||||
if (targeted)
|
||||
{
|
||||
newMessageAlert(g->getGroupWidget());
|
||||
g->setMentionedFlag(true); // useful for highlighting line or desktop notifications
|
||||
}
|
||||
g->getGroupWidget()->updateStatusLight();
|
||||
}
|
||||
g->setEventFlag(static_cast<GenericChatroomWidget*>(g->getGroupWidget()) != activeChatroomWidget);
|
||||
|
||||
if (targeted || Settings::getInstance().getGroupAlwaysNotify())
|
||||
newMessageAlert(g->getGroupWidget());
|
||||
|
||||
if (targeted)
|
||||
g->setMentionedFlag(true); // useful for highlighting line or desktop notifications
|
||||
|
||||
g->getGroupWidget()->updateStatusLight();
|
||||
}
|
||||
|
||||
void Widget::onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t Change)
|
||||
|
|
|
@ -44,6 +44,7 @@ class FriendListWidget;
|
|||
class MaskablePixmapWidget;
|
||||
class QTimer;
|
||||
class QTranslator;
|
||||
class SystemTrayIcon;
|
||||
|
||||
class Widget : public QMainWindow
|
||||
{
|
||||
|
@ -81,6 +82,7 @@ public:
|
|||
public slots:
|
||||
void onSettingsClicked();
|
||||
void setWindowTitle(const QString& title);
|
||||
void forceShow();
|
||||
|
||||
signals:
|
||||
void friendRequestAccepted(const QString& userId);
|
||||
|
@ -90,6 +92,7 @@ signals:
|
|||
void usernameChanged(const QString& username);
|
||||
void statusMessageChanged(const QString& statusMessage);
|
||||
void changeProfile(const QString& profile);
|
||||
void resized();
|
||||
|
||||
private slots:
|
||||
void onConnected();
|
||||
|
@ -147,7 +150,7 @@ private:
|
|||
void saveSplitterGeometry();
|
||||
QString askProfiles();
|
||||
QString detectProfile();
|
||||
QSystemTrayIcon *icon;
|
||||
SystemTrayIcon *icon;
|
||||
QMenu *trayMenu;
|
||||
QAction *statusOnline,
|
||||
*statusAway,
|
||||
|
@ -171,6 +174,7 @@ private:
|
|||
Status beforeDisconnect = Status::Offline;
|
||||
QTimer* idleTimer;
|
||||
QTranslator* translator;
|
||||
QRegExp nameMention, sanitizedNameMention;
|
||||
};
|
||||
|
||||
void toxActivateEventHandler(const QByteArray& data);
|
||||
|
|
467
translations/de.ts
vendored
467
translations/de.ts
vendored
File diff suppressed because it is too large
Load Diff
628
translations/fr.ts
vendored
628
translations/fr.ts
vendored
File diff suppressed because it is too large
Load Diff
1
translations/i18n.pri
vendored
1
translations/i18n.pri
vendored
|
@ -6,6 +6,7 @@ TRANSLATIONS = translations/es.ts \
|
|||
translations/fi.ts \
|
||||
translations/fr.ts \
|
||||
translations/it.ts \
|
||||
translations/lt.ts \
|
||||
translations/mannol.ts \
|
||||
translations/pirate.ts \
|
||||
translations/pl.ts \
|
||||
|
|
714
translations/it.ts
vendored
714
translations/it.ts
vendored
File diff suppressed because it is too large
Load Diff
1579
translations/lt.ts
vendored
Normal file
1579
translations/lt.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
765
translations/pl.ts
vendored
765
translations/pl.ts
vendored
File diff suppressed because it is too large
Load Diff
BIN
ui/acceptCall/acceptCall.png
Normal file
BIN
ui/acceptCall/acceptCall.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
|
@ -30,3 +30,8 @@ div.alert_name {
|
|||
background-color: @orange;
|
||||
font: @bigBold;
|
||||
}
|
||||
|
||||
a {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
GenericChatroomWidget
|
||||
{
|
||||
GenericChatroomWidget
|
||||
{
|
||||
background-color: @themeMedium;
|
||||
}
|
||||
|
||||
|
@ -8,31 +8,55 @@ GenericChatroomWidget[active="true"]
|
|||
background-color: @white;
|
||||
}
|
||||
|
||||
GenericChatroomWidget[active="false"]:hover
|
||||
{
|
||||
background-color: @themeLight;
|
||||
}
|
||||
GenericChatroomWidget[active="false"]:hover
|
||||
{
|
||||
background-color: @themeLight;
|
||||
}
|
||||
|
||||
GenericChatroomWidget[active="true"] > QLabel#status
|
||||
GenericChatroomWidget[active="true"][compact="true"] > QLabel#status
|
||||
{
|
||||
font: @small;
|
||||
color: @mediumGrey;
|
||||
}
|
||||
|
||||
GenericChatroomWidget[active="false"][compact="true"] > QLabel#status
|
||||
{
|
||||
font: @small;
|
||||
color: @lightGrey;
|
||||
}
|
||||
|
||||
GenericChatroomWidget[active="true"][compact="true"] > QLabel#name
|
||||
{
|
||||
font: @medium;
|
||||
color: @darkGrey;
|
||||
}
|
||||
|
||||
GenericChatroomWidget[active="false"][compact="true"] > QLabel#name
|
||||
{
|
||||
font: @medium;
|
||||
color: @white;
|
||||
}
|
||||
|
||||
GenericChatroomWidget[active="true"][compact="false"] > QLabel#status
|
||||
{
|
||||
font: @medium;
|
||||
color: @mediumGrey;
|
||||
}
|
||||
|
||||
GenericChatroomWidget[active="false"] > QLabel#status
|
||||
GenericChatroomWidget[active="false"][compact="false"] > QLabel#status
|
||||
{
|
||||
font: @medium;
|
||||
color: @lightGrey;
|
||||
}
|
||||
|
||||
GenericChatroomWidget[active="true"] > QLabel#name
|
||||
GenericChatroomWidget[active="true"][compact="false"] > QLabel#name
|
||||
{
|
||||
font: @big;
|
||||
color: @darkGrey;
|
||||
}
|
||||
|
||||
GenericChatroomWidget[active="false"] > QLabel#name
|
||||
GenericChatroomWidget[active="false"][compact="false"] > QLabel#name
|
||||
{
|
||||
font: @big;
|
||||
color: @white;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ QPushButton#green
|
|||
background-image: url(":/ui/micButton/micButton.png");
|
||||
background-repeat: none;
|
||||
border: none;
|
||||
width: 25px;
|
||||
height: 20px;
|
||||
width: 22px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
QPushButton#green:hover
|
||||
|
@ -19,8 +19,8 @@ QPushButton#red
|
|||
background-image: url(":/ui/micButton/micButtonPressed.png");
|
||||
background-repeat: none;
|
||||
border: none;
|
||||
width: 25px;
|
||||
height: 20px;
|
||||
width: 22px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
QPushButton#grey
|
||||
|
@ -29,8 +29,8 @@ QPushButton#grey
|
|||
background-image: url(":/ui/micButton/micButtonDisabled.png");
|
||||
background-repeat: none;
|
||||
border: none;
|
||||
width: 25px;
|
||||
height: 20px;
|
||||
width: 22px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
QPushButton:focus {
|
||||
|
|
BIN
ui/rejectCall/rejectCall.png
Normal file
BIN
ui/rejectCall/rejectCall.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
|
@ -1,4 +1,4 @@
|
|||
QWidget
|
||||
QWidget .QLabel, QWidget .QLineEdit
|
||||
{
|
||||
color: black;
|
||||
background: white;
|
||||
|
|
|
@ -4,7 +4,7 @@ QPushButton#green
|
|||
background-image: url(":/ui/volButton/volButton.png");
|
||||
background-repeat: none;
|
||||
border: none;
|
||||
width: 25px;
|
||||
width: 22px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,17 @@ QPushButton#red
|
|||
background-image: url(":/ui/volButton/volButtonPressed.png");
|
||||
background-repeat: none;
|
||||
border: none;
|
||||
width: 25px;
|
||||
width: 22px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
QPushButton#grey
|
||||
{
|
||||
background-color: transparent;
|
||||
background-image: url(":/ui/volButton/volButtonDisabled.png");
|
||||
background-repeat: none;
|
||||
border: none;
|
||||
width: 22px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
|
|
BIN
ui/volButton/volButtonDisabled.png
Normal file
BIN
ui/volButton/volButtonDisabled.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 582 B |
|
@ -58,6 +58,7 @@ Widget::~Widget()
|
|||
void Widget::setProgress(int value)
|
||||
{
|
||||
ui->progress->setValue(value);
|
||||
ui->progress->repaint();
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
|
@ -126,7 +127,7 @@ void Widget::update()
|
|||
setProgress(5);
|
||||
|
||||
/// 2. Check the update (5-50%)
|
||||
float checkProgressStep = 45/diff.size();
|
||||
float checkProgressStep = 45.0/(float)diff.size();
|
||||
float checkProgress = 5;
|
||||
for (UpdateFileMeta fileMeta : diff)
|
||||
{
|
||||
|
@ -152,21 +153,23 @@ void Widget::update()
|
|||
setProgress(50);
|
||||
|
||||
/// 3. Install the update (50-95%)
|
||||
float installProgressStep = 45/diff.size();
|
||||
float installProgressStep = 45.0/(float)diff.size();
|
||||
float installProgress = 50;
|
||||
for (UpdateFileMeta fileMeta : diff)
|
||||
{
|
||||
// Backup old files
|
||||
if (QFile(fileMeta.installpath).exists())
|
||||
{
|
||||
QFile(fileMeta.installpath+".bak").remove();
|
||||
QFile(fileMeta.installpath).rename(fileMeta.installpath+".bak");
|
||||
backups.append(fileMeta.installpath);
|
||||
}
|
||||
|
||||
// Install new ones
|
||||
QDir().mkpath(QFileInfo(fileMeta.installpath).absolutePath());
|
||||
QFile fileFile(updateDirStr+fileMeta.installpath);
|
||||
if (!fileFile.copy(fileMeta.installpath))
|
||||
fatalError(tr("Unable to copy the update's files."));
|
||||
fatalError(tr("Unable to copy the update's files from ")+(updateDirStr+fileMeta.installpath)+" to "+fileMeta.installpath);
|
||||
installProgress += installProgressStep;
|
||||
setProgress(installProgress);
|
||||
}
|
||||
|
|
109
windows/bootstrap.sh
Normal file
109
windows/bootstrap.sh
Normal file
|
@ -0,0 +1,109 @@
|
|||
#!/bin/sh
|
||||
QTOX_DIR=`pwd`/..
|
||||
|
||||
if [ -d $QTOX_DIR/libs ]; then
|
||||
echo "Remove ./libs and redownload/recompile dependencies?"
|
||||
read -p "m/a/N (missing/all/no): " yn
|
||||
yn=$(echo $yn | tr "[:upper:]" "[:lower:]")
|
||||
if [ "$yn" == "a" ]; then
|
||||
rm -rf $QTOX_DIR/libs
|
||||
elif [ "$yn" == "n" ]; then
|
||||
exit -1
|
||||
elif [ "$yn" != "m" ]; then
|
||||
exit -1
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p $QTOX_DIR/libs
|
||||
cd $QTOX_DIR/libs
|
||||
|
||||
|
||||
## toxcore
|
||||
if [ ! -f "libtoxcore-win32-i686.zip" ]; then
|
||||
wget --no-check-certificate http://jenkins.libtoxcore.so/job/libtoxcore-win32-i686/lastSuccessfulBuild/artifact/libtoxcore-win32-i686.zip
|
||||
rm -rf include/tox
|
||||
fi
|
||||
|
||||
if [ ! -d "include/tox" ]; then
|
||||
$QTOX_DIR/tools/unzip -o libtoxcore-win32-i686.zip -d ./
|
||||
fi
|
||||
|
||||
## filter_audio
|
||||
if [ ! -f "bin/libfilteraudio.dll" ]; then
|
||||
$QTOX_DIR/install_libfilteraudio.sh $QTOX_DIR/libs/filter_audio $QTOX_DIR/libs
|
||||
fi
|
||||
|
||||
|
||||
## OpenAL
|
||||
if [ ! -f "openal-soft-1.16.0.tar.bz2" ]; then
|
||||
wget http://kcat.strangesoft.net/openal-releases/openal-soft-1.16.0.tar.bz2
|
||||
rm -rf openal-soft-1.16.0
|
||||
fi
|
||||
|
||||
if [ ! -d "openal-soft-1.16.0" ]; then
|
||||
tar -xvf openal-soft-1.16.0.tar.bz2
|
||||
rm bin/OpenAL32.dll
|
||||
fi
|
||||
|
||||
if [ ! -f "bin/OpenAL32.dll" ]; then
|
||||
pushd openal-soft-1.16.0/build
|
||||
cmake -G "MSYS Makefiles" -DQT_QMAKE_EXECUTABLE=NOTFOUND -DCMAKE_BUILD_TYPE=Release -DALSOFT_REQUIRE_DSOUND=NO -DCMAKE_INSTALL_PREFIX=$QTOX_DIR/libs ..
|
||||
make
|
||||
make install
|
||||
popd
|
||||
fi
|
||||
|
||||
## opencv
|
||||
if [ ! -f "opencv-2.4.9.tar.gz" ]; then
|
||||
wget --no-check-certificate https://github.com/Itseez/opencv/archive/2.4.9.tar.gz -O opencv-2.4.9.tar.gz
|
||||
rm -rf opencv-2.4.9
|
||||
fi
|
||||
|
||||
if [ ! -d "opencv-2.4.9" ]; then
|
||||
tar -xvf opencv-2.4.9.tar.gz
|
||||
rm bin/libopencv_core249.dll
|
||||
fi
|
||||
|
||||
if [ ! -f "bin/libopencv_core249.dll" ]; then
|
||||
mkdir opencv-2.4.9/build
|
||||
pushd opencv-2.4.9/build
|
||||
cmake -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$QTOX_DIR/libs \
|
||||
-DBUILD_opencv_apps=NO \
|
||||
-DBUILD_opencv_calib3d=NO \
|
||||
-DBUILD_opencv_contrib=NO \
|
||||
-DBUILD_opencv_core=YES \
|
||||
-DBUILD_opencv_features2d=NO \
|
||||
-DBUILD_opencv_flann=NO \
|
||||
-DBUILD_opencv_gpu=NO \
|
||||
-DBUILD_opencv_highgui=YES \
|
||||
-DBUILD_opencv_imgproc=YES \
|
||||
-DBUILD_opencv_legacy=NO \
|
||||
-DBUILD_opencv_ml=NO \
|
||||
-DBUILD_opencv_nonfree=NO \
|
||||
-DBUILD_opencv_objdetect=NO \
|
||||
-DBUILD_opencv_ocl=NO \
|
||||
-DBUILD_opencv_photo=NO \
|
||||
-DBUILD_opencv_stiching=NO \
|
||||
-DBUILD_opencv_superres=NO \
|
||||
-DBUILD_opencv_ts=NO \
|
||||
-DBUILD_opencv_video=NO \
|
||||
-DBUILD_opencv_videostab=NO \
|
||||
-DBUILD_opencv_world=NO \
|
||||
-DWITH_QT=NO \
|
||||
-DBUILD_EXAMPLES=NO \
|
||||
..
|
||||
|
||||
make
|
||||
make install
|
||||
for arch in x86 x64
|
||||
do
|
||||
if [ -d $QTOX_DIR/libs/$arch/mingw ]; then
|
||||
mv $QTOX_DIR/libs/$arch/mingw/bin/* $QTOX_DIR/libs/bin/
|
||||
mv $QTOX_DIR/libs/$arch/mingw/lib/* $QTOX_DIR/libs/lib/
|
||||
rm -rf $QTOX_DIR/libs/$arch
|
||||
fi
|
||||
done
|
||||
popd
|
||||
fi
|
||||
|
||||
echo **Done**
|
357
windows/qtox64.nsi
Normal file
357
windows/qtox64.nsi
Normal file
|
@ -0,0 +1,357 @@
|
|||
###################
|
||||
#META
|
||||
###################
|
||||
!define APP_NAME "qTox"
|
||||
!define COMP_NAME "Tox"
|
||||
!define WEB_SITE "https://github.com/tux3/qTox"
|
||||
!define VERSION "1.0.0.0"
|
||||
!define DESCRIPTION "qTox Installer"
|
||||
!define COPYRIGHT "The Tox Project"
|
||||
!define INSTALLER_NAME "setup-qtox.exe"
|
||||
!define MAIN_APP_EXE "bin\qtox.exe"
|
||||
!define INSTALL_TYPE "SetShellVarContext current"
|
||||
!define REG_ROOT "HKCU"
|
||||
!define REG_APP_PATH "Software\Microsoft\Windows\CurrentVersion\App Paths\qtox.exe"
|
||||
!define UNINSTALL_PATH "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}"
|
||||
!define REG_START_MENU "Start Menu Folder"
|
||||
var SM_Folder
|
||||
|
||||
Name "${APP_NAME}"
|
||||
Caption "${APP_NAME}"
|
||||
OutFile "${INSTALLER_NAME}"
|
||||
BrandingText "${APP_NAME}"
|
||||
InstallDir "$PROGRAMFILES64\${APP_NAME}"
|
||||
SetCompressor /SOLID lzma
|
||||
|
||||
VIProductVersion "${VERSION}"
|
||||
VIAddVersionKey "ProductName" "${APP_NAME}"
|
||||
VIAddVersionKey "CompanyName" "${COMP_NAME}"
|
||||
VIAddVersionKey "LegalCopyright" "${COPYRIGHT}"
|
||||
VIAddVersionKey "FileDescription" "${DESCRIPTION}"
|
||||
VIAddVersionKey "FileVersion" "${VERSION}"
|
||||
|
||||
##############
|
||||
#UNINSTALL LOG
|
||||
##############
|
||||
;AddItem macro
|
||||
!macro AddItem Path
|
||||
FileWrite $UninstLog "${Path}$\r$\n"
|
||||
!macroend
|
||||
|
||||
;File macro
|
||||
!macro File FileName
|
||||
IfFileExists "$OUTDIR\${FileName}" +2
|
||||
FileWrite $UninstLog "$OUTDIR\${FileName}$\r$\n"
|
||||
File "${FileName}"
|
||||
!macroend
|
||||
|
||||
;CreateShortcut macro
|
||||
!macro CreateShortcut FilePath FilePointer Pamameters Icon IconIndex
|
||||
FileWrite $UninstLog "${FilePath}$\r$\n"
|
||||
CreateShortcut "${FilePath}" "${FilePointer}" "${Pamameters}" "${Icon}" "${IconIndex}"
|
||||
!macroend
|
||||
|
||||
;Copy files macro
|
||||
!macro CopyFiles SourcePath DestPath
|
||||
IfFileExists "${DestPath}" +2
|
||||
FileWrite $UninstLog "${DestPath}$\r$\n"
|
||||
CopyFiles "${SourcePath}" "${DestPath}"
|
||||
!macroend
|
||||
|
||||
;Rename macro
|
||||
!macro Rename SourcePath DestPath
|
||||
IfFileExists "${DestPath}" +2
|
||||
FileWrite $UninstLog "${DestPath}$\r$\n"
|
||||
Rename "${SourcePath}" "${DestPath}"
|
||||
!macroend
|
||||
|
||||
;CreateDirectory macro
|
||||
!macro CreateDirectory Path
|
||||
CreateDirectory "${Path}"
|
||||
FileWrite $UninstLog "${Path}$\r$\n"
|
||||
!macroend
|
||||
|
||||
;SetOutPath macro
|
||||
!macro SetOutPath Path
|
||||
SetOutPath "${Path}"
|
||||
FileWrite $UninstLog "${Path}$\r$\n"
|
||||
!macroend
|
||||
|
||||
;WriteUninstaller macro
|
||||
!macro WriteUninstaller Path
|
||||
WriteUninstaller "${Path}"
|
||||
FileWrite $UninstLog "${Path}$\r$\n"
|
||||
!macroend
|
||||
|
||||
;WriteIniStr macro
|
||||
!macro WriteIniStr IniFile SectionName EntryName NewValue
|
||||
IfFileExists "${IniFile}" +2
|
||||
FileWrite $UninstLog "${IniFile}$\r$\n"
|
||||
WriteIniStr "${IniFile}" "${SectionName}" "${EntryName}" "${NewValue}"
|
||||
!macroend
|
||||
|
||||
;WriteRegStr macro
|
||||
!macro WriteRegStr RegRoot UnInstallPath Key Value
|
||||
FileWrite $UninstLog "${RegRoot} ${UnInstallPath}$\r$\n"
|
||||
WriteRegStr "${RegRoot}" "${UnInstallPath}" "${Key}" "${Value}"
|
||||
!macroend
|
||||
|
||||
|
||||
;WriteRegDWORD macro
|
||||
!macro WriteRegDWORD RegRoot UnInstallPath Key Value
|
||||
FileWrite $UninstLog "${RegRoot} ${UnInstallPath}$\r$\n"
|
||||
WriteRegDWORD "${RegRoot}" "${UnInstallPath}" "${Key}" "${Value}"
|
||||
!macroend
|
||||
|
||||
;BackupFile macro
|
||||
!macro BackupFile FILE_DIR FILE BACKUP_TO
|
||||
IfFileExists "${BACKUP_TO}\*.*" +2
|
||||
CreateDirectory "${BACKUP_TO}"
|
||||
IfFileExists "${FILE_DIR}\${FILE}" 0 +2
|
||||
Rename "${FILE_DIR}\${FILE}" "${BACKUP_TO}\${FILE}"
|
||||
!macroend
|
||||
|
||||
;RestoreFile macro
|
||||
!macro RestoreFile BUP_DIR FILE RESTORE_TO
|
||||
IfFileExists "${BUP_DIR}\${FILE}" 0 +2
|
||||
Rename "${BUP_DIR}\${FILE}" "${RESTORE_TO}\${FILE}"
|
||||
!macroend
|
||||
|
||||
;BackupFiles macro
|
||||
!macro BackupFiles FILE_DIR FILE BACKUP_TO
|
||||
IfFileExists "${BACKUP_TO}\*.*" +2
|
||||
CreateDirectory "22222"
|
||||
IfFileExists "${FILE_DIR}\${FILE}" 0 +7
|
||||
FileWrite $UninstLog "${FILE_DIR}\${FILE}$\r$\n"
|
||||
FileWrite $UninstLog "${BACKUP_TO}\${FILE}$\r$\n"
|
||||
FileWrite $UninstLog "FileBackup$\r$\n"
|
||||
Rename "${FILE_DIR}\${FILE}" "${BACKUP_TO}\${FILE}"
|
||||
SetOutPath "${FILE_DIR}"
|
||||
File "${FILE}" #After the Original file is backed up write the new file.
|
||||
!macroend
|
||||
|
||||
;RestoreFiles macro
|
||||
!macro RestoreFiles BUP_FILE RESTORE_FILE
|
||||
IfFileExists "${BUP_FILE}" 0 +2
|
||||
CopyFiles "${BUP_FILE}" "${RESTORE_FILE}"
|
||||
!macroend
|
||||
|
||||
###################
|
||||
#PREPARE UNINST LOG
|
||||
###################
|
||||
;Set the name of the uninstall log
|
||||
!define UninstLog "uninstall.log"
|
||||
Var UninstLog
|
||||
|
||||
;Uninstall log file missing.
|
||||
LangString UninstLogMissing ${LANG_ENGLISH} "${UninstLog} not found!$\r$\nUninstallation cannot proceed!"
|
||||
|
||||
;AddItem macro
|
||||
!define AddItem "!insertmacro AddItem"
|
||||
|
||||
;BackupFile macro
|
||||
!define BackupFile "!insertmacro BackupFile"
|
||||
|
||||
;BackupFiles macro
|
||||
!define BackupFiles "!insertmacro BackupFiles"
|
||||
|
||||
;Copy files macro
|
||||
!define CopyFiles "!insertmacro CopyFiles"
|
||||
|
||||
;CreateDirectory macro
|
||||
!define CreateDirectory "!insertmacro CreateDirectory"
|
||||
|
||||
;CreateShortcut macro
|
||||
!define CreateShortcut "!insertmacro CreateShortcut"
|
||||
|
||||
;File macro
|
||||
!define File "!insertmacro File"
|
||||
|
||||
;Rename macro
|
||||
!define Rename "!insertmacro Rename"
|
||||
|
||||
;RestoreFile macro
|
||||
!define RestoreFile "!insertmacro RestoreFile"
|
||||
|
||||
;RestoreFiles macro
|
||||
!define RestoreFiles "!insertmacro RestoreFiles"
|
||||
|
||||
;SetOutPath macro
|
||||
!define SetOutPath "!insertmacro SetOutPath"
|
||||
|
||||
;WriteRegDWORD macro
|
||||
!define WriteRegDWORD "!insertmacro WriteRegDWORD"
|
||||
|
||||
;WriteRegStr macro
|
||||
!define WriteRegStr "!insertmacro WriteRegStr"
|
||||
|
||||
;WriteUninstaller macro
|
||||
!define WriteUninstaller "!insertmacro WriteUninstaller"
|
||||
|
||||
Section -openlogfile
|
||||
CreateDirectory "$INSTDIR"
|
||||
IfFileExists "$INSTDIR\${UninstLog}" +3
|
||||
FileOpen $UninstLog "$INSTDIR\${UninstLog}" w
|
||||
Goto +4
|
||||
SetFileAttributes "$INSTDIR\${UninstLog}" NORMAL
|
||||
FileOpen $UninstLog "$INSTDIR\${UninstLog}" a
|
||||
FileSeek $UninstLog 0 END
|
||||
SectionEnd
|
||||
|
||||
##############
|
||||
#MODERN UI
|
||||
##############
|
||||
!include "MUI.nsh"
|
||||
|
||||
!define MUI_ABORTWARNING
|
||||
!define MUI_FINISHPAGE_NOAUTOCLOSE
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!ifdef REG_START_MENU
|
||||
!define MUI_STARTMENUPAGE_NODISABLE
|
||||
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "qTox"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "${REG_ROOT}"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_KEY "${UNINSTALL_PATH}"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${REG_START_MENU}"
|
||||
!insertmacro MUI_PAGE_STARTMENU Application $SM_Folder
|
||||
!endif
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
|
||||
Function finishpageaction
|
||||
${CreateShortcut} "$DESKTOP\qTox.lnk" "$INSTDIR\${MAIN_APP_EXE}" "" "" ""
|
||||
FunctionEnd
|
||||
|
||||
!define MUI_FINISHPAGE_SHOWREADME ""
|
||||
!define MUI_FINISHPAGE_SHOWREADME_TEXT "Create Desktop Shortcut"
|
||||
!define MUI_FINISHPAGE_SHOWREADME_FUNCTION finishpageaction
|
||||
|
||||
!define MUI_FINISHPAGE_RUN "$INSTDIR\${MAIN_APP_EXE}"
|
||||
!define MUI_FINISHPAGE_LINK "Find qTox on GitHub"
|
||||
!define MUI_FINISHPAGE_LINK_LOCATION "https://github.com/tux3/qTox"
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
!define MUI_UNABORTWARNING
|
||||
!define MUI_UNFINISHPAGE_NOAUTOCLOSE
|
||||
!insertmacro MUI_UNPAGE_WELCOME
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
!insertmacro MUI_UNPAGE_FINISH
|
||||
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
#################
|
||||
#INSTALL
|
||||
#################
|
||||
Section "Install"
|
||||
# Install files
|
||||
${SetOutPath} "$INSTDIR"
|
||||
${WriteUninstaller} "uninstall.exe"
|
||||
|
||||
${CreateDirectory} "bin"
|
||||
${SetOutPath} "$INSTDIR\bin"
|
||||
${File} "qtox\*.*"
|
||||
|
||||
${CreateDirectory} "imageformats"
|
||||
${SetOutPath} "$INSTDIR\bin\imageformats"
|
||||
${File} "qtox\imageformats\*.*"
|
||||
${SetOutPath} "$INSTDIR\bin"
|
||||
|
||||
${CreateDirectory} "platforms"
|
||||
${SetOutPath} "$INSTDIR\bin\platforms"
|
||||
${File} "qtox\platforms\*.*"
|
||||
${SetOutPath} "$INSTDIR\bin"
|
||||
|
||||
${CreateDirectory} "sqldrivers"
|
||||
${SetOutPath} "$INSTDIR\bin\sqldrivers"
|
||||
${File} "qtox\sqldrivers\*.*"
|
||||
${SetOutPath} "$INSTDIR\bin"
|
||||
|
||||
# Create shortcuts
|
||||
${CreateDirectory} "$SMPROGRAMS\qTox"
|
||||
${CreateShortCut} "$SMPROGRAMS\qTox\qTox.lnk" "$INSTDIR\${MAIN_APP_EXE}" "" "" ""
|
||||
${CreateShortCut} "$SMPROGRAMS\qTox\Uninstall qTox.lnk" "$INSTDIR\uninstall.exe" "" "" ""
|
||||
|
||||
# Write setup/app info into the registry
|
||||
${WriteRegStr} "${REG_ROOT}" "${REG_APP_PATH}" "" "$INSTDIR\${MAIN_APP_EXE}"
|
||||
${WriteRegStr} "${REG_ROOT}" "${REG_APP_PATH}" "Path" "$INSTDIR\bin\"
|
||||
${WriteRegStr} ${REG_ROOT} "${UNINSTALL_PATH}" "UninstallString" "$INSTDIR\uninstall.exe"
|
||||
|
||||
# Register the tox: protocol
|
||||
${WriteRegStr} HKCR "tox" "" "URL:tox Protocol"
|
||||
${WriteRegStr} HKCR "tox" "URL Protocol" ""
|
||||
${WriteRegStr} HKCR "tox\shell\open\command" "" "$INSTDIR\${MAIN_APP_EXE} %1"
|
||||
|
||||
# Register the .tox file associations
|
||||
${WriteRegStr} "HKCR" "Applications\qtox.exe\SupportedTypes" ".tox" ""
|
||||
${WriteRegStr} HKCR ".tox" "" "toxsave"
|
||||
${WriteRegStr} HKCR "toxsave" "" "Tox save file"
|
||||
${WriteRegStr} HKCR "toxsave\DefaultIcon" "" "$INSTDIR\${MAIN_APP_EXE}"
|
||||
${WriteRegStr} HKCR "toxsave\shell\open\command" "" "$INSTDIR\${MAIN_APP_EXE} %1"
|
||||
SectionEnd
|
||||
|
||||
|
||||
################
|
||||
#UNINSTALL
|
||||
################
|
||||
Section Uninstall
|
||||
;If there's no uninstall log, we'll try anyway to clean what we can
|
||||
IfFileExists "$INSTDIR\${UninstLog}" +3
|
||||
Goto noLog
|
||||
|
||||
Push $R0
|
||||
Push $R1
|
||||
Push $R2
|
||||
SetFileAttributes "$INSTDIR\${UninstLog}" NORMAL
|
||||
FileOpen $UninstLog "$INSTDIR\${UninstLog}" r
|
||||
StrCpy $R1 -1
|
||||
|
||||
GetLineCount:
|
||||
ClearErrors
|
||||
FileRead $UninstLog $R0
|
||||
IntOp $R1 $R1 + 1
|
||||
StrCpy $R0 $R0 -2
|
||||
Push $R0
|
||||
IfErrors 0 GetLineCount
|
||||
|
||||
Pop $R0
|
||||
|
||||
LoopRead:
|
||||
StrCmp $R1 0 LoopDone
|
||||
Pop $R0
|
||||
|
||||
IfFileExists "$R0\*.*" 0 +3
|
||||
RMDir $R0 #is dir
|
||||
Goto +9
|
||||
IfFileExists $R0 0 +3
|
||||
Delete $R0 #is file
|
||||
Goto +6
|
||||
StrCmp $R0 "${REG_ROOT} ${REG_APP_PATH}" 0 +3
|
||||
DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}" #is Reg Element
|
||||
Goto +3
|
||||
StrCmp $R0 "${REG_ROOT} ${UNINSTALL_PATH}" 0 +2
|
||||
DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}" #is Reg Element
|
||||
|
||||
IntOp $R1 $R1 - 1
|
||||
Goto LoopRead
|
||||
LoopDone:
|
||||
FileClose $UninstLog
|
||||
Delete "$INSTDIR\${UninstLog}"
|
||||
noLog:
|
||||
Delete /REBOOTOK "$INSTDIR\uninstall.exe"
|
||||
RMDir /r /REBOOTOK "$INSTDIR\bin"
|
||||
RMDir /REBOOTOK "$INSTDIR"
|
||||
Pop $R2
|
||||
Pop $R1
|
||||
Pop $R0
|
||||
|
||||
;Remove start menu entries
|
||||
RMDir /r /REBOOTOK "$SMPROGRAMS\qTox"
|
||||
|
||||
;Remove registry keys
|
||||
DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}"
|
||||
DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}"
|
||||
DeleteRegKey HKCR "Applications\qtox.exe"
|
||||
DeleteRegKey HKCR ".tox"
|
||||
DeleteRegKey HKCR "tox"
|
||||
DeleteRegKey HKCR "toxsave"
|
||||
SectionEnd
|
Loading…
Reference in New Issue
Block a user