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

Merge commit '5a005a1aafe96061301a4e113cb5450770009b88' into profiles

Conflicts:
	core.cpp
	widget/form/settingsform.cpp
	widget/form/settingsform.h
This commit is contained in:
Dubslow 2014-09-12 13:53:29 -05:00
commit d16b6cd283
69 changed files with 673 additions and 423 deletions

6
.gitignore vendored
View File

@ -1,2 +1,8 @@
*.pro.user* *.pro.user*
libs libs
*.o
moc_*
ui_*
qrc_*
Makefile
qtox

View File

@ -131,17 +131,17 @@ First of all install the dependencies of Tox Core.
Debian: Debian:
```bash ```bash
sudo apt-get install libtool autotools-dev automake checkinstall check yasm libopus-dev libvpx-dev sudo apt-get install libtool autotools-dev automake checkinstall check libopus-dev libvpx-dev
``` ```
Ubuntu: Ubuntu:
```bash ```bash
sudo apt-get install libtool autotools-dev automake checkinstall check yasm libopus-dev libvpx-dev sudo apt-get install libtool autotools-dev automake checkinstall check libopus-dev libvpx-dev
``` ```
Arch Linux: (Arch Linux provides the package "tox-git" in AUR) Arch Linux: (Arch Linux provides the package "tox-git" in AUR)
```bash ```bash
sudo pacman -S --needed yasm opus vpx sudo pacman -S --needed opus vpx
``` ```
Fedora: Fedora:

View File

@ -25,8 +25,7 @@ This client runs on Windows, Linux and Mac natively.<br/>
<h3>Screenshots</h3> <h3>Screenshots</h3>
<h5>Note: The screenshots may not always be up to date, but they should give a good idea of the general look and features</h5> <h5>Note: The screenshots may not always be up to date, but they should give a good idea of the general look and features</h5>
<img src="http://i.imgur.com/mMUdr6u.png"/> <img src="https://i.imgur.com/7Jg5tQa.png">/
<img src="http://i.imgur.com/66ARBGC.png"/>
##Documentation: ##Documentation:

BIN
audio/notification.pcm Normal file

Binary file not shown.

Binary file not shown.

View File

@ -21,7 +21,7 @@ TOX_CORE_DIR=libtoxcore-latest
# the default value is 'false' and will be set to 'true' # the default value is 'false' and will be set to 'true'
# if this script gets the parameter -t or --tox # if this script gets the parameter -t or --tox
TOX_ONLY=false TOX_ONLY=false
GLOBAL=false GLOBAL=true
KEEP=false KEEP=false
if [ -z "$BASE_DIR" ]; then if [ -z "$BASE_DIR" ]; then
@ -49,8 +49,8 @@ while [ $# -ge 1 ] ; do
if [ ${1} = "-t" -o ${1} = "--tox" ] ; then if [ ${1} = "-t" -o ${1} = "--tox" ] ; then
TOX_ONLY=true TOX_ONLY=true
shift shift
elif [ ${1} = "-g" -o ${1} = "--global" ] ; then elif [ ${1} = "-l" -o ${1} = "--local" ] ; then
GLOBAL=true GLOBAL=false
shift shift
elif [ ${1} = "-k" -o ${1} = "--keep" ]; then elif [ ${1} = "-k" -o ${1} = "--keep" ]; then
KEEP=true KEEP=true
@ -71,8 +71,8 @@ while [ $# -ge 1 ] ; do
echo " -h|--help : displays this help" echo " -h|--help : displays this help"
echo " -t|--tox : only install/update libtoxcore" echo " -t|--tox : only install/update libtoxcore"
echo " requires an already installed libsodium" echo " requires an already installed libsodium"
echo " -g|--global: installs libtox* and libsodium globally" echo " -l|--local : installs libtox* and libsodium in the current directory,"
echo " (also disables local configure prefixes)" echo " as opposed to the system directories"
echo " -k|--keep : does not delete the build directories afterwards" echo " -k|--keep : does not delete the build directories afterwards"
echo "" echo ""
echo "example usages:" echo "example usages:"
@ -147,6 +147,10 @@ fi
popd popd
if [[ $GLOBAL = "true" ]]; then
sudo ldconfig
fi
############### cleanup step ############### ############### cleanup step ###############
# remove cloned repositories # remove cloned repositories
if [[ $KEEP = "false" ]]; then if [[ $KEEP = "false" ]]; then

View File

@ -15,6 +15,8 @@
*/ */
#include "cdata.h" #include "cdata.h"
#include <QString>
#include <tox/tox.h>
// CData // CData
@ -54,6 +56,8 @@ uint16_t CData::fromString(const QString& data, uint8_t* cData)
// CUserId // CUserId
const uint16_t CUserId::SIZE{TOX_CLIENT_ID_SIZE};
CUserId::CUserId(const QString &userId) : CUserId::CUserId(const QString &userId) :
CData(userId, SIZE) CData(userId, SIZE)
{ {
@ -68,6 +72,8 @@ QString CUserId::toString(const uint8_t* cUserId)
// CFriendAddress // CFriendAddress
const uint16_t CFriendAddress::SIZE{TOX_FRIEND_ADDRESS_SIZE};
CFriendAddress::CFriendAddress(const QString &friendAddress) : CFriendAddress::CFriendAddress(const QString &friendAddress) :
CData(friendAddress, SIZE) CData(friendAddress, SIZE)
{ {

View File

@ -18,9 +18,8 @@
#define CDATA_H #define CDATA_H
#include <cstdint> #include <cstdint>
#include <QString>
#include "tox/tox.h"
class QString;
class CData class CData
{ {
public: public:
@ -48,7 +47,7 @@ public:
static QString toString(const uint8_t *cUserId); static QString toString(const uint8_t *cUserId);
private: private:
static const uint16_t SIZE = TOX_CLIENT_ID_SIZE; static const uint16_t SIZE;
}; };
@ -60,7 +59,7 @@ public:
static QString toString(const uint8_t* cFriendAddress); static QString toString(const uint8_t* cFriendAddress);
private: private:
static const uint16_t SIZE = TOX_FRIEND_ADDRESS_SIZE; static const uint16_t SIZE;
}; };

View File

@ -20,6 +20,8 @@
#include "settings.h" #include "settings.h"
#include "widget/widget.h" #include "widget/widget.h"
#include <tox/tox.h>
#include <ctime> #include <ctime>
#include <functional> #include <functional>
@ -28,9 +30,10 @@
#include <QFile> #include <QFile>
#include <QSaveFile> #include <QSaveFile>
#include <QStandardPaths> #include <QStandardPaths>
#include <QtEndian>
#include <QThread> #include <QThread>
#include <QtConcurrent/QtConcurrent> #include <QTimer>
#include <QCoreApplication>
#include <QDateTime>
const QString Core::CONFIG_FILE_NAME = "data"; const QString Core::CONFIG_FILE_NAME = "data";
const QString Core::TOX_EXT = ".tox"; const QString Core::TOX_EXT = ".tox";
@ -113,6 +116,11 @@ Core::~Core()
alcCaptureCloseDevice(alInDev); alcCaptureCloseDevice(alInDev);
} }
Core* Core::getInstance()
{
return Widget::getInstance()->getCore();
}
void Core::get_tox() void Core::get_tox()
{ {
// IPv6 needed for LAN discovery, but can crash some weird routers. On by default, can be disabled in options. // IPv6 needed for LAN discovery, but can crash some weird routers. On by default, can be disabled in options.
@ -406,6 +414,14 @@ void Core::onFileControlCallback(Tox* tox, int32_t friendnumber, uint8_t receive
tox_file_send_control(tox, file->friendId, 1, file->fileNum, TOX_FILECONTROL_FINISHED, nullptr, 0); tox_file_send_control(tox, file->friendId, 1, file->fileNum, TOX_FILECONTROL_FINISHED, nullptr, 0);
removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum); removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum);
} }
else if (receive_send == 0 && control_type == TOX_FILECONTROL_ACCEPT)
{
emit static_cast<Core*>(core)->fileTransferRemotePausedUnpaused(*file, false);
}
else if ((receive_send == 0 || receive_send == 1) && control_type == TOX_FILECONTROL_PAUSE)
{
emit static_cast<Core*>(core)->fileTransferRemotePausedUnpaused(*file, true);
}
else else
{ {
qDebug() << QString("Core: File control callback, receive_send=%1, control_type=%2") qDebug() << QString("Core: File control callback, receive_send=%1, control_type=%2")
@ -702,15 +718,6 @@ void Core::removeGroup(int groupId)
tox_del_groupchat(tox, groupId); tox_del_groupchat(tox, groupId);
} }
QString Core::getIDString()
{
uint8_t friendAddress[TOX_FRIEND_ADDRESS_SIZE];
tox_get_address(tox, friendAddress);
return CFriendAddress::toString(friendAddress).left(12);
// 12 is the smallest multiple of four such that
// 16^n > 10^10 (which is roughly the planet's population)
}
QString Core::getUsername() QString Core::getUsername()
{ {
int size = tox_get_self_name_size(tox); int size = tox_get_self_name_size(tox);
@ -734,6 +741,21 @@ void Core::setUsername(const QString& username)
} }
} }
QString Core::getSelfId()
{
uint8_t friendAddress[TOX_FRIEND_ADDRESS_SIZE];
tox_get_address(tox, friendAddress);
return CFriendAddress::toString(friendAddress);
}
QString Core::getIDString()
{
return getSelfId().left(12);
// 12 is the smallest multiple of four such that
// 16^n > 10^10 (which is roughly the planet's population)
}
QString Core::getStatusMessage() QString Core::getStatusMessage()
{ {
int size = tox_get_self_status_message_size(tox); int size = tox_get_self_status_message_size(tox);

96
core.h
View File

@ -17,102 +17,24 @@
#ifndef CORE_HPP #ifndef CORE_HPP
#define CORE_HPP #define CORE_HPP
#include <tox/tox.h>
#include <tox/toxav.h>
#if defined(__APPLE__) && defined(__MACH__)
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#endif
#include <cstdint> #include <cstdint>
#include <QDateTime>
#include <QObject> #include <QObject>
#include <QTimer>
#include <QString>
#include <QFile>
#include <QList>
#include <QByteArray>
#define TOXAV_MAX_CALLS 16 #include "corestructs.h"
#define GROUPCHAT_MAX_SIZE 32 #include "coreav.h"
#define TOX_SAVE_INTERVAL 30*1000 #include "coredefines.h"
#define TOX_FILE_INTERVAL 0
#define TOX_BOOTSTRAP_INTERVAL 5*1000
#define TOXAV_RINGING_TIME 15
// TODO: Put that in the settings
#define TOXAV_MAX_VIDEO_WIDTH 1600
#define TOXAV_MAX_VIDEO_HEIGHT 1200
template <typename T> class QList;
class Camera; class Camera;
class QTimer;
enum class Status : int {Online = 0, Away, Busy, Offline}; class QString;
struct DhtServer
{
QString name;
QString userId;
QString address;
int port;
};
struct ToxFile
{
enum FileStatus
{
STOPPED,
PAUSED,
TRANSMITTING
};
enum FileDirection : bool
{
SENDING,
RECEIVING
};
ToxFile()=default;
ToxFile(int FileNum, int FriendId, QByteArray FileName, QString FilePath, FileDirection Direction)
: fileNum(FileNum), friendId(FriendId), fileName{FileName}, filePath{FilePath}, file{new QFile(filePath)},
bytesSent{0}, filesize{0}, status{STOPPED}, direction{Direction}, sendTimer{nullptr} {}
~ToxFile(){}
void setFilePath(QString path) {filePath=path; file->setFileName(path);}
bool open(bool write) {return write?file->open(QIODevice::ReadWrite):file->open(QIODevice::ReadOnly);}
int fileNum;
int friendId;
QByteArray fileName;
QString filePath;
QFile* file;
long long bytesSent;
long long filesize;
FileStatus status;
FileDirection direction;
QTimer* sendTimer;
};
struct ToxCall
{
public:
ToxAvCSettings codecSettings;
QTimer *sendAudioTimer, *sendVideoTimer;
int callId;
int friendId;
bool videoEnabled;
bool active;
bool muteMic;
ALuint alSource;
};
class Core : public QObject class Core : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit Core(Camera* cam, QThread* coreThread); explicit Core(Camera* cam, QThread* coreThread);
static Core* getInstance(); ///< Returns the global widget's Core instance
~Core(); ~Core();
static const QString TOX_EXT; static const QString TOX_EXT;
@ -133,6 +55,7 @@ public:
QString getUsername(); QString getUsername();
QString getStatusMessage(); QString getStatusMessage();
QString getSelfId();
void increaseVideoBusyness(); void increaseVideoBusyness();
void decreaseVideoBusyness(); void decreaseVideoBusyness();
@ -230,6 +153,7 @@ signals:
void fileDownloadFinished(const QString& path); void fileDownloadFinished(const QString& path);
void fileTransferPaused(int FriendId, int FileNum, ToxFile::FileDirection direction); void fileTransferPaused(int FriendId, int FileNum, ToxFile::FileDirection direction);
void fileTransferInfo(int FriendId, int FileNum, int64_t Filesize, int64_t BytesSent, ToxFile::FileDirection direction); void fileTransferInfo(int FriendId, int FileNum, int64_t Filesize, int64_t BytesSent, ToxFile::FileDirection direction);
void fileTransferRemotePausedUnpaused(ToxFile file, bool paused);
void avInvite(int friendId, int callIndex, bool video); void avInvite(int friendId, int callIndex, bool video);
void avStart(int friendId, int callIndex, bool video); void avStart(int friendId, int callIndex, bool video);
@ -308,7 +232,7 @@ private:
QList<DhtServer> dhtServerList; QList<DhtServer> dhtServerList;
int dhtServerId; int dhtServerId;
static QList<ToxFile> fileSendQueue, fileRecvQueue; static QList<ToxFile> fileSendQueue, fileRecvQueue;
static ToxCall calls[TOXAV_MAX_CALLS]; static ToxCall calls[];
static const QString CONFIG_FILE_NAME; static const QString CONFIG_FILE_NAME;
static const int videobufsize; static const int videobufsize;

View File

@ -15,7 +15,9 @@
*/ */
#include "core.h" #include "core.h"
#include "widget/widget.h" #include "widget/camera.h"
#include <QDebug>
#include <QTimer>
ToxCall Core::calls[TOXAV_MAX_CALLS]; ToxCall Core::calls[TOXAV_MAX_CALLS];
const int Core::videobufsize{TOXAV_MAX_VIDEO_WIDTH * TOXAV_MAX_VIDEO_HEIGHT * 4}; const int Core::videobufsize{TOXAV_MAX_VIDEO_WIDTH * TOXAV_MAX_VIDEO_HEIGHT * 4};
@ -55,7 +57,7 @@ void Core::prepareCall(int friendId, int callId, ToxAv* toxav, bool videoEnabled
if (calls[callId].videoEnabled) if (calls[callId].videoEnabled)
{ {
calls[callId].sendVideoTimer->start(); calls[callId].sendVideoTimer->start();
Widget::getInstance()->getCamera()->suscribe(); Camera::getInstance()->suscribe();
} }
} }
@ -71,12 +73,12 @@ void Core::onAvMediaChange(void* toxav, int32_t callId, void* core)
{ {
calls[callId].videoEnabled = false; calls[callId].videoEnabled = false;
calls[callId].sendVideoTimer->stop(); calls[callId].sendVideoTimer->stop();
Widget::getInstance()->getCamera()->unsuscribe(); Camera::getInstance()->unsuscribe();
emit ((Core*)core)->avMediaChange(friendId, callId, false); emit ((Core*)core)->avMediaChange(friendId, callId, false);
} }
else else
{ {
Widget::getInstance()->getCamera()->suscribe(); Camera::getInstance()->suscribe();
calls[callId].videoEnabled = true; calls[callId].videoEnabled = true;
calls[callId].sendVideoTimer->start(); calls[callId].sendVideoTimer->start();
emit ((Core*)core)->avMediaChange(friendId, callId, true); emit ((Core*)core)->avMediaChange(friendId, callId, true);
@ -159,7 +161,7 @@ void Core::cleanupCall(int callId)
calls[callId].sendAudioTimer->stop(); calls[callId].sendAudioTimer->stop();
calls[callId].sendVideoTimer->stop(); calls[callId].sendVideoTimer->stop();
if (calls[callId].videoEnabled) if (calls[callId].videoEnabled)
Widget::getInstance()->getCamera()->unsuscribe(); Camera::getInstance()->unsuscribe();
alcCaptureStop(alInDev); alcCaptureStop(alInDev);
} }
@ -224,7 +226,7 @@ void Core::playCallVideo(ToxAv*, int32_t callId, vpx_image_t* img, void *user_da
if (videoBusyness >= 1) if (videoBusyness >= 1)
qWarning() << "Core: playCallVideo: Busy, dropping current frame"; qWarning() << "Core: playCallVideo: Busy, dropping current frame";
else else
emit Widget::getInstance()->getCore()->videoFrameReceived(img); emit Core::getInstance()->videoFrameReceived(img);
vpx_img_free(img); vpx_img_free(img);
} }

29
coreav.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef COREAV_H
#define COREAV_H
#include <tox/toxav.h>
#if defined(__APPLE__) && defined(__MACH__)
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#endif
class QTimer;
struct ToxCall
{
public:
ToxAvCSettings codecSettings;
QTimer *sendAudioTimer, *sendVideoTimer;
int callId;
int friendId;
bool videoEnabled;
bool active;
bool muteMic;
ALuint alSource;
};
#endif // COREAV_H

15
coredefines.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef COREDEFINES_H
#define COREDEFINES_H
#define TOXAV_MAX_CALLS 16
#define GROUPCHAT_MAX_SIZE 32
#define TOX_SAVE_INTERVAL 30*1000
#define TOX_FILE_INTERVAL 0
#define TOX_BOOTSTRAP_INTERVAL 5*1000
#define TOXAV_RINGING_TIME 15
// TODO: Put that in the settings
#define TOXAV_MAX_VIDEO_WIDTH 1600
#define TOXAV_MAX_VIDEO_HEIGHT 1200
#endif // COREDEFINES_H

19
corestructs.cpp Normal file
View File

@ -0,0 +1,19 @@
#include "corestructs.h"
#include <QFile>
ToxFile::ToxFile(int FileNum, int FriendId, QByteArray FileName, QString FilePath, FileDirection Direction)
: fileNum(FileNum), friendId(FriendId), fileName{FileName}, filePath{FilePath}, file{new QFile(filePath)},
bytesSent{0}, filesize{0}, status{STOPPED}, direction{Direction}, sendTimer{nullptr}
{
}
void ToxFile::setFilePath(QString path)
{
filePath=path;
file->setFileName(path);
}
bool ToxFile::open(bool write)
{
return write ? file->open(QIODevice::ReadWrite) : file->open(QIODevice::ReadOnly);
}

54
corestructs.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef CORESTRUCTS_H
#define CORESTRUCTS_H
// Some headers use Core structs but don't need to include all of core.h
// They should include this file directly instead to reduce compilation times
#include <QString>
class QFile;
class QTimer;
enum class Status : int {Online = 0, Away, Busy, Offline};
struct DhtServer
{
QString name;
QString userId;
QString address;
int port;
};
struct ToxFile
{
enum FileStatus
{
STOPPED,
PAUSED,
TRANSMITTING
};
enum FileDirection : bool
{
SENDING,
RECEIVING
};
ToxFile()=default;
ToxFile(int FileNum, int FriendId, QByteArray FileName, QString FilePath, FileDirection Direction);
~ToxFile(){}
void setFilePath(QString path);
bool open(bool write);
int fileNum;
int friendId;
QByteArray fileName;
QString filePath;
QFile* file;
long long bytesSent;
long long filesize;
FileStatus status;
FileDirection direction;
QTimer* sendTimer;
};
#endif // CORESTRUCTS_H

View File

@ -15,6 +15,7 @@
*/ */
#include "cstring.h" #include "cstring.h"
#include <QString>
CString::CString(const QString& string) CString::CString(const QString& string)
{ {

View File

@ -18,7 +18,8 @@
#define CSTRING_H #define CSTRING_H
#include <cstdint> #include <cstdint>
#include <QString>
class QString;
class CString class CString
{ {

View File

@ -15,15 +15,12 @@
*/ */
#include "filetransferinstance.h" #include "filetransferinstance.h"
#include "widget/widget.h"
#include "core.h" #include "core.h"
#include "math.h" #include <math.h>
#include "style.h"
#include <QFileDialog> #include <QFileDialog>
#include <QPixmap>
#include <QPainter>
#include <QMessageBox> #include <QMessageBox>
#include <QBuffer> #include <QBuffer>
#include <QDebug>
uint FileTransferInstance::Idconter = 0; uint FileTransferInstance::Idconter = 0;
@ -33,6 +30,7 @@ FileTransferInstance::FileTransferInstance(ToxFile File)
{ {
id = Idconter++; id = Idconter++;
state = tsPending; state = tsPending;
remotePaused = false;
filename = File.fileName; filename = File.fileName;
size = getHumanReadableSize(File.filesize); size = getHumanReadableSize(File.filesize);
@ -64,7 +62,7 @@ void FileTransferInstance::onFileTransferInfo(int FriendId, int FileNum, int64_t
if (FileNum != fileNum || FriendId != friendId || Direction != direction) if (FileNum != fileNum || FriendId != friendId || Direction != direction)
return; return;
state = tsProcessing; // state = tsProcessing;
QDateTime newtime = QDateTime::currentDateTime(); QDateTime newtime = QDateTime::currentDateTime();
int timediff = lastUpdate.secsTo(newtime); int timediff = lastUpdate.secsTo(newtime);
if (timediff <= 0) if (timediff <= 0)
@ -93,7 +91,7 @@ void FileTransferInstance::onFileTransferCancelled(int FriendId, int FileNum, To
{ {
if (FileNum != fileNum || FriendId != friendId || Direction != direction) if (FileNum != fileNum || FriendId != friendId || Direction != direction)
return; return;
disconnect(Widget::getInstance()->getCore(),0,this,0); disconnect(Core::getInstance(),0,this,0);
state = tsCanceled; state = tsCanceled;
emit stateUpdated(); emit stateUpdated();
@ -103,7 +101,7 @@ void FileTransferInstance::onFileTransferFinished(ToxFile File)
{ {
if (File.fileNum != fileNum || File.friendId != friendId || File.direction != direction) if (File.fileNum != fileNum || File.friendId != friendId || File.direction != direction)
return; return;
disconnect(Widget::getInstance()->getCore(),0,this,0); disconnect(Core::getInstance(),0,this,0);
if (File.direction == ToxFile::RECEIVING) if (File.direction == ToxFile::RECEIVING)
{ {
@ -124,16 +122,47 @@ void FileTransferInstance::onFileTransferFinished(ToxFile File)
emit stateUpdated(); emit stateUpdated();
} }
void FileTransferInstance::onFileTransferAccepted(ToxFile File)
{
if (File.fileNum != fileNum || File.friendId != friendId || File.direction != direction)
return;
remotePaused = false;
state = tsProcessing;
emit stateUpdated();
}
void FileTransferInstance::onFileTransferRemotePausedUnpaused(ToxFile File, bool paused)
{
if (File.fileNum != fileNum || File.friendId != friendId || File.direction != direction)
return;
remotePaused = paused;
emit stateUpdated();
}
void FileTransferInstance::onFileTransferPaused(int FriendId, int FileNum, ToxFile::FileDirection Direction)
{
if (FileNum != fileNum || FriendId != friendId || Direction != direction)
return;
state = tsPaused;
emit stateUpdated();
}
void FileTransferInstance::cancelTransfer() void FileTransferInstance::cancelTransfer()
{ {
Widget::getInstance()->getCore()->cancelFileSend(friendId, fileNum); Core::getInstance()->cancelFileSend(friendId, fileNum);
state = tsCanceled; state = tsCanceled;
emit stateUpdated(); emit stateUpdated();
} }
void FileTransferInstance::rejectRecvRequest() void FileTransferInstance::rejectRecvRequest()
{ {
Widget::getInstance()->getCore()->rejectFileRecvRequest(friendId, fileNum); Core::getInstance()->rejectFileRecvRequest(friendId, fileNum);
onFileTransferCancelled(friendId, fileNum, direction); onFileTransferCancelled(friendId, fileNum, direction);
state = tsCanceled; state = tsCanceled;
emit stateUpdated(); emit stateUpdated();
@ -159,7 +188,7 @@ void FileTransferInstance::acceptRecvRequest()
QString path; QString path;
while (true) while (true)
{ {
path = QFileDialog::getSaveFileName(Widget::getInstance(), tr("Save a file","Title of the file saving dialog"), QDir::current().filePath(filename)); path = QFileDialog::getSaveFileName(0, tr("Save a file","Title of the file saving dialog"), QDir::current().filePath(filename));
if (path.isEmpty()) if (path.isEmpty())
return; return;
else else
@ -170,13 +199,13 @@ void FileTransferInstance::acceptRecvRequest()
if (isFileWritable(path)) if (isFileWritable(path))
break; break;
else else
QMessageBox::warning(Widget::getInstance(), tr("Location not writable","Title of permissions popup"), tr("You do not have permission to write that location. Choose another, or cancel the save dialog.", "text of permissions popup")); QMessageBox::warning(0, tr("Location not writable","Title of permissions popup"), tr("You do not have permission to write that location. Choose another, or cancel the save dialog.", "text of permissions popup"));
} }
} }
savePath = path; savePath = path;
Widget::getInstance()->getCore()->acceptFileRecvRequest(friendId, fileNum, path); Core::getInstance()->acceptFileRecvRequest(friendId, fileNum, path);
state = tsProcessing; state = tsProcessing;
emit stateUpdated(); emit stateUpdated();
@ -184,19 +213,33 @@ void FileTransferInstance::acceptRecvRequest()
void FileTransferInstance::pauseResumeRecv() void FileTransferInstance::pauseResumeRecv()
{ {
Widget::getInstance()->getCore()->pauseResumeFileRecv(friendId, fileNum); if (!(state == tsProcessing || state == tsPaused))
if (state == tsProcessing) return;
state = tsPaused;
else state = tsProcessing; if (remotePaused)
return;
Core::getInstance()->pauseResumeFileRecv(friendId, fileNum);
// if (state == tsProcessing)
// state = tsPaused;
// else state = tsProcessing;
emit stateUpdated(); emit stateUpdated();
} }
void FileTransferInstance::pauseResumeSend() void FileTransferInstance::pauseResumeSend()
{ {
Widget::getInstance()->getCore()->pauseResumeFileSend(friendId, fileNum); if (!(state == tsProcessing || state == tsPaused))
if (state == tsProcessing) return;
state = tsPaused;
else state = tsProcessing; if (remotePaused)
return;
Core::getInstance()->pauseResumeFileSend(friendId, fileNum);
// if (state == tsProcessing)
// state = tsPaused;
// else state = tsProcessing;
emit stateUpdated(); emit stateUpdated();
} }
@ -223,7 +266,15 @@ QString FileTransferInstance::getHtmlImage()
else if (state == tsPaused) else if (state == tsPaused)
rightBtnImg = QImage(":/ui/fileTransferInstance/resumeFileButton.png"); rightBtnImg = QImage(":/ui/fileTransferInstance/resumeFileButton.png");
else else
rightBtnImg = QImage(":/ui/fileTransferInstance/acceptFileButton.png"); {
if (direction == ToxFile::SENDING)
rightBtnImg = QImage(":/ui/fileTransferInstance/pauseGreyFileButton.png");
else
rightBtnImg = QImage(":/ui/fileTransferInstance/acceptFileButton.png");
}
if (remotePaused)
rightBtnImg = QImage(":/ui/fileTransferInstance/pauseGreyFileButton.png");
res = draw2ButtonsForm("silver", leftBtnImg, rightBtnImg); res = draw2ButtonsForm("silver", leftBtnImg, rightBtnImg);
} else if (state == tsCanceled) } else if (state == tsCanceled)

View File

@ -17,29 +17,32 @@
#define FILETRANSFERINSTANCE_H #define FILETRANSFERINSTANCE_H
#include <QObject> #include <QObject>
#include <QLabel>
#include <QPushButton>
#include <QProgressBar>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QDateTime> #include <QDateTime>
#include <QImage>
#include "core.h" #include "corestructs.h"
struct ToxFile; struct ToxFile;
class FileTransferInstance : public QObject class FileTransferInstance : public QObject
{ {
Q_OBJECT Q_OBJECT
public:
enum TransfState {tsPending, tsProcessing, tsPaused, tsFinished, tsCanceled};
public: public:
explicit FileTransferInstance(ToxFile File); explicit FileTransferInstance(ToxFile File);
QString getHtmlImage(); QString getHtmlImage();
uint getId(){return id;} uint getId(){return id;}
TransfState getState() {return state;}
public slots: public slots:
void onFileTransferInfo(int FriendId, int FileNum, int64_t Filesize, int64_t BytesSent, ToxFile::FileDirection Direction); void onFileTransferInfo(int FriendId, int FileNum, int64_t Filesize, int64_t BytesSent, ToxFile::FileDirection Direction);
void onFileTransferCancelled(int FriendId, int FileNum, ToxFile::FileDirection Direction); void onFileTransferCancelled(int FriendId, int FileNum, ToxFile::FileDirection Direction);
void onFileTransferFinished(ToxFile File); void onFileTransferFinished(ToxFile File);
void onFileTransferAccepted(ToxFile File);
void onFileTransferPaused(int FriendId, int FileNum, ToxFile::FileDirection Direction);
void onFileTransferRemotePausedUnpaused(ToxFile File, bool paused);
void pressFromHtml(QString); void pressFromHtml(QString);
signals: signals:
@ -61,12 +64,11 @@ private:
QString wrapIntoForm(const QString &content, const QString &type, const QString &imgAstr, const QString &imgBstr); QString wrapIntoForm(const QString &content, const QString &type, const QString &imgAstr, const QString &imgBstr);
private: private:
enum TransfState {tsPending, tsProcessing, tsPaused, tsFinished, tsCanceled};
static uint Idconter; static uint Idconter;
uint id; uint id;
TransfState state; TransfState state;
bool remotePaused;
QImage pic; QImage pic;
QString filename, size, speed, eta; QString filename, size, speed, eta;
QDateTime lastUpdate; QDateTime lastUpdate;

View File

@ -17,6 +17,7 @@
#include "friend.h" #include "friend.h"
#include "friendlist.h" #include "friendlist.h"
#include "widget/friendwidget.h" #include "widget/friendwidget.h"
#include "widget/form/chatform.h"
Friend::Friend(int FriendId, QString UserId) Friend::Friend(int FriendId, QString UserId)
: friendId(FriendId), userId(UserId) : friendId(FriendId), userId(UserId)

View File

@ -18,9 +18,10 @@
#define FRIEND_H #define FRIEND_H
#include <QString> #include <QString>
#include "widget/form/chatform.h" #include "corestructs.h"
struct FriendWidget; struct FriendWidget;
class ChatForm;
struct Friend struct Friend
{ {
@ -38,7 +39,6 @@ public:
ChatForm* chatForm; ChatForm* chatForm;
int hasNewEvents; int hasNewEvents;
Status friendStatus; Status friendStatus;
QPixmap avatar;
}; };
#endif // FRIEND_H #endif // FRIEND_H

View File

@ -21,7 +21,7 @@
QList<Friend*> FriendList::friendList; QList<Friend*> FriendList::friendList;
Friend* FriendList::addFriend(int friendId, QString userId) Friend* FriendList::addFriend(int friendId, const QString& userId)
{ {
for (Friend* f : friendList) for (Friend* f : friendList)
if (f->friendId == friendId) if (f->friendId == friendId)

View File

@ -17,16 +17,15 @@
#ifndef FRIENDLIST_H #ifndef FRIENDLIST_H
#define FRIENDLIST_H #define FRIENDLIST_H
#include <QString> template <class T> class QList;
#include <QList>
struct Friend; struct Friend;
class QString;
class FriendList class FriendList
{ {
public: public:
FriendList(); FriendList();
static Friend* addFriend(int friendId, QString userId); static Friend* addFriend(int friendId, const QString& userId);
static Friend* findFriend(int friendId); static Friend* findFriend(int friendId);
static void removeFriend(int friendId); static void removeFriend(int friendId);

View File

@ -19,18 +19,18 @@
#include "widget/form/groupchatform.h" #include "widget/form/groupchatform.h"
#include "friendlist.h" #include "friendlist.h"
#include "friend.h" #include "friend.h"
#include "widget/widget.h"
#include "core.h" #include "core.h"
#include <QDebug> #include <QDebug>
#include <QTimer>
Group::Group(int GroupId, QString Name) Group::Group(int GroupId, QString Name)
: groupId(GroupId), nPeers{0}, hasPeerInfo{false} : groupId(GroupId), nPeers{0}, hasPeerInfo{false}, peerInfoTimer{new QTimer}
{ {
widget = new GroupWidget(groupId, Name); widget = new GroupWidget(groupId, Name);
chatForm = new GroupChatForm(this); chatForm = new GroupChatForm(this);
connect(&peerInfoTimer, SIGNAL(timeout()), this, SLOT(queryPeerInfo())); connect(peerInfoTimer, SIGNAL(timeout()), this, SLOT(queryPeerInfo()));
peerInfoTimer.setInterval(500); peerInfoTimer->setInterval(500);
peerInfoTimer.setSingleShot(false); peerInfoTimer->setSingleShot(false);
//peerInfoTimer.start(); //peerInfoTimer.start();
//in groupchats, we only notify on messages containing your name //in groupchats, we only notify on messages containing your name
@ -42,11 +42,12 @@ Group::~Group()
{ {
delete chatForm; delete chatForm;
delete widget; delete widget;
delete peerInfoTimer;
} }
void Group::queryPeerInfo() void Group::queryPeerInfo()
{ {
const Core* core = Widget::getInstance()->getCore(); const Core* core = Core::getInstance();
int nPeersResult = core->getGroupNumberPeers(groupId); int nPeersResult = core->getGroupNumberPeers(groupId);
if (nPeersResult == -1) if (nPeersResult == -1)
{ {
@ -86,7 +87,7 @@ void Group::queryPeerInfo()
{ {
qDebug() << "Group::queryPeerInfo: Successfully loaded names"; qDebug() << "Group::queryPeerInfo: Successfully loaded names";
hasPeerInfo = true; hasPeerInfo = true;
peerInfoTimer.stop(); peerInfoTimer->stop();
} }
} }

View File

@ -17,15 +17,15 @@
#ifndef GROUP_H #ifndef GROUP_H
#define GROUP_H #define GROUP_H
#include <QList>
#include <QMap> #include <QMap>
#include <QTimer> #include <QObject>
#define RETRY_PEER_INFO_INTERVAL 500 #define RETRY_PEER_INFO_INTERVAL 500
struct Friend; struct Friend;
class GroupWidget; class GroupWidget;
class GroupChatForm; class GroupChatForm;
class QTimer;
class Group : public QObject class Group : public QObject
{ {
@ -47,7 +47,7 @@ public:
GroupWidget* widget; GroupWidget* widget;
GroupChatForm* chatForm; GroupChatForm* chatForm;
bool hasPeerInfo; bool hasPeerInfo;
QTimer peerInfoTimer; QTimer* peerInfoTimer;
int hasNewMessages, userWasMentioned; int hasNewMessages, userWasMentioned;
}; };

View File

@ -19,7 +19,7 @@
QList<Group*> GroupList::groupList; QList<Group*> GroupList::groupList;
Group* GroupList::addGroup(int groupId, QString name) Group* GroupList::addGroup(int groupId, const QString& name)
{ {
Group* newGroup = new Group(groupId, name); Group* newGroup = new Group(groupId, name);
groupList.append(newGroup); groupList.append(newGroup);

View File

@ -17,17 +17,16 @@
#ifndef GROUPLIST_H #ifndef GROUPLIST_H
#define GROUPLIST_H #define GROUPLIST_H
#include <QString> template <typename T>
#include <QList> class QList;
#include <QMap>
class Group; class Group;
class QString;
class GroupList class GroupList
{ {
public: public:
GroupList(); GroupList();
static Group* addGroup(int groupId, QString name); static Group* addGroup(int groupId, const QString& name);
static Group* findGroup(int groupId); static Group* findGroup(int groupId);
static void removeGroup(int groupId); static void removeGroup(int groupId);

View File

@ -19,6 +19,7 @@
#include <QApplication> #include <QApplication>
#include <QFontDatabase> #include <QFontDatabase>
#include <QTranslator> #include <QTranslator>
#include <QDebug>
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@ -31,7 +32,7 @@ int main(int argc, char *argv[])
if (Settings::getInstance().getUseTranslations()) if (Settings::getInstance().getUseTranslations())
{ {
QString locale = QLocale::system().name().section('_', 0, 0); QString locale = QLocale::system().name().section('_', 0, 0);
if (translator.load(locale,":translations/")) if (locale=="en" || translator.load(locale,":translations/"))
qDebug() << "Loaded translation "+locale; qDebug() << "Loaded translation "+locale;
else else
qDebug() << "Error loading translation "+locale; qDebug() << "Error loading translation "+locale;
@ -50,45 +51,3 @@ int main(int argc, char *argv[])
return errorcode; return errorcode;
} }
/** TODO
* ">using a dedicated tool to maintain a TODO list" edition
*
* QRC FILES DO YOU EVEN INTO THEM ? Fix it soon for packaging and Urras.
* Most cameras use YUYV, implement YUYV -> YUV240
* Sending large files (~380MB) "restarts" after ~10MB. Goes back to 0%, consumes twice as much ram (reloads the file?)
* => Don't load the whole file at once, load small chunks (25MB?) when needed, then free them and load the next
* Don't do anything if a friend is disconnected, don't print to the chat
* Changing online/away/busy/offline by clicking the bubble
* /me action messages
* Popup windows for adding friends and changing settings
* And logging of the chat
* Show the picture's size between name and size after transfer completion if it's a pic
* Adjust all status icons to match the mockup, including scooting the friendslist ones to the left and making the user one the same size
* Sidepanel (friendlist) should be resizeable
* An extra side panel for groupchats, like Venom does (?)
*
* In the file transfer widget:
* >There is more padding on the left side compared to the right.
* >Maybe put the file size should be in the same row as the name.
* >Right-align the ETA.
*
*/
/** NAMES :
Botox
Ricin
Anthrax
Sarin
Cyanide
Polonium
Mercury
Arsenic
qTox
plague
Britney
Nightshade
Belladonna
toxer
GoyIM
*/

View File

@ -107,7 +107,10 @@ HEADERS += widget/form/addfriendform.h \
widget/form/genericchatform.h \ widget/form/genericchatform.h \
widget/tool/chataction.h \ widget/tool/chataction.h \
widget/chatareawidget.h \ widget/chatareawidget.h \
filetransferinstance.h filetransferinstance.h \
corestructs.h \
coredefines.h \
coreav.h
SOURCES += \ SOURCES += \
widget/form/addfriendform.cpp \ widget/form/addfriendform.cpp \
@ -143,4 +146,5 @@ SOURCES += \
widget/form/genericchatform.cpp \ widget/form/genericchatform.cpp \
widget/tool/chataction.cpp \ widget/tool/chataction.cpp \
widget/chatareawidget.cpp \ widget/chatareawidget.cpp \
filetransferinstance.cpp filetransferinstance.cpp \
corestructs.cpp

View File

@ -6,7 +6,6 @@
<file alias="DejaVuSans.ttf">res/DejaVuSans.ttf</file> <file alias="DejaVuSans.ttf">res/DejaVuSans.ttf</file>
</qresource> </qresource>
<qresource prefix="/"> <qresource prefix="/">
<file>audio/notification.wav</file>
<file>img/icon.png</file> <file>img/icon.png</file>
<file>img/contact.png</file> <file>img/contact.png</file>
<file>img/contact_dark.png</file> <file>img/contact_dark.png</file>
@ -128,11 +127,13 @@
<file>ui/volButton/volButton.css</file> <file>ui/volButton/volButton.css</file>
<file>ui/fileTransferInstance/acceptFileButton.png</file> <file>ui/fileTransferInstance/acceptFileButton.png</file>
<file>ui/fileTransferInstance/pauseFileButton.png</file> <file>ui/fileTransferInstance/pauseFileButton.png</file>
<file>ui/fileTransferInstance/pauseGreyFileButton.png</file>
<file>ui/fileTransferInstance/resumeFileButton.png</file> <file>ui/fileTransferInstance/resumeFileButton.png</file>
<file>ui/fileTransferInstance/stopFileButton.png</file> <file>ui/fileTransferInstance/stopFileButton.png</file>
<file>ui/fileTransferInstance/emptyLGreenFileButton.png</file> <file>ui/fileTransferInstance/emptyLGreenFileButton.png</file>
<file>ui/fileTransferInstance/emptyLRedFileButton.png</file> <file>ui/fileTransferInstance/emptyLRedFileButton.png</file>
<file>ui/fileTransferInstance/emptyRGreenFileButton.png</file> <file>ui/fileTransferInstance/emptyRGreenFileButton.png</file>
<file>ui/fileTransferInstance/emptyRRedFileButton.png</file> <file>ui/fileTransferInstance/emptyRRedFileButton.png</file>
<file>audio/notification.pcm</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -16,8 +16,8 @@
#include "settings.h" #include "settings.h"
#include "smileypack.h" #include "smileypack.h"
#include "widget/widget.h"
#include <QFont>
#include <QApplication> #include <QApplication>
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>

View File

@ -18,8 +18,7 @@
#define SETTINGS_HPP #define SETTINGS_HPP
#include <QHash> #include <QHash>
#include <QMainWindow> #include <QObject>
#include <QSplitter>
class Settings : public QObject class Settings : public QObject
{ {

17
simple_make.sh Executable file
View File

@ -0,0 +1,17 @@
#! /bin/bash
if which apt-get; then
sudo apt-get install build-essential qt5-qmake qt5-default libopenal-dev libopencv-dev \
libtool autotools-dev automake checkinstall check libopus-dev libvpx-dev
elif which pacman; then
sudo pacman -S --needed base-devel qt5 opencv openal opus vpx
elif which yum; then
yum groupinstall "Development Tools"
yum install qt-devel qt-doc qt-creator opencv-devel openal-soft-devel libtool autoconf automake check check-devel
else
echo "Unknown package manager, attempting to compile anyways"
fi
./bootstrap.sh
qmake
make

View File

@ -19,8 +19,14 @@
#include <QFileInfo> #include <QFileInfo>
#include <QFile> #include <QFile>
#include <QtXml> #include <QIcon>
#include <QDebug> #include <QPixmap>
#include <QDir>
#include <QCoreApplication>
#include <QDomDocument>
#include <QDomElement>
#include <QBuffer>
#include <QStringBuilder>
SmileyPack::SmileyPack() SmileyPack::SmileyPack()
{ {

View File

@ -17,7 +17,7 @@
#ifndef STYLE_H #ifndef STYLE_H
#define STYLE_H #define STYLE_H
#include <QString> class QString;
class Style class Style
{ {

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 B

After

Width:  |  Height:  |  Size: 403 B

View File

@ -15,7 +15,7 @@
*/ */
#include "camera.h" #include "camera.h"
#include <QMessageBox> #include "widget.h"
using namespace cv; using namespace cv;
@ -114,3 +114,8 @@ vpx_image Camera::getLastVPXImage()
} }
return img; return img;
} }
Camera* Camera::getInstance()
{
return Widget::getInstance()->getCamera();
}

View File

@ -31,6 +31,7 @@ class Camera
{ {
public: public:
Camera(); Camera();
static Camera* getInstance(); ///< Returns the global widget's Camera instance
void suscribe(); ///< Call this once before trying to get frames void suscribe(); ///< Call this once before trying to get frames
void unsuscribe(); ///< Call this once when you don't need frames anymore void unsuscribe(); ///< Call this once when you don't need frames anymore
cv::Mat getLastFrame(); ///< Get the last captured frame cv::Mat getLastFrame(); ///< Get the last captured frame

View File

@ -15,23 +15,49 @@
*/ */
#include "chatareawidget.h" #include "chatareawidget.h"
#include <QAbstractTextDocumentLayout> #include "widget/tool/chataction.h"
#include <QMessageBox>
#include <QScrollBar> #include <QScrollBar>
#include <QDesktopServices>
#include <QTextTable>
#include <QAbstractTextDocumentLayout>
ChatAreaWidget::ChatAreaWidget(QWidget *parent) : ChatAreaWidget::ChatAreaWidget(QWidget *parent) :
QTextEdit(parent) QTextBrowser(parent)
{ {
setReadOnly(true); setReadOnly(true);
viewport()->setCursor(Qt::ArrowCursor); viewport()->setCursor(Qt::ArrowCursor);
setContextMenuPolicy(Qt::CustomContextMenu); setContextMenuPolicy(Qt::CustomContextMenu);
setUndoRedoEnabled(false); setUndoRedoEnabled(false);
setOpenExternalLinks(false);
setOpenLinks(false);
setAcceptRichText(false);
chatTextTable = textCursor().insertTable(1,3);
QTextTableFormat tableFormat;
tableFormat.setColumnWidthConstraints({QTextLength(QTextLength::VariableLength,0),
QTextLength(QTextLength::PercentageLength,100),
QTextLength(QTextLength::VariableLength,0)});
tableFormat.setBorderStyle(QTextFrameFormat::BorderStyle_None);
chatTextTable->setFormat(tableFormat);
chatTextTable->format().setCellSpacing(2);
chatTextTable->format().setWidth(QTextLength(QTextLength::PercentageLength,100));
nameFormat.setAlignment(Qt::AlignRight);
nameFormat.setNonBreakableLines(true);
dateFormat.setAlignment(Qt::AlignLeft);
dateFormat.setNonBreakableLines(true);
connect(this, &ChatAreaWidget::anchorClicked, this, &ChatAreaWidget::onAnchorClicked);
connect(verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(onSliderRangeChanged()));
} }
ChatAreaWidget::~ChatAreaWidget() ChatAreaWidget::~ChatAreaWidget()
{ {
for (ChatAction *it : messages) for (ChatAction* action : messages)
delete it; delete action;
messages.clear();
} }
void ChatAreaWidget::mouseReleaseEvent(QMouseEvent * event) void ChatAreaWidget::mouseReleaseEvent(QMouseEvent * event)
@ -65,16 +91,9 @@ void ChatAreaWidget::mouseReleaseEvent(QMouseEvent * event)
} }
} }
QString ChatAreaWidget::getHtmledMessages() void ChatAreaWidget::onAnchorClicked(const QUrl &url)
{ {
QString res("<table width=100%>\n"); QDesktopServices::openUrl(url);
for (ChatAction *it : messages)
{
res += it->getHtml();
}
res += "</table>";
return res;
} }
void ChatAreaWidget::insertMessage(ChatAction *msgAction) void ChatAreaWidget::insertMessage(ChatAction *msgAction)
@ -82,31 +101,33 @@ void ChatAreaWidget::insertMessage(ChatAction *msgAction)
if (msgAction == nullptr) if (msgAction == nullptr)
return; return;
messages.append(msgAction); checkSlider();
//updateChatContent();
moveCursor(QTextCursor::End); int row = chatTextTable->rows() - 1;
moveCursor(QTextCursor::PreviousCell); chatTextTable->cellAt(row,0).firstCursorPosition().setBlockFormat(nameFormat);
insertHtml(msgAction->getHtml()); chatTextTable->cellAt(row,2).firstCursorPosition().setBlockFormat(dateFormat);
QTextCursor cur = chatTextTable->cellAt(row,1).firstCursorPosition();
cur.clearSelection();
cur.setKeepPositionOnInsert(true);
chatTextTable->cellAt(row,0).firstCursorPosition().insertHtml(msgAction->getName());
chatTextTable->cellAt(row,1).firstCursorPosition().insertHtml(msgAction->getMessage());
chatTextTable->cellAt(row,2).firstCursorPosition().insertHtml(msgAction->getDate());
chatTextTable->appendRows(1);
msgAction->setTextCursor(cur);
messages.append(msgAction);
} }
void ChatAreaWidget::updateChatContent() void ChatAreaWidget::onSliderRangeChanged()
{
QScrollBar* scroll = verticalScrollBar();
if (lockSliderToBottom)
scroll->setValue(scroll->maximum());
}
void ChatAreaWidget::checkSlider()
{ {
QScrollBar* scroll = verticalScrollBar(); QScrollBar* scroll = verticalScrollBar();
lockSliderToBottom = scroll && scroll->value() == scroll->maximum(); lockSliderToBottom = scroll && scroll->value() == scroll->maximum();
setUpdatesEnabled(false);
setHtml(getHtmledMessages());
setUpdatesEnabled(true);
if (lockSliderToBottom)
sliderPosition = scroll->maximum();
scroll->setValue(sliderPosition);
}
void ChatAreaWidget::clearMessages()
{
for (ChatAction *it : messages)
delete it;
updateChatContent();
} }

View File

@ -17,18 +17,19 @@
#ifndef CHATAREAWIDGET_H #ifndef CHATAREAWIDGET_H
#define CHATAREAWIDGET_H #define CHATAREAWIDGET_H
#include <QTextEdit> #include <QTextBrowser>
#include <QList> #include <QList>
#include "widget/tool/chataction.h"
class ChatAreaWidget : public QTextEdit class ChatAction;
class QTextTable;
class ChatAreaWidget : public QTextBrowser
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit ChatAreaWidget(QWidget *parent = 0); explicit ChatAreaWidget(QWidget *parent = 0);
virtual ~ChatAreaWidget(); virtual ~ChatAreaWidget();
void insertMessage(ChatAction *msgAction); void insertMessage(ChatAction *msgAction);
void clearMessages();
signals: signals:
void onFileTranfertInterract(QString widgetName, QString buttonName); void onFileTranfertInterract(QString widgetName, QString buttonName);
@ -36,14 +37,18 @@ signals:
protected: protected:
void mouseReleaseEvent(QMouseEvent * event); void mouseReleaseEvent(QMouseEvent * event);
public slots: private slots:
void updateChatContent(); void onAnchorClicked(const QUrl& url);
void onSliderRangeChanged();
private: private:
QString getHtmledMessages(); void checkSlider();
QList<ChatAction*> messages; QList<ChatAction*> messages;
bool lockSliderToBottom; bool lockSliderToBottom;
int sliderPosition; int sliderPosition;
QTextTable *chatTextTable;
QTextBlockFormat nameFormat, dateFormat;
}; };
#endif // CHATAREAWIDGET_H #endif // CHATAREAWIDGET_H

View File

@ -16,6 +16,7 @@
#include "croppinglabel.h" #include "croppinglabel.h"
#include <QResizeEvent> #include <QResizeEvent>
#include <QLineEdit>
CroppingLabel::CroppingLabel(QWidget* parent) CroppingLabel::CroppingLabel(QWidget* parent)
: QLabel(parent) : QLabel(parent)

View File

@ -18,7 +18,8 @@
#define CROPPINGLABEL_H #define CROPPINGLABEL_H
#include <QLabel> #include <QLabel>
#include <QLineEdit>
class QLineEdit;
class CroppingLabel : public QLabel class CroppingLabel : public QLabel
{ {

View File

@ -19,6 +19,8 @@
#include <QFont> #include <QFont>
#include <QMessageBox> #include <QMessageBox>
#include <tox/tox.h> #include <tox/tox.h>
#include "ui_mainwindow.h"
#include "core.h"
#define TOX_ID_LENGTH 2*TOX_FRIEND_ADDRESS_SIZE #define TOX_ID_LENGTH 2*TOX_FRIEND_ADDRESS_SIZE
@ -74,6 +76,7 @@ bool AddFriendForm::isToxId(const QString &value) const
void AddFriendForm::showWarning(const QString &message) const void AddFriendForm::showWarning(const QString &message) const
{ {
QMessageBox warning(main); QMessageBox warning(main);
warning.setWindowTitle("Tox");
warning.setText(message); warning.setText(message);
warning.setIcon(QMessageBox::Warning); warning.setIcon(QMessageBox::Warning);
warning.exec(); warning.exec();
@ -92,7 +95,10 @@ void AddFriendForm::onSendTriggered()
if (id.isEmpty()) { if (id.isEmpty()) {
showWarning(tr("Please fill in a valid Tox ID","Tox ID of the friend you're sending a friend request to")); showWarning(tr("Please fill in a valid Tox ID","Tox ID of the friend you're sending a friend request to"));
} else if (isToxId(id)) { } else if (isToxId(id)) {
emit friendRequested(id, getMessage()); if (id.toUpper() == Core::getInstance()->getSelfId().toUpper())
showWarning(tr("You can't add yourself as a friend !","When trying to add your own Tox ID as friend"));
else
emit friendRequested(id, getMessage());
this->toxId.setText(""); this->toxId.setText("");
this->message.setText(""); this->message.setText("");
} else { } else {

View File

@ -17,8 +17,6 @@
#ifndef ADDFRIENDFORM_H #ifndef ADDFRIENDFORM_H
#define ADDFRIENDFORM_H #define ADDFRIENDFORM_H
#include "ui_mainwindow.h"
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QLabel> #include <QLabel>
#include <QLineEdit> #include <QLineEdit>
@ -26,6 +24,8 @@
#include <QPushButton> #include <QPushButton>
#include <QDnsLookup> #include <QDnsLookup>
namespace Ui {class MainWindow;}
class AddFriendForm : public QObject class AddFriendForm : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -42,8 +42,8 @@ signals:
void friendRequested(const QString& friendAddress, const QString& message); void friendRequested(const QString& friendAddress, const QString& message);
private slots: private slots:
void onSendTriggered(); void onSendTriggered();
void handleDnsLookup(); void handleDnsLookup();
private: private:
QLabel headLabel, toxIdLabel, messageLabel; QLabel headLabel, toxIdLabel, messageLabel;

View File

@ -14,14 +14,21 @@
See the COPYING file for more details. See the COPYING file for more details.
*/ */
#include <QDebug>
#include <QScrollBar>
#include <QFileDialog>
#include <QMessageBox>
#include <QPushButton>
#include "chatform.h" #include "chatform.h"
#include "friend.h" #include "friend.h"
#include "widget/friendwidget.h" #include "widget/friendwidget.h"
#include "filetransferinstance.h" #include "filetransferinstance.h"
#include "widget/tool/chataction.h"
#include "widget/netcamview.h"
#include "widget/chatareawidget.h"
#include "widget/tool/chattextedit.h"
#include "core.h"
#include "widget/widget.h" #include "widget/widget.h"
#include <QScrollBar>
#include <QFileDialog>
#include <QMessageBox>
ChatForm::ChatForm(Friend* chatFriend) ChatForm::ChatForm(Friend* chatFriend)
: f(chatFriend) : f(chatFriend)
@ -35,15 +42,15 @@ ChatForm::ChatForm(Friend* chatFriend)
headTextLayout->addWidget(statusMessageLabel); headTextLayout->addWidget(statusMessageLabel);
headTextLayout->addStretch(); headTextLayout->addStretch();
connect(Widget::getInstance()->getCore(), &Core::fileSendStarted, this, &ChatForm::startFileSend); connect(Core::getInstance(), &Core::fileSendStarted, this, &ChatForm::startFileSend);
connect(Widget::getInstance()->getCore(), &Core::videoFrameReceived, netcam, &NetCamView::updateDisplay); connect(Core::getInstance(), &Core::videoFrameReceived, netcam, &NetCamView::updateDisplay);
connect(sendButton, &QPushButton::clicked, this, &ChatForm::onSendTriggered); connect(sendButton, &QPushButton::clicked, this, &ChatForm::onSendTriggered);
connect(fileButton, &QPushButton::clicked, this, &ChatForm::onAttachClicked); connect(fileButton, &QPushButton::clicked, this, &ChatForm::onAttachClicked);
connect(callButton, &QPushButton::clicked, this, &ChatForm::onCallTriggered); connect(callButton, &QPushButton::clicked, this, &ChatForm::onCallTriggered);
connect(videoButton, &QPushButton::clicked, this, &ChatForm::onVideoCallTriggered); connect(videoButton, &QPushButton::clicked, this, &ChatForm::onVideoCallTriggered);
connect(msgEdit, &ChatTextEdit::enterPressed, this, &ChatForm::onSendTriggered); connect(msgEdit, &ChatTextEdit::enterPressed, this, &ChatForm::onSendTriggered);
connect(micButton, SIGNAL(clicked()), this, SLOT(onMicMuteToggle())); connect(micButton, SIGNAL(clicked()), this, SLOT(onMicMuteToggle()));
connect(chatWidget, SIGNAL(onFileTranfertInterract(QString,QString)), this, SLOT(onFileTansBtnClicked(QString,QString))); connect(chatWidget, &ChatAreaWidget::onFileTranfertInterract, this, &ChatForm::onFileTansBtnClicked);
} }
ChatForm::~ChatForm() ChatForm::~ChatForm()
@ -98,10 +105,12 @@ void ChatForm::startFileSend(ToxFile file)
FileTransferInstance* fileTrans = new FileTransferInstance(file); FileTransferInstance* fileTrans = new FileTransferInstance(file);
ftransWidgets.insert(fileTrans->getId(), fileTrans); ftransWidgets.insert(fileTrans->getId(), fileTrans);
connect(Widget::getInstance()->getCore(), &Core::fileTransferInfo, fileTrans, &FileTransferInstance::onFileTransferInfo); connect(Core::getInstance(), &Core::fileTransferInfo, fileTrans, &FileTransferInstance::onFileTransferInfo);
connect(Widget::getInstance()->getCore(), &Core::fileTransferCancelled, fileTrans, &FileTransferInstance::onFileTransferCancelled); connect(Core::getInstance(), &Core::fileTransferCancelled, fileTrans, &FileTransferInstance::onFileTransferCancelled);
connect(Widget::getInstance()->getCore(), &Core::fileTransferFinished, fileTrans, &FileTransferInstance::onFileTransferFinished); connect(Core::getInstance(), &Core::fileTransferFinished, fileTrans, &FileTransferInstance::onFileTransferFinished);
connect(fileTrans, SIGNAL(stateUpdated()), chatWidget, SLOT(updateChatContent())); connect(Core::getInstance(), SIGNAL(fileTransferAccepted(ToxFile)), fileTrans, SLOT(onFileTransferAccepted(ToxFile)));
connect(Core::getInstance(), SIGNAL(fileTransferPaused(int,int,ToxFile::FileDirection)), fileTrans, SLOT(onFileTransferPaused(int,int,ToxFile::FileDirection)));
connect(Core::getInstance(), SIGNAL(fileTransferRemotePausedUnpaused(ToxFile,bool)), fileTrans, SLOT(onFileTransferRemotePausedUnpaused(ToxFile,bool)));
QString name = Widget::getInstance()->getUsername(); QString name = Widget::getInstance()->getUsername();
if (name == previousName) if (name == previousName)
@ -119,10 +128,12 @@ void ChatForm::onFileRecvRequest(ToxFile file)
FileTransferInstance* fileTrans = new FileTransferInstance(file); FileTransferInstance* fileTrans = new FileTransferInstance(file);
ftransWidgets.insert(fileTrans->getId(), fileTrans); ftransWidgets.insert(fileTrans->getId(), fileTrans);
connect(Widget::getInstance()->getCore(), &Core::fileTransferInfo, fileTrans, &FileTransferInstance::onFileTransferInfo); connect(Core::getInstance(), &Core::fileTransferInfo, fileTrans, &FileTransferInstance::onFileTransferInfo);
connect(Widget::getInstance()->getCore(), &Core::fileTransferCancelled, fileTrans, &FileTransferInstance::onFileTransferCancelled); connect(Core::getInstance(), &Core::fileTransferCancelled, fileTrans, &FileTransferInstance::onFileTransferCancelled);
connect(Widget::getInstance()->getCore(), &Core::fileTransferFinished, fileTrans, &FileTransferInstance::onFileTransferFinished); connect(Core::getInstance(), &Core::fileTransferFinished, fileTrans, &FileTransferInstance::onFileTransferFinished);
connect(fileTrans, SIGNAL(stateUpdated()), chatWidget, SLOT(updateChatContent())); connect(Core::getInstance(), SIGNAL(fileTransferAccepted(ToxFile)), fileTrans, SLOT(onFileTransferAccepted(ToxFile)));
connect(Core::getInstance(), SIGNAL(fileTransferPaused(int,int,ToxFile::FileDirection)), fileTrans, SLOT(onFileTransferPaused(int,int,ToxFile::FileDirection)));
connect(Core::getInstance(), SIGNAL(fileTransferRemotePausedUnpaused(ToxFile,bool)), fileTrans, SLOT(onFileTransferRemotePausedUnpaused(ToxFile,bool)));
Widget* w = Widget::getInstance(); Widget* w = Widget::getInstance();
if (!w->isFriendWidgetCurActiveWidget(f)|| w->getIsWindowMinimized() || !w->isActiveWindow()) if (!w->isFriendWidgetCurActiveWidget(f)|| w->getIsWindowMinimized() || !w->isActiveWindow())

View File

@ -18,11 +18,11 @@
#define CHATFORM_H #define CHATFORM_H
#include "genericchatform.h" #include "genericchatform.h"
#include "core.h" #include "corestructs.h"
#include "widget/netcamview.h"
struct Friend; struct Friend;
class FileTransferInstance; class FileTransferInstance;
class NetCamView;
class ChatForm : public GenericChatForm class ChatForm : public GenericChatForm
{ {

View File

@ -15,6 +15,11 @@
*/ */
#include "filesform.h" #include "filesform.h"
#include "ui_mainwindow.h"
#include <QFileInfo>
#include <QUrl>
#include <QDebug>
#include <QDesktopServices>
FilesForm::FilesForm() FilesForm::FilesForm()
: QObject() : QObject()

View File

@ -17,17 +17,14 @@
#ifndef FILESFORM_H #ifndef FILESFORM_H
#define FILESFORM_H #define FILESFORM_H
#include "ui_mainwindow.h" #include <QListWidgetItem>
#include <QListWidget>
#include <QTabWidget> #include <QTabWidget>
#include <QString> #include <QString>
#include <QDesktopServices>
#include <QLabel> #include <QLabel>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QUrl>
#include <QDebug> namespace Ui {class MainWindow;}
#include <QFileInfo> class QListWidget;
class FilesForm : public QObject class FilesForm : public QObject
{ {

View File

@ -22,6 +22,9 @@
#include "style.h" #include "style.h"
#include "widget/widget.h" #include "widget/widget.h"
#include "settings.h" #include "settings.h"
#include "widget/tool/chataction.h"
#include "widget/chatareawidget.h"
#include "widget/tool/chattextedit.h"
GenericChatForm::GenericChatForm(QObject *parent) : GenericChatForm::GenericChatForm(QObject *parent) :
QObject(parent) QObject(parent)
@ -200,3 +203,8 @@ void GenericChatForm::onEmoteInsertRequested(QString str)
msgEdit->setFocus(); // refocus so that we can continue typing msgEdit->setFocus(); // refocus so that we can continue typing
} }
void GenericChatForm::focusInput()
{
msgEdit->setFocus();
}

View File

@ -19,19 +19,18 @@
#include <QObject> #include <QObject>
#include <QPoint> #include <QPoint>
#include <QTime> #include <QDateTime>
#include <QLabel>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include "widget/croppinglabel.h"
#include "widget/chatareawidget.h"
#include "widget/tool/chattextedit.h"
// Spacing in px inserted when the author of the last message changes // Spacing in px inserted when the author of the last message changes
#define AUTHOR_CHANGE_SPACING 5 #define AUTHOR_CHANGE_SPACING 5
class QLabel;
class QVBoxLayout;
class QPushButton;
class CroppingLabel;
class ChatTextEdit;
class ChatAreaWidget;
namespace Ui { namespace Ui {
class MainWindow; class MainWindow;
} }
@ -51,6 +50,7 @@ signals:
void sendMessage(int, QString); void sendMessage(int, QString);
public slots: public slots:
void focusInput();
protected slots: protected slots:
void onChatContextMenuRequested(QPoint pos); void onChatContextMenuRequested(QPoint pos);

View File

@ -17,7 +17,9 @@
#include "groupchatform.h" #include "groupchatform.h"
#include "group.h" #include "group.h"
#include "widget/groupwidget.h" #include "widget/groupwidget.h"
#include "widget/widget.h" #include "widget/tool/chattextedit.h"
#include "widget/croppinglabel.h"
#include <QPushButton>
GroupChatForm::GroupChatForm(Group* chatGroup) GroupChatForm::GroupChatForm(Group* chatGroup)
: group(chatGroup) : group(chatGroup)

View File

@ -18,9 +18,8 @@
#define GROUPCHATFORM_H #define GROUPCHATFORM_H
#include "genericchatform.h" #include "genericchatform.h"
#include "widget/tool/chattextedit.h"
#include "ui_mainwindow.h"
namespace Ui {class MainWindow;}
class Group; class Group;
class GroupChatForm : public GenericChatForm class GroupChatForm : public GenericChatForm

View File

@ -18,11 +18,14 @@
#include "widget/widget.h" #include "widget/widget.h"
#include "settings.h" #include "settings.h"
#include "smileypack.h" #include "smileypack.h"
#include "ui_mainwindow.h"
#include <QFont> #include <QFont>
#include <QClipboard> #include <QClipboard>
#include <QApplication> #include <QApplication>
#include <QFileDialog> #include <QFileDialog>
#include <QDir> #include <QDir>
#include <QMessageBox>
#include "core.h"
SettingsForm::SettingsForm() SettingsForm::SettingsForm()
: QObject() : QObject()
@ -32,6 +35,7 @@ SettingsForm::SettingsForm()
QFont bold, small; QFont bold, small;
bold.setBold(true); bold.setBold(true);
small.setPixelSize(13); small.setPixelSize(13);
small.setKerning(false);
headLabel.setText(tr("User Settings","\"Headline\" of the window")); headLabel.setText(tr("User Settings","\"Headline\" of the window"));
headLabel.setFont(bold); headLabel.setFont(bold);
@ -41,7 +45,7 @@ SettingsForm::SettingsForm()
id.setReadOnly(true); id.setReadOnly(true);
id.setFrameStyle(QFrame::NoFrame); id.setFrameStyle(QFrame::NoFrame);
id.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); id.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
id.setFixedHeight(id.document()->size().height()); id.setFixedHeight(id.document()->size().height()*2);
profilesLabel.setText(tr("Available profiles:", "Labels the profile selection box")); profilesLabel.setText(tr("Available profiles:", "Labels the profile selection box"));
loadConf.setText(tr("Load profile", "button to load selected profile")); loadConf.setText(tr("Load profile", "button to load selected profile"));
@ -120,12 +124,14 @@ QList<QString> SettingsForm::searchProfiles()
QString SettingsForm::getSelectedSavePath() QString SettingsForm::getSelectedSavePath()
{ {
return Settings::getSettingsDirPath() + QDir::separator() + profiles.currentText() + Widget::getInstance()->getCore()->TOX_EXT; return Settings::getSettingsDirPath() + QDir::separator() + profiles.currentText() + Core::getInstance()->TOX_EXT;
} }
void SettingsForm::setFriendAddress(const QString& friendAddress) void SettingsForm::setFriendAddress(const QString& friendAddress)
{ {
id.setText(friendAddress); QString txt{friendAddress};
txt.insert(38,'\n');
id.setText(txt);
} }
void SettingsForm::show(Ui::MainWindow &ui) void SettingsForm::show(Ui::MainWindow &ui)
@ -143,13 +149,13 @@ void SettingsForm::show(Ui::MainWindow &ui)
void SettingsForm::onLoadClicked() void SettingsForm::onLoadClicked()
{ {
Widget::getInstance()->getCore()->switchConfiguration(profiles.currentText()); Core::getInstance()->switchConfiguration(profiles.currentText());
} }
void SettingsForm::onExportClicked() void SettingsForm::onExportClicked()
{ {
QString current = getSelectedSavePath(); QString current = getSelectedSavePath();
QString path = QFileDialog::getSaveFileName(0, tr("Export profile", "save dialog title"), QDir::homePath() + QDir::separator() + profiles.currentText() + Widget::getInstance()->getCore()->TOX_EXT, tr("Tox save file (*.tox)", "save dialog filter")); QString path = QFileDialog::getSaveFileName(0, tr("Export profile", "save dialog title"), QDir::homePath() + QDir::separator() + profiles.currentText() + Core::getInstance()->TOX_EXT, tr("Tox save file (*.tox)", "save dialog filter"));
QFile::copy(getSelectedSavePath(), path); QFile::copy(getSelectedSavePath(), path);
} }
@ -176,11 +182,11 @@ void SettingsForm::onImportClicked()
QString path = QFileDialog::getOpenFileName(0, tr("Import profile", "import dialog title"), QDir::homePath(), tr("Tox save file (*.tox)", "import dialog filter")); QString path = QFileDialog::getOpenFileName(0, tr("Import profile", "import dialog title"), QDir::homePath(), tr("Tox save file (*.tox)", "import dialog filter"));
QFileInfo info(path); QFileInfo info(path);
QString profile = info.completeBaseName(); QString profile = info.completeBaseName();
QString profilePath = Settings::getSettingsDirPath() + profile + Widget::getInstance()->getCore()->TOX_EXT; QString profilePath = Settings::getSettingsDirPath() + profile + Core::getInstance()->TOX_EXT;
Settings::getInstance().setCurrentProfile(profile); Settings::getInstance().setCurrentProfile(profile);
QFile::copy(path, profilePath); QFile::copy(path, profilePath);
profiles.addItem(profile); profiles.addItem(profile);
Widget::getInstance()->getCore()->switchConfiguration(profile); Core::getInstance()->switchConfiguration(profile);
} }
void SettingsForm::onTestVideoClicked() void SettingsForm::onTestVideoClicked()
@ -195,8 +201,10 @@ void SettingsForm::onEnableIPv6Updated()
void SettingsForm::copyIdClicked() void SettingsForm::copyIdClicked()
{ {
id.selectAll();; id.selectAll();
QApplication::clipboard()->setText(id.toPlainText()); QString txt = id.toPlainText();
txt.replace('\n',"");
QApplication::clipboard()->setText(txt);
} }
void SettingsForm::onUseTranslationUpdated() void SettingsForm::onUseTranslationUpdated()

View File

@ -20,21 +20,16 @@
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QLabel> #include <QLabel>
#include <QLineEdit> #include <QLineEdit>
#include <QString>
#include <QObject> #include <QObject>
#include <QSpacerItem>
#include <QCheckBox> #include <QCheckBox>
#include <QPushButton> #include <QPushButton>
#include <QTextEdit> #include <QTextEdit>
#include <QComboBox> #include <QComboBox>
#include <QDir>
#include <QFileInfo>
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox>
#include "ui_mainwindow.h"
#include "widget/selfcamview.h"
#include "widget/croppinglabel.h" #include "widget/croppinglabel.h"
#include "core.h"
namespace Ui {class MainWindow;}
class QString;
class SettingsForm : public QObject class SettingsForm : public QObject
{ {

View File

@ -15,6 +15,7 @@
*/ */
#include "friendlistwidget.h" #include "friendlistwidget.h"
#include <QDebug> #include <QDebug>
#include <QGridLayout>
FriendListWidget::FriendListWidget(QWidget *parent) : FriendListWidget::FriendListWidget(QWidget *parent) :
QWidget(parent) QWidget(parent)

View File

@ -18,8 +18,11 @@
#define FRIENDLISTWIDGET_H #define FRIENDLISTWIDGET_H
#include <QWidget> #include <QWidget>
#include <QGridLayout> #include <QHash>
#include "core.h" #include "corestructs.h"
class QLayout;
class QGridLayout;
class FriendListWidget : public QWidget class FriendListWidget : public QWidget
{ {

View File

@ -18,9 +18,10 @@
#include "group.h" #include "group.h"
#include "grouplist.h" #include "grouplist.h"
#include "groupwidget.h" #include "groupwidget.h"
#include "widget.h"
#include "friendlist.h" #include "friendlist.h"
#include "friend.h" #include "friend.h"
#include "core.h"
#include "widget/form/chatform.h"
#include <QContextMenuEvent> #include <QContextMenuEvent>
#include <QMenu> #include <QMenu>
@ -112,7 +113,7 @@ void FriendWidget::contextMenuEvent(QContextMenuEvent * event)
else if (groupActions.contains(selectedItem)) else if (groupActions.contains(selectedItem))
{ {
Group* group = groupActions[selectedItem]; Group* group = groupActions[selectedItem];
Widget::getInstance()->getCore()->groupInviteFriend(friendId, group->groupId); Core::getInstance()->groupInviteFriend(friendId, group->groupId);
} }
} }
} }

View File

@ -17,10 +17,7 @@
#ifndef FRIENDWIDGET_H #ifndef FRIENDWIDGET_H
#define FRIENDWIDGET_H #define FRIENDWIDGET_H
#include <QWidget>
#include <QLabel> #include <QLabel>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include "genericchatroomwidget.h" #include "genericchatroomwidget.h"
#include "croppinglabel.h" #include "croppinglabel.h"

View File

@ -17,7 +17,6 @@
#ifndef GROUPWIDGET_H #ifndef GROUPWIDGET_H
#define GROUPWIDGET_H #define GROUPWIDGET_H
#include <QWidget>
#include <QLabel> #include <QLabel>
#include "genericchatroomwidget.h" #include "genericchatroomwidget.h"

View File

@ -16,9 +16,8 @@
#include "netcamview.h" #include "netcamview.h"
#include "core.h" #include "core.h"
#include "widget.h" #include <QLabel>
#include <QApplication> #include <QHBoxLayout>
#include <QtConcurrent/QtConcurrent>
static inline void fromYCbCrToRGB( static inline void fromYCbCrToRGB(
uint8_t Y, uint8_t Cb, uint8_t Cr, uint8_t Y, uint8_t Cb, uint8_t Cr,
@ -70,7 +69,7 @@ void NetCamView::updateDisplay(vpx_image* frame)
if (!frame->w || !frame->h) if (!frame->w || !frame->h)
return; return;
Core* core = Widget::getInstance()->getCore(); Core* core = Core::getInstance();
core->increaseVideoBusyness(); core->increaseVideoBusyness();

View File

@ -18,14 +18,13 @@
#define NETCAMVIEW_H #define NETCAMVIEW_H
#include <QWidget> #include <QWidget>
#include <QHBoxLayout>
#include <QTimer>
#include <QLabel>
#include <vpx/vpx_image.h>
class QCloseEvent; class QCloseEvent;
class QShowEvent; class QShowEvent;
class QPainter; class QPainter;
class QLabel;
class QHBoxLayout;
class vpx_image;
class NetCamView : public QWidget class NetCamView : public QWidget
{ {

View File

@ -15,46 +15,45 @@
*/ */
#include "selfcamview.h" #include "selfcamview.h"
#include "camera.h"
#include <QCloseEvent> #include <QCloseEvent>
#include <QShowEvent> #include <QShowEvent>
#include <QTimer>
#include "widget.h" #include <QLabel>
#include <QHBoxLayout>
#include <opencv2/opencv.hpp>
using namespace cv; using namespace cv;
SelfCamView::SelfCamView(Camera* Cam, QWidget* parent) SelfCamView::SelfCamView(Camera* Cam, QWidget* parent)
: QWidget(parent), displayLabel{new QLabel}, : QWidget(parent), displayLabel{new QLabel},
mainLayout{new QHBoxLayout()}, cam(Cam) mainLayout{new QHBoxLayout()}, cam(Cam), updateDisplayTimer{new QTimer}
{ {
setLayout(mainLayout); setLayout(mainLayout);
setWindowTitle(SelfCamView::tr("Tox video test","Title of the window to test the video/webcam")); setWindowTitle(SelfCamView::tr("Tox video test","Title of the window to test the video/webcam"));
setMinimumSize(320,240); setMinimumSize(320,240);
updateDisplayTimer.setInterval(5); updateDisplayTimer->setInterval(5);
updateDisplayTimer.setSingleShot(false); updateDisplayTimer->setSingleShot(false);
displayLabel->setScaledContents(true); displayLabel->setScaledContents(true);
mainLayout->addWidget(displayLabel); mainLayout->addWidget(displayLabel);
connect(&updateDisplayTimer, SIGNAL(timeout()), this, SLOT(updateDisplay())); connect(updateDisplayTimer, SIGNAL(timeout()), this, SLOT(updateDisplay()));
}
SelfCamView::~SelfCamView()
{
} }
void SelfCamView::closeEvent(QCloseEvent* event) void SelfCamView::closeEvent(QCloseEvent* event)
{ {
cam->unsuscribe(); cam->unsuscribe();
updateDisplayTimer.stop(); updateDisplayTimer->stop();
event->accept(); event->accept();
} }
void SelfCamView::showEvent(QShowEvent* event) void SelfCamView::showEvent(QShowEvent* event)
{ {
cam->suscribe(); cam->suscribe();
updateDisplayTimer.start(); updateDisplayTimer->start();
event->accept(); event->accept();
} }

View File

@ -18,14 +18,14 @@
#define SELFCAMVIEW_H #define SELFCAMVIEW_H
#include <QWidget> #include <QWidget>
#include <QHBoxLayout>
#include <QTimer>
#include <QLabel>
#include "camera.h"
class QCloseEvent; class QCloseEvent;
class QShowEvent; class QShowEvent;
class QPainter; class QPainter;
class Camera;
class QLabel;
class QHBoxLayout;
class QTimer;
class SelfCamView : public QWidget class SelfCamView : public QWidget
{ {
@ -33,7 +33,6 @@ class SelfCamView : public QWidget
public: public:
SelfCamView(Camera* Cam, QWidget *parent=0); SelfCamView(Camera* Cam, QWidget *parent=0);
~SelfCamView();
private slots: private slots:
void updateDisplay(); void updateDisplay();
@ -47,7 +46,7 @@ private:
QLabel *displayLabel; QLabel *displayLabel;
QHBoxLayout* mainLayout; QHBoxLayout* mainLayout;
Camera* cam; Camera* cam;
QTimer updateDisplayTimer; QTimer* updateDisplayTimer;
}; };
#endif // SELFCAMVIEW_H #endif // SELFCAMVIEW_H

View File

@ -18,10 +18,11 @@
#include "smileypack.h" #include "smileypack.h"
#include <QStringList> #include <QStringList>
#include <QBuffer> #include <QBuffer>
#include "filetransferinstance.h"
QString ChatAction::toHtmlChars(const QString &str) QString ChatAction::toHtmlChars(const QString &str)
{ {
static QList<QPair<QString, QString>> replaceList = {{"&","&amp;"}, {" ","&nbsp;"}, {">","&gt;"}, {"<","&lt;"}}; static QList<QPair<QString, QString>> replaceList = {{"&","&amp;"}, {">","&gt;"}, {"<","&lt;"}};
QString res = str; QString res = str;
for (auto &it : replaceList) for (auto &it : replaceList)
@ -39,37 +40,63 @@ QString ChatAction::QImage2base64(const QImage &img)
return ba.toBase64(); return ba.toBase64();
} }
QString ChatAction::wrapName(const QString &name) QString ChatAction::getName()
{ {
if (isMe) if (isMe)
return QString("<td><div class=name_me>" + name + "</div></td>\n"); return QString("<div class=name_me>" + toHtmlChars(name) + "</div>");
else else
return QString("<td><div class=name>" + name + "</div></td>\n"); return QString("<div class=name>" + toHtmlChars(name) + "</div>");
} }
QString ChatAction::wrapDate(const QString &date) QString ChatAction::getDate()
{ {
QString res = "<td align=right><div class=date>" + date + "</div></td>\n"; QString res = "<div class=date>" + date + "</div>";
return res;
}
QString ChatAction::wrapMessage(const QString &message)
{
QString res = "<td width=100%><div class=message>" + message + "</div></td>\n";
return res;
}
QString ChatAction::wrapWholeLine(const QString &line)
{
QString res = "<tr>\n" + line + "</tr>\n";
return res; return res;
} }
MessageAction::MessageAction(const QString &author, const QString &message, const QString &date, const bool &me) : MessageAction::MessageAction(const QString &author, const QString &message, const QString &date, const bool &me) :
ChatAction(me) ChatAction(me, author, date),
message(message)
{
}
void MessageAction::setTextCursor(QTextCursor cursor)
{
// When this function is called, we're supposed to only update ourselve when needed
// Nobody should ask us to do anything with our content, we're on our own
// Except we never udpate on our own, so we can safely free our resources
(void) cursor;
message.clear();
message.squeeze();
name.clear();
name.squeeze();
date.clear();
date.squeeze();
}
QString MessageAction::getMessage()
{ {
QString message_ = SmileyPack::getInstance().smileyfied(toHtmlChars(message)); QString message_ = SmileyPack::getInstance().smileyfied(toHtmlChars(message));
// detect urls
QRegExp exp("(www\\.|http[s]?:\\/\\/|ftp:\\/\\/)\\S+");
int offset = 0;
while ((offset = exp.indexIn(message_, offset)) != -1)
{
QString url = exp.cap();
// add scheme if not specified
if (exp.cap(1) == "www.")
url.prepend("http://");
QString htmledUrl = QString("<a href=\"%1\">%1</a>").arg(url);
message_.replace(offset, exp.cap().length(), htmledUrl);
offset += htmledUrl.length();
}
// detect text quotes
QStringList messageLines = message_.split("\n"); QStringList messageLines = message_.split("\n");
message_ = ""; message_ = "";
for (QString& s : messageLines) for (QString& s : messageLines)
@ -81,40 +108,62 @@ MessageAction::MessageAction(const QString &author, const QString &message, cons
} }
message_ = message_.left(message_.length()-4); message_ = message_.left(message_.length()-4);
content = wrapWholeLine(wrapName(author) + wrapMessage(message_) + wrapDate(date)); return QString("<div class=message>" + message_ + "</div>");
}
QString MessageAction::getHtml()
{
return content;
} }
FileTransferAction::FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me) : FileTransferAction::FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me) :
ChatAction(me), ChatAction(me, author, date)
sender(author),
timestamp(date)
{ {
w = widget; w = widget;
connect(w, &FileTransferInstance::stateUpdated, this, &FileTransferAction::updateHtml);
} }
FileTransferAction::~FileTransferAction() FileTransferAction::~FileTransferAction()
{ {
} }
QString FileTransferAction::getHtml() QString FileTransferAction::getMessage()
{ {
QString widgetHtml; QString widgetHtml;
if (w != nullptr) if (w != nullptr)
widgetHtml = w->getHtmlImage(); widgetHtml = w->getHtmlImage();
else else
widgetHtml = "<div class=quote>EMPTY CONTENT</div>"; widgetHtml = "<div class=quote>EMPTY CONTENT</div>";
QString res = wrapWholeLine(wrapName(sender) + wrapMessage(widgetHtml) + wrapDate(timestamp));; return widgetHtml;
return res;
} }
QString FileTransferAction::wrapMessage(const QString &message) void FileTransferAction::setTextCursor(QTextCursor cursor)
{ {
QString res = "<td width=100%>" + message + "</td>\n"; cur = cursor;
return res; cur.setKeepPositionOnInsert(true);
int end=cur.selectionEnd();
cur.setPosition(cur.position());
cur.setPosition(end, QTextCursor::KeepAnchor);
}
void FileTransferAction::updateHtml()
{
if (cur.isNull())
return;
int pos = cur.selectionStart();
cur.removeSelectedText();
cur.setKeepPositionOnInsert(false);
cur.insertHtml(getMessage());
cur.setKeepPositionOnInsert(true);
int end = cur.position();
cur.setPosition(pos);
cur.setPosition(end, QTextCursor::KeepAnchor);
// Free our ressources if we'll never need to update again
if (w->getState() == FileTransferInstance::TransfState::tsCanceled
|| w->getState() == FileTransferInstance::TransfState::tsFinished)
{
name.clear();
name.squeeze();
date.clear();
date.squeeze();
cur = QTextCursor();
}
} }

View File

@ -18,26 +18,28 @@
#define CHATACTION_H #define CHATACTION_H
#include <QString> #include <QString>
#include "filetransferinstance.h" #include <QTextCursor>
class ChatAction class FileTransferInstance;
class ChatAction : public QObject
{ {
public: public:
ChatAction(const bool &me) : isMe(me) {;} ChatAction(const bool &me, const QString &author, const QString &date) : isMe(me), name(author), date(date) {;}
virtual ~ChatAction(){;} virtual ~ChatAction(){;}
virtual QString getHtml() = 0; virtual void setTextCursor(QTextCursor cursor){(void)cursor;} ///< Call once, and then you MUST let the object update itself
virtual QString getName();
virtual QString getMessage() = 0;
virtual QString getDate();
protected: protected:
QString toHtmlChars(const QString &str); QString toHtmlChars(const QString &str);
QString QImage2base64(const QImage &img); QString QImage2base64(const QImage &img);
virtual QString wrapName(const QString &name); protected:
virtual QString wrapDate(const QString &date);
virtual QString wrapMessage(const QString &message);
virtual QString wrapWholeLine(const QString &line);
private:
bool isMe; bool isMe;
QString name, date;
}; };
class MessageAction : public ChatAction class MessageAction : public ChatAction
@ -45,23 +47,28 @@ class MessageAction : public ChatAction
public: public:
MessageAction(const QString &author, const QString &message, const QString &date, const bool &me); MessageAction(const QString &author, const QString &message, const QString &date, const bool &me);
virtual ~MessageAction(){;} virtual ~MessageAction(){;}
virtual QString getHtml(); virtual QString getMessage();
virtual void setTextCursor(QTextCursor cursor) final;
private: private:
QString content; QString message;
}; };
class FileTransferAction : public ChatAction class FileTransferAction : public ChatAction
{ {
Q_OBJECT
public: public:
FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me); FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me);
virtual ~FileTransferAction(); virtual ~FileTransferAction();
virtual QString getHtml(); virtual QString getMessage();
virtual QString wrapMessage(const QString &message); virtual void setTextCursor(QTextCursor cursor) final;
private slots:
void updateHtml();
private: private:
FileTransferInstance *w; FileTransferInstance *w;
QString sender, timestamp; QTextCursor cur;
}; };
#endif // CHATACTION_H #endif // CHATACTION_H

View File

@ -21,6 +21,7 @@ ChatTextEdit::ChatTextEdit(QWidget *parent) :
QTextEdit(parent) QTextEdit(parent)
{ {
setPlaceholderText("Type your message here..."); setPlaceholderText("Type your message here...");
setAcceptRichText(false);
} }
void ChatTextEdit::keyPressEvent(QKeyEvent * event) void ChatTextEdit::keyPressEvent(QKeyEvent * event)

View File

@ -16,6 +16,7 @@
#include "widget.h" #include "widget.h"
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
#include "core.h"
#include "settings.h" #include "settings.h"
#include "friend.h" #include "friend.h"
#include "friendlist.h" #include "friendlist.h"
@ -26,17 +27,19 @@
#include "widget/groupwidget.h" #include "widget/groupwidget.h"
#include "widget/form/groupchatform.h" #include "widget/form/groupchatform.h"
#include "style.h" #include "style.h"
#include "selfcamview.h"
#include "widget/friendlistwidget.h"
#include "camera.h"
#include "widget/form/chatform.h"
#include <QMessageBox> #include <QMessageBox>
#include <QDebug> #include <QDebug>
#include <QTextStream>
#include <QFile> #include <QFile>
#include <QString> #include <QString>
#include <QPainter> #include <QPainter>
#include <QMouseEvent> #include <QMouseEvent>
#include <QDesktopWidget>
#include <QCursor>
#include <QSettings>
#include <QClipboard> #include <QClipboard>
#include <QThread>
#include <tox/tox.h>
Widget *Widget::instance{nullptr}; Widget *Widget::instance{nullptr};
@ -382,13 +385,15 @@ void Widget::setStatusMessage(const QString &statusMessage)
void Widget::addFriend(int friendId, const QString &userId) void Widget::addFriend(int friendId, const QString &userId)
{ {
qDebug() << "Adding friend with id "+userId;
qDebug() << "Widget: Adding friend with id "+userId;
Friend* newfriend = FriendList::addFriend(friendId, userId); Friend* newfriend = FriendList::addFriend(friendId, userId);
QLayout* layout = contactListWidget->getFriendLayout(Status::Offline); QLayout* layout = contactListWidget->getFriendLayout(Status::Offline);
layout->addWidget(newfriend->widget); layout->addWidget(newfriend->widget);
connect(newfriend->widget, SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), this, SLOT(onChatroomWidgetClicked(GenericChatroomWidget*))); connect(newfriend->widget, SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), this, SLOT(onChatroomWidgetClicked(GenericChatroomWidget*)));
connect(newfriend->widget, SIGNAL(removeFriend(int)), this, SLOT(removeFriend(int))); connect(newfriend->widget, SIGNAL(removeFriend(int)), this, SLOT(removeFriend(int)));
connect(newfriend->widget, SIGNAL(copyFriendIdToClipboard(int)), this, SLOT(copyFriendIdToClipboard(int))); connect(newfriend->widget, SIGNAL(copyFriendIdToClipboard(int)), this, SLOT(copyFriendIdToClipboard(int)));
connect(newfriend->widget, SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), newfriend->chatForm, SLOT(focusInput()));
connect(newfriend->chatForm, SIGNAL(sendMessage(int,QString)), core, SLOT(sendMessage(int,QString))); connect(newfriend->chatForm, SIGNAL(sendMessage(int,QString)), core, SLOT(sendMessage(int,QString)));
connect(newfriend->chatForm, SIGNAL(sendFile(int32_t, QString, QString, long long)), core, SLOT(sendFile(int32_t, QString, QString, long long))); connect(newfriend->chatForm, SIGNAL(sendFile(int32_t, QString, QString, long long)), core, SLOT(sendFile(int32_t, QString, QString, long long)));
connect(newfriend->chatForm, SIGNAL(answerCall(int)), core, SLOT(answerCall(int))); connect(newfriend->chatForm, SIGNAL(answerCall(int)), core, SLOT(answerCall(int)));
@ -510,7 +515,7 @@ void Widget::newMessageAlert()
{ {
QApplication::alert(this); QApplication::alert(this);
static QFile sndFile(":audio/notification.wav"); static QFile sndFile(":audio/notification.pcm");
static QByteArray sndData; static QByteArray sndData;
if (sndData.isEmpty()) if (sndData.isEmpty())
{ {
@ -521,7 +526,7 @@ void Widget::newMessageAlert()
ALuint buffer; ALuint buffer;
alGenBuffers(1, &buffer); alGenBuffers(1, &buffer);
alBufferData(buffer, AL_FORMAT_STEREO16, sndData.data(), sndData.size(), 44100); alBufferData(buffer, AL_FORMAT_MONO16, sndData.data(), sndData.size(), 44100);
alSourcei(core->alMainSource, AL_BUFFER, buffer); alSourcei(core->alMainSource, AL_BUFFER, buffer);
alSourcePlay(core->alMainSource); alSourcePlay(core->alMainSource);
} }
@ -608,7 +613,12 @@ void Widget::onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t Cha
TOX_CHAT_CHANGE change = static_cast<TOX_CHAT_CHANGE>(Change); TOX_CHAT_CHANGE change = static_cast<TOX_CHAT_CHANGE>(Change);
if (change == TOX_CHAT_CHANGE_PEER_ADD) if (change == TOX_CHAT_CHANGE_PEER_ADD)
g->addPeer(peernumber,"<Unknown>"); {
QString name = core->getGroupPeerName(groupnumber, peernumber);
if (name.isEmpty())
name = tr("<Unknown>", "Placeholder when we don't know someone's name in a group chat");
g->addPeer(peernumber,name);
}
else if (change == TOX_CHAT_CHANGE_PEER_DEL) else if (change == TOX_CHAT_CHANGE_PEER_DEL)
g->removePeer(peernumber); g->removePeer(peernumber);
else if (change == TOX_CHAT_CHANGE_PEER_NAME) else if (change == TOX_CHAT_CHANGE_PEER_NAME)
@ -650,6 +660,7 @@ Group *Widget::createGroup(int groupId)
connect(newgroup->widget, SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), this, SLOT(onChatroomWidgetClicked(GenericChatroomWidget*))); connect(newgroup->widget, SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), this, SLOT(onChatroomWidgetClicked(GenericChatroomWidget*)));
connect(newgroup->widget, SIGNAL(removeGroup(int)), this, SLOT(removeGroup(int))); connect(newgroup->widget, SIGNAL(removeGroup(int)), this, SLOT(removeGroup(int)));
connect(newgroup->widget, SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), newgroup->chatForm, SLOT(focusInput()));
connect(newgroup->chatForm, SIGNAL(sendMessage(int,QString)), core, SLOT(sendGroupMessage(int,QString))); connect(newgroup->chatForm, SIGNAL(sendMessage(int,QString)), core, SLOT(sendGroupMessage(int,QString)));
return newgroup; return newgroup;
} }

View File

@ -17,17 +17,11 @@
#ifndef WIDGET_H #ifndef WIDGET_H
#define WIDGET_H #define WIDGET_H
#include <QThread>
#include <QMainWindow> #include <QMainWindow>
#include <QString>
#include <QHBoxLayout>
#include <QMenu>
#include "core.h"
#include "widget/form/addfriendform.h" #include "widget/form/addfriendform.h"
#include "widget/form/settingsform.h" #include "widget/form/settingsform.h"
#include "widget/form/filesform.h" #include "widget/form/filesform.h"
#include "camera.h" #include "corestructs.h"
#include "friendlistwidget.h"
#define PIXELS_TO_ACT 7 #define PIXELS_TO_ACT 7
@ -38,6 +32,12 @@ class MainWindow;
class GenericChatroomWidget; class GenericChatroomWidget;
class Group; class Group;
struct Friend; struct Friend;
class QSplitter;
class SelfCamView;
class QMenu;
class Core;
class Camera;
class FriendListWidget;
class Widget : public QMainWindow class Widget : public QMainWindow
{ {