1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

Merge branches 'pr920', 'pr1001', 'pr1003' and 'pr1005'

This commit is contained in:
Dubslow 2015-01-12 06:01:50 -06:00
commit d74b95a7b7
No known key found for this signature in database
GPG Key ID: 3DB8E05315C220AA
86 changed files with 5426 additions and 1223 deletions

View File

@ -14,6 +14,7 @@
| Tox Core | most recent | core, av |
| OpenCV | >= 2.4.9 | core, highgui, imgproc |
| OpenAL Soft | >= 1.16.0 | |
| filter_audio | most recent | |
<a name="linux" />
@ -127,6 +128,12 @@ cd /home/user/qTox
./bootstrap.sh # use -h or --help for more information
```
###filter_audio
You also need to install filter_audio library separately if you did not run ``./bootstrap.sh``.
```bash
./install_libfilteraudio.sh
```
After all the dependencies are thus reeady to go, compiling should be as simple as
```bash
qmake

View File

@ -37,6 +37,6 @@ This client runs on Windows, Linux and Mac natively.<br/>
##Developer overview:
[GitStats](http://207.12.89.155/index.html)<br/>
[GitStats](http://104.219.184.93/index.html)<br/>
[Mac & Linux jenkins](https://jenkins.libtoxcore.so/user/tux3/my-views/view/qTox/)<br/>
[Windows jenkins](http://207.12.89.155:8080)<br/>
[Windows jenkins](http://104.219.184.93:8080)<br/>

View File

@ -15,6 +15,7 @@ SODIUM_VER=1.0.0
# directory names of cloned repositories
SODIUM_DIR=libsodium-$SODIUM_VER
TOX_CORE_DIR=libtoxcore-latest
FILTER_AUDIO_DIR=filter_audio
# this boolean describes whether the installation of
# libsodium should be skipped or not
@ -42,6 +43,11 @@ if [ -z "$TOX_CORE_DIR" ]; then
exit 1
fi
if [ -z "$FILTER_AUDIO_DIR" ]; then
echo "internal error detected!"
echo "FILTER_AUDIO_DIR should not be empty... aborting"
exit 1
fi
########## check input parameters ##########
@ -95,7 +101,7 @@ mkdir -p ${BASE_DIR}
# if exists, otherwise cloning them may fail
rm -rf ${BASE_DIR}/${SODIUM_DIR}
rm -rf ${BASE_DIR}/${TOX_CORE_DIR}
rm -rf ${BASE_DIR}/${FILTER_AUDIO_DIR}
############### install step ###############
@ -122,6 +128,12 @@ if [[ $TOX_ONLY = "false" ]]; then
fi
popd
if [[ $GLOBAL = "false" ]]; then
./install_libfilteraudio.sh ${BASE_DIR}/${FILTER_AUDIO_DIR} ${BASE_DIR}
else
./install_libfilteraudio.sh ${BASE_DIR}/${FILTER_AUDIO_DIR}
fi
fi
# clone current master of libtoxcore

View File

Before

Width:  |  Height:  |  Size: 420 B

After

Width:  |  Height:  |  Size: 420 B

View File

Before

Width:  |  Height:  |  Size: 716 B

After

Width:  |  Height:  |  Size: 716 B

View File

Before

Width:  |  Height:  |  Size: 410 B

After

Width:  |  Height:  |  Size: 410 B

View File

Before

Width:  |  Height:  |  Size: 719 B

After

Width:  |  Height:  |  Size: 719 B

View File

Before

Width:  |  Height:  |  Size: 478 B

After

Width:  |  Height:  |  Size: 478 B

View File

Before

Width:  |  Height:  |  Size: 704 B

After

Width:  |  Height:  |  Size: 704 B

View File

Before

Width:  |  Height:  |  Size: 395 B

After

Width:  |  Height:  |  Size: 395 B

View File

Before

Width:  |  Height:  |  Size: 711 B

After

Width:  |  Height:  |  Size: 711 B

View File

Before

Width:  |  Height:  |  Size: 374 B

After

Width:  |  Height:  |  Size: 374 B

View File

Before

Width:  |  Height:  |  Size: 637 B

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

40
install_libfilteraudio.sh Executable file
View File

@ -0,0 +1,40 @@
#!/bin/sh
if [ -z $1 ]; then
SOURCE_DIR="filter_audio/"
else
SOURCE_DIR="$1/"
fi
if [ -z "$2" ]; then
LIB_DIR="/usr/local/lib/"
INCLUDE_DIR="/usr/local/include/"
else
LIB_DIR="$2/lib/"
INCLUDE_DIR="$2/include/"
fi
echo "Cloning filter_audio from GitHub.com"
git clone https://github.com/irungentoo/filter_audio.git $SOURCE_DIR
echo "Compiling filter_audio"
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
echo "Cleaning up"
rm *.o
muhcmd="cp libfilteraudio.so $LIB_DIR"
[ -z "$2" ] && muhcmd="sudo $muhcmd"
echo "Installing libfilteraudio.so with $muhcmd"
$muhcmd
muhcmd="cp *.h $INCLUDE_DIR"
[ -z "$2" ] && muhcmd="sudo $muhcmd"
echo "Installing include files with $muhcmd"
$muhcmd
echo "Finished."

View File

@ -1,97 +0,0 @@
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"os/user"
)
func fs_type(path string) int {
//name := "FileOrDir"
f, err := os.Open(path)
if err != nil {
fmt.Println(err)
return -1
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
fmt.Println(err)
return -1
}
switch mode := fi.Mode(); {
case mode.IsDir():
return 0
case mode.IsRegular():
return 1
}
return -1
}
func main() {
usr, e := user.Current()
if e != nil {
log.Fatal(e)
}
update_dir := usr.HomeDir + "/Library/Preferences/tox/update/"
if _, err := os.Stat(update_dir); os.IsNotExist(err) {
fmt.Println("Error: No update folder, is check for updates enabled?")
return
}
fmt.Println("qTox Updater")
files, _ := ioutil.ReadDir(update_dir)
killqtox := exec.Command("/usr/bin/killall", "qtox")
_ = killqtox.Run()
for _, file := range files {
if fs_type(update_dir+file.Name()) == 1 {
fmt.Print("Installing: ")
fmt.Println("/Applications/qtox.app/Contents/" + file.Name())
if _, err := os.Stat("/Applications/qtox.app/Contents/" + file.Name()); os.IsNotExist(err) {
newfile := exec.Command("/usr/libexec/authopen", "-c", "-x", "-m", "drwxrwxr-x+", "/Applications/qtox.app/Contents/"+file.Name())
newfile.Run()
}
cat := exec.Command("/bin/cat", update_dir+file.Name())
auth := exec.Command("/usr/libexec/authopen", "-w", "/Applications/qtox.app/Contents/"+file.Name())
auth.Stdin, _ = cat.StdoutPipe()
auth.Stdout = os.Stdout
auth.Stderr = os.Stderr
_ = auth.Start()
_ = cat.Run()
_ = auth.Wait()
} else {
files, _ := ioutil.ReadDir(update_dir + file.Name())
for _, file2 := range files {
fmt.Print("Installing: ")
fmt.Println("/Applications/qtox.app/Contents/" + file.Name() + "/" + file2.Name())
if _, err := os.Stat("/Applications/qtox.app/Contents/" + file.Name() + "/" + file2.Name()); os.IsNotExist(err) {
newfile := exec.Command("/usr/libexec/authopen", "-c", "-x", "-m", "drwxrwxr-x+", "/Applications/qtox.app/Contents/"+file.Name()+"/"+file2.Name())
newfile.Run()
}
cat := exec.Command("/bin/cat", update_dir+file.Name()+"/"+file2.Name())
auth := exec.Command("/usr/libexec/authopen", "-w", "/Applications/qtox.app/Contents/"+file.Name()+"/"+file2.Name())
auth.Stdin, _ = cat.StdoutPipe()
auth.Stdout = os.Stdout
auth.Stderr = os.Stderr
_ = auth.Start()
_ = cat.Run()
_ = auth.Wait()
}
}
}
os.RemoveAll(update_dir)
fmt.Println("Update metadata wiped, launching qTox")
launchqtox := exec.Command("/usr/bin/open", "-b", "im.tox.qtox")
launchqtox.Run()
}

23
osx/updater/.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test

13
osx/updater/README.md Normal file
View File

@ -0,0 +1,13 @@
The qTox OS X updater is a mix of objective C and Go compiled as static binaries used do effortless updates in the background.
It uses Objective C to access Apples own security framework and call some long dead APIs in order to give the statically linked go updater permissions to install the latest build without prompting the user for every file.
* Release commits: ``https://github.com/Tox/qTox_updater``
* Development commits: ``https://github.mit.edu/sean-2/updater``
Compiling:
* ```clang qtox_sudo.m -framework corefoundation -framework security -framework cocoa -Os -o qtox_sudo```
* ```go build updater.go```
(Starting with this commit all commits will be signed with [this key](http://pgp.mit.edu/pks/lookup?op=get&search=0x13D2043169D25DF4).)

273
osx/updater/qtox_sudo.m Normal file
View File

@ -0,0 +1,273 @@
// Modifications listed here GPLv3: https://gist.githubusercontent.com/stqism/2e82352026915f8f6ab3/raw/fca6f6f16fb8d61a64b6053dacf50c3433c2e0af/gistfile1.txt
//
// Copyright 2009 Performant Design, LLC. All rights reserved.
// Copyright (C) 2014 Tox Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <http://www.gnu.org/licenses/>.
//
#import <Cocoa/Cocoa.h>
#include <sys/stat.h>
#include <unistd.h>
#include <Security/Authorization.h>
#include <Security/AuthorizationTags.h>
char *addFileToPath(const char *path, const char *filename) {
char *outbuf;
char *lc;
lc = (char *)path + strlen(path) - 1;
if (lc < path || *lc != '/') {
lc = NULL;
}
while (*filename == '/') {
filename++;
}
outbuf = malloc(strlen(path) + strlen(filename) + 1 + (lc == NULL ? 1 : 0));
sprintf(outbuf, "%s%s%s", path, (lc == NULL) ? "/" : "", filename);
return outbuf;
}
int isExecFile(const char *name) {
struct stat s;
return (!access(name, X_OK) && !stat(name, &s) && S_ISREG(s.st_mode));
}
char *which(const char *filename)
{
char *path, *p, *n;
path = getenv("PATH");
if (!path) {
return NULL;
}
p = path = strdup(path);
while (p) {
n = strchr(p, ':');
if (n) {
*n++ = '\0';
}
if (*p != '\0') {
p = addFileToPath(p, filename);
if (isExecFile(p)) {
free(path);
return p;
}
free(p);
}
p = n;
}
free(path);
return NULL;
}
int cocoaSudo(char *executable, char *commandArgs[], char *icon, char *prompt) {
int retVal = 1;
OSStatus status;
AuthorizationRef authRef;
AuthorizationItem right = {kAuthorizationRightExecute, 0, NULL, 0};
AuthorizationRights rightSet = {1, &right};
AuthorizationEnvironment myAuthorizationEnvironment;
AuthorizationItem kAuthEnv[2];
myAuthorizationEnvironment.items = kAuthEnv;
AuthorizationFlags flags = kAuthorizationFlagDefaults;
if (prompt && icon) {
kAuthEnv[0].name = kAuthorizationEnvironmentPrompt;
kAuthEnv[0].valueLength = strlen(prompt);
kAuthEnv[0].value = prompt;
kAuthEnv[0].flags = 0;
kAuthEnv[1].name = kAuthorizationEnvironmentIcon;
kAuthEnv[1].valueLength = strlen(icon);
kAuthEnv[1].value = icon;
kAuthEnv[1].flags = 0;
myAuthorizationEnvironment.count = 2;
}
else if (prompt) {
kAuthEnv[0].name = kAuthorizationEnvironmentPrompt;
kAuthEnv[0].valueLength = strlen(prompt);
kAuthEnv[0].value = prompt;
kAuthEnv[0].flags = 0;
myAuthorizationEnvironment.count = 1;
}
else if (icon) {
kAuthEnv[0].name = kAuthorizationEnvironmentIcon;
kAuthEnv[0].valueLength = strlen(icon);
kAuthEnv[0].value = icon;
kAuthEnv[0].flags = 0;
myAuthorizationEnvironment.count = 1;
}
else {
myAuthorizationEnvironment.count = 0;
}
status = AuthorizationCreate(NULL, &myAuthorizationEnvironment, flags, &authRef);
if (status != errAuthorizationSuccess) {
NSLog(@"Could not create authorization reference object.");
status = errAuthorizationBadAddress;
}
else {
flags = kAuthorizationFlagDefaults |
kAuthorizationFlagInteractionAllowed |
kAuthorizationFlagPreAuthorize |
kAuthorizationFlagExtendRights;
status = AuthorizationCopyRights(authRef, &rightSet, &myAuthorizationEnvironment, flags, NULL);
}
if (status == errAuthorizationSuccess) {
FILE *ioPipe;
char buffer[1024];
int bytesRead;
flags = kAuthorizationFlagDefaults;
status = AuthorizationExecuteWithPrivileges(authRef, executable, flags, commandArgs, &ioPipe);
/* Just pipe processes' stdout to our stdout for now; hopefully can add stdin pipe later as well */
for (;;) {
bytesRead = fread(buffer, sizeof(char), 1024, ioPipe);
if (bytesRead < 1) {
break;
}
write(STDOUT_FILENO, buffer, bytesRead * sizeof(char));
}
pid_t pid;
int pidStatus;
do {
pid = wait(&pidStatus);
}
while (pid != -1);
if (status == errAuthorizationSuccess) {
retVal = 0;
}
}
else {
AuthorizationFree(authRef, kAuthorizationFlagDestroyRights);
authRef = NULL;
if (status != errAuthorizationCanceled) {
// pre-auth failed
NSLog(@"Pre-auth failed");
}
}
return retVal;
}
void usage(char *appNameFull) {
char *appName = strrchr(appNameFull, '/');
if (appName == NULL) {
appName = appNameFull;
}
else {
appName++;
}
fprintf(stderr, "usage: %s command\n", appName);
}
int main(int argc, char *argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int retVal = 1;
int programArgsStartAt = 1;
char *icon = NULL;
char *prompt = NULL;
if (programArgsStartAt >= argc) {
usage(argv[0]);
}
else {
char *executable;
if (strchr(argv[programArgsStartAt], '/')) {
executable = isExecFile(argv[programArgsStartAt]) ? strdup(argv[programArgsStartAt]) : NULL;
}
else {
executable = which(argv[programArgsStartAt]);
}
if (executable) {
char **commandArgs = malloc((argc - programArgsStartAt) * sizeof(char**));
memcpy(commandArgs, argv + programArgsStartAt + 1, (argc - programArgsStartAt - 1) * sizeof(char**));
commandArgs[argc - programArgsStartAt - 1] = NULL;
retVal = cocoaSudo(executable, commandArgs, icon, prompt);
free(commandArgs);
free(executable);
}
else {
fprintf(stderr, "Unable to find %s\n", argv[programArgsStartAt]);
usage(argv[0]);
}
}
if (prompt) {
free(prompt);
}
[pool release];
return retVal;
}

133
osx/updater/updater.go Normal file
View File

@ -0,0 +1,133 @@
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"os/user"
"syscall"
"bitbucket.org/kardianos/osext"
)
var custom_user string
func fs_type(path string) int {
//name := "FileOrDir"
f, err := os.Open(path)
if err != nil {
fmt.Println(err)
return -1
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
fmt.Println(err)
return -1
}
switch mode := fi.Mode(); {
case mode.IsDir():
return 0
case mode.IsRegular():
return 1
}
return -1
}
func install(path string, pathlen int) int {
files, _ := ioutil.ReadDir(path)
for _, file := range files {
if fs_type(path+file.Name()) == 1 {
addpath := ""
if len(path) != pathlen {
addpath = path[pathlen:len(path)]
}
fmt.Print("Installing: ")
fmt.Println("/Applications/qtox.app/Contents/" + addpath + file.Name())
if _, err := os.Stat("/Applications/qtox.app/Contents/" + file.Name()); os.IsNotExist(err) {
newfile := exec.Command("/usr/libexec/authopen", "-c", "-x", "-m", "drwxrwxr-x+", "/Applications/qtox.app/Contents/"+addpath+file.Name())
newfile.Run()
}
cat := exec.Command("/bin/cat", path+file.Name())
auth := exec.Command("/usr/libexec/authopen", "-w", "/Applications/qtox.app/Contents/"+addpath+file.Name())
auth.Stdin, _ = cat.StdoutPipe()
auth.Stdout = os.Stdout
auth.Stderr = os.Stderr
_ = auth.Start()
_ = cat.Run()
_ = auth.Wait()
} else {
install(path+file.Name()+"/", pathlen)
}
}
return 0
}
func main() {
syscall.Setuid(0)
usr, e := user.Current()
if e != nil {
log.Fatal(e)
}
CHECK:
if usr.Name != "System Administrator" {
fmt.Println("Not running as root, relaunching")
appdir, _ := osext.Executable()
appdir_len := len(appdir)
sudo_path := appdir[0:(appdir_len-7)] + "qtox_sudo" //qtox_sudo is a fork of cocoasudo with all of its flags and other features stripped out
if _, err := os.Stat(sudo_path); os.IsNotExist(err) {
fmt.Println("Error: No qtox_sudo binary installed, falling back")
custom_user = usr.Name
usr.Name = "System Administrator"
goto CHECK
}
relaunch := exec.Command(sudo_path, appdir, usr.Name)
relaunch.Stdout = os.Stdout
relaunch.Stderr = os.Stderr
relaunch.Run()
return
} else {
if len(os.Args) > 1 || custom_user != "" {
if custom_user == "" {
custom_user = os.Args[1]
}
update_dir := "/Users/" + custom_user + "/Library/Preferences/tox/update/"
if _, err := os.Stat(update_dir); os.IsNotExist(err) {
fmt.Println("Error: No update folder, is check for updates enabled?")
return
}
fmt.Println("qTox Updater")
killqtox := exec.Command("/usr/bin/killall", "qtox")
_ = killqtox.Run()
install(update_dir, len(update_dir))
os.RemoveAll(update_dir)
fmt.Println("Update metadata wiped, launching qTox")
launchqtox := exec.Command("/usr/bin/open", "-b", "im.tox.qtox")
launchqtox.Run()
} else {
fmt.Println("Error: no user passed")
}
}
}

View File

@ -59,6 +59,12 @@ contains(DISABLE_PLATFORM_EXT, YES) {
DEFINES += QTOX_PLATFORM_EXT
}
contains(DISABLE_FILTER_AUDIO, YES) {
} else {
DEFINES += QTOX_FILTER_AUDIO
}
contains(JENKINS,YES) {
INCLUDEPATH += ./libs/include/
} else {
@ -71,6 +77,14 @@ win32 {
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
contains(DEFINES, QTOX_FILTER_AUDIO) {
contains(STATICPKG, YES) {
LIBS += -Wl,-Bstatic -lfilteraudio
} else {
LIBS += -lfilteraudio
}
}
} else {
macx {
BUNDLEID = im.tox.qtox
@ -78,6 +92,7 @@ win32 {
QMAKE_INFO_PLIST = osx/info.plist
LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lvpx -framework OpenAL -lopencv_core -lopencv_highgui
contains(DEFINES, QTOX_PLATFORM_EXT) { LIBS += -framework IOKit -framework CoreFoundation }
contains(DEFINES, QTOX_FILTER_AUDIO) { LIBS += -lfilteraudio }
} else {
# If we're building a package, static link libtox[core,av] and libsodium, since they are not provided by any package
contains(STATICPKG, YES) {
@ -94,8 +109,16 @@ win32 {
LIBS += -lX11 -lXss
}
contains(DEFINES, QTOX_FILTER_AUDIO) {
contains(STATICPKG, YES) {
LIBS += -Wl,-Bstatic -lfilteraudio
} else {
LIBS += -lfilteraudio
}
}
contains(JENKINS, YES) {
LIBS = ./libs/lib/libtoxav.a ./libs/lib/libvpx.a ./libs/lib/libopus.a ./libs/lib/libtoxdns.a ./libs/lib/libtoxencryptsave.a ./libs/lib/libtoxcore.a ./libs/lib/libsodium.a /usr/lib/libopencv_core.so /usr/lib/libopencv_highgui.so /usr/lib/libopencv_imgproc.so -lopenal -lX11 -lXss -s
LIBS = ./libs/lib/libtoxav.a ./libs/lib/libvpx.a ./libs/lib/libopus.a ./libs/lib/libtoxdns.a ./libs/lib/libtoxencryptsave.a ./libs/lib/libtoxcore.a ./libs/lib/libsodium.a ./libs/lib/libfilteraudio.a /usr/lib/libopencv_core.so /usr/lib/libopencv_highgui.so /usr/lib/libopencv_imgproc.so -lopenal -lX11 -lXss -s
}
}
}
@ -234,6 +257,11 @@ SOURCES += \
src/widget/form/settings/advancedform.cpp \
src/audio.cpp
contains(DEFINES, QTOX_FILTER_AUDIO) {
HEADERS += src/audiofilterer.h
SOURCES += src/audiofilterer.cpp
}
contains(DEFINES, QTOX_PLATFORM_EXT) {
HEADERS += src/platform/timer.h
SOURCES += src/platform/timer_osx.cpp \

14
res.qrc
View File

@ -37,10 +37,14 @@
<file>img/status/dot_online.png</file>
<file>img/status/dot_online_2x.png</file>
<file>img/status/dot_online_notification.png</file>
<file>img/taskbar/taskbar_online_2x.png</file>
<file>img/taskbar/taskbar_idle_2x.png</file>
<file>img/taskbar/taskbar_busy_2x.png</file>
<file>img/taskbar/taskbar_offline_2x.png</file>
<file>img/taskbar/dark/taskbar_online_2x.png</file>
<file>img/taskbar/dark/taskbar_idle_2x.png</file>
<file>img/taskbar/dark/taskbar_busy_2x.png</file>
<file>img/taskbar/dark/taskbar_offline_2x.png</file>
<file>img/taskbar/light/taskbar_online_2x.png</file>
<file>img/taskbar/light/taskbar_idle_2x.png</file>
<file>img/taskbar/light/taskbar_busy_2x.png</file>
<file>img/taskbar/light/taskbar_offline_2x.png</file>
<file>img/transfer.png</file>
<file>smileys/cylgom/angel.png</file>
<file>smileys/cylgom/angry.png</file>
@ -120,9 +124,11 @@
<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>
<file>translations/pt.qm</file>
<file>translations/ru.qm</file>
<file>translations/sv.qm</file>
<file>translations/uk.qm</file>

View File

@ -1,42 +1,86 @@
[DHT%20Server]
dhtServerList\size=9
dhtServerList\size=21
dhtServerList\1\name=Nikolai Toryzin
dhtServerList\1\userId=951C88B7E75C867418ACDB5D273821372BB5BD652740BCDF623A4FA293E75D2F
dhtServerList\1\address=192.254.75.98
dhtServerList\1\port=33445
dhtServerList\2\name=sonOfRa
dhtServerList\2\userId=04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F
dhtServerList\2\address=144.76.60.215
dhtServerList\2\port=33445
dhtServerList\3\name=stal
dhtServerList\3\userId=A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074
dhtServerList\3\address=23.226.230.47
dhtServerList\2\name=Nikolai Toryzin
dhtServerList\2\userId=2A4B50D1D525DA2E669592A20C327B5FAD6C7E5962DC69296F9FEC77C4436E4E
dhtServerList\2\address=31.7.57.236
dhtServerList\2\port=443
dhtServerList\3\name=sonOfRa
dhtServerList\3\userId=04119E835DF3E78BACF0F84235B300546AF8B936F035185E2A8E9E0A67C8924F
dhtServerList\3\address=144.76.60.215
dhtServerList\3\port=33445
dhtServerList\4\name=aitjcize
dhtServerList\4\userId=7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029
dhtServerList\4\address=54.199.139.199
dhtServerList\4\name=stal
dhtServerList\4\userId=A09162D68618E742FFBCA1C2C70385E6679604B2D80EA6E84AD0996A1AC8A074
dhtServerList\4\address=23.226.230.47
dhtServerList\4\port=33445
dhtServerList\5\name=astonex
dhtServerList\5\userId=B98A2CEAA6C6A2FADC2C3632D284318B60FE5375CCB41EFA081AB67F500C1B0B
dhtServerList\5\address=37.59.102.176
dhtServerList\5\userId=10B20C49ACBD968D7C80F2E8438F92EA51F189F4E70CFBBB2C2C8C799E97F03E
dhtServerList\5\address=178.62.125.224
dhtServerList\5\port=33445
dhtServerList\6\name=nurupo
dhtServerList\6\userId=F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67
dhtServerList\6\address=192.210.149.121
dhtServerList\6\name=mousey
dhtServerList\6\userId=5EB67C51D3FF5A9D528D242B669036ED2A30F8A60E674C45E7D43010CB2E1331
dhtServerList\6\address=37.187.46.132
dhtServerList\6\port=33445
dhtServerList\7\name=mousey
dhtServerList\7\userId=5EB67C51D3FF5A9D528D242B669036ED2A30F8A60E674C45E7D43010CB2E1331
dhtServerList\7\address=37.187.46.132
dhtServerList\7\name=SylvieLorxu
dhtServerList\7\userId=4B2C19E924972CB9B57732FB172F8A8604DE13EEDA2A6234E348983344B23057
dhtServerList\7\address=178.21.112.187
dhtServerList\7\port=33445
dhtServerList\8\name=Proplex
dhtServerList\8\userId=7BE3951B97CA4B9ECDDA768E8C52BA19E9E2690AB584787BF4C90E04DBB75111
dhtServerList\8\address=107.161.17.51
dhtServerList\8\name=Munrek
dhtServerList\8\userId=E398A69646B8CEACA9F0B84F553726C1C49270558C57DF5F3C368F05A7D71354
dhtServerList\8\address=195.154.119.113
dhtServerList\8\port=33445
dhtServerList\9\name=SylvieLorxu
dhtServerList\9\userId=4B2C19E924972CB9B57732FB172F8A8604DE13EEDA2A6234E348983344B23057
dhtServerList\9\address=178.21.112.187
dhtServerList\9\name=nurupo
dhtServerList\9\userId=F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67
dhtServerList\9\address=192.210.149.121
dhtServerList\9\port=33445
dhtServerList\10\name=Unknown (uTox)
dhtServerList\10\userId=7187969BB10B54C98538BAE94C069CE5C84E650D54F7E596543D8FB1ECF4CF23
dhtServerList\10\address=95.85.13.245
dhtServerList\10\name=aitjcize
dhtServerList\10\userId=7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029
dhtServerList\10\address=54.199.139.199
dhtServerList\10\port=33445
dhtServerList\11\name=Jfreegman
dhtServerList\11\userId=8CD087E31C67568103E8C2A28653337E90E6B8EDA0D765D57C6B5172B4F1F04C
dhtServerList\11\address=104.219.184.206
dhtServerList\11\port=443
dhtServerList\12\name=bunslow
dhtServerList\12\userId=93574A3FAB7D612FEA29FD8D67D3DD10DFD07A075A5D62E8AF3DD9F5D0932E11
dhtServerList\12\address=76.191.23.96
dhtServerList\12\port=33445
dhtServerList\13\name=Martin Schröder
dhtServerList\13\userId=F5A1A38EFB6BD3C2C8AF8B10D85F0F89E931704D349F1D0720C3C4059AF2440A
dhtServerList\13\address=46.38.239.179
dhtServerList\13\port=33445
dhtServerList\14\name=lkwg82
dhtServerList\14\userId=2C308B4518862740AD9A121598BCA7713AFB25858B747313A4D073E2F6AC506C
dhtServerList\14\address=144.76.93.230
dhtServerList\14\port=33445
dhtServerList\15\name=Impyy
dhtServerList\15\userId=788236D34978D1D5BD822F0A5BEBD2C53C64CC31CD3149350EE27D4D9A2F9B6B
dhtServerList\15\address=178.62.250.138
dhtServerList\15\port=33445
dhtServerList\16\name=Thierry Thomas
dhtServerList\16\userId=7A2306BFBA665E5480AE59B31E116BE9C04DCEFE04D9FE25082316FA34B4DA0C
dhtServerList\16\address=78.225.128.39
dhtServerList\16\port=33445
dhtServerList\17\name=Manolis
dhtServerList\17\userId=461FA3776EF0FA655F1A05477DF1B3B614F7D6B124F7DB1DD4FE3C08B03B640F
dhtServerList\17\address=130.133.110.14
dhtServerList\17\port=33445
dhtServerList\18\name=lawk1
dhtServerList\18\userId=58D2DE4B169502669941E50780C1630FAA48A0B7026D6F4066C320D47AC6401E
dhtServerList\18\address=178.62.150.106
dhtServerList\18\port=33445
dhtServerList\19\name=noisykeyboard
dhtServerList\19\userId=5918AC3C06955962A75AD7DF4F80A5D7C34F7DB9E1498D2E0495DE35B3FE8A57
dhtServerList\19\address=104.167.101.29
dhtServerList\19\port=33445
dhtServerList\20\name=aceawan
dhtServerList\20\userId=391C96CB67AE893D4782B8E4495EB9D89CF1031F48460C06075AA8CE76D50A21
dhtServerList\20\address=195.154.109.148
dhtServerList\20\port=33445
dhtServerList\21\name=pastly
dhtServerList\21\userId=3E1FFDEB667BFF549F619EC6737834762124F50A89C8D0DBF1DDF64A2DD6CD1B
dhtServerList\21\address=192.3.173.88
dhtServerList\21\port=33445

View File

@ -15,22 +15,40 @@
*/
// Output some extra debug info
#define AUDIO_DEBUG 1
// Fix a 7 years old openal-soft/alsa bug
// http://blog.gmane.org/gmane.comp.lib.openal.devel/month=20080501
// If set to 1, the capture will be started as long as the device is open
#define FIX_SND_PCM_PREPARE_BUG 0
#include "audio.h"
#include "src/core.h"
#include <QDebug>
#include <QThread>
#include <QMutexLocker>
#include <cassert>
std::atomic<int> Audio::userCount{0};
Audio* Audio::instance{nullptr};
QThread* Audio::audioThread{nullptr};
QMutex* Audio::audioInLock{nullptr};
QMutex* Audio::audioOutLock{nullptr};
ALCdevice* Audio::alInDev{nullptr};
ALCdevice* Audio::alOutDev{nullptr};
ALCcontext* Audio::alContext{nullptr};
ALuint Audio::alMainSource{0};
void audioDebugLog(QString msg)
{
#if (AUDIO_DEBUG)
qDebug()<<"Audio: "<<msg;
#endif
}
Audio& Audio::getInstance()
{
if (!instance)
@ -39,6 +57,8 @@ Audio& Audio::getInstance()
audioThread = new QThread(instance);
audioThread->setObjectName("qTox Audio");
audioThread->start();
audioInLock = new QMutex(QMutex::Recursive);
audioOutLock = new QMutex(QMutex::Recursive);
instance->moveToThread(audioThread);
}
return *instance;
@ -46,18 +66,46 @@ Audio& Audio::getInstance()
void Audio::suscribeInput()
{
if (!alInDev)
{
qWarning()<<"Audio::suscribeInput: input device is closed";
return;
}
audioDebugLog("suscribing");
QMutexLocker lock(audioInLock);
if (!userCount++ && alInDev)
{
#if (!FIX_SND_PCM_PREPARE_BUG)
audioDebugLog("starting capture");
alcCaptureStart(alInDev);
#endif
}
}
void Audio::unsuscribeInput()
{
if (!alInDev)
{
qWarning()<<"Audio::unsuscribeInput: input device is closed";
return;
}
audioDebugLog("unsuscribing");
QMutexLocker lock(audioInLock);
if (!--userCount && alInDev)
{
#if (!FIX_SND_PCM_PREPARE_BUG)
audioDebugLog("stopping capture");
alcCaptureStop(alInDev);
#endif
}
}
void Audio::openInput(const QString& inDevDescr)
{
audioDebugLog("Trying to open input "+inDevDescr);
QMutexLocker lock(audioInLock);
auto* tmp = alInDev;
alInDev = nullptr;
if (tmp)
@ -80,11 +128,22 @@ void Audio::openInput(const QString& inDevDescr)
// Restart the capture if necessary
if (userCount.load() != 0 && alInDev)
{
alcCaptureStart(alInDev);
}
else
{
#if (FIX_SND_PCM_PREPARE_BUG)
alcCaptureStart(alInDev);
#endif
}
}
void Audio::openOutput(const QString& outDevDescr)
{
audioDebugLog("Trying to open output "+outDevDescr);
QMutexLocker lock(audioOutLock);
auto* tmp = alOutDev;
alOutDev = nullptr;
if (outDevDescr.isEmpty())
@ -97,11 +156,8 @@ void Audio::openOutput(const QString& outDevDescr)
}
else
{
if (alContext)
{
alcMakeContextCurrent(nullptr);
if (alContext && alcMakeContextCurrent(nullptr) == ALC_TRUE)
alcDestroyContext(alContext);
}
if (tmp)
alcCloseDevice(tmp);
alContext=alcCreateContext(alOutDev,nullptr);
@ -122,26 +178,48 @@ void Audio::openOutput(const QString& outDevDescr)
void Audio::closeInput()
{
audioDebugLog("Closing input");
QMutexLocker lock(audioInLock);
if (alInDev)
alcCaptureCloseDevice(alInDev);
userCount = 0;
{
if (alcCaptureCloseDevice(alInDev) == ALC_TRUE)
{
alInDev = nullptr;
userCount = 0;
}
else
{
qWarning() << "Audio: Failed to close input";
}
}
}
void Audio::closeOutput()
{
if (alContext)
{
alcMakeContextCurrent(nullptr);
audioDebugLog("Closing output");
QMutexLocker lock(audioOutLock);
if (alContext && alcMakeContextCurrent(nullptr) == ALC_TRUE)
alcDestroyContext(alContext);
}
if (alOutDev)
alcCloseDevice(alOutDev);
{
if (alcCloseDevice(alOutDev) == ALC_TRUE)
{
alOutDev = nullptr;
}
else
{
qWarning() << "Audio: Failed to close output";
}
}
}
void Audio::playMono16Sound(const QByteArray& data)
{
QMutexLocker lock(audioOutLock);
if (!alOutDev)
return;
ALuint buffer;
alGenBuffers(1, &buffer);
alBufferData(buffer, AL_FORMAT_MONO16, data.data(), data.size(), 44100);
@ -163,6 +241,8 @@ void Audio::playGroupAudio(int group, int peer, const int16_t* data,
{
assert(QThread::currentThread() == audioThread);
QMutexLocker lock(audioOutLock);
ToxGroupCall& call = Core::groupCalls[group];
if (!call.active || call.muteVol)
@ -178,20 +258,22 @@ void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, u
{
assert(channels == 1 || channels == 2);
QMutexLocker lock(audioOutLock);
ALuint bufid;
ALint processed = 0, queued = 16;
alGetSourcei(alSource, AL_BUFFERS_PROCESSED, &processed);
alGetSourcei(alSource, AL_BUFFERS_QUEUED, &queued);
alSourcei(alSource, AL_LOOPING, AL_FALSE);
if(processed)
if (processed)
{
ALuint bufids[processed];
alSourceUnqueueBuffers(alSource, processed, bufids);
alDeleteBuffers(processed - 1, bufids + 1);
bufid = bufids[0];
}
else if(queued < 16)
else if (queued < 16)
{
alGenBuffers(1, &bufid);
}
@ -207,6 +289,30 @@ void Audio::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, u
ALint state;
alGetSourcei(alSource, AL_SOURCE_STATE, &state);
if(state != AL_PLAYING)
if (state != AL_PLAYING)
alSourcePlay(alSource);
}
bool Audio::isInputReady()
{
return (alInDev && userCount);
}
bool Audio::isOutputClosed()
{
return (alOutDev);
}
bool Audio::tryCaptureSamples(uint8_t* buf, int framesize)
{
QMutexLocker lock(audioInLock);
ALint samples=0;
alcGetIntegerv(Audio::alInDev, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
if (samples < framesize)
return false;
memset(buf, 0, framesize * 2 * av_DefaultSettings.audio_channels); // Avoid uninitialized values (Valgrind)
alcCaptureSamples(Audio::alInDev, buf, framesize);
return true;
}

View File

@ -34,6 +34,7 @@ class QString;
class QByteArray;
class QTimer;
class QThread;
class QMutex;
struct Tox;
class Audio : QObject
@ -52,7 +53,11 @@ public:
static void closeInput(); ///< Close an input device, please don't use unless everyone's unsuscribed
static void closeOutput(); ///< Close an output device
static bool isInputReady(); ///< Returns true if the input device is open and suscribed to
static bool isOutputClosed(); ///< Returns true if the output device is open
static void playMono16Sound(const QByteArray& data); ///< Play a 44100Hz mono 16bit PCM sound
static bool tryCaptureSamples(uint8_t* buf, int framesize); ///< Does nothing and return false on failure
/// May be called from any thread, will always queue a call to playGroupAudio
/// The first and last argument are ignored, but allow direct compatibility with toxcore
@ -66,7 +71,6 @@ public slots:
public:
static QThread* audioThread;
static ALCdevice* alOutDev, *alInDev;
static ALCcontext* alContext;
static ALuint alMainSource;
@ -77,6 +81,8 @@ private:
private:
static Audio* instance;
static std::atomic<int> userCount;
static ALCdevice* alOutDev, *alInDev;
static QMutex* audioInLock, *audioOutLock;
};
#endif // AUDIO_H

53
src/audiofilterer.cpp Normal file
View File

@ -0,0 +1,53 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#ifdef QTOX_FILTER_AUDIO
#include "audiofilterer.h"
extern "C"{
#include <filter_audio.h>
}
void AudioFilterer::startFilter(unsigned int fs)
{
closeFilter();
filter = new_filter_audio(fs);
}
void AudioFilterer::closeFilter()
{
if (filter)
kill_filter_audio(filter);
filter = nullptr;
}
void AudioFilterer::filterAudio(int16_t* data, int framesize)
{
if (!filter)
return;
filter_audio(filter, (int16_t*) data, framesize);
}
AudioFilterer::~AudioFilterer()
{
closeFilter();
}
#endif // QTOX_FILTER_AUDIO

41
src/audiofilterer.h Normal file
View File

@ -0,0 +1,41 @@
/*
Copyright (C) 2014 by Project Tox <https://tox.im>
This file is part of qTox, a Qt-based graphical interface for Tox.
This program is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the COPYING file for more details.
*/
#ifdef QTOX_FILTER_AUDIO
#ifndef AUDIOFILTERER_H
#define AUDIOFILTERER_H
#include <cstdint>
#ifndef _FILTER_AUDIO
typedef struct Filter_Audio Filter_Audio;
#endif
class AudioFilterer
{
public:
explicit AudioFilterer() = default;
~AudioFilterer();
void startFilter(unsigned int fs);
void filterAudio(int16_t* data, int framesize);
void closeFilter();
private:
struct Filter_Audio* filter{nullptr};
};
#endif // AUDIOFILTERER_H
#endif // QTOX_FILTER_AUDIO

View File

@ -64,6 +64,7 @@ unsigned char AutoUpdater::key[crypto_sign_PUBLICKEYBYTES];
const QString AutoUpdater::checkURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/version";
const QString AutoUpdater::flistURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/flist";
const QString AutoUpdater::filesURI = AutoUpdater::updateServer+"/qtox/"+AutoUpdater::platform+"/files/";
bool AutoUpdater::abortFlag{false};
bool AutoUpdater::isUpdateAvailable()
{
@ -251,7 +252,11 @@ AutoUpdater::UpdateFile AutoUpdater::getUpdateFile(UpdateFileMeta fileMeta)
QNetworkAccessManager *manager = new QNetworkAccessManager;
QNetworkReply* reply = manager->get(QNetworkRequest(QUrl(filesURI+fileMeta.id)));
while (!reply->isFinished())
{
if (abortFlag)
return file;
qApp->processEvents();
}
if (reply->error() != QNetworkReply::NoError)
{
@ -280,6 +285,9 @@ bool AutoUpdater::downloadUpdate()
QList<UpdateFileMeta> newFlist = parseFlist(newFlistData);
QList<UpdateFileMeta> diff = genUpdateDiff(newFlist);
if (abortFlag)
return false;
qDebug() << "AutoUpdater: Need to update "<<diff.size()<<" files";
// Create an empty directory to download updates into
@ -308,6 +316,9 @@ bool AutoUpdater::downloadUpdate()
// Download and write each new file
for (UpdateFileMeta fileMeta : diff)
{
if (abortFlag)
return false;
qDebug() << "AutoUpdater: Downloading '"+fileMeta.installpath+"' ...";
// Create subdirs if necessary
@ -317,6 +328,8 @@ bool AutoUpdater::downloadUpdate()
// Download
UpdateFile file = getUpdateFile(fileMeta);
if (abortFlag)
return false;
if (file.data.isNull())
{
qWarning() << "AutoUpdater::downloadUpdate: Error downloading a file, aborting...";
@ -357,7 +370,7 @@ bool AutoUpdater::isLocalUpdateReady()
if (!updateDir.exists())
return false;
// Check that we have a flist and that every file on the diff exists
// Check that we have a flist and generate a diff
QFile updateFlistFile(updateDirStr+"flist");
if (!updateFlistFile.open(QIODevice::ReadOnly))
return false;
@ -367,9 +380,23 @@ 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
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;
}
@ -433,3 +460,8 @@ void AutoUpdater::checkUpdatesAsyncInteractiveWorker()
downloadUpdate();
}
}
void AutoUpdater::abortUpdates()
{
abortFlag = true;
}

View File

@ -78,15 +78,18 @@ public:
/// Will try to download an update, if successful returns true and qTox will apply it after a restart
/// Will try to follow qTox's proxy settings, may block and processEvents
static bool downloadUpdate();
/// Returns true if an update is downloaded and ready to be installed
/// If so, call installLocalUpdate. If not, call downloadUpdate.
/// This only checks that we downloaded an update and didn't stop in the middle, not that every file is still valid
/// Returns true if an update is downloaded and ready to be installed,
/// if so, call installLocalUpdate.
/// If an update was partially downloaded, the function will resume asynchronously and return false
static bool isLocalUpdateReady();
/// Launches the qTox updater to try to install the local update and exits immediately
/// Will not check that the update actually exists, use isLocalUpdateReady first for that
/// The qTox updater will restart us after the update is done
/// Note: If we fail to start the qTox updater, we will delete the update and exit
[[ noreturn ]] static void installLocalUpdate();
/// Aborting will make some functions try to return early
/// Call before qTox exits to avoid the updater running in the background
static void abortUpdates();
protected:
/// Parses and validates a flist file. Returns an empty list on error
@ -118,6 +121,7 @@ private:
static const QString filesURI; ///< URI of the actual files of the latest version
static const QString updaterBin; ///< Path to the qtox-updater binary
static unsigned char key[];
static bool abortFlag; ///< If true, try to abort everything.
};
#endif // AUTOUPDATE_H

View File

@ -49,6 +49,8 @@ QList<ToxFile> Core::fileRecvQueue;
QHash<int, ToxGroupCall> Core::groupCalls;
QThread* Core::coreThread{nullptr};
#define MAX_GROUP_MESSAGE_LEN 1024
Core::Core(Camera* cam, QThread *CoreThread, QString loadPath) :
tox(nullptr), camera(cam), loadPath(loadPath), ready{false}
{
@ -121,7 +123,7 @@ void Core::make_tox()
// IPv6 needed for LAN discovery, but can crash some weird routers. On by default, can be disabled in options.
bool enableIPv6 = Settings::getInstance().getEnableIPv6();
bool forceTCP = Settings::getInstance().getForceTCP();
bool useProxy = Settings::getInstance().getUseProxy();
ProxyType proxyType = Settings::getInstance().getProxyType();
if (enableIPv6)
qDebug() << "Core starting with IPv6 enabled";
@ -133,11 +135,11 @@ void Core::make_tox()
toxOptions.udp_disabled = forceTCP;
// No proxy by default
toxOptions.proxy_enabled = false;
toxOptions.proxy_type = TOX_PROXY_NONE;
toxOptions.proxy_address[0] = 0;
toxOptions.proxy_port = 0;
if (useProxy)
if (proxyType != ProxyType::ptNone)
{
QString proxyAddr = Settings::getInstance().getProxyAddr();
int proxyPort = Settings::getInstance().getProxyPort();
@ -149,7 +151,11 @@ void Core::make_tox()
else if (proxyAddr != "" && proxyPort > 0)
{
qDebug() << "Core: using proxy" << proxyAddr << ":" << proxyPort;
toxOptions.proxy_enabled = true;
// protection against changings in TOX_PROXY_TYPE enum
if (proxyType == ProxyType::ptSOCKS5)
toxOptions.proxy_type = TOX_PROXY_SOCKS5;
else if (proxyType == ProxyType::ptHTTP)
toxOptions.proxy_type = TOX_PROXY_HTTP;
uint16_t sz = CString::fromString(proxyAddr, (unsigned char*)toxOptions.proxy_address);
toxOptions.proxy_address[sz] = 0;
toxOptions.proxy_port = proxyPort;
@ -165,7 +171,7 @@ void Core::make_tox()
tox = tox_new(&toxOptions);
if (tox == nullptr)
{
if (toxOptions.proxy_enabled)
if (toxOptions.proxy_type != TOX_PROXY_NONE)
{
//QMessageBox::critical(Widget::getInstance(), tr("Proxy failure", "popup title"),
//tr("toxcore failed to start with your proxy settings. qTox cannot run; please modify your "
@ -183,7 +189,7 @@ void Core::make_tox()
else
qWarning() << "Core failed to start with IPv6, falling back to IPv4. LAN discovery may not work properly.";
}
else if (toxOptions.proxy_enabled)
else if (toxOptions.proxy_type != TOX_PROXY_NONE)
{
emit badProxy();
return;
@ -728,7 +734,7 @@ void Core::requestFriendship(const QString& friendAddress, const QString& messag
{
const QString userId = friendAddress.mid(0, TOX_CLIENT_ID_SIZE * 2);
if(hasFriendWithAddress(friendAddress))
if (hasFriendWithAddress(friendAddress))
{
emit failedToAddFriend(userId, QString(tr("Friend is already added")));
}
@ -779,7 +785,7 @@ void Core::sendTyping(int friendId, bool typing)
void Core::sendGroupMessage(int groupId, const QString& message)
{
QList<CString> cMessages = splitMessage(message);
QList<CString> cMessages = splitMessage(message, MAX_GROUP_MESSAGE_LEN);
for (auto &cMsg :cMessages)
{
@ -792,7 +798,7 @@ void Core::sendGroupMessage(int groupId, const QString& message)
void Core::sendGroupAction(int groupId, const QString& message)
{
QList<CString> cMessages = splitMessage(message);
QList<CString> cMessages = splitMessage(message, MAX_GROUP_MESSAGE_LEN);
for (auto &cMsg :cMessages)
{
@ -1677,7 +1683,7 @@ void Core::createGroup(uint8_t type)
bool Core::hasFriendWithAddress(const QString &addr) const
{
// Valid length check
if(addr.length() != (TOX_FRIEND_ADDRESS_SIZE * 2))
if (addr.length() != (TOX_FRIEND_ADDRESS_SIZE * 2))
{
return false;
}
@ -1689,7 +1695,7 @@ bool Core::hasFriendWithAddress(const QString &addr) const
bool Core::hasFriendWithPublicKey(const QString &pubkey) const
{
// Valid length check
if(pubkey.length() != (TOX_CLIENT_ID_SIZE * 2))
if (pubkey.length() != (TOX_CLIENT_ID_SIZE * 2))
{
return false;
}
@ -1706,7 +1712,7 @@ bool Core::hasFriendWithPublicKey(const QString &pubkey) const
QString addrOrId = getFriendAddress(ids[i]);
// Set true if found
if(addrOrId.toUpper().startsWith(pubkey.toUpper()))
if (addrOrId.toUpper().startsWith(pubkey.toUpper()))
{
found = true;
break;
@ -1741,17 +1747,17 @@ QString Core::getFriendUsername(int friendnumber) const
return CString::toString(name, tox_get_name_size(tox, friendnumber));
}
QList<CString> Core::splitMessage(const QString &message)
QList<CString> Core::splitMessage(const QString &message, int maxLen)
{
QList<CString> splittedMsgs;
QByteArray ba_message(message.toUtf8());
while (ba_message.size() > TOX_MAX_MESSAGE_LENGTH)
while (ba_message.size() > maxLen)
{
int splitPos = ba_message.lastIndexOf(' ', TOX_MAX_MESSAGE_LENGTH - 1);
int splitPos = ba_message.lastIndexOf(' ', maxLen - 1);
if (splitPos <= 0)
{
splitPos = TOX_MAX_MESSAGE_LENGTH;
splitPos = maxLen;
if (ba_message[splitPos] & 0x80)
{
do {

View File

@ -33,6 +33,9 @@ class QTimer;
class QString;
class CString;
class VideoSource;
#ifdef QTOX_FILTER_AUDIO
class AudioFilterer;
#endif
class Core : public QObject
{
@ -47,7 +50,7 @@ public:
static const QString TOX_EXT;
static const QString CONFIG_FILE_NAME;
static QString sanitize(QString name);
static QList<CString> splitMessage(const QString &message);
static QList<CString> splitMessage(const QString &message, int maxLen);
QString getPeerName(const ToxID& id) const;
@ -283,6 +286,9 @@ private:
int dhtServerId;
static QList<ToxFile> fileSendQueue, fileRecvQueue;
static ToxCall calls[TOXAV_MAX_CALLS];
#ifdef QTOX_FILTER_AUDIO
static AudioFilterer * filterer[TOXAV_MAX_CALLS];
#endif
static QHash<int, ToxGroupCall> groupCalls; // Maps group IDs to ToxGroupCalls
QMutex fileSendMutex, messageSendMutex;
bool ready;

View File

@ -17,10 +17,17 @@
#include "core.h"
#include "video/camera.h"
#include "audio.h"
#ifdef QTOX_FILTER_AUDIO
#include "audiofilterer.h"
#endif
#include "misc/settings.h"
#include <QDebug>
#include <QTimer>
ToxCall Core::calls[TOXAV_MAX_CALLS];
#ifdef QTOX_FILTER_AUDIO
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;
@ -65,6 +72,19 @@ void Core::prepareCall(int friendId, int callId, ToxAv* toxav, bool videoEnabled
calls[callId].sendVideoTimer->start();
Camera::getInstance()->subscribe();
}
#ifdef QTOX_FILTER_AUDIO
if (Settings::getInstance().getFilterAudio())
{
Core::filterer[callId] = new AudioFilterer();
filterer[callId]->startFilter(48000);
}
else
{
delete filterer[callId];
filterer[callId] = nullptr;
}
#endif
}
void Core::onAvMediaChange(void* toxav, int32_t callId, void* core)
@ -194,6 +214,7 @@ void Core::cleanupCall(int callId)
if (calls[callId].videoEnabled)
Camera::getInstance()->unsubscribe();
Audio::unsuscribeInput();
toxav_kill_transmission(Core::getInstance()->toxav, callId);
}
void Core::playCallAudio(void* toxav, int32_t callId, const int16_t *data, uint16_t samples, void *user_data)
@ -207,7 +228,7 @@ void Core::playCallAudio(void* toxav, int32_t callId, const int16_t *data, uint1
alGenSources(1, &calls[callId].alSource);
ToxAvCSettings dest;
if(toxav_get_peer_csettings((ToxAv*)toxav, callId, 0, &dest) == 0)
if (toxav_get_peer_csettings((ToxAv*)toxav, callId, 0, &dest) == 0)
playAudioBuffer(calls[callId].alSource, data, samples, dest.audio_channels, dest.audio_sample_rate);
}
@ -216,7 +237,7 @@ void Core::sendCallAudio(int callId, ToxAv* toxav)
if (!calls[callId].active)
return;
if (calls[callId].muteMic || !Audio::alInDev)
if (calls[callId].muteMic || !Audio::isInputReady())
{
calls[callId].sendAudioTimer->start();
return;
@ -226,28 +247,25 @@ void Core::sendCallAudio(int callId, ToxAv* toxav)
const int bufsize = framesize * 2 * av_DefaultSettings.audio_channels;
uint8_t buf[bufsize], dest[bufsize];
bool frame = false;
ALint samples;
alcGetIntegerv(Audio::alInDev, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
if(samples >= framesize)
{
memset(buf, 0, bufsize); // Avoid uninitialized values (Valgrind)
alcCaptureSamples(Audio::alInDev, buf, framesize);
frame = 1;
}
if(frame)
if (Audio::tryCaptureSamples(buf, framesize))
{
int r;
if((r = toxav_prepare_audio_frame(toxav, callId, dest, framesize*2, (int16_t*)buf, framesize)) < 0)
if ((r = toxav_prepare_audio_frame(toxav, callId, dest, framesize*2, (int16_t*)buf, framesize)) < 0)
{
qDebug() << "Core: toxav_prepare_audio_frame error";
calls[callId].sendAudioTimer->start();
return;
}
if((r = toxav_send_audio(toxav, callId, dest, r)) < 0)
#ifdef QTOX_FILTER_AUDIO
if (filterer[callId])
filterer[callId]->filterAudio((int16_t*) buf, framesize);
#endif
if ((r = toxav_send_audio(toxav, callId, dest, r)) < 0)
{
qDebug() << "Core: toxav_send_audio error";
}
}
calls[callId].sendAudioTimer->start();
}
@ -271,7 +289,7 @@ void Core::sendCallVideo(int callId)
if (frame.w && frame.h)
{
int result;
if((result = toxav_prepare_video_frame(toxav, callId, videobuf, videobufsize, &frame)) < 0)
if ((result = toxav_prepare_video_frame(toxav, callId, videobuf, videobufsize, &frame)) < 0)
{
qDebug() << QString("Core: toxav_prepare_video_frame: error %1").arg(result);
vpx_img_free(&frame);
@ -279,7 +297,7 @@ void Core::sendCallVideo(int callId)
return;
}
if((result = toxav_send_video(toxav, callId, (uint8_t*)videobuf, result)) < 0)
if ((result = toxav_send_video(toxav, callId, (uint8_t*)videobuf, result)) < 0)
qDebug() << QString("Core: toxav_send_video error: %1").arg(result);
vpx_img_free(&frame);
@ -294,14 +312,16 @@ void Core::sendCallVideo(int callId)
void Core::micMuteToggle(int callId)
{
if (calls[callId].active) {
if (calls[callId].active)
{
calls[callId].muteMic = !calls[callId].muteMic;
}
}
void Core::volMuteToggle(int callId)
{
if (calls[callId].active) {
if (calls[callId].active)
{
calls[callId].muteVol = !calls[callId].muteVol;
alSourcef(calls[callId].alSource, AL_GAIN, calls[callId].muteVol ? 0.f : 1.f);
}
@ -321,6 +341,15 @@ void Core::onAvCancel(void* _toxav, int32_t callId, void* core)
calls[callId].active = false;
#ifdef QTOX_FILTER_AUDIO
if (filterer[callId])
{
filterer[callId]->closeFilter();
delete filterer[callId];
filterer[callId] = nullptr;
}
#endif
emit static_cast<Core*>(core)->avCancel(friendId, callId);
}
@ -379,59 +408,6 @@ void Core::onAvRinging(void* _toxav, int32_t call_index, void* core)
}
}
//void Core::onAvStarting(void* _toxav, int32_t call_index, void* core)
//{
// ToxAv* toxav = static_cast<ToxAv*>(_toxav);
// int friendId = toxav_get_peer_id(toxav, call_index, 0);
// if (friendId < 0)
// {
// qWarning() << "Core: Received invalid AV starting";
// return;
// }
// ToxAvCSettings* transSettings = new ToxAvCSettings;
// int err = toxav_get_peer_csettings(toxav, call_index, 0, transSettings);
// if (err != ErrorNone)
// {
// qWarning() << "Core::onAvStarting: error getting call type";
// delete transSettings;
// return;
// }
// if (transSettings->call_type == TypeVideo)
// {
// qDebug() << QString("Core: AV starting from %1 with video").arg(friendId);
// prepareCall(friendId, call_index, toxav, true);
// emit static_cast<Core*>(core)->avStarting(friendId, call_index, true);
// }
// else
// {
// qDebug() << QString("Core: AV starting from %1 without video").arg(friendId);
// prepareCall(friendId, call_index, toxav, false);
// emit static_cast<Core*>(core)->avStarting(friendId, call_index, false);
// }
// delete transSettings;
//}
//void Core::onAvEnding(void* _toxav, int32_t call_index, void* core)
//{
// ToxAv* toxav = static_cast<ToxAv*>(_toxav);
// int friendId = toxav_get_peer_id(toxav, call_index, 0);
// if (friendId < 0)
// {
// qWarning() << "Core: Received invalid AV ending";
// return;
// }
// qDebug() << QString("Core: AV ending from %1").arg(friendId);
// cleanupCall(call_index);
// emit static_cast<Core*>(core)->avEnding(friendId, call_index);
//}
void Core::onAvRequestTimeout(void* _toxav, int32_t call_index, void* core)
{
ToxAv* toxav = static_cast<ToxAv*>(_toxav);
@ -540,7 +516,7 @@ void Core::onAvStart(void* _toxav, int32_t call_index, void* core)
// This function's logic was shamelessly stolen from uTox
void Core::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, unsigned channels, int sampleRate)
{
if(!channels || channels > 2)
if (!channels || channels > 2)
{
qWarning() << "Core::playAudioBuffer: trying to play on "<<channels<<" channels! Giving up.";
return;
@ -552,14 +528,14 @@ void Core::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, un
alGetSourcei(alSource, AL_BUFFERS_QUEUED, &queued);
alSourcei(alSource, AL_LOOPING, AL_FALSE);
if(processed)
if (processed)
{
ALuint bufids[processed];
alSourceUnqueueBuffers(alSource, processed, bufids);
alDeleteBuffers(processed - 1, bufids + 1);
bufid = bufids[0];
}
else if(queued < 32)
else if (queued < 32)
{
alGenBuffers(1, &bufid);
}
@ -575,7 +551,7 @@ void Core::playAudioBuffer(ALuint alSource, const int16_t *data, int samples, un
ALint state;
alGetSourcei(alSource, AL_SOURCE_STATE, &state);
if(state != AL_PLAYING)
if (state != AL_PLAYING)
{
alSourcePlay(alSource);
//qDebug() << "Core: Starting audio source " << (int)alSource;
@ -630,7 +606,7 @@ void Core::sendGroupCallAudio(int groupId, ToxAv* toxav)
if (!groupCalls[groupId].active)
return;
if (groupCalls[groupId].muteMic || !Audio::alInDev)
if (groupCalls[groupId].muteMic || !Audio::isInputReady())
{
groupCalls[groupId].sendAudioTimer->start();
return;
@ -640,20 +616,10 @@ void Core::sendGroupCallAudio(int groupId, ToxAv* toxav)
const int bufsize = framesize * 2 * av_DefaultSettings.audio_channels;
uint8_t buf[bufsize];
bool frame = false;
ALint samples;
alcGetIntegerv(Audio::alInDev, ALC_CAPTURE_SAMPLES, sizeof(samples), &samples);
if(samples >= framesize)
{
memset(buf, 0, bufsize); // Avoid uninitialized values (Valgrind)
alcCaptureSamples(Audio::alInDev, buf, framesize);
frame = 1;
}
if(frame)
if (Audio::tryCaptureSamples(buf, framesize))
{
int r;
if((r = toxav_group_send_audio(toxav_get_tox(toxav), groupId, (int16_t*)buf,
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)
{
qDebug() << "Core: toxav_group_send_audio error";

View File

@ -145,7 +145,9 @@ GroupWidget *Group::getGroupWidget()
QStringList Group::getPeerList() const
{
return peers.values();
QStringList peerNames(peers.values());
peerNames.sort(Qt::CaseInsensitive);
return peerNames;
}
void Group::setEventFlag(int f)

View File

@ -70,7 +70,7 @@ int main(int argc, char *argv[])
parser.process(a);
Settings::getInstance(); // Build our Settings singleton as soon as QApplication is ready, not before
if(parser.isSet("P"))
if (parser.isSet("P"))
Settings::getInstance().setCurrentProfile(parser.value("P"));
sodium_init(); // For the auto-updater
@ -156,7 +156,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);

View File

@ -1034,7 +1034,7 @@ QSplitter:handle{
<x>0</x>
<y>0</y>
<width>284</width>
<height>401</height>
<height>399</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5"/>
@ -1665,7 +1665,7 @@ QSplitter:handle{
<property name="minimumSize">
<size>
<width>0</width>
<height>57</height>
<height>0</height>
</size>
</property>
<property name="maximumSize">
@ -1775,7 +1775,7 @@ QSplitter:handle{
<x>0</x>
<y>0</y>
<width>775</width>
<height>19</height>
<height>21</height>
</rect>
</property>
</widget>

View File

@ -130,7 +130,7 @@ void Settings::load()
autostartInTray = s.value("autostartInTray", false).toBool();
closeToTray = s.value("closeToTray", false).toBool();
forceTCP = s.value("forceTCP", false).toBool();
useProxy = s.value("useProxy", false).toBool();
setProxyType(s.value("proxyType", static_cast<int>(ProxyType::ptNone)).toInt());
proxyAddr = s.value("proxyAddr", "").toString();
proxyPort = s.value("proxyPort", 0).toInt();
currentProfile = s.value("currentProfile", "").toString();
@ -168,6 +168,7 @@ void Settings::load()
timestampFormat = s.value("timestampFormat", "hh:mm").toString();
minimizeOnClose = s.value("minimizeOnClose", false).toBool();
minimizeToTray = s.value("minimizeToTray", false).toBool();
lightTrayIcon = s.value("lightTrayIcon", false).toBool();
useNativeStyle = s.value("nativeStyle", false).toBool();
useEmoticons = s.value("useEmoticons", true).toBool();
statusChangeNotificationEnabled = s.value("statusChangeNotificationEnabled", false).toBool();
@ -189,7 +190,7 @@ void Settings::load()
s.endGroup();
s.beginGroup("Privacy");
typingNotification = s.value("typingNotification", false).toBool();
typingNotification = s.value("typingNotification", true).toBool();
enableLogging = s.value("enableLogging", false).toBool();
encryptLogs = s.value("encryptLogs", false).toBool();
encryptTox = s.value("encryptTox", false).toBool();
@ -198,6 +199,7 @@ void Settings::load()
s.beginGroup("Audio");
inDev = s.value("inDev", "").toString();
outDev = s.value("outDev", "").toString();
filterAudio = s.value("filterAudio", false).toBool();
s.endGroup();
// Read the embedded DHT bootsrap nodes list if needed
@ -281,7 +283,7 @@ void Settings::save(QString path, bool writeFriends)
s.setValue("showSystemTray", showSystemTray);
s.setValue("autostartInTray",autostartInTray);
s.setValue("closeToTray", closeToTray);
s.setValue("useProxy", useProxy);
s.setValue("proxyType", static_cast<int>(proxyType));
s.setValue("forceTCP", forceTCP);
s.setValue("proxyAddr", proxyAddr);
s.setValue("proxyPort", proxyPort);
@ -317,6 +319,7 @@ void Settings::save(QString path, bool writeFriends)
s.setValue("timestampFormat", timestampFormat);
s.setValue("minimizeOnClose", minimizeOnClose);
s.setValue("minimizeToTray", minimizeToTray);
s.setValue("lightTrayIcon", lightTrayIcon);
s.setValue("nativeStyle", useNativeStyle);
s.setValue("useEmoticons", useEmoticons);
s.setValue("themeColor", themeColor);
@ -340,6 +343,7 @@ void Settings::save(QString path, bool writeFriends)
s.beginGroup("Audio");
s.setValue("inDev", inDev);
s.setValue("outDev", outDev);
s.setValue("filterAudio", filterAudio);
s.endGroup();
if (!writeFriends || currentProfile.isEmpty()) // Core::switchConfiguration
@ -532,6 +536,16 @@ void Settings::setMinimizeToTray(bool newValue)
minimizeToTray = newValue;
}
bool Settings::getLightTrayIcon() const
{
return lightTrayIcon;
}
void Settings::setLightTrayIcon(bool newValue)
{
lightTrayIcon = newValue;
}
bool Settings::getStatusChangeNotificationEnabled() const
{
return statusChangeNotificationEnabled;
@ -572,13 +586,17 @@ void Settings::setForceTCP(bool newValue)
forceTCP = newValue;
}
bool Settings::getUseProxy() const
ProxyType Settings::getProxyType() const
{
return useProxy;
return proxyType;
}
void Settings::setUseProxy(bool newValue)
void Settings::setProxyType(int newValue)
{
useProxy = newValue;
if (newValue >= 0 && newValue <= 2)
proxyType = static_cast<ProxyType>(newValue);
else
proxyType = ProxyType::ptNone;
}
QString Settings::getProxyAddr() const
@ -888,6 +906,16 @@ void Settings::setOutDev(const QString& deviceSpecifier)
outDev = deviceSpecifier;
}
bool Settings::getFilterAudio() const
{
return filterAudio;
}
void Settings::setFilterAudio(bool newValue)
{
filterAudio = newValue;
}
QString Settings::getFriendAdress(const QString &publicKey) const
{
QString key = ToxID::fromString(publicKey).publicKey;

View File

@ -24,6 +24,8 @@
struct ToxID;
namespace Db { enum class syncType; }
enum ProxyType {ptNone, ptSOCKS5, ptHTTP};
class Settings : public QObject
{
Q_OBJECT
@ -61,6 +63,9 @@ public:
bool getMinimizeToTray() const;
void setMinimizeToTray(bool newValue);
bool getLightTrayIcon() const;
void setLightTrayIcon(bool newValue);
QString getStyle() const;
void setStyle(const QString& newValue);
@ -86,8 +91,8 @@ public:
QString getProxyAddr() const;
void setProxyAddr(const QString& newValue);
bool getUseProxy() const;
void setUseProxy(bool newValue);
ProxyType getProxyType() const;
void setProxyType(int newValue);
int getProxyPort() const;
void setProxyPort(int newValue);
@ -125,6 +130,9 @@ public:
QString getOutDev() const;
void setOutDev(const QString& deviceSpecifier);
bool getFilterAudio() const;
void setFilterAudio(bool 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,
@ -248,13 +256,14 @@ private:
bool autostartInTray;
bool closeToTray;
bool minimizeToTray;
bool lightTrayIcon;
bool useEmoticons;
bool checkUpdates;
bool showInFront;
bool forceTCP;
bool useProxy;
ProxyType proxyType;
QString proxyAddr;
int proxyPort;
@ -298,6 +307,7 @@ private:
// Audio
QString inDev;
QString outDev;
bool filterAudio;
struct friendProp
{

View File

@ -69,9 +69,9 @@ QList<QPair<QString, QString> > SmileyPack::listSmileyPacks(const QStringList &p
if (relPath.leftRef(2) == "..")
{
if(!smileyPacks.contains(QPair<QString, QString>(packageName, absPath)))
if (!smileyPacks.contains(QPair<QString, QString>(packageName, absPath)))
smileyPacks << QPair<QString, QString>(packageName, absPath);
else if(!smileyPacks.contains(QPair<QString, QString>(packageName, relPath)))
else if (!smileyPacks.contains(QPair<QString, QString>(packageName, relPath)))
smileyPacks << QPair<QString, QString>(packageName, relPath); // use relative path for subdirectories
}
}
@ -97,7 +97,7 @@ bool SmileyPack::load(const QString& filename)
// open emoticons.xml
QFile xmlFile(filename);
if(!xmlFile.open(QIODevice::ReadOnly))
if (!xmlFile.open(QIODevice::ReadOnly))
return false; // cannot open file
/* parse the cfg file
@ -138,14 +138,14 @@ bool SmileyPack::load(const QString& filename)
QPixmap pm;
pm.loadFromData(getCachedSmiley(emoticon), "PNG");
if(pm.size().width() > 0)
if (pm.size().width() > 0)
emoticonSet.push_back(emoticon);
stringElement = stringElement.nextSibling().toElement();
}
if(emoticonSet.size() > 0)
if (emoticonSet.size() > 0)
emoticons.push_back(emoticonSet);
}

View File

@ -24,7 +24,7 @@ uint32_t Platform::getIdleTime()
{
LASTINPUTINFO info = { 0 };
info.cbSize = sizeof(info);
if(GetLastInputInfo(&info))
if (GetLastInputInfo(&info))
return GetTickCount() - info.dwTime;
return 0;
}

View File

@ -25,7 +25,7 @@ uint32_t Platform::getIdleTime()
uint32_t idleTime = 0;
Display *display = XOpenDisplay(NULL);
if(!display)
if (!display)
{
qDebug() << "XOpenDisplay(NULL) failed";
return 0;
@ -33,10 +33,10 @@ uint32_t Platform::getIdleTime()
int32_t x11event = 0, x11error = 0;
static int32_t hasExtension = XScreenSaverQueryExtension(display, &x11event, &x11error);
if(hasExtension)
if (hasExtension)
{
XScreenSaverInfo *info = XScreenSaverAllocInfo();
if(info)
if (info)
{
XScreenSaverQueryInfo(display, DefaultRootWindow(display), info);
idleTime = info->idle;

View File

@ -219,6 +219,11 @@ fallbackOnTox1:
tox_dns3_kill(tox_dns3);
#if TOX1_SILENT_FALLBACK
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)
queryTox1(record, silent);
#endif
return toxIdStr;
}
@ -258,6 +263,11 @@ ToxID ToxDNS::resolveToxAddress(const QString &address, bool silent)
{
#if TOX1_SILENT_FALLBACK
toxId = ToxID::fromString(queryTox1(address, 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)
toxId = ToxID::fromString(queryTox1(address, silent));
#else
return toxId;
#endif

View File

@ -25,6 +25,9 @@
/// Tox1 is not encrypted, it's unsafe
#define TOX1_SILENT_FALLBACK 0
/// That said if the user insists ...
#define TOX1_ASK_FALLBACK 1
/// Handles tox1 and tox3 DNS queries
class ToxDNS : public QObject
{

View File

@ -129,7 +129,7 @@ void CameraWorker::applyProps()
if (!cam.isOpened())
return;
for(int prop : props.keys())
for (int prop : props.keys())
cam.set(prop, props.value(prop));
}
@ -148,7 +148,7 @@ void CameraWorker::subscribe()
void CameraWorker::unsubscribe()
{
if(--refCount <= 0)
if (--refCount <= 0)
{
cam.release();
refCount = 0;

View File

@ -65,7 +65,7 @@ void ChatAreaWidget::mouseReleaseEvent(QMouseEvent * event)
QTextCursor cursor(document());
cursor.setPosition(pos);
if(!cursor.atEnd())
if (!cursor.atEnd())
{
cursor.setPosition(pos+1);

View File

@ -95,7 +95,7 @@ void AddFriendForm::onSendTriggered()
this->toxId.clear();
this->message.clear();
} else {
if (Settings::getInstance().getUseProxy())
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);

View File

@ -54,6 +54,15 @@ ChatForm::ChatForm(Friend* chatFriend)
statusMessageLabel->setFont(Style::getFont(Style::Medium));
statusMessageLabel->setMinimumHeight(Style::getFont(Style::Medium).pixelSize());
isTypingLabel = new QLabel();
QFont font = isTypingLabel->font();
font.setItalic(true);
font.setPixelSize(8);
isTypingLabel->setFont(font);
QVBoxLayout* mainLayout = dynamic_cast<QVBoxLayout*>(layout());
mainLayout->insertWidget(1, isTypingLabel);
netcam = new NetCamView();
timer = nullptr;
@ -71,6 +80,7 @@ ChatForm::ChatForm(Friend* chatFriend)
connect(callButton, &QPushButton::clicked, this, &ChatForm::onCallTriggered);
connect(videoButton, &QPushButton::clicked, this, &ChatForm::onVideoCallTriggered);
connect(msgEdit, &ChatTextEdit::enterPressed, this, &ChatForm::onSendTriggered);
connect(msgEdit, &ChatTextEdit::textChanged, this, &ChatForm::onTextEditChanged);
connect(micButton, SIGNAL(clicked()), this, SLOT(onMicMuteToggle()));
connect(volButton, SIGNAL(clicked()), this, SLOT(onVolMuteToggle()));
connect(chatWidget, &ChatAreaWidget::onFileTranfertInterract, this, &ChatForm::onFileTansBtnClicked);
@ -103,7 +113,7 @@ void ChatForm::onSendTriggered()
if (isAction)
msg = msg = msg.right(msg.length() - 4);
QList<CString> splittedMsg = Core::splitMessage(msg);
QList<CString> splittedMsg = Core::splitMessage(msg, TOX_MAX_MESSAGE_LENGTH);
QDateTime timestamp = QDateTime::currentDateTime();
for (CString& c_msg : splittedMsg)
@ -132,6 +142,21 @@ void ChatForm::onSendTriggered()
msgEdit->clear();
}
void ChatForm::onTextEditChanged()
{
bool isNowTyping;
if (!Settings::getInstance().isTypingNotificationEnabled())
isNowTyping = false;
else
isNowTyping = msgEdit->toPlainText().length() > 0;
if (isTyping != isNowTyping)
{
isTyping = isNowTyping;
Core::getInstance()->sendTyping(f->getFriendID(), isTyping);
}
}
void ChatForm::onAttachClicked()
{
QStringList paths = QFileDialog::getOpenFileNames(0,tr("Send a file"));
@ -230,10 +255,11 @@ void ChatForm::onFileRecvRequest(ToxFile file)
void ChatForm::onAvInvite(int FriendId, int CallId, bool video)
{
qDebug() << "onAvInvite";
if (FriendId != f->getFriendID())
return;
qDebug() << "onAvInvite";
callId = CallId;
callButton->disconnect();
videoButton->disconnect();
@ -267,10 +293,11 @@ void ChatForm::onAvInvite(int FriendId, int CallId, bool video)
void ChatForm::onAvStart(int FriendId, int CallId, bool video)
{
qDebug() << "onAvStart";
if (FriendId != f->getFriendID())
return;
qDebug() << "onAvStart";
audioInputFlag = true;
audioOutputFlag = true;
callId = CallId;
@ -301,11 +328,12 @@ void ChatForm::onAvStart(int FriendId, int CallId, bool video)
void ChatForm::onAvCancel(int FriendId, int)
{
qDebug() << "onAvCancel";
if (FriendId != f->getFriendID())
return;
qDebug() << "onAvCancel";
stopCounter();
audioInputFlag = false;
@ -330,11 +358,11 @@ void ChatForm::onAvCancel(int FriendId, int)
void ChatForm::onAvEnd(int FriendId, int)
{
qDebug() << "onAvEnd";
if (FriendId != f->getFriendID())
return;
qDebug() << "onAvEnd";
audioInputFlag = false;
audioOutputFlag = false;
micButton->setObjectName("green");
@ -357,10 +385,11 @@ void ChatForm::onAvEnd(int FriendId, int)
void ChatForm::onAvRinging(int FriendId, int CallId, bool video)
{
qDebug() << "onAvRinging";
if (FriendId != f->getFriendID())
return;
qDebug() << "onAvRinging";
callId = CallId;
callButton->disconnect();
videoButton->disconnect();
@ -386,11 +415,11 @@ void ChatForm::onAvRinging(int FriendId, int CallId, bool video)
void ChatForm::onAvStarting(int FriendId, int CallId, bool video)
{
qDebug() << "onAvStarting";
if (FriendId != f->getFriendID())
return;
qDebug() << "onAvStarting";
callButton->disconnect();
videoButton->disconnect();
if (video)
@ -417,11 +446,11 @@ void ChatForm::onAvStarting(int FriendId, int CallId, bool video)
void ChatForm::onAvEnding(int FriendId, int)
{
qDebug() << "onAvEnding";
if (FriendId != f->getFriendID())
return;
qDebug() << "onAvEnding";
audioInputFlag = false;
audioOutputFlag = false;
micButton->setObjectName("green");
@ -446,11 +475,11 @@ void ChatForm::onAvEnding(int FriendId, int)
void ChatForm::onAvRequestTimeout(int FriendId, int)
{
qDebug() << "onAvRequestTimeout";
if (FriendId != f->getFriendID())
return;
qDebug() << "onAvRequestTimeout";
audioInputFlag = false;
audioOutputFlag = false;
micButton->setObjectName("green");
@ -473,11 +502,11 @@ void ChatForm::onAvRequestTimeout(int FriendId, int)
void ChatForm::onAvPeerTimeout(int FriendId, int)
{
qDebug() << "onAvPeerTimeout";
if (FriendId != f->getFriendID())
return;
qDebug() << "onAvPeerTimeout";
audioInputFlag = false;
audioOutputFlag = false;
micButton->setObjectName("green");
@ -500,11 +529,11 @@ void ChatForm::onAvPeerTimeout(int FriendId, int)
void ChatForm::onAvRejected(int FriendId, int)
{
qDebug() << "onAvRejected";
if (FriendId != f->getFriendID())
return;
qDebug() << "onAvRejected";
audioInputFlag = false;
audioOutputFlag = false;
micButton->setObjectName("green");
@ -529,11 +558,11 @@ void ChatForm::onAvRejected(int FriendId, int)
void ChatForm::onAvMediaChange(int FriendId, int CallId, bool video)
{
qDebug() << "onAvMediaChange";
if (FriendId != f->getFriendID() || CallId != callId)
return;
qDebug() << "onAvMediaChange";
if (video)
{
netcam->show(Core::getInstance()->getVideoSourceFromCall(CallId), f->getDisplayedName());
@ -554,7 +583,7 @@ void ChatForm::onAnswerCallTriggered()
}
void ChatForm::onHangupCallTriggered()
{
{
qDebug() << "onHangupCallTriggered";
audioInputFlag = false;
@ -590,11 +619,11 @@ void ChatForm::onVideoCallTriggered()
void ChatForm::onAvCallFailed(int FriendId)
{
qDebug() << "onAvCallFailed";
if (FriendId != f->getFriendID())
return;
qDebug() << "onAvCallFailed";
audioInputFlag = false;
audioOutputFlag = false;
callButton->disconnect();
@ -793,7 +822,7 @@ void ChatForm::onLoadHistory()
void ChatForm::startCounter()
{
if(!timer)
if (!timer)
{
timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(updateTime()));
@ -805,7 +834,7 @@ void ChatForm::startCounter()
void ChatForm::stopCounter()
{
if(timer)
if (timer)
{
addSystemInfoMessage(tr("Call with %1 ended. %2").arg(f->getDisplayedName(),
secondsToDHMS(timeElapsed.elapsed()/1000)),
@ -834,10 +863,10 @@ QString ChatForm::secondsToDHMS(quint32 duration)
int hours = (int) (duration % 24);
int days = (int) (duration / 24);
if(minutes == 0)
if (minutes == 0)
return cD + res.sprintf("%02ds", seconds);
if(hours == 0 && days == 0)
if (hours == 0 && days == 0)
return cD + res.sprintf("%02dm %02ds", minutes, seconds);
if (days == 0)
@ -870,6 +899,14 @@ void ChatForm::dischargeReceipt(int receipt)
}
}
void ChatForm::setFriendTyping(bool isTyping)
{
if (isTyping)
isTypingLabel->setText(f->getDisplayedName() + " " + tr("is typing..."));
else
isTypingLabel->clear();
}
void ChatForm::clearReciepts()
{
receipts.clear();

View File

@ -39,6 +39,7 @@ public:
void loadHistory(QDateTime since, bool processUndelivered = false);
void dischargeReceipt(int receipt);
void setFriendTyping(bool isTyping);
signals:
void sendFile(int32_t friendId, QString, QString, long long);
@ -75,6 +76,7 @@ public slots:
private slots:
void onSendTriggered();
void onTextEditChanged();
void onAttachClicked();
void onCallTriggered();
void onVideoCallTriggered();
@ -100,6 +102,7 @@ private:
QLabel *callDuration;
QTimer *timer;
QElapsedTimer timeElapsed;
QLabel *isTypingLabel;
QHash<uint, FileTransferInstance*> ftransWidgets;
void startCounter();
@ -107,6 +110,7 @@ private:
QString secondsToDHMS(quint32 duration);
QHash<int, int> receipts;
QMap<int, MessageActionPtr> undeliveredMsgs;
bool isTyping;
};
#endif // CHATFORM_H

View File

@ -52,10 +52,13 @@ GenericChatForm::GenericChatForm(QWidget *parent) :
nameLabel->setEditable(true);
avatar = new MaskablePixmapWidget(this, QSize(40,40), ":/img/avatar_mask.png");
QHBoxLayout *headLayout = new QHBoxLayout(), *mainFootLayout = new QHBoxLayout();
headTextLayout = new QVBoxLayout();
QVBoxLayout *mainLayout = new QVBoxLayout();
QVBoxLayout *footButtonsSmall = new QVBoxLayout(), *volMicLayout = new QVBoxLayout();
QHBoxLayout *headLayout = new QHBoxLayout(),
*mainFootLayout = new QHBoxLayout();
QVBoxLayout *mainLayout = new QVBoxLayout(),
*footButtonsSmall = new QVBoxLayout(),
*volMicLayout = new QVBoxLayout();
headTextLayout = new QVBoxLayout();
chatWidget = new ChatAreaWidget();
@ -76,10 +79,10 @@ GenericChatForm::GenericChatForm(QWidget *parent) :
videoButton->setFixedSize(50,40);
videoButton->setToolTip(tr("Video call: RED means you're on a call"));
volButton = new QPushButton();
volButton->setFixedSize(25,20);
//volButton->setFixedSize(25,20);
volButton->setToolTip(tr("Toggle speakers volume: RED is OFF"));
micButton = new QPushButton();
micButton->setFixedSize(25,20);
// micButton->setFixedSize(25,20);
micButton->setToolTip(tr("Toggle microphone: RED is OFF"));
footButtonsSmall->setSpacing(2);
@ -119,6 +122,13 @@ GenericChatForm::GenericChatForm(QWidget *parent) :
mainFootLayout->addSpacing(5);
mainFootLayout->addWidget(sendButton);
mainFootLayout->setSpacing(0);
headTextLayout->addStretch();
headTextLayout->addWidget(nameLabel);
volMicLayout->addWidget(micButton, Qt::AlignTop);
volMicLayout->addSpacing(2);
volMicLayout->addWidget(volButton, Qt::AlignBottom);
headWidget->setLayout(headLayout);
headLayout->addWidget(avatar);
@ -130,16 +140,6 @@ GenericChatForm::GenericChatForm(QWidget *parent) :
headLayout->addWidget(videoButton);
headLayout->setSpacing(0);
volMicLayout->addStretch();
volMicLayout->addSpacing(1);
volMicLayout->addWidget(micButton);
volMicLayout->addSpacing(2);
volMicLayout->addWidget(volButton);
volMicLayout->addStretch();
headTextLayout->addStretch();
headTextLayout->addWidget(nameLabel);
//Fix for incorrect layouts on OS X as per
//https://bugreports.qt-project.org/browse/QTBUG-14591
sendButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
@ -255,7 +255,8 @@ void GenericChatForm::onEmoteButtonClicked()
void GenericChatForm::onChatWidgetClicked()
{
msgEdit->setFocus();
if (!chatWidget->textCursor().hasSelection())
msgEdit->setFocus();
}
void GenericChatForm::onEmoteInsertRequested(QString str)

View File

@ -32,5 +32,11 @@ LoadHistoryDialog::~LoadHistoryDialog()
QDateTime LoadHistoryDialog::getFromDate()
{
QDateTime res(ui->fromDate->selectedDate());
if (res.date().month() != ui->fromDate->monthShown() || res.date().year() != ui->fromDate->yearShown())
{
QDate newDate(ui->fromDate->yearShown(), ui->fromDate->monthShown(), 1);
res.setDate(newDate);
}
return res;
}

View File

@ -33,12 +33,19 @@ AVForm::AVForm() :
bodyUI = new Ui::AVSettings;
bodyUI->setupUi(this);
#ifdef QTOX_FILTER_AUDIO
bodyUI->filterAudio->setChecked(Settings::getInstance().getFilterAudio());
#else
bodyUI->filterAudio->setDisabled(true);
#endif
connect(Camera::getInstance(), &Camera::propProbingFinished, this, &AVForm::onPropProbingFinished);
connect(Camera::getInstance(), &Camera::resolutionProbingFinished, this, &AVForm::onResProbingFinished);
auto qcomboboxIndexChanged = (void(QComboBox::*)(const QString&)) &QComboBox::currentIndexChanged;
connect(bodyUI->inDevCombobox, qcomboboxIndexChanged, this, &AVForm::onInDevChanged);
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();});
}
@ -189,3 +196,8 @@ void AVForm::onOutDevChanged(const QString& deviceDescriptor)
Settings::getInstance().setOutDev(deviceDescriptor);
Audio::openOutput(deviceDescriptor);
}
void AVForm::onFilterAudioToggled(bool filterAudio)
{
Settings::getInstance().setFilterAudio(filterAudio);
}

View File

@ -52,6 +52,7 @@ private slots:
// audio
void onInDevChanged(const QString& deviceDescriptor);
void onOutDevChanged(const QString& deviceDescriptor);
void onFilterAudioToggled(bool filterAudio);
// camera
void onPropProbingFinished(Camera::Prop prop, double val);

View File

@ -30,8 +30,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>810</width>
<height>496</height>
<width>808</width>
<height>618</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
@ -96,6 +96,13 @@
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="filterAudio">
<property name="text">
<string>Filter audio</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -30,8 +30,8 @@
#include "src/autoupdate.h"
static QStringList locales = {"bg", "de", "en", "es", "fr", "it", "mannol", "pirate", "pl", "ru", "fi", "sv", "uk"};
static QStringList langs = {"Български", "Deutsch", "English", "Español", "Français", "Italiano", "mannol", "Pirate", "Polski", "Русский", "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"};
@ -54,7 +54,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
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);
@ -62,6 +62,8 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
bodyUI->closeToTray->setEnabled(showSystemTray);
bodyUI->minimizeToTray->setChecked(Settings::getInstance().getMinimizeToTray());
bodyUI->minimizeToTray->setEnabled(showSystemTray);
bodyUI->lightTrayIcon->setChecked(Settings::getInstance().getLightTrayIcon());
bodyUI->lightTrayIcon->setEnabled(showSystemTray);
bodyUI->statusChanges->setChecked(Settings::getInstance().getStatusChangeNotificationEnabled());
bodyUI->useEmoticons->setChecked(Settings::getInstance().getUseEmoticons());
bodyUI->autoacceptFiles->setChecked(Settings::getInstance().getAutoSaveEnabled());
@ -80,7 +82,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
bodyUI->styleBrowser->addItem(tr("None"));
bodyUI->styleBrowser->addItems(QStyleFactory::keys());
if(QStyleFactory::keys().contains(Settings::getInstance().getStyle()))
if (QStyleFactory::keys().contains(Settings::getInstance().getStyle()))
bodyUI->styleBrowser->setCurrentText(Settings::getInstance().getStyle());
else
bodyUI->styleBrowser->setCurrentText(tr("None"));
@ -110,7 +112,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
if (port != -1)
bodyUI->proxyPort->setValue(port);
bodyUI->cbUseProxy->setChecked(Settings::getInstance().getUseProxy());
bodyUI->proxyType->setCurrentIndex(static_cast<int>(Settings::getInstance().getProxyType()));
onUseProxyUpdated();
//general
@ -121,11 +123,12 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
connect(bodyUI->startInTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetAutostartInTray);
connect(bodyUI->closeToTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetCloseToTray);
connect(bodyUI->minimizeToTray, &QCheckBox::stateChanged, this, &GeneralForm::onSetMinimizeToTray);
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->showInFront, &QCheckBox::stateChanged, this, &GeneralForm::onSetShowInFront);
connect(bodyUI->autoacceptFiles, &QCheckBox::stateChanged, this, &GeneralForm::onAutoAcceptFileChange);
if(bodyUI->autoacceptFiles->isChecked())
if (bodyUI->autoacceptFiles->isChecked())
connect(bodyUI->autoSaveFilesDir, SIGNAL(clicked()), this, SLOT(onAutoSaveDirChange()));
//theme
connect(bodyUI->useEmoticons, &QCheckBox::stateChanged, this, &GeneralForm::onUseEmoticonsChange);
@ -137,7 +140,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
//connection
connect(bodyUI->cbEnableIPv6, &QCheckBox::stateChanged, this, &GeneralForm::onEnableIPv6Updated);
connect(bodyUI->cbEnableUDP, &QCheckBox::stateChanged, this, &GeneralForm::onUDPUpdated);
connect(bodyUI->cbUseProxy, &QCheckBox::stateChanged, this, &GeneralForm::onUseProxyUpdated);
connect(bodyUI->proxyType, SIGNAL(currentIndexChanged(int)), this, SLOT(onUseProxyUpdated()));
connect(bodyUI->proxyAddr, &QLineEdit::editingFinished, this, &GeneralForm::onProxyAddrEdited);
connect(bodyUI->proxyPort, SIGNAL(valueChanged(int)), this, SLOT(onProxyPortEdited(int)));
connect(bodyUI->reconnectButton, &QPushButton::clicked, this, &GeneralForm::onReconnectClicked);
@ -187,6 +190,12 @@ void GeneralForm::onSetCloseToTray()
Settings::getInstance().setCloseToTray(bodyUI->closeToTray->isChecked());
}
void GeneralForm::onSetLightTrayIcon()
{
Settings::getInstance().setLightTrayIcon(bodyUI->lightTrayIcon->isChecked());
Widget::getInstance()->updateTrayIcon();
}
void GeneralForm::onSetMinimizeToTray()
{
Settings::getInstance().setMinimizeToTray(bodyUI->minimizeToTray->isChecked());
@ -194,7 +203,7 @@ void GeneralForm::onSetMinimizeToTray()
void GeneralForm::onStyleSelected(QString style)
{
if(bodyUI->styleBrowser->currentIndex() == 0)
if (bodyUI->styleBrowser->currentIndex() == 0)
Settings::getInstance().setStyle("None");
else
Settings::getInstance().setStyle(style);
@ -223,7 +232,7 @@ void GeneralForm::onAutoAcceptFileChange()
{
Settings::getInstance().setAutoSaveEnabled(bodyUI->autoacceptFiles->isChecked());
if(bodyUI->autoacceptFiles->isChecked() == true)
if (bodyUI->autoacceptFiles->isChecked() == true)
connect(bodyUI->autoSaveFilesDir, SIGNAL(clicked()), this, SLOT(onAutoSaveDirChange()));
else
disconnect(bodyUI->autoSaveFilesDir, SIGNAL(clicked()),this, SLOT(onAutoSaveDirChange()));
@ -233,7 +242,7 @@ void GeneralForm::onAutoSaveDirChange()
{
QString previousDir = Settings::getInstance().getGlobalAutoAcceptDir();
QString directory = QFileDialog::getExistingDirectory(0, tr("Choose an auto accept directory","popup title"));
if(directory.isEmpty())
if (directory.isEmpty())
directory = previousDir;
Settings::getInstance().setGlobalAutoAcceptDir(directory);
@ -279,11 +288,11 @@ void GeneralForm::onProxyPortEdited(int port)
void GeneralForm::onUseProxyUpdated()
{
bool state = bodyUI->cbUseProxy->isChecked();
int proxytype = bodyUI->proxyType->currentIndex();
bodyUI->proxyAddr->setEnabled(state);
bodyUI->proxyPort->setEnabled(state);
Settings::getInstance().setUseProxy(state);
bodyUI->proxyAddr->setEnabled(proxytype);
bodyUI->proxyPort->setEnabled(proxytype);
Settings::getInstance().setProxyType(proxytype);
}
void GeneralForm::onReconnectClicked()
@ -301,7 +310,7 @@ void GeneralForm::reloadSmiles()
QStringList smiles;
smiles << ":)" << ";)" << ":p" << ":O" << ":["; //just in case...
for(int i = 0; i < emoticons.size(); i++)
for (int i = 0; i < emoticons.size(); i++)
smiles.push_front(emoticons.at(i).first());
int pixSize = 30;

View File

@ -37,6 +37,7 @@ private slots:
void onSetShowSystemTray();
void onSetAutostartInTray();
void onSetCloseToTray();
void onSetLightTrayIcon();
void onSmileyBrowserIndexChanged(int index);
void onUDPUpdated();
void onProxyAddrEdited();

View File

@ -38,12 +38,12 @@
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>509</width>
<height>849</height>
<y>-173</y>
<width>511</width>
<height>797</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0,1">
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0,0">
<property name="spacing">
<number>9</number>
</property>
@ -109,7 +109,7 @@
</property>
</widget>
</item>
<item row="1" column="0">
<item row="1" column="0" colspan="2">
<layout class="QHBoxLayout" name="trayBehavior">
<item>
<widget class="QCheckBox" name="startInTray">
@ -152,6 +152,13 @@
</item>
</layout>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="lightTrayIcon">
<property name="text">
<string>Light icon</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -216,6 +223,9 @@
<property name="toolTip">
<string>Set to 0 to disable</string>
</property>
<property name="showGroupSeparator" stdset="0">
<bool>true</bool>
</property>
<property name="suffix">
<string> minutes</string>
</property>
@ -225,9 +235,6 @@
<property name="maximum">
<number>2147483647</number>
</property>
<property name="showGroupSeparator" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
@ -294,6 +301,9 @@
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<property name="topMargin">
<number>0</number>
</property>
@ -317,23 +327,6 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="styleLabel">
<property name="text">
<string>Style</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="1" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,0">
<property name="sizeConstraint">
@ -391,6 +384,23 @@
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="styleLabel">
<property name="text">
<string>Style</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">
@ -462,7 +472,7 @@
</layout>
</widget>
</item>
<item alignment="Qt::AlignTop">
<item>
<widget class="QGroupBox" name="connectionGroup">
<property name="title">
<string>Connection Settings</string>
@ -492,11 +502,40 @@
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbUseProxy">
<property name="text">
<string>Use proxy (SOCKS5)</string>
</property>
</widget>
<layout class="QHBoxLayout" name="proxyLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Proxy type</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="proxyType">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>SOCKS5</string>
</property>
</item>
<item>
<property name="text">
<string>HTTP</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="proxyLayout">

View File

@ -43,11 +43,11 @@
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QCheckBox" name="cbTypingNotification">
<property name="enabled">
<bool>false</bool>
<property name="toolTip">
<string extracomment="Your friends will be able to see when you are typing."/>
</property>
<property name="text">
<string>Typing Notification</string>
<string>Send Typing Notifications</string>
</property>
</widget>
</item>

View File

@ -52,7 +52,7 @@ void TabCompleter::buildCompletionList()
// that section is then used as the completion regex
QRegExp regex(QString("^[-_\\[\\]{}|`^.\\\\]*").append(QRegExp::escape(tabAbbrev)), Qt::CaseInsensitive);
for(auto name : group->getPeerList())
for (auto name : group->getPeerList())
if (regex.indexIn(name) > -1)
completionMap[name.toLower()] = name;

View File

@ -32,7 +32,7 @@ FriendListWidget::FriendListWidget(QWidget *parent) :
for (Status s : {Status::Online, Status::Away, Status::Busy, Status::Offline})
{
QLayout *l = new QVBoxLayout();
QVBoxLayout *l = new QVBoxLayout();
l->setSpacing(0);
l->setMargin(0);
@ -46,12 +46,12 @@ FriendListWidget::FriendListWidget(QWidget *parent) :
mainLayout->addLayout(layouts[static_cast<int>(Status::Offline)], 4, 0);
}
QLayout* FriendListWidget::getGroupLayout()
QVBoxLayout* FriendListWidget::getGroupLayout()
{
return groupLayout;
}
QLayout* FriendListWidget::getFriendLayout(Status s)
QVBoxLayout* FriendListWidget::getFriendLayout(Status s)
{
auto res = layouts.find(static_cast<int>(s));
if (res != layouts.end())
@ -61,8 +61,11 @@ QLayout* FriendListWidget::getFriendLayout(Status s)
return layouts[static_cast<int>(Status::Online)];
}
void FriendListWidget::moveWidget(QWidget *w, Status s)
void FriendListWidget::moveWidget(QWidget *w, Status s, int hasNewEvents)
{
mainLayout->removeWidget(w);
getFriendLayout(s)->addWidget(w);
if (hasNewEvents == 0)
getFriendLayout(s)->addWidget(w);
else
getFriendLayout(s)->insertWidget(0, w);
}

View File

@ -21,7 +21,7 @@
#include <QHash>
#include "src/corestructs.h"
class QLayout;
class QVBoxLayout;
class QGridLayout;
class QPixmap;
@ -31,17 +31,17 @@ class FriendListWidget : public QWidget
public:
explicit FriendListWidget(QWidget *parent = 0);
QLayout* getGroupLayout();
QLayout* getFriendLayout(Status s);
void moveWidget(QWidget *w, Status s);
QVBoxLayout* getGroupLayout();
QVBoxLayout* getFriendLayout(Status s);
void moveWidget(QWidget *w, Status s, int hasNewEvents);
signals:
public slots:
private:
QHash<int, QLayout*> layouts;
QLayout *groupLayout;
QHash<int, QVBoxLayout*> layouts;
QVBoxLayout *groupLayout;
QGridLayout *mainLayout;
};

View File

@ -130,6 +130,6 @@ void MaskablePixmapWidget::paintEvent(QPaintEvent *)
void MaskablePixmapWidget::mousePressEvent(QMouseEvent*)
{
if(clickable)
if (clickable)
emit clicked();
}

View File

@ -29,7 +29,7 @@ MessageAction::MessageAction(const QString &author, const QString &message, cons
QString MessageAction::getMessage(QString div)
{
QString message_;
if(Settings::getInstance().getUseEmoticons())
if (Settings::getInstance().getUseEmoticons())
message_ = SmileyPack::getInstance().smileyfied(toHtmlChars(message));
else
message_ = toHtmlChars(message);

View File

@ -54,7 +54,7 @@
void toxActivateEventHandler(const QByteArray& data)
{
if(data != "$activate")
if (data != "$activate")
return;
Widget::getInstance()->show();
Widget::getInstance()->activateWindow();
@ -96,12 +96,11 @@ void Widget::init()
statusAway->setIcon(QIcon(":ui/statusButton/dot_idle.png"));
connect(statusAway, SIGNAL(triggered()), this, SLOT(setStatusAway()));
statusBusy = new QAction(tr("Busy"), this);
connect(statusBusy, SIGNAL(triggered()), this, SLOT(setStatusBusy()));
statusBusy->setIcon(QIcon(":ui/statusButton/dot_busy.png"));
connect(statusBusy, SIGNAL(triggered()), this, SLOT(setStatusBusy()));
actionQuit = new QAction(tr("&Quit"), this);
connect(actionQuit, SIGNAL(triggered()), qApp, SLOT(quit()));
trayMenu->addAction(new QAction(tr("Change status to:"), this));
trayMenu->addAction(statusOnline);
trayMenu->addAction(statusAway);
trayMenu->addAction(statusBusy);
@ -116,7 +115,7 @@ void Widget::init()
if (Settings::getInstance().getShowSystemTray()){
icon->show();
if(Settings::getInstance().getAutostartInTray() == false)
if (Settings::getInstance().getAutostartInTray() == false)
this->show();
}
else
@ -149,7 +148,7 @@ void Widget::init()
ui->tooliconsZone->setStyleSheet(Style::resolve("QPushButton{background-color:@themeDark;border:none;}QPushButton:hover{background-color:@themeMediumDark;border:none;}"));
if(QStyleFactory::keys().contains(Settings::getInstance().getStyle())
if (QStyleFactory::keys().contains(Settings::getInstance().getStyle())
&& Settings::getInstance().getStyle() != "None")
{
ui->mainHead->setStyle(QStyleFactory::create(Settings::getInstance().getStyle()));
@ -243,6 +242,7 @@ void Widget::init()
connect(core, &Core::avInvite, this, &Widget::playRingtone);
connect(core, &Core::blockingClearContacts, this, &Widget::clearContactsList, Qt::BlockingQueuedConnection);
connect(core, &Core::blockingGetPassword, this, &Widget::getPassword, Qt::BlockingQueuedConnection);
connect(core, &Core::friendTypingChanged, this, &Widget::onFriendTypingChanged);
connect(core, SIGNAL(messageSentResult(int,QString,int)), this, SLOT(onMessageSendResult(int,QString,int)));
connect(core, SIGNAL(groupSentResult(int,QString,int)), this, SLOT(onGroupSendResult(int,QString,int)));
@ -300,14 +300,15 @@ void Widget::updateTrayIcon()
return;
QString status = ui->statusButton->property("status").toString();
QString pic;
QString color = Settings::getInstance().getLightTrayIcon() ? "light" : "dark";
if (status == "online")
pic = ":img/taskbar/taskbar_online_2x.png";
pic = ":img/taskbar/" + color + "/taskbar_online_2x.png";
else if (status == "away")
pic = ":img/taskbar/taskbar_idle_2x.png";
pic = ":img/taskbar/" + color + "/taskbar_idle_2x.png";
else if (status == "busy")
pic = ":img/taskbar/taskbar_busy_2x.png";
pic = ":img/taskbar/" + color + "/taskbar_busy_2x.png";
else
pic = ":img/taskbar/taskbar_offline_2x.png";
pic = ":img/taskbar/" + color + "/taskbar_offline_2x.png";
icon->setIcon(QIcon(pic));
}
@ -318,6 +319,7 @@ Widget::~Widget()
coreThread->wait(500); // In case of deadlock (can happen with QtAudio/PA bugs)
if (!coreThread->isFinished())
coreThread->terminate();
AutoUpdater::abortUpdates();
delete core;
delete settingsWidget;
delete addFriendForm;
@ -348,7 +350,7 @@ QThread* Widget::getCoreThread()
void Widget::closeEvent(QCloseEvent *event)
{
if(Settings::getInstance().getShowSystemTray() && Settings::getInstance().getCloseToTray() == true)
if (Settings::getInstance().getShowSystemTray() && Settings::getInstance().getCloseToTray() == true)
{
event->ignore();
this->hide();
@ -365,7 +367,7 @@ void Widget::changeEvent(QEvent *event)
{
if (event->type() == QEvent::WindowStateChange)
{
if(isMinimized() && Settings::getInstance().getMinimizeToTray())
if (isMinimized() && Settings::getInstance().getMinimizeToTray())
{
this->hide();
}
@ -415,7 +417,7 @@ QList<QString> Widget::searchProfiles()
QDir dir(Settings::getSettingsDirPath());
dir.setFilter(QDir::Files | QDir::NoDotAndDotDot);
dir.setNameFilters(QStringList("*.tox"));
for(QFileInfo file : dir.entryInfoList())
for (QFileInfo file : dir.entryInfoList())
out += file.completeBaseName();
return out;
}
@ -591,7 +593,7 @@ void Widget::onIconClick(QSystemTrayIcon::ActivationReason reason)
{
switch (reason) {
case QSystemTrayIcon::Trigger:
if(this->isHidden() == true)
if (this->isHidden() == true)
{
this->show();
this->activateWindow();
@ -712,7 +714,7 @@ void Widget::addFriend(int friendId, const QString &userId)
void Widget::addFriendFailed(const QString&, const QString& errorInfo)
{
QString info = QString(tr("Couldn't request friendship"));
if(!errorInfo.isEmpty()) {
if (!errorInfo.isEmpty()) {
info = info + (QString(": ") + errorInfo);
}
@ -725,7 +727,7 @@ void Widget::onFriendStatusChanged(int friendId, Status status)
if (!f)
return;
contactListWidget->moveWidget(f->getFriendWidget(), status);
contactListWidget->moveWidget(f->getFriendWidget(), status, f->getEventFlag());
bool isActualChange = f->getStatus() != status;
@ -733,7 +735,7 @@ void Widget::onFriendStatusChanged(int friendId, Status status)
f->getFriendWidget()->updateStatusLight();
//won't print the message if there were no messages before
if(!f->getChatForm()->isEmpty()
if (!f->getChatForm()->isEmpty()
&& Settings::getInstance().getStatusChangeNotificationEnabled())
{
QString fStatus = "";
@ -1178,6 +1180,14 @@ void Widget::getPassword(QString info, int passtype, uint8_t* salt)
}
}
void Widget::onFriendTypingChanged(int friendId, bool isTyping)
{
Friend* f = FriendList::findFriend(friendId);
if (!f)
return;
f->getChatForm()->setFriendTyping(isTyping);
}
void Widget::onSetShowSystemTray(bool newValue){
icon->setVisible(newValue);
}

View File

@ -132,6 +132,7 @@ private slots:
void onIconClick(QSystemTrayIcon::ActivationReason);
void onUserAwayCheck();
void getPassword(QString info, int passtype, uint8_t* salt);
void onFriendTypingChanged(int friendId, bool isTyping);
void onSetShowSystemTray(bool newValue);
void onSplitterMoved(int pos, int index);

539
translations/de.ts vendored

File diff suppressed because it is too large Load Diff

140
translations/fr.ts vendored
View File

@ -76,13 +76,13 @@
<message>
<location filename="../src/widget/form/addfriendform.cpp" line="34"/>
<source>Add Friends</source>
<translation>Ajouter des amis</translation>
<translation>Ajouter des contacts</translation>
</message>
<message>
<location filename="../src/widget/form/addfriendform.cpp" line="37"/>
<source>Tox ID</source>
<comment>Tox ID of the person you&apos;re sending a friend request to</comment>
<translation>ID Tox</translation>
<translation>Tox ID</translation>
</message>
<message>
<location filename="../src/widget/form/addfriendform.cpp" line="38"/>
@ -93,25 +93,25 @@
<message>
<location filename="../src/widget/form/addfriendform.cpp" line="39"/>
<source>Send friend request</source>
<translation>Envoyer la demande d&apos;ami</translation>
<translation>Envoyer la demande de contact</translation>
</message>
<message>
<location filename="../src/widget/form/addfriendform.cpp" line="40"/>
<source>Tox me maybe?</source>
<comment>Default message in friend requests if the field is left blank. Write something appropriate!</comment>
<translation>Je souhaiterais vous ajouter à mes contacts</translation>
<translation>Je souhaiterais vous ajouter à mes contacts.</translation>
</message>
<message>
<location filename="../src/widget/form/addfriendform.cpp" line="89"/>
<source>Please fill in a valid Tox ID</source>
<comment>Tox ID of the friend you&apos;re sending a friend request to</comment>
<translation>Merci de remplir un ID Tox valide</translation>
<translation>Merci d&apos;entrer un Tox ID valide</translation>
</message>
<message>
<location filename="../src/widget/form/addfriendform.cpp" line="92"/>
<source>You can&apos;t add yourself as a friend!</source>
<comment>When trying to add your own Tox ID as friend</comment>
<translation>Vous ne pouvez pas vous ajouter vous même en temps qu&apos;ami!</translation>
<translation>Vous ne pouvez pas vous ajouter vous-même !</translation>
</message>
<message>
<location filename="../src/widget/form/addfriendform.cpp" line="100"/>
@ -123,19 +123,19 @@ Ignorer le proxy et se connecter directement à Internet ?</translation>
<message>
<source>qTox needs to use the Tox DNS, but can&apos;t do it through a proxy
Ignore the proxy and connect to the Internet directly ?</source>
<translation type="vanished">qTox as besoin d&apos;utiliser le DNS Tox, mais ne peut pas le faire avec un proxy
<translation type="vanished">qTox a besoin d&apos;utiliser le DNS Tox, mais ne peut pas le faire avec un proxy
Ignorer le proxy et se connecter directement à Internet ?</translation>
</message>
<message>
<location filename="../src/widget/form/addfriendform.cpp" line="110"/>
<source>This Tox ID does not exist</source>
<comment>DNS error</comment>
<translation>Cet ID Tox n&apos;existe pas</translation>
<translation>Ce Tox ID n&apos;existe pas</translation>
</message>
<message>
<source>This address does not exist</source>
<comment>The DNS gives the Tox ID associated to toxme.se addresses</comment>
<translation type="vanished">Cette addresse n&apos;existe pas</translation>
<translation type="vanished">Cette adresse n&apos;existe pas</translation>
</message>
<message>
<source>Error while looking up DNS</source>
@ -178,22 +178,22 @@ Ignorer le proxy et se connecter directement à Internet ?</translation>
<message>
<location filename="../src/widget/form/chatform.cpp" line="148"/>
<source>Bad Idea</source>
<translation>Mauvaise Idée</translation>
<translation>Mauvaise idée</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="148"/>
<source>You&apos;re trying to send a special (sequential) file, that&apos;s not going to work!</source>
<translation>Vous êtes en train d&apos;essayer d&apos;envoyer un fichier spécial (sequentiel), ça ne marchera pas!</translation>
<translation>Vous êtes en train d&apos;essayer d&apos;envoyer un fichier spécial (sequentiel), ça ne fonctionnera pas !</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="254"/>
<source>%1 calling</source>
<translation>%1 appelle</translation>
<translation>%1 appel</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="323"/>
<source>%1 stopped calling</source>
<translation>%1a arreté l&apos;appel</translation>
<translation>%1 a arreté l&apos;appel</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="379"/>
@ -229,7 +229,7 @@ Ignorer le proxy et se connecter directement à Internet ?</translation>
<message>
<location filename="../src/core.cpp" line="256"/>
<source>Toxing on qTox</source>
<translation>Toxer avec qTox</translation>
<translation>Je Tox sur qTox</translation>
</message>
<message>
<location filename="../src/core.cpp" line="257"/>
@ -239,7 +239,7 @@ Ignorer le proxy et se connecter directement à Internet ?</translation>
<message>
<location filename="../src/core.cpp" line="746"/>
<source>Friend is already added</source>
<translation>Cet ami est déjà dans cos contact</translation>
<translation>Ce contact est déjà dans vos contacts</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1176"/>
@ -249,7 +249,7 @@ Ignorer le proxy et se connecter directement à Internet ?</translation>
<message>
<location filename="../src/core.cpp" line="1176"/>
<source>The .tox file is encrypted, but encryption was not checked, continuing regardless.</source>
<translation>Le fichier .tox est chiffré, mais l&apos;encryption n&apos;as pas été activée. Le problème sera ignoré.</translation>
<translation>Le fichier .tox est chiffré, mais le chiffrement n&apos;a pas été activé. Le problème sera ignoré.</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1183"/>
@ -261,14 +261,14 @@ Ignorer le proxy et se connecter directement à Internet ?</translation>
<location filename="../src/core.cpp" line="1197"/>
<location filename="../src/core.cpp" line="1261"/>
<source>Password error</source>
<translation>Mod de passe invalide</translation>
<translation>Mot de passe invalide</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1185"/>
<location filename="../src/core.cpp" line="1261"/>
<source>Failed to setup password.
Empty password.</source>
<translation>Impossible de mettre ne place le mot de passe.
<translation>Impossible de mettre en place le mot de passe.
Le mot de passe est vide.</translation>
</message>
<message>
@ -289,7 +289,7 @@ Le mot de passe est vide.</translation>
<message>
<location filename="../src/core.cpp" line="1198"/>
<source>Wrong password has been entered</source>
<translation>Un mauvais mot de passe à été entré</translation>
<translation>Un mauvais mot de passe a été entré</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1259"/>
@ -316,7 +316,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<message>
<location filename="../src/core.cpp" line="1277"/>
<source>Due to incorret password logging will be disabled</source>
<translation>À cause d&apos;un mauvais mot de passe, l&apos;historique sera désactivé</translation>
<translation>Due à l&apos;utilisation d&apos;un mauvais mot de passe, l&apos;historique sera désactivé</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1350"/>
@ -326,7 +326,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<message>
<location filename="../src/core.cpp" line="1350"/>
<source>Will be saved without encryption!</source>
<translation>L&apos;historique sera sauvegardé sans être chiffré!</translation>
<translation>L&apos;historique sera sauvegardé sans être chiffré !</translation>
</message>
</context>
<context>
@ -380,12 +380,12 @@ Voulez-vous essayer un mot de passe différent?</translation>
<location filename="../src/widget/tool/friendrequestdialog.cpp" line="30"/>
<source>Friend request</source>
<comment>Title of the window to aceept/deny a friend request</comment>
<translation>Demande d&apos;ami</translation>
<translation>Demande de contact</translation>
</message>
<message>
<location filename="../src/widget/tool/friendrequestdialog.cpp" line="32"/>
<source>Someone wants to make friends with you</source>
<translation>Quelqu&apos;un veut devenir votre ami</translation>
<translation>Quelqu&apos;un vient de vous ajouter dans sa liste de contacts</translation>
</message>
<message>
<location filename="../src/widget/tool/friendrequestdialog.cpp" line="33"/>
@ -395,7 +395,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<message>
<location filename="../src/widget/tool/friendrequestdialog.cpp" line="37"/>
<source>Friend request message:</source>
<translation>Message de demande d&apos;ami:</translation>
<translation>Message au sujet de la demande:</translation>
</message>
<message>
<location filename="../src/widget/tool/friendrequestdialog.cpp" line="44"/>
@ -422,7 +422,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<location filename="../src/widget/friendwidget.cpp" line="56"/>
<source>Copy friend ID</source>
<comment>Menu to copy the Tox ID of that friend</comment>
<translation>Copier l&apos;ID ami</translation>
<translation>Copier l&apos;ID du contact</translation>
</message>
<message>
<location filename="../src/widget/friendwidget.cpp" line="68"/>
@ -458,7 +458,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<message>
<source>Disable global auto accept</source>
<comment>context menu entry</comment>
<translation type="vanished">Désactiver l&apos;acceptation automatique de fichier</translation>
<translation type="vanished">Désactiver le téléchargement automatique de fichiers</translation>
</message>
<message>
<location filename="../src/widget/friendwidget.cpp" line="109"/>
@ -470,7 +470,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<location filename="../src/widget/friendwidget.cpp" line="76"/>
<source>Remove friend</source>
<comment>Menu to remove the friend from our friendlist</comment>
<translation>Supprimer ami</translation>
<translation>Supprimer ce contact</translation>
</message>
</context>
<context>
@ -502,7 +502,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<location filename="../src/widget/form/settings/generalform.cpp" line="267"/>
<source>You can&apos;t disconnect while a call is active!</source>
<comment>popup text</comment>
<translation>Vous ne pouvez pas vous déconnecter avec un appel en cours!</translation>
<translation>Vous ne pouvez pas vous déconnecter avec un appel en cours !</translation>
</message>
</context>
<context>
@ -520,7 +520,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<location filename="../src/widget/form/settings/generalsettings.ui" line="64"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="80"/>
<source>The translation may not load until qTox restarts.</source>
<translation>La translation peut ne pas se charger jusqu&apos;à ce que qTox redémarre.</translation>
<translation>La traduction peut ne pas prendre effet immédiatement. Redémarrez qTox si ce n&apos;est pas le cas.</translation>
</message>
<message>
<source>Translation:</source>
@ -550,7 +550,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="133"/>
<source>Minimize to tray</source>
<translation>Minimizer dans la barre d&apos;état</translation>
<translation>Minimiser dans la barre d&apos;état</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="142"/>
@ -564,7 +564,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
</message>
<message>
<source>Auto away after (0 to disable):</source>
<translation type="vanished">Auto-absent après (0 pour désactiver):</translation>
<translation type="vanished">Se rendre absent après (0 pour désactiver):</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="191"/>
@ -620,7 +620,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<location filename="../src/widget/form/settings/generalsettings.ui" line="492"/>
<source>Reconnect</source>
<comment>reconnect button</comment>
<translation>Reconnection</translation>
<translation>Se reconnecter</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="422"/>
@ -640,7 +640,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="156"/>
<source>Focus qTox when a message is received</source>
<translation>Montrer qTox quand un message est reçu</translation>
<translation>Montrer la fênetre qTox quand un message est reçu</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="163"/>
@ -713,7 +713,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<message>
<source>This allows, e.g., toxing over Tor. It adds load to the Tox network however, so use only when necessary.</source>
<extracomment>force tcp checkbox tooltip</extracomment>
<translation type="vanished">Permet par exemple d&apos;utiliser Tox à travers Tor, mais ce n&apos;est à utiliser que si nécessaire, car cela ralenti le réseau Tox.</translation>
<translation type="vanished">Permet par exemple d&apos;utiliser Tox à travers Tor, mais ce n&apos;est à utiliser que si nécessaire car cela ralenti le réseau Tox.</translation>
</message>
<message>
<source>Disable UDP (not recommended)</source>
@ -748,7 +748,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="64"/>
<source>Smileys</source>
<translation>Emoticones</translation>
<translation>Émoticônes</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="68"/>
@ -768,7 +768,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="77"/>
<source>Toggle speakers volume</source>
<translation>Couper les haut parleurs</translation>
<translation>Couper les haut-parleurs</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="80"/>
@ -818,7 +818,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<location filename="../src/widget/groupwidget.cpp" line="44"/>
<location filename="../src/widget/groupwidget.cpp" line="66"/>
<source>0 users in chat</source>
<translation>0 personnes</translation>
<translation>Le groupe est vide</translation>
</message>
<message>
<location filename="../src/widget/groupwidget.cpp" line="53"/>
@ -844,7 +844,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<location filename="../src/widget/form/settings/identityform.cpp" line="133"/>
<source>You can&apos;t switch profiles while a call is active!</source>
<comment>popup text</comment>
<translation>Vous ne pouvez pas changer de profil quand un appel est en cours!</translation>
<translation>Vous ne pouvez pas changer de profil quand un appel est en cours !</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="143"/>
@ -894,7 +894,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="186"/>
<source>The file you chose could not be written to.</source>
<translation>Le fichier que vous avez choisi n&apos;as pas pu être écrit.</translation>
<translation>Le fichier que vous avez choisi n&apos;es pas disponible en écriture.</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="194"/>
@ -912,7 +912,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<location filename="../src/widget/form/settings/identityform.cpp" line="198"/>
<source>Deletion imminent!</source>
<comment>deletion confirmation title</comment>
<translation>Suppression imminente!</translation>
<translation>Suppression imminente !</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="199"/>
@ -936,13 +936,13 @@ Voulez-vous essayer un mot de passe différent?</translation>
<location filename="../src/widget/form/settings/identityform.cpp" line="223"/>
<source>Ignoring non-Tox file</source>
<comment>popup title</comment>
<translation>Fichier non-Tox ignoré</translation>
<translation>Fichier incompatible avec Tox ignoré</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="224"/>
<source>Warning: you&apos;ve chosen a file that is not a Tox save file; ignoring.</source>
<comment>popup text</comment>
<translation>Attention: Vous avez sélectionné un fichier qui n&apos;est pas une sauvegarde Tox: il sera ignoré.</translation>
<translation>Attention: Vous avez sélectionné un fichier qui n&apos;est pas une sauvegarde Tox, il sera ignoré.</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="230"/>
@ -986,7 +986,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<message>
<location filename="../src/widget/form/settings/identitysettings.ui" line="88"/>
<source>Your Tox ID (click to copy)</source>
<translation>Votre ID Tox (cliquez pour copier)</translation>
<translation>Votre Tox ID (cliquez pour copier)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identitysettings.ui" line="98"/>
@ -1033,7 +1033,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<location filename="../src/widget/form/settings/identitysettings.ui" line="151"/>
<source>This is useful to remain safe on public computers</source>
<comment>delete profile button tooltip</comment>
<translation>Util pour sécuriser sur un ordinateur public</translation>
<translation>Utile pour rester en sécurité sur un ordinateur public</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identitysettings.ui" line="165"/>
@ -1045,7 +1045,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<location filename="../src/widget/form/settings/identitysettings.ui" line="175"/>
<source>New Tox ID</source>
<comment>new profile button</comment>
<translation>Nouvel ID Tox</translation>
<translation>Nouvel Tox ID</translation>
</message>
</context>
<context>
@ -1093,12 +1093,12 @@ Voulez-vous essayer un mot de passe différent?</translation>
<message>
<location filename="../src/mainwindow.ui" line="1101"/>
<source>Add friends</source>
<translation>Ajouter des amis</translation>
<translation>Ajouter des contacts</translation>
</message>
<message>
<location filename="../src/mainwindow.ui" line="1139"/>
<source>Create a group chat</source>
<translation>Creer un groupe</translation>
<translation>Créer un groupe</translation>
</message>
<message>
<location filename="../src/mainwindow.ui" line="1174"/>
@ -1125,7 +1125,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<message>
<location filename="../src/widget/netcamview.cpp" line="28"/>
<source>Tox video</source>
<translation>Vidéo tox</translation>
<translation>Vidéo Tox</translation>
</message>
</context>
<context>
@ -1145,7 +1145,7 @@ Voulez-vous essayer un mot de passe différent?</translation>
<source>You already have history log file encrypted with different password
Do you want to delete old history file?</source>
<translation>Vous avez déjà un historique chiffré avec un autre mot de passe
Voulez vous supprimer l&apos;ancien historique?</translation>
Voulez vous supprimer l&apos;ancien historique ?</translation>
</message>
</context>
<context>
@ -1192,7 +1192,7 @@ Voulez vous supprimer l&apos;ancien historique?</translation>
<location filename="../src/widget/toxsave.cpp" line="64"/>
<source>Warning: you&apos;ve chosen a file that is not a Tox save file; ignoring.</source>
<comment>popup text</comment>
<translation>Attention: Vous avez sélectionné un fichier qui n&apos;est pas une sauvegarde Tox: il sera ignoré.</translation>
<translation>Attention: Vous avez sélectionné un fichier qui n&apos;est pas une sauvegarde Tox, il sera ignoré.</translation>
</message>
<message>
<location filename="../src/widget/toxsave.cpp" line="70"/>
@ -1233,12 +1233,12 @@ Voulez vous supprimer l&apos;ancien historique?</translation>
<source>An update is available, do you want to download it now ?
It will be installed when qTox restarts.</source>
<translation>Une mise à jour est disponible, voulez vous la télécharger maintenant ?
Elle sera installée au prochain démarrage de qTox</translation>
Elle sera installée au prochain démarrage de qTox.</translation>
</message>
<message>
<location filename="../src/main.cpp" line="68"/>
<source>Tox URI to parse</source>
<translation>URI Tox à utiliser</translation>
<translation>URL Tox à utiliser</translation>
</message>
</context>
<context>
@ -1255,7 +1255,7 @@ Elle sera installée au prochain démarrage de qTox</translation>
<message>
<location filename="../src/widget/form/setpassworddialog.ui" line="37"/>
<source>Repeat Password</source>
<translation>Répetez le mot de passe</translation>
<translation>Retapez le mot de passe</translation>
</message>
</context>
<context>
@ -1270,13 +1270,13 @@ Elle sera installée au prochain démarrage de qTox</translation>
<location filename="../src/toxdns.cpp" line="70"/>
<source>This address does not exist</source>
<comment>The DNS gives the Tox ID associated to toxme.se addresses</comment>
<translation>Cette addresse n&apos;existe pas</translation>
<translation>Cette adresse n&apos;existe pas</translation>
</message>
<message>
<location filename="../src/toxdns.cpp" line="75"/>
<source>Error while looking up DNS</source>
<comment>The DNS gives the Tox ID associated to toxme.se addresses</comment>
<translation>Erreur en consultant le serveur DNS</translation>
<translation>Une erreur s&apos;est produite en consultant le serveur DNS</translation>
</message>
<message>
<location filename="../src/toxdns.cpp" line="82"/>
@ -1316,22 +1316,22 @@ Elle sera installée au prochain démarrage de qTox</translation>
<location filename="../src/widget/toxuri.cpp" line="80"/>
<source>Add a friend</source>
<comment>Title of the window to add a friend through Tox URI</comment>
<translation>Ajouter un ami</translation>
<translation>Ajouter un contact</translation>
</message>
<message>
<location filename="../src/widget/toxuri.cpp" line="82"/>
<source>Do you want to add %1 as a friend ?</source>
<translation>Voulez-vous ajouter %1 à vos amis ?</translation>
<translation>Voulez-vous ajouter %1 à vos contacts ?</translation>
</message>
<message>
<location filename="../src/widget/toxuri.cpp" line="83"/>
<source>User ID:</source>
<translation>ID utilisateur:</translation>
<translation>ID d&apos;utilisateur:</translation>
</message>
<message>
<location filename="../src/widget/toxuri.cpp" line="87"/>
<source>Friend request message:</source>
<translation>Message de demande d&apos;ami:</translation>
<translation>Associer un message à cette demande:</translation>
</message>
<message>
<location filename="../src/widget/toxuri.cpp" line="92"/>
@ -1354,7 +1354,7 @@ Elle sera installée au prochain démarrage de qTox</translation>
</message>
<message>
<source>away</source>
<translation type="vanished">indisponnible</translation>
<translation type="vanished">absent</translation>
</message>
<message>
<source>busy</source>
@ -1368,7 +1368,7 @@ Elle sera installée au prochain démarrage de qTox</translation>
<message>
<location filename="../src/widget/widget.cpp" line="77"/>
<source>Away</source>
<translation>Indisponible</translation>
<translation>Absent</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="80"/>
@ -1383,7 +1383,7 @@ Elle sera installée au prochain démarrage de qTox</translation>
<message>
<location filename="../src/widget/widget.cpp" line="86"/>
<source>Change status to:</source>
<translation>Changer le status en:</translation>
<translation>Changer le status par:</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="155"/>
@ -1395,7 +1395,7 @@ Elle sera installée au prochain démarrage de qTox</translation>
<location filename="../src/widget/widget.cpp" line="157"/>
<source>Away</source>
<comment>Button to set your status to &apos;Away&apos;</comment>
<translation>Indisponible</translation>
<translation>Absent</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="159"/>
@ -1443,18 +1443,18 @@ Elle sera installée au prochain démarrage de qTox</translation>
<message>
<location filename="../src/widget/widget.cpp" line="477"/>
<source>Toxcore failed to start, the application will terminate after you close this message.</source>
<translation>Toxcore n&apos;as pas pu démarrer correctement, l&apos;application va quitter quand vous fermerez ce message.</translation>
<translation>ToxCore n&apos;as pas pu démarrer correctement, l&apos;application va s&apos;arrêter quand vous fermerez cette alerte.</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="486"/>
<source>toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart.</source>
<comment>popup text</comment>
<translation>Toxcore n&apos;as pas pu démarrer avec ces paramètres de proxy, qTox ne peut pas continuer; merci de modifier vos paramètres et redémarrer.</translation>
<translation>ToxCore n&apos;as pas pu démarrer avec ces paramètres proxy. Merci de modifier ou désactiver vos paramètres et redémarrer l&apos;application.</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="521"/>
<source>Add friend</source>
<translation>Ajouter un ami</translation>
<translation>Ajouter un contact</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="533"/>
@ -1469,13 +1469,13 @@ Elle sera installée au prochain démarrage de qTox</translation>
<message>
<location filename="../src/widget/widget.cpp" line="656"/>
<source>Couldn&apos;t request friendship</source>
<translation>Impossible de demander en ami</translation>
<translation>Impossible d&apos;envoyer la demande de contact</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="684"/>
<source>away</source>
<comment>contact status</comment>
<translation>indisponnible</translation>
<translation>absent</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="686"/>
@ -1487,7 +1487,7 @@ Elle sera installée au prochain démarrage de qTox</translation>
<location filename="../src/widget/widget.cpp" line="688"/>
<source>offline</source>
<comment>contact status</comment>
<translation>déconnecté</translation>
<translation>hors ligne</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="690"/>
@ -1510,7 +1510,7 @@ Elle sera installée au prochain démarrage de qTox</translation>
<message>
<location filename="../src/widget/widget.cpp" line="1091"/>
<source>Message failed to send</source>
<translation>Le message n&apos;as pas pu être envoyé</translation>
<translation>Le message n&apos;as pu être envoyé</translation>
</message>
</context>
</TS>

View File

@ -6,12 +6,14 @@ 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 \
translations/ru.ts \
translations/sv.ts \
translations/uk.ts
translations/uk.ts \
translations/pt.ts
#rules to generate ts
isEmpty(QMAKE_LUPDATE) {

243
translations/it.ts vendored
View File

@ -12,12 +12,12 @@
<context>
<name>AVSettings</name>
<message>
<location filename="../src/widget/form/settings/avsettings.ui" line="105"/>
<location filename="../src/widget/form/settings/avsettings.ui" line="112"/>
<source>Video Settings</source>
<translation>Impostazioni Video</translation>
</message>
<message>
<location filename="../src/widget/form/settings/avsettings.ui" line="116"/>
<location filename="../src/widget/form/settings/avsettings.ui" line="123"/>
<source>Resolution</source>
<translation>Risoluzione</translation>
</message>
@ -52,22 +52,27 @@
<translation>Cerca dispositivi audio</translation>
</message>
<message>
<location filename="../src/widget/form/settings/avsettings.ui" line="133"/>
<location filename="../src/widget/form/settings/avsettings.ui" line="102"/>
<source>Filter audio</source>
<translation>Filtra audio</translation>
</message>
<message>
<location filename="../src/widget/form/settings/avsettings.ui" line="140"/>
<source>Hue</source>
<translation>Colore</translation>
</message>
<message>
<location filename="../src/widget/form/settings/avsettings.ui" line="147"/>
<location filename="../src/widget/form/settings/avsettings.ui" line="154"/>
<source>Brightness</source>
<translation>Luminoistà</translation>
</message>
<message>
<location filename="../src/widget/form/settings/avsettings.ui" line="161"/>
<location filename="../src/widget/form/settings/avsettings.ui" line="168"/>
<source>Saturation</source>
<translation>Saturazione</translation>
</message>
<message>
<location filename="../src/widget/form/settings/avsettings.ui" line="175"/>
<location filename="../src/widget/form/settings/avsettings.ui" line="182"/>
<source>Contrast</source>
<translation>Contrasto</translation>
</message>
@ -182,62 +187,72 @@ Ignorare le impostazioni del proxy e connettersi direttamente alla rete Tox?</tr
<context>
<name>ChatForm</name>
<message>
<location filename="../src/widget/form/chatform.cpp" line="66"/>
<location filename="../src/widget/form/chatform.cpp" line="75"/>
<source>Load History...</source>
<translation>Carica log...</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="137"/>
<location filename="../src/widget/form/chatform.cpp" line="162"/>
<source>Send a file</source>
<translation>Invia un file</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="145"/>
<location filename="../src/widget/form/chatform.cpp" line="170"/>
<source>File not read</source>
<translation>Impossibile leggere il file</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="145"/>
<location filename="../src/widget/form/chatform.cpp" line="170"/>
<source>qTox wasn&apos;t able to open %1</source>
<translation>qTox non è riuscito ad aprire %1</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="150"/>
<location filename="../src/widget/form/chatform.cpp" line="175"/>
<source>Bad Idea</source>
<translation>Pessima idea</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="150"/>
<location filename="../src/widget/form/chatform.cpp" line="175"/>
<source>You&apos;re trying to send a special (sequential) file, that&apos;s not going to work!</source>
<translation>Stai cercando di inviare un file speciale (sequenziale), questo non funzionerà!</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="257"/>
<location filename="../src/widget/form/chatform.cpp" line="283"/>
<source>%1 is calling</source>
<translation>%1 ti sta chiamando</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="326"/>
<location filename="../src/widget/form/chatform.cpp" line="356"/>
<source>%1 stopped calling</source>
<translation>%1 ha fermato la chiamata</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="382"/>
<location filename="../src/widget/form/chatform.cpp" line="413"/>
<source>Calling to %1</source>
<translation>Stai chiamando %1</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="808"/>
<location filename="../src/widget/form/chatform.cpp" line="705"/>
<source>Failed to send file &quot;%1&quot;</source>
<translation>Invio del file &quot;%1&quot; fallito</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="839"/>
<source>Call with %1 ended. %2</source>
<translation>Chiamata con %1 terminata. %2</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="827"/>
<location filename="../src/widget/form/chatform.cpp" line="858"/>
<source>Call duration: </source>
<translation>Durata chiamata: </translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="523"/>
<location filename="../src/widget/form/chatform.cpp" line="905"/>
<source>is typing...</source>
<translation>sta scrivendo...</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="554"/>
<source>Call rejected</source>
<translation>Chiamata rifiutata</translation>
</message>
@ -253,105 +268,105 @@ Ignorare le impostazioni del proxy e connettersi direttamente alla rete Tox?</tr
<context>
<name>Core</name>
<message>
<location filename="../src/core.cpp" line="225"/>
<location filename="../src/core.cpp" line="234"/>
<source>Toxing on qTox</source>
<translation>Toxing on qTox</translation>
</message>
<message>
<location filename="../src/core.cpp" line="226"/>
<location filename="../src/core.cpp" line="235"/>
<source>qTox User</source>
<translation>qTox User</translation>
</message>
<message>
<location filename="../src/core.cpp" line="730"/>
<location filename="../src/core.cpp" line="739"/>
<source>Friend is already added</source>
<translation>Questo contatto è già presente nella tua lista</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1171"/>
<location filename="../src/core.cpp" line="1180"/>
<source>Encryption error</source>
<translation>Errore crittografia</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1171"/>
<location filename="../src/core.cpp" line="1180"/>
<source>The .tox file is encrypted, but encryption was not checked, continuing regardless.</source>
<translation>Il Tox datafile è criptato, ma la crittografia non è abilitata nelle impostazioni.
Continuo ignorando le impostazioni.</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1178"/>
<location filename="../src/core.cpp" line="1187"/>
<source>Tox datafile decryption password</source>
<translation>Password per decriptare il Tox datafile</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1180"/>
<location filename="../src/core.cpp" line="1192"/>
<location filename="../src/core.cpp" line="1256"/>
<location filename="../src/core.cpp" line="1189"/>
<location filename="../src/core.cpp" line="1201"/>
<location filename="../src/core.cpp" line="1265"/>
<source>Password error</source>
<translation>Errore password</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1180"/>
<location filename="../src/core.cpp" line="1256"/>
<location filename="../src/core.cpp" line="1189"/>
<location filename="../src/core.cpp" line="1265"/>
<source>Failed to setup password.
Empty password.</source>
<translation>Impossibile impostare la password.
Password vuota.</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1188"/>
<location filename="../src/core.cpp" line="1197"/>
<source>Try Again</source>
<translation>Riprova</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1189"/>
<location filename="../src/core.cpp" line="1198"/>
<source>Change profile</source>
<translation>Cambia profilo</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1190"/>
<location filename="../src/core.cpp" line="1199"/>
<source>Reinit current profile</source>
<translation>Reinizializza il profilo corrente</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1193"/>
<location filename="../src/core.cpp" line="1202"/>
<source>Wrong password has been entered</source>
<translation>È stata inserita una password sbagliata</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1254"/>
<location filename="../src/core.cpp" line="1263"/>
<source>History Log decryption password</source>
<translation>Password per decriptare i log</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1261"/>
<location filename="../src/core.cpp" line="1270"/>
<source>Encrypted log</source>
<translation>Log criptato</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1262"/>
<location filename="../src/core.cpp" line="1271"/>
<source>Your history is encrypted with different password.
Do you want to try another password?</source>
<translation>I log delle chat sono criptati con una password diversa.
Vuoi provare ad inserire un&apos;altra password?</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1272"/>
<location filename="../src/core.cpp" line="1281"/>
<source>History</source>
<translation>Chat Log</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1272"/>
<location filename="../src/core.cpp" line="1281"/>
<source>Due to incorret password history will be disabled.</source>
<translation>Password errata, i log delle chat non saranno caricati.</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1345"/>
<location filename="../src/core.cpp" line="1354"/>
<source>NO Password</source>
<translation>Nessuna password</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1345"/>
<location filename="../src/core.cpp" line="1354"/>
<source>Will be saved without encryption!</source>
<translation>Il Tox datafile sarà salvato senza password!</translation>
</message>
@ -538,17 +553,22 @@ Soprannome:</translation>
<translation>Mostra icona nella traybar</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="226"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="158"/>
<source>Light icon</source>
<translation>Icona brillante</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="217"/>
<source>Set to 0 to disable</source>
<translation>Imposta 0 per disabilitare</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="477"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="471"/>
<source>Connection Settings</source>
<translation>Impostazioni Connessione</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="489"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="483"/>
<source>Enable IPv6 (recommended)</source>
<extracomment>Text on a checkbox to enable IPv6</extracomment>
<translation>Abilita IPv6 (consigliato)</translation>
@ -590,143 +610,148 @@ Soprannome:</translation>
<translation>Minimizza nella traybar</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="164"/>
<source>Tray icon displays user status</source>
<translation>Mostra lo stato nell&apos;icona della traybar</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="167"/>
<source>This is a temporary work around until proper systray status icons are available.</source>
<translation>Questo è un workaround temporaneo fino a quando non saranno disponibili icone di stato adeguate.</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="177"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="168"/>
<source>Show contacts&apos; status changes</source>
<translation>Mostra quando i contatti cambiano stato</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="184"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="175"/>
<source>Check for updates on startup (unstable)</source>
<translation>Controlla aggiornamenti all&apos;avvio (unstable)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="191"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="182"/>
<source>Focus qTox when a message is received</source>
<translation>Dai il focus a qTox quando arriva un messaggio</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="198"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="189"/>
<source>Faux offline messaging</source>
<translation>Falsi messaggi offline</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="207"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="198"/>
<source>Provided in minutes</source>
<translation>Espresso in minuti</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="213"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="204"/>
<source>Auto away after (0 to disable)</source>
<translation>Imposta assenza dopo</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="229"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="223"/>
<source> minutes</source>
<translation> minuti</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="249"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="240"/>
<source>You can set this on a per-friend basis by right clicking them.</source>
<comment>autoaccept cb tooltip</comment>
<translation>Puoi impostare questa preferenza per ogni singolo contatto usando il click destro sul suo nome.</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="252"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="243"/>
<source>Autoaccept files</source>
<translation>Accetta automaticamente i trasferimenti di files</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="261"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="252"/>
<source>Save files in</source>
<translation>Salva i files in</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="274"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="265"/>
<source>PushButton</source>
<translation>Sfoglia</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="294"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="285"/>
<source>Theme</source>
<translation>Impostazioni Tema</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="300"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="291"/>
<source>Use emoticons</source>
<translation>Usa emoticons</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="315"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="309"/>
<source>Smiley Pack</source>
<extracomment>Text on smiley pack label</extracomment>
<translation>Emoticons</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="332"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="383"/>
<source>Style</source>
<translation>Stile</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="406"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="400"/>
<source>Theme color</source>
<translation>Colore</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="423"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="417"/>
<source>Emoticon size</source>
<translation>Dimensione emoticons</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="439"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="433"/>
<source> px</source>
<translation> px</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="455"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="449"/>
<source>Timestamp format</source>
<translation>Formato data/ora</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="496"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="490"/>
<source>Disabling this allows, e.g., toxing over Tor. It adds load to the Tox network however, so uncheck only when necessary.</source>
<extracomment>force tcp checkbox tooltip</extracomment>
<translation>Disabilitando questo sarà possibile usare qTox con Tor. Tuttavia verrà aggiunto carico alla rete Tox, quindi disabilitare solo se necessario.</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="499"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="493"/>
<source>Enable UDP (recommended)</source>
<extracomment>Text on checkbox to disable UDP</extracomment>
<translation>Abilita UDP (consigliato)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="506"/>
<source>Use proxy (SOCKS5)</source>
<translation>Usa proxy (SOCKS5)</translation>
<location filename="../src/widget/form/settings/generalsettings.ui" line="502"/>
<source>Proxy type</source>
<translation>Proxy</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="518"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="516"/>
<source>None</source>
<translation>Nessuno</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="521"/>
<source>SOCKS5</source>
<translation>SOCKS 5</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="526"/>
<source>HTTP</source>
<translation>HTTP</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="541"/>
<source>Address</source>
<extracomment>Text on proxy addr label</extracomment>
<translation>IP</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="528"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="551"/>
<source>Port</source>
<extracomment>Text on proxy port label</extracomment>
<translation>Porta</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="547"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="570"/>
<source>Reconnect</source>
<comment>reconnect button</comment>
<translation>Riconnetti</translation>
@ -735,43 +760,43 @@ Soprannome:</translation>
<context>
<name>GenericChatForm</name>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="65"/>
<location filename="../src/widget/form/genericchatform.cpp" line="68"/>
<source>Send message</source>
<translation>Invia messaggio</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="67"/>
<location filename="../src/widget/form/genericchatform.cpp" line="70"/>
<source>Smileys</source>
<translation>Emoticons</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="71"/>
<location filename="../src/widget/form/genericchatform.cpp" line="74"/>
<source>Send file(s)</source>
<translation>Invia file(s)</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="74"/>
<location filename="../src/widget/form/genericchatform.cpp" line="77"/>
<source>Audio call: RED means you&apos;re on a call</source>
<translation>Chiamata audio: ROSSO significa che la chiamata è in corso</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="77"/>
<location filename="../src/widget/form/genericchatform.cpp" line="80"/>
<source>Video call: RED means you&apos;re on a call</source>
<translation>Videochiamata: ROSSO significa che la chiamata è in corso</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="80"/>
<location filename="../src/widget/form/genericchatform.cpp" line="83"/>
<source>Toggle speakers volume: RED is OFF</source>
<translation>Imposta volume altoparlanti: ROSSO è SPENTO</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="83"/>
<location filename="../src/widget/form/genericchatform.cpp" line="86"/>
<source>Toggle microphone: RED is OFF</source>
<translation>Imposta microfono: ROSSO è SPENTO</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="149"/>
<location filename="../src/widget/form/genericchatform.cpp" line="191"/>
<location filename="../src/widget/form/genericchatform.cpp" line="192"/>
<source>Save chat log</source>
<translation>Salva il log della chat</translation>
</message>
@ -781,7 +806,7 @@ Soprannome:</translation>
<translation>Rimuovi messaggi visualizzati</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="290"/>
<location filename="../src/widget/form/genericchatform.cpp" line="297"/>
<source>Cleared</source>
<translation>Pulito</translation>
</message>
@ -927,42 +952,44 @@ Nome gruppo:</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="199"/>
<source>Are you sure you want to delete this profile?</source>
<source>Are you sure you want to delete this profile?
Associated friend information and chat logs will be deleted as well.</source>
<comment>deletion confirmation text</comment>
<translation>Sei sicuro di voler eliminare questo profilo?</translation>
<translation>Sei sicuro di voler eliminare questo profilo?
I contatti e i log delle chat associati ad esso, saranno eliminati.</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="211"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="218"/>
<source>Import profile</source>
<comment>import dialog title</comment>
<translation>Importa profilo</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="213"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="220"/>
<source>Tox save file (*.tox)</source>
<comment>import dialog filter</comment>
<translation>Tox save file (*.tox)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="223"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="230"/>
<source>Ignoring non-Tox file</source>
<comment>popup title</comment>
<translation>File ignorato</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="224"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="231"/>
<source>Warning: you&apos;ve chosen a file that is not a Tox save file; ignoring.</source>
<comment>popup text</comment>
<translation>Attenzione: hai scelto un file che non contiente un profilo Tox.\nQuesto file verrà ignorato.</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="230"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="237"/>
<source>Profile already exists</source>
<comment>import confirm title</comment>
<translation>Profilo già esistente</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="231"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="238"/>
<source>A profile named &quot;%1&quot; already exists. Do you want to erase it?</source>
<comment>import confirm text</comment>
<translation>Un profilo chiamato &quot;%1&quot; esiste già. Vuoi sovrascriverlo?</translation>
@ -1151,8 +1178,8 @@ Vuoi eliminare il vecchio file?</translation>
<name>PrivacySettings</name>
<message>
<location filename="../src/widget/form/settings/privacysettings.ui" line="50"/>
<source>Typing Notification</source>
<translation>Notifica quando qualcuno sta scrivendo</translation>
<source>Send Typing Notifications</source>
<translation>Permetti ai miei contatti di vedere quando sto scrivendo</translation>
</message>
<message>
<location filename="../src/widget/form/settings/privacysettings.ui" line="60"/>
@ -1233,13 +1260,13 @@ Vuoi eliminare il vecchio file?</translation>
<translation>%1.tox è stato importato con successo</translation>
</message>
<message>
<location filename="../src/autoupdate.cpp" line="430"/>
<location filename="../src/autoupdate.cpp" line="457"/>
<source>Update</source>
<comment>The title of a message box</comment>
<translation>Nuova versione</translation>
</message>
<message>
<location filename="../src/autoupdate.cpp" line="431"/>
<location filename="../src/autoupdate.cpp" line="458"/>
<source>An update is available, do you want to download it now?
It will be installed when qTox restarts.</source>
<translation>È disponibile una nuova versione di qTox, vuoi scaricarla adesso?
@ -1350,6 +1377,15 @@ Verrà installata al riavvio del programma.</translation>
<comment>Error with the DNS</comment>
<translation>La risposta del server DNS non contiene un Tox ID valido</translation>
</message>
<message>
<location filename="../src/toxdns.cpp" line="223"/>
<location filename="../src/toxdns.cpp" line="267"/>
<source>It appears that qTox has to use the old tox1 protocol.
Unfortunately tox1 is not secure. Should it be used anyway?</source>
<translation>Sembra che qTox debba usare il vecchio protocollo tox1.
Sfortunatamente il protocollo tox1 non è sicuro.
Usare comunque il protocollo tox1?</translation>
</message>
</context>
<context>
<name>ToxURIDialog</name>
@ -1409,11 +1445,6 @@ Verrà installata al riavvio del programma.</translation>
<source>&amp;Quit</source>
<translation>&amp;Esci</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="104"/>
<source>Change status to:</source>
<translation>Cambia stato in:</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="173"/>
<source>Online</source>

1579
translations/lt.ts vendored Normal file

File diff suppressed because it is too large Load Diff

1578
translations/pt.ts vendored Normal file

File diff suppressed because it is too large Load Diff

414
translations/ru.ts vendored
View File

@ -12,12 +12,12 @@
<context>
<name>AVSettings</name>
<message>
<location filename="../src/widget/form/settings/avsettings.ui" line="98"/>
<location filename="../src/widget/form/settings/avsettings.ui" line="112"/>
<source>Video Settings</source>
<translation>Настройки видео</translation>
</message>
<message>
<location filename="../src/widget/form/settings/avsettings.ui" line="109"/>
<location filename="../src/widget/form/settings/avsettings.ui" line="123"/>
<source>Resolution</source>
<translation>Разрешение</translation>
</message>
@ -47,22 +47,32 @@
<translation>Устройство записи</translation>
</message>
<message>
<location filename="../src/widget/form/settings/avsettings.ui" line="126"/>
<location filename="../src/widget/form/settings/avsettings.ui" line="95"/>
<source>Rescan audio devices</source>
<translation>Повторить поиск аудиоустройств</translation>
</message>
<message>
<location filename="../src/widget/form/settings/avsettings.ui" line="102"/>
<source>Filter audio</source>
<translation>Фильтрация звука</translation>
</message>
<message>
<location filename="../src/widget/form/settings/avsettings.ui" line="140"/>
<source>Hue</source>
<translation>Тон</translation>
</message>
<message>
<location filename="../src/widget/form/settings/avsettings.ui" line="140"/>
<location filename="../src/widget/form/settings/avsettings.ui" line="154"/>
<source>Brightness</source>
<translation>Яркость</translation>
</message>
<message>
<location filename="../src/widget/form/settings/avsettings.ui" line="154"/>
<location filename="../src/widget/form/settings/avsettings.ui" line="168"/>
<source>Saturation</source>
<translation>Насыщенность</translation>
</message>
<message>
<location filename="../src/widget/form/settings/avsettings.ui" line="168"/>
<location filename="../src/widget/form/settings/avsettings.ui" line="182"/>
<source>Contrast</source>
<translation>Контраст</translation>
</message>
@ -113,8 +123,14 @@
<message>
<location filename="../src/widget/form/addfriendform.cpp" line="100"/>
<source>qTox needs to use the Tox DNS, but can&apos;t do it through a proxy.
Ignore the proxy and connect to the Internet directly ?</source>
Ignore the proxy and connect to the Internet directly?</source>
<translation>qTox необходимо воспользоваться Tox DNS, но это нельзя сделать через прокси.
Игнорировать прокси и подлючиться напрямую через интернет?</translation>
</message>
<message>
<source>qTox needs to use the Tox DNS, but can&apos;t do it through a proxy.
Ignore the proxy and connect to the Internet directly ?</source>
<translation type="vanished">qTox необходимо воспользоваться Tox DNS, но это нельзя сделать через прокси.
Игнорировать прокси и подлючиться напрямую через интернет?</translation>
</message>
<message>
@ -152,7 +168,7 @@ Ignore the proxy and connect to the Internet directly ?</source>
<message>
<location filename="../src/widget/form/settings/advancedsettings.ui" line="14"/>
<source>Form</source>
<translation type="unfinished"></translation>
<translation>Form</translation>
</message>
<message>
<location filename="../src/widget/form/settings/advancedsettings.ui" line="35"/>
@ -183,48 +199,68 @@ Ignore the proxy and connect to the Internet directly ?</source>
<translation>Загрузить историю...</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="135"/>
<location filename="../src/widget/form/chatform.cpp" line="137"/>
<source>Send a file</source>
<translation>Отправить файл</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="145"/>
<source>File not read</source>
<translation>Файл не прочитать</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="145"/>
<source>qTox wasn&apos;t able to open %1</source>
<translatorcomment>Паравозик не смог. Не сможешь и ты!</translatorcomment>
<translation>qTox не смог открыть %1</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="150"/>
<source>Bad Idea</source>
<translation>Плохая идея</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="145"/>
<location filename="../src/widget/form/chatform.cpp" line="150"/>
<source>You&apos;re trying to send a special (sequential) file, that&apos;s not going to work!</source>
<translatorcomment>...передаёте последовательный файл и получаете te-le-fun-ken. И переводчик работает по другой линии. По линии «Библиотека».</translatorcomment>
<translation>Вы пытаетесь отправить специальный (последовательный) файл. Это так не работает!</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="251"/>
<source>%1 calling</source>
<location filename="../src/widget/form/chatform.cpp" line="257"/>
<source>%1 is calling</source>
<translation>%1 звонит</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="320"/>
<source>%1 calling</source>
<translation type="vanished">%1 звонит</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="328"/>
<source>%1 stopped calling</source>
<translation>%1 прекратил звонить</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="376"/>
<location filename="../src/widget/form/chatform.cpp" line="384"/>
<source>Calling to %1</source>
<translation>Звоним %1</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="517"/>
<location filename="../src/widget/form/chatform.cpp" line="525"/>
<source>Call rejected</source>
<translation>Звонок отклонён</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="801"/>
<location filename="../src/widget/form/chatform.cpp" line="676"/>
<source>Failed to send file &quot;%1&quot;</source>
<translation>Не удалось отправить файл «%1»</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="810"/>
<source>Call with %1 ended. %2</source>
<translation>Разговор с %1 завершился. %2</translation>
</message>
<message>
<location filename="../src/widget/form/chatform.cpp" line="820"/>
<location filename="../src/widget/form/chatform.cpp" line="829"/>
<source>Call duration: </source>
<translation>Длительность разговора:</translation>
</message>
@ -240,106 +276,120 @@ Ignore the proxy and connect to the Internet directly ?</source>
<context>
<name>Core</name>
<message>
<location filename="../src/core.cpp" line="226"/>
<location filename="../src/core.cpp" line="228"/>
<source>Toxing on qTox</source>
<translatorcomment>Как-то так. Может, можно ещё что-нибудь придумать?</translatorcomment>
<translation type="unfinished">Всем привет из qTox&apos;а</translation>
</message>
<message>
<location filename="../src/core.cpp" line="227"/>
<location filename="../src/core.cpp" line="229"/>
<source>qTox User</source>
<translation>Пользователь qTox</translation>
</message>
<message>
<location filename="../src/core.cpp" line="727"/>
<location filename="../src/core.cpp" line="733"/>
<source>Friend is already added</source>
<translation>Друг уже добавлен</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1168"/>
<location filename="../src/core.cpp" line="1174"/>
<source>Encryption error</source>
<translation>Ошибка шифрования</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1168"/>
<location filename="../src/core.cpp" line="1174"/>
<source>The .tox file is encrypted, but encryption was not checked, continuing regardless.</source>
<translation>Файл .tox зашифрован, однако шифрование в настройках включено не было. Продолжаем вопреки.</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1175"/>
<location filename="../src/core.cpp" line="1181"/>
<source>Tox datafile decryption password</source>
<translation>Пароль для расшифровки файла данных Tox</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1177"/>
<location filename="../src/core.cpp" line="1189"/>
<location filename="../src/core.cpp" line="1253"/>
<location filename="../src/core.cpp" line="1183"/>
<location filename="../src/core.cpp" line="1195"/>
<location filename="../src/core.cpp" line="1259"/>
<source>Password error</source>
<translation>Ошибка пароля</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1177"/>
<location filename="../src/core.cpp" line="1253"/>
<location filename="../src/core.cpp" line="1183"/>
<location filename="../src/core.cpp" line="1259"/>
<source>Failed to setup password.
Empty password.</source>
<translation>Не удалось установить пароль.
Пустой пароль.</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1185"/>
<location filename="../src/core.cpp" line="1191"/>
<source>Try Again</source>
<translation>Попробуйте ещё</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1186"/>
<location filename="../src/core.cpp" line="1192"/>
<source>Change profile</source>
<translation>Сменить профиль</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1187"/>
<location filename="../src/core.cpp" line="1193"/>
<source>Reinit current profile</source>
<translatorcomment>Увы, никто не знает, что разработчики имели в виду. Ту би транслейтед.</translatorcomment>
<translation>Сбросить данные текущего профиля</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1190"/>
<location filename="../src/core.cpp" line="1196"/>
<source>Wrong password has been entered</source>
<translation>Введён неправильный пароль</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1251"/>
<location filename="../src/core.cpp" line="1257"/>
<source>History Log decryption password</source>
<translation>Пароль для расшифровки журнала переписки</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1258"/>
<location filename="../src/core.cpp" line="1264"/>
<source>Encrypted log</source>
<translation>Зашифрованный журнал</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1259"/>
<source>Your history is encrypted with different password
<location filename="../src/core.cpp" line="1265"/>
<source>Your history is encrypted with different password.
Do you want to try another password?</source>
<translation>Ваша переписка зашифрована другим паролем
<translation>Ваша переписка зашифрована другим паролем.
Ходите попробовать другой пароль?</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1275"/>
<source>History</source>
<translation>История</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1275"/>
<source>Due to incorret password history will be disabled.</source>
<translation>Из-за некорректного пароля журналирование будет отключено.</translation>
</message>
<message>
<source>Your history is encrypted with different password
Do you want to try another password?</source>
<translation type="vanished">Ваша переписка зашифрована другим паролем
Ходите попробовать другой пароль?</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1269"/>
<source>Loggin</source>
<translation>Журналирование</translation>
<translation type="vanished">Журналирование</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1269"/>
<source>Due to incorret password logging will be disabled</source>
<translation>Из-за некорректного пароля журналирование будет отключено</translation>
<translation type="vanished">Из-за некорректного пароля журналирование будет отключено</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1342"/>
<location filename="../src/core.cpp" line="1348"/>
<source>NO Password</source>
<translation>БЕЗ пароля</translation>
</message>
<message>
<location filename="../src/core.cpp" line="1342"/>
<location filename="../src/core.cpp" line="1348"/>
<source>Will be saved without encryption!</source>
<translation>Будет сохранено без шифрования!</translation>
</message>
@ -466,14 +516,20 @@ Do you want to try another password?</source>
<translation>Выбрать папку для автоматического приёма</translation>
</message>
<message>
<location filename="../src/widget/friendwidget.cpp" line="226"/>
<location filename="../src/widget/friendwidget.cpp" line="238"/>
<source>User alias</source>
<translation>Псевдоним пользователя</translation>
</message>
<message>
<location filename="../src/widget/friendwidget.cpp" line="226"/>
<location filename="../src/widget/friendwidget.cpp" line="238"/>
<source>You can also set this by clicking the chat form name.
Alias:</source>
<translation>Можно также установить, щёлкнув по имени вверху окна чата.
Псевдоним:</translation>
</message>
<message>
<source>Alias:</source>
<translation>Новый псевдоним:</translation>
<translation type="obsolete">Новый псевдоним:</translation>
</message>
</context>
<context>
@ -484,25 +540,25 @@ Do you want to try another password?</source>
<translation>Общие</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalform.cpp" line="73"/>
<location filename="../src/widget/form/settings/generalform.cpp" line="79"/>
<location filename="../src/widget/form/settings/generalform.cpp" line="81"/>
<location filename="../src/widget/form/settings/generalform.cpp" line="87"/>
<source>None</source>
<translation>Отсутствует</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalform.cpp" line="223"/>
<location filename="../src/widget/form/settings/generalform.cpp" line="242"/>
<source>Choose an auto accept directory</source>
<comment>popup title</comment>
<translation>Выбрать папку для автоматического приёма</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalform.cpp" line="280"/>
<location filename="../src/widget/form/settings/generalform.cpp" line="299"/>
<source>Call active</source>
<comment>popup title</comment>
<translation>Идёт звонок</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalform.cpp" line="281"/>
<location filename="../src/widget/form/settings/generalform.cpp" line="300"/>
<source>You can&apos;t disconnect while a call is active!</source>
<comment>popup text</comment>
<translation>Нельзя отключиться пока идёт звонок!</translation>
@ -522,130 +578,140 @@ Do you want to try another password?</source>
<translation>Перевод не изменится до перезапуска qTox.</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="101"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="99"/>
<source>System tray integration</source>
<translation>Настройки трея</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="108"/>
<source>Show system tray icon</source>
<translation>Показывать иконку в трее</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="127"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="136"/>
<source>Close to tray</source>
<translation>Сворачивать в трей при закрытии</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="140"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="149"/>
<source>Minimize to tray</source>
<translation>Сворачивать в трей</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="156"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="158"/>
<source>Light icon</source>
<translation>Светлая иконка</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="175"/>
<source>Check for updates on startup (unstable)</source>
<translation>Проверять на наличие обновлений (нестабильно)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="163"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="182"/>
<source>Focus qTox when a message is received</source>
<translation>Захватывать фокус при приёме сообщений</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="170"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="189"/>
<source>Faux offline messaging</source>
<translation>Имитация офлайнового обмена сообщениями</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="185"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="204"/>
<source>Auto away after (0 to disable)</source>
<translation>Менять статус на «Отошёл» после (0 — не менять)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="198"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="217"/>
<source>Set to 0 to disable</source>
<translation>Укажите 0, чтобы отключить</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="221"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="240"/>
<source>You can set this on a per-friend basis by right clicking them.</source>
<comment>autoaccept cb tooltip</comment>
<translation>Можно настроить отдельно для каждого друга (щёлкнув правой кнопкой мыши по другу и выбрав соответствующий пункт меню).</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="272"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="291"/>
<source>Use emoticons</source>
<translation>Использовать смайлики</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="281"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="306"/>
<source>Smiley Pack</source>
<extracomment>Text on smiley pack label</extracomment>
<translation>Набор смайликов</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="359"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="323"/>
<source>Style</source>
<translation>Стиль</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="380"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="397"/>
<source>Theme color</source>
<translation>Цвет темы</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="401"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="414"/>
<source>Emoticon size</source>
<translation>Размер смайликов</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="417"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="430"/>
<source> px</source>
<translatorcomment>По аналогии с Мпикс. Хотя, может лучше принять http://ilyabirman.ru/meanwhile/all/px/?</translatorcomment>
<translation> пикс</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="437"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="446"/>
<source>Timestamp format</source>
<translation>Формат времени</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="459"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="468"/>
<source>Connection Settings</source>
<translation>Настройки соединения</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="471"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="480"/>
<source>Enable IPv6 (recommended)</source>
<extracomment>Text on a checkbox to enable IPv6</extracomment>
<translation>Включить IPv6 (рекомендуется)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="478"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="487"/>
<source>Disabling this allows, e.g., toxing over Tor. It adds load to the Tox network however, so uncheck only when necessary.</source>
<extracomment>force tcp checkbox tooltip</extracomment>
<translation>Отключение позволяет, например, использовать Tox поверх Tor. Однако это добавляет нагрузку на сеть Tox, так что отключайте только в случае необходимости.</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="481"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="490"/>
<source>Enable UDP (recommended)</source>
<extracomment>Text on checkbox to disable UDP</extracomment>
<translation>Включить UDP (рекомендуется)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="488"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="497"/>
<source>Use proxy (SOCKS5)</source>
<translation>Использовать прокси (SOCKS5)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="500"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="509"/>
<source>Address</source>
<extracomment>Text on proxy addr label</extracomment>
<translation>Адрес</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="510"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="519"/>
<source>Port</source>
<extracomment>Text on proxy port label</extracomment>
<translation>Порт</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="529"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="538"/>
<source>Reconnect</source>
<comment>reconnect button</comment>
<translation>Переподключиться</translation>
@ -667,42 +733,42 @@ Do you want to try another password?</source>
<translation>Портативный режим</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="114"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="123"/>
<source>Start in tray</source>
<translation>Запускать свёрнутым в трей</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="149"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="168"/>
<source>Show contacts&apos; status changes</source>
<translation>Показывать изменения статусов контактов</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="179"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="198"/>
<source>Provided in minutes</source>
<translation>Выставлено в минутах</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="204"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="220"/>
<source> minutes</source>
<translation> минут</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="224"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="243"/>
<source>Autoaccept files</source>
<translation>Автоматически принимать файлы</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="233"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="252"/>
<source>Save files in</source>
<translation>Сохранять в</translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="246"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="265"/>
<source>PushButton</source>
<translation></translation>
</message>
<message>
<location filename="../src/widget/form/settings/generalsettings.ui" line="266"/>
<location filename="../src/widget/form/settings/generalsettings.ui" line="285"/>
<source>Theme</source>
<translation>Тема</translation>
</message>
@ -710,53 +776,53 @@ Do you want to try another password?</source>
<context>
<name>GenericChatForm</name>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="62"/>
<location filename="../src/widget/form/genericchatform.cpp" line="65"/>
<source>Send message</source>
<translation>Отправить сообщение</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="64"/>
<location filename="../src/widget/form/genericchatform.cpp" line="67"/>
<source>Smileys</source>
<translation>Смайлики</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="68"/>
<location filename="../src/widget/form/genericchatform.cpp" line="71"/>
<source>Send file(s)</source>
<translation>Отправить файл(ы)</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="71"/>
<source>Audio call: RED means you&apos;re on a call</source>
<translation>Позвонить, только аудио (красная кнопка значит что вы на связи)</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="74"/>
<source>Video call: RED means you&apos;re on a call</source>
<translation>Видеозвонок (красная кнопка значит что вы на связи)</translation>
<source>Audio call: RED means you&apos;re on a call</source>
<translation>Позвонить, только аудио (красная кнопка означает что вы на связи)</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="77"/>
<source>Toggle speakers volume: RED is OFF</source>
<translation>Включить или выключить звук (красная кнопка значит что звук выключен)</translation>
<source>Video call: RED means you&apos;re on a call</source>
<translation>Видеозвонок (красная кнопка означает что вы на связи)</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="80"/>
<source>Toggle microphone: RED is OFF</source>
<translation>Включить или выключить микрофон (красная кнопка значит что микрофон выключен)</translation>
<source>Toggle speakers volume: RED is OFF</source>
<translation>Включить или выключить звук (красная кнопка означает что звук выключен)</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="146"/>
<location filename="../src/widget/form/genericchatform.cpp" line="188"/>
<location filename="../src/widget/form/genericchatform.cpp" line="83"/>
<source>Toggle microphone: RED is OFF</source>
<translation>Включить или выключить микрофон (красная кнопка означает что микрофон выключен)</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="149"/>
<location filename="../src/widget/form/genericchatform.cpp" line="192"/>
<source>Save chat log</source>
<translation>Сохранить журнал чата</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="147"/>
<location filename="../src/widget/form/genericchatform.cpp" line="150"/>
<source>Clear displayed messages</source>
<translation>Очистить показываемые сообщения</translation>
</message>
<message>
<location filename="../src/widget/form/genericchatform.cpp" line="305"/>
<location filename="../src/widget/form/genericchatform.cpp" line="296"/>
<source>Cleared</source>
<translation>Очищено</translation>
</message>
@ -764,13 +830,13 @@ Do you want to try another password?</source>
<context>
<name>GroupChatForm</name>
<message>
<location filename="../src/widget/form/groupchatform.cpp" line="58"/>
<location filename="../src/widget/form/groupchatform.cpp" line="57"/>
<source>%1 users in chat</source>
<comment>Number of users in chat</comment>
<translation>%1 пользователей в чате</translation>
</message>
<message>
<location filename="../src/widget/form/groupchatform.cpp" line="109"/>
<location filename="../src/widget/form/groupchatform.cpp" line="108"/>
<source>%1 users in chat</source>
<translation>%1 пользователей в чате</translation>
</message>
@ -778,23 +844,40 @@ Do you want to try another password?</source>
<context>
<name>GroupWidget</name>
<message>
<location filename="../src/widget/groupwidget.cpp" line="53"/>
<location filename="../src/widget/groupwidget.cpp" line="55"/>
<source>Quit group</source>
<comment>Menu to quit a groupchat</comment>
<translation>Покинуть группу</translation>
</message>
<message>
<location filename="../src/widget/groupwidget.cpp" line="42"/>
<location filename="../src/widget/groupwidget.cpp" line="64"/>
<location filename="../src/widget/groupwidget.cpp" line="43"/>
<location filename="../src/widget/groupwidget.cpp" line="80"/>
<source>%1 users in chat</source>
<translation>%1 пользователей в чате</translation>
</message>
<message>
<location filename="../src/widget/groupwidget.cpp" line="44"/>
<location filename="../src/widget/groupwidget.cpp" line="66"/>
<location filename="../src/widget/groupwidget.cpp" line="45"/>
<location filename="../src/widget/groupwidget.cpp" line="82"/>
<source>0 users in chat</source>
<translation>Ни одного пользователя в чате</translation>
</message>
<message>
<location filename="../src/widget/groupwidget.cpp" line="54"/>
<source>Set title...</source>
<translation>Установить заголовок...</translation>
</message>
<message>
<location filename="../src/widget/groupwidget.cpp" line="67"/>
<source>Group title</source>
<translation>Заголовок группы</translation>
</message>
<message>
<location filename="../src/widget/groupwidget.cpp" line="67"/>
<source>You can also set this by clicking the chat form name.
Title:</source>
<translation>Можно также установить, щёлкнув по заголовку вверху окна чата.
Заголовок:</translation>
</message>
</context>
<context>
<name>IdentityForm</name>
@ -885,42 +968,49 @@ Do you want to try another password?</source>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="199"/>
<source>Are you sure you want to delete this profile?</source>
<source>Are you sure you want to delete this profile?
Associated friend information and chat logs will be deleted as well.</source>
<comment>deletion confirmation text</comment>
<translation>Вы действительно хотите удалить этот профиль?</translation>
<translation>Вы действительно хотите удалить этот профиль?
Связанная с ним информация о друзьях и история переписки будут также удалены.</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="211"/>
<source>Are you sure you want to delete this profile?</source>
<comment>deletion confirmation text</comment>
<translation type="vanished">Вы действительно хотите удалить этот профиль?</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="218"/>
<source>Import profile</source>
<comment>import dialog title</comment>
<translation>Импортировать профиль</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="213"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="220"/>
<source>Tox save file (*.tox)</source>
<comment>import dialog filter</comment>
<translation>Файл Tox (*.tox)</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="223"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="230"/>
<source>Ignoring non-Tox file</source>
<comment>popup title</comment>
<translation>Выбран не файл Tox</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="224"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="231"/>
<source>Warning: you&apos;ve chosen a file that is not a Tox save file; ignoring.</source>
<comment>popup text</comment>
<translation>Внимание: вы выбрали не файл Tox; игнорирование.</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="230"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="237"/>
<source>Profile already exists</source>
<comment>import confirm title</comment>
<translation>Профиль уже существует</translation>
</message>
<message>
<location filename="../src/widget/form/settings/identityform.cpp" line="231"/>
<location filename="../src/widget/form/settings/identityform.cpp" line="238"/>
<source>A profile named &quot;%1&quot; already exists. Do you want to erase it?</source>
<comment>import confirm text</comment>
<translation>Профиль с именем «%1» уже существует. Перезаписать?</translation>
@ -1151,16 +1241,22 @@ Do you want to delete old history file?</source>
<context>
<name>QObject</name>
<message>
<location filename="../src/autoupdate.cpp" line="431"/>
<location filename="../src/autoupdate.cpp" line="430"/>
<source>Update</source>
<comment>The title of a message box</comment>
<translation>Обновление</translation>
</message>
<message>
<location filename="../src/autoupdate.cpp" line="432"/>
<location filename="../src/autoupdate.cpp" line="431"/>
<source>An update is available, do you want to download it now?
It will be installed when qTox restarts.</source>
<translation>Обновление доступно, не желаете ли скачать его прямо сейчас?
Оно будет установлено после того, как qTox будет перезапущен.</translation>
</message>
<message>
<source>An update is available, do you want to download it now ?
It will be installed when qTox restarts.</source>
<translation>Обновление доступно, не желаете ли скачать его прамо сейчас?
<translation type="vanished">Обновление доступно, не желаете ли скачать его прамо сейчас?
Оно будет установлено после того, как qTox будет перезапущен.</translation>
</message>
<message>
@ -1209,6 +1305,18 @@ It will be installed when qTox restarts.</source>
<translatorcomment>Без перевода, так как весь остальной CLI на английском</translatorcomment>
<translation>Tox URI to parse</translation>
</message>
<message>
<location filename="../src/main.cpp" line="69"/>
<source>Starts new instance and loads specified profile.</source>
<translatorcomment>Без перевода, так как весь остальной CLI на английском</translatorcomment>
<translation>Starts new instance and loads specified profile.</translation>
</message>
<message>
<location filename="../src/main.cpp" line="69"/>
<source>profile</source>
<translatorcomment>Без перевода, так как весь остальной CLI на английском</translatorcomment>
<translation>profile</translation>
</message>
<message>
<location filename="../src/misc/style.cpp" line="72"/>
<source>Default</source>
@ -1309,8 +1417,12 @@ It will be installed when qTox restarts.</source>
<translation>Добавить друга</translation>
</message>
<message>
<location filename="../src/widget/toxuri.cpp" line="82"/>
<source>Do you want to add %1 as a friend ?</source>
<translation type="vanished">Хотите добавить %1 в друзья?</translation>
</message>
<message>
<location filename="../src/widget/toxuri.cpp" line="82"/>
<source>Do you want to add %1 as a friend?</source>
<translation>Хотите добавить %1 в друзья?</translation>
</message>
<message>
@ -1339,160 +1451,160 @@ It will be installed when qTox restarts.</source>
<context>
<name>Widget</name>
<message>
<location filename="../src/widget/widget.cpp" line="75"/>
<location filename="../src/widget/widget.cpp" line="92"/>
<source>Online</source>
<translation>В сети</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="78"/>
<location filename="../src/widget/widget.cpp" line="95"/>
<source>Away</source>
<translation>Отошёл</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="81"/>
<location filename="../src/widget/widget.cpp" line="98"/>
<source>Busy</source>
<translation>Занят</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="84"/>
<location filename="../src/widget/widget.cpp" line="101"/>
<source>&amp;Quit</source>
<translation>В&amp;ыход</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="87"/>
<location filename="../src/widget/widget.cpp" line="104"/>
<source>Change status to:</source>
<translation>Сменить статус на:</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="161"/>
<location filename="../src/widget/widget.cpp" line="174"/>
<source>Online</source>
<comment>Button to set your status to &apos;Online&apos;</comment>
<translation>В сети</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="163"/>
<location filename="../src/widget/widget.cpp" line="176"/>
<source>Away</source>
<comment>Button to set your status to &apos;Away&apos;</comment>
<translatorcomment>Вероятно, это не столь долгое путешествие</translatorcomment>
<translation>Отошёл</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="165"/>
<location filename="../src/widget/widget.cpp" line="178"/>
<source>Busy</source>
<comment>Button to set your status to &apos;Busy&apos;</comment>
<translation>Занят</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="397"/>
<location filename="../src/widget/widget.cpp" line="430"/>
<source>Choose a profile</source>
<translation>Выберите профиль</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="398"/>
<location filename="../src/widget/widget.cpp" line="431"/>
<source>Please choose which identity to use</source>
<translation>Выберите личность, которую хотите использовать</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="419"/>
<location filename="../src/widget/widget.cpp" line="452"/>
<source>Choose a profile picture</source>
<translation>Выбрать картинку для профиля</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="426"/>
<location filename="../src/widget/widget.cpp" line="433"/>
<location filename="../src/widget/widget.cpp" line="454"/>
<location filename="../src/widget/widget.cpp" line="459"/>
<location filename="../src/widget/widget.cpp" line="466"/>
<location filename="../src/widget/widget.cpp" line="487"/>
<source>Error</source>
<translation>Ошибка</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="426"/>
<location filename="../src/widget/widget.cpp" line="459"/>
<source>Unable to open this file</source>
<translation>Невозможно открыть файл</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="433"/>
<location filename="../src/widget/widget.cpp" line="466"/>
<source>Unable to read this image</source>
<translation>Невозможно прочесть это изображение</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="454"/>
<location filename="../src/widget/widget.cpp" line="487"/>
<source>This image is too big</source>
<translation>Это изображение слишком большое</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="481"/>
<location filename="../src/widget/widget.cpp" line="527"/>
<source>Toxcore failed to start, the application will terminate after you close this message.</source>
<translation>Не удалось запустить toxcore, приложение будет завершено после того как вы закроете это сообщение.</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="490"/>
<location filename="../src/widget/widget.cpp" line="536"/>
<source>toxcore failed to start with your proxy settings. qTox cannot run; please modify your settings and restart.</source>
<comment>popup text</comment>
<translation>Не удалось запустить toxcore с вашими настройками прокси, qTox не может работать; измените ваши настройки и перезапустите его.</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="530"/>
<location filename="../src/widget/widget.cpp" line="575"/>
<source>Add friend</source>
<translation>Добавить друга</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="542"/>
<location filename="../src/widget/widget.cpp" line="587"/>
<source>File transfers</source>
<translation>Передачи файлов</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="567"/>
<location filename="../src/widget/widget.cpp" line="615"/>
<source>Settings</source>
<translation>Настройки</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="666"/>
<location filename="../src/widget/widget.cpp" line="715"/>
<source>Couldn&apos;t request friendship</source>
<translation type="unfinished">Не удалось запросить добавление в друзья</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="694"/>
<location filename="../src/widget/widget.cpp" line="743"/>
<source>away</source>
<comment>contact status</comment>
<translation>отсутствует</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="696"/>
<location filename="../src/widget/widget.cpp" line="745"/>
<source>busy</source>
<comment>contact status</comment>
<translation>занят</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="698"/>
<location filename="../src/widget/widget.cpp" line="747"/>
<source>offline</source>
<comment>contact status</comment>
<translation>офлайн</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="700"/>
<location filename="../src/widget/widget.cpp" line="749"/>
<source>online</source>
<comment>contact status</comment>
<translation>в сети</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="703"/>
<location filename="../src/widget/widget.cpp" line="752"/>
<source>%1 is now %2</source>
<comment>e.g. &quot;Dubslow is now online&quot;</comment>
<translation>%1 сейчас %2</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="937"/>
<location filename="../src/widget/widget.cpp" line="989"/>
<source>&lt;Unknown&gt;</source>
<comment>Placeholder when we don&apos;t know someone&apos;s name in a group chat</comment>
<translation>&lt;Неизвестный&gt;</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="960"/>
<location filename="../src/widget/widget.cpp" line="1014"/>
<source>%1 has set the title to %2</source>
<translation>%1 сменил заголовок на %2</translation>
</message>
<message>
<location filename="../src/widget/widget.cpp" line="1109"/>
<location filename="../src/widget/widget.cpp" line="1165"/>
<source>Message failed to send</source>
<translation>Не удалось отправить сообщение</translation>
</message>

422
translations/uk.ts vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,9 @@
QLineEdit {
color: @black;
background: white;
border: 0px;
}
#nameLabel {
color: @black;
font: @mediumBold;

View File

@ -34,7 +34,7 @@ div.date_me {
}
span.quote {
color: #6bc260;
color: #279419;
}
div.green {
@ -87,3 +87,7 @@ div.button {
margin-left: 0px;
color: @white;
}
a {
color: blue;
}

View File

@ -5,7 +5,7 @@ QPushButton#green
background-repeat: none;
border: none;
width: 25px;
height: 20px;
height: 18px;
}
QPushButton#green:hover
@ -20,7 +20,7 @@ QPushButton#red
background-repeat: none;
border: none;
width: 25px;
height: 20px;
height: 18px;
}
QPushButton:focus {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 637 B

After

Width:  |  Height:  |  Size: 624 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 597 B

After

Width:  |  Height:  |  Size: 590 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 629 B

After

Width:  |  Height:  |  Size: 617 B