diff --git a/.gitignore b/.gitignore index e92651a06..228d0418e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,8 @@ *.pro.user* libs +*.o +moc_* +ui_* +qrc_* +Makefile +qtox diff --git a/INSTALL.md b/INSTALL.md index f53adbeb4..b5b2d5f11 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -131,17 +131,17 @@ First of all install the dependencies of Tox Core. Debian: ```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: ```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) ```bash -sudo pacman -S --needed yasm opus vpx +sudo pacman -S --needed opus vpx ``` Fedora: diff --git a/README.md b/README.md index 6bc803bb5..d6358283e 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,7 @@ This client runs on Windows, Linux and Mac natively.

Screenshots

Note: The screenshots may not always be up to date, but they should give a good idea of the general look and features
- - +/ ##Documentation: diff --git a/audio/notification.pcm b/audio/notification.pcm new file mode 100644 index 000000000..d57ac783d Binary files /dev/null and b/audio/notification.pcm differ diff --git a/audio/notification.wav b/audio/notification.wav deleted file mode 100644 index 2be40fd7f..000000000 Binary files a/audio/notification.wav and /dev/null differ diff --git a/bootstrap.sh b/bootstrap.sh index 2f7067fb6..9c67a7af9 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -21,7 +21,7 @@ TOX_CORE_DIR=libtoxcore-latest # the default value is 'false' and will be set to 'true' # if this script gets the parameter -t or --tox TOX_ONLY=false -GLOBAL=false +GLOBAL=true KEEP=false if [ -z "$BASE_DIR" ]; then @@ -49,8 +49,8 @@ while [ $# -ge 1 ] ; do if [ ${1} = "-t" -o ${1} = "--tox" ] ; then TOX_ONLY=true shift - elif [ ${1} = "-g" -o ${1} = "--global" ] ; then - GLOBAL=true + elif [ ${1} = "-l" -o ${1} = "--local" ] ; then + GLOBAL=false shift elif [ ${1} = "-k" -o ${1} = "--keep" ]; then KEEP=true @@ -71,8 +71,8 @@ while [ $# -ge 1 ] ; do echo " -h|--help : displays this help" echo " -t|--tox : only install/update libtoxcore" echo " requires an already installed libsodium" - echo " -g|--global: installs libtox* and libsodium globally" - echo " (also disables local configure prefixes)" + echo " -l|--local : installs libtox* and libsodium in the current directory," + echo " as opposed to the system directories" echo " -k|--keep : does not delete the build directories afterwards" echo "" echo "example usages:" @@ -147,6 +147,10 @@ fi popd +if [[ $GLOBAL = "true" ]]; then + sudo ldconfig +fi + ############### cleanup step ############### # remove cloned repositories if [[ $KEEP = "false" ]]; then diff --git a/cdata.cpp b/cdata.cpp index 3ab947a51..65f81d842 100644 --- a/cdata.cpp +++ b/cdata.cpp @@ -15,6 +15,8 @@ */ #include "cdata.h" +#include +#include // CData @@ -54,6 +56,8 @@ uint16_t CData::fromString(const QString& data, uint8_t* cData) // CUserId +const uint16_t CUserId::SIZE{TOX_CLIENT_ID_SIZE}; + CUserId::CUserId(const QString &userId) : CData(userId, SIZE) { @@ -68,6 +72,8 @@ QString CUserId::toString(const uint8_t* cUserId) // CFriendAddress +const uint16_t CFriendAddress::SIZE{TOX_FRIEND_ADDRESS_SIZE}; + CFriendAddress::CFriendAddress(const QString &friendAddress) : CData(friendAddress, SIZE) { diff --git a/cdata.h b/cdata.h index cd9558667..6433e9bac 100644 --- a/cdata.h +++ b/cdata.h @@ -18,9 +18,8 @@ #define CDATA_H #include -#include -#include "tox/tox.h" +class QString; class CData { public: @@ -48,7 +47,7 @@ public: static QString toString(const uint8_t *cUserId); 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); private: - static const uint16_t SIZE = TOX_FRIEND_ADDRESS_SIZE; + static const uint16_t SIZE; }; diff --git a/core.cpp b/core.cpp index 12452eee6..548cc075b 100644 --- a/core.cpp +++ b/core.cpp @@ -20,6 +20,8 @@ #include "settings.h" #include "widget/widget.h" +#include + #include #include @@ -28,9 +30,10 @@ #include #include #include -#include #include -#include +#include +#include +#include const QString Core::CONFIG_FILE_NAME = "data"; const QString Core::TOX_EXT = ".tox"; @@ -113,6 +116,11 @@ Core::~Core() alcCaptureCloseDevice(alInDev); } +Core* Core::getInstance() +{ + return Widget::getInstance()->getCore(); +} + void Core::get_tox() { // 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); removeFileFromQueue((bool)receive_send, file->friendId, file->fileNum); } + else if (receive_send == 0 && control_type == TOX_FILECONTROL_ACCEPT) + { + emit static_cast(core)->fileTransferRemotePausedUnpaused(*file, false); + } + else if ((receive_send == 0 || receive_send == 1) && control_type == TOX_FILECONTROL_PAUSE) + { + emit static_cast(core)->fileTransferRemotePausedUnpaused(*file, true); + } else { 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); } -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() { 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() { int size = tox_get_self_status_message_size(tox); diff --git a/core.h b/core.h index 49edb606e..16d3be50b 100644 --- a/core.h +++ b/core.h @@ -17,102 +17,24 @@ #ifndef CORE_HPP #define CORE_HPP -#include -#include - -#if defined(__APPLE__) && defined(__MACH__) - #include - #include -#else - #include - #include -#endif - #include -#include #include -#include -#include -#include -#include -#include -#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 +#include "corestructs.h" +#include "coreav.h" +#include "coredefines.h" +template class QList; class Camera; - -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) - : 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 QTimer; +class QString; class Core : public QObject { Q_OBJECT public: explicit Core(Camera* cam, QThread* coreThread); + static Core* getInstance(); ///< Returns the global widget's Core instance ~Core(); static const QString TOX_EXT; @@ -133,6 +55,7 @@ public: QString getUsername(); QString getStatusMessage(); + QString getSelfId(); void increaseVideoBusyness(); void decreaseVideoBusyness(); @@ -230,6 +153,7 @@ signals: void fileDownloadFinished(const QString& path); 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 fileTransferRemotePausedUnpaused(ToxFile file, bool paused); void avInvite(int friendId, int callIndex, bool video); void avStart(int friendId, int callIndex, bool video); @@ -308,7 +232,7 @@ private: QList dhtServerList; int dhtServerId; static QList fileSendQueue, fileRecvQueue; - static ToxCall calls[TOXAV_MAX_CALLS]; + static ToxCall calls[]; static const QString CONFIG_FILE_NAME; static const int videobufsize; diff --git a/coreav.cpp b/coreav.cpp index 2a3ce7a67..9244fe433 100644 --- a/coreav.cpp +++ b/coreav.cpp @@ -15,7 +15,9 @@ */ #include "core.h" -#include "widget/widget.h" +#include "widget/camera.h" +#include +#include ToxCall Core::calls[TOXAV_MAX_CALLS]; 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) { 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].sendVideoTimer->stop(); - Widget::getInstance()->getCamera()->unsuscribe(); + Camera::getInstance()->unsuscribe(); emit ((Core*)core)->avMediaChange(friendId, callId, false); } else { - Widget::getInstance()->getCamera()->suscribe(); + Camera::getInstance()->suscribe(); calls[callId].videoEnabled = true; calls[callId].sendVideoTimer->start(); emit ((Core*)core)->avMediaChange(friendId, callId, true); @@ -159,7 +161,7 @@ void Core::cleanupCall(int callId) calls[callId].sendAudioTimer->stop(); calls[callId].sendVideoTimer->stop(); if (calls[callId].videoEnabled) - Widget::getInstance()->getCamera()->unsuscribe(); + Camera::getInstance()->unsuscribe(); alcCaptureStop(alInDev); } @@ -224,7 +226,7 @@ void Core::playCallVideo(ToxAv*, int32_t callId, vpx_image_t* img, void *user_da if (videoBusyness >= 1) qWarning() << "Core: playCallVideo: Busy, dropping current frame"; else - emit Widget::getInstance()->getCore()->videoFrameReceived(img); + emit Core::getInstance()->videoFrameReceived(img); vpx_img_free(img); } diff --git a/coreav.h b/coreav.h new file mode 100644 index 000000000..ea563d6ce --- /dev/null +++ b/coreav.h @@ -0,0 +1,29 @@ +#ifndef COREAV_H +#define COREAV_H + +#include + +#if defined(__APPLE__) && defined(__MACH__) + #include + #include +#else + #include + #include +#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 diff --git a/coredefines.h b/coredefines.h new file mode 100644 index 000000000..cb6fcffed --- /dev/null +++ b/coredefines.h @@ -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 diff --git a/corestructs.cpp b/corestructs.cpp new file mode 100644 index 000000000..e7c8245b0 --- /dev/null +++ b/corestructs.cpp @@ -0,0 +1,19 @@ +#include "corestructs.h" +#include + +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); +} diff --git a/corestructs.h b/corestructs.h new file mode 100644 index 000000000..ebaab4534 --- /dev/null +++ b/corestructs.h @@ -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 +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 diff --git a/cstring.cpp b/cstring.cpp index 7bcd29cb3..6d7815e9c 100644 --- a/cstring.cpp +++ b/cstring.cpp @@ -15,6 +15,7 @@ */ #include "cstring.h" +#include CString::CString(const QString& string) { diff --git a/cstring.h b/cstring.h index 8d6e7efd3..a75ed6468 100644 --- a/cstring.h +++ b/cstring.h @@ -18,7 +18,8 @@ #define CSTRING_H #include -#include + +class QString; class CString { diff --git a/filetransferinstance.cpp b/filetransferinstance.cpp index e927545c6..9bcc7b6e1 100644 --- a/filetransferinstance.cpp +++ b/filetransferinstance.cpp @@ -15,15 +15,12 @@ */ #include "filetransferinstance.h" -#include "widget/widget.h" #include "core.h" -#include "math.h" -#include "style.h" +#include #include -#include -#include #include #include +#include uint FileTransferInstance::Idconter = 0; @@ -33,6 +30,7 @@ FileTransferInstance::FileTransferInstance(ToxFile File) { id = Idconter++; state = tsPending; + remotePaused = false; filename = File.fileName; size = getHumanReadableSize(File.filesize); @@ -64,7 +62,7 @@ void FileTransferInstance::onFileTransferInfo(int FriendId, int FileNum, int64_t if (FileNum != fileNum || FriendId != friendId || Direction != direction) return; - state = tsProcessing; +// state = tsProcessing; QDateTime newtime = QDateTime::currentDateTime(); int timediff = lastUpdate.secsTo(newtime); if (timediff <= 0) @@ -93,7 +91,7 @@ void FileTransferInstance::onFileTransferCancelled(int FriendId, int FileNum, To { if (FileNum != fileNum || FriendId != friendId || Direction != direction) return; - disconnect(Widget::getInstance()->getCore(),0,this,0); + disconnect(Core::getInstance(),0,this,0); state = tsCanceled; emit stateUpdated(); @@ -103,7 +101,7 @@ void FileTransferInstance::onFileTransferFinished(ToxFile File) { if (File.fileNum != fileNum || File.friendId != friendId || File.direction != direction) return; - disconnect(Widget::getInstance()->getCore(),0,this,0); + disconnect(Core::getInstance(),0,this,0); if (File.direction == ToxFile::RECEIVING) { @@ -124,16 +122,47 @@ void FileTransferInstance::onFileTransferFinished(ToxFile File) 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() { - Widget::getInstance()->getCore()->cancelFileSend(friendId, fileNum); + Core::getInstance()->cancelFileSend(friendId, fileNum); state = tsCanceled; emit stateUpdated(); } void FileTransferInstance::rejectRecvRequest() { - Widget::getInstance()->getCore()->rejectFileRecvRequest(friendId, fileNum); + Core::getInstance()->rejectFileRecvRequest(friendId, fileNum); onFileTransferCancelled(friendId, fileNum, direction); state = tsCanceled; emit stateUpdated(); @@ -159,7 +188,7 @@ void FileTransferInstance::acceptRecvRequest() QString path; 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()) return; else @@ -170,13 +199,13 @@ void FileTransferInstance::acceptRecvRequest() if (isFileWritable(path)) break; 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; - Widget::getInstance()->getCore()->acceptFileRecvRequest(friendId, fileNum, path); + Core::getInstance()->acceptFileRecvRequest(friendId, fileNum, path); state = tsProcessing; emit stateUpdated(); @@ -184,19 +213,33 @@ void FileTransferInstance::acceptRecvRequest() void FileTransferInstance::pauseResumeRecv() { - Widget::getInstance()->getCore()->pauseResumeFileRecv(friendId, fileNum); - if (state == tsProcessing) - state = tsPaused; - else state = tsProcessing; + if (!(state == tsProcessing || state == tsPaused)) + return; + + if (remotePaused) + return; + + Core::getInstance()->pauseResumeFileRecv(friendId, fileNum); +// if (state == tsProcessing) +// state = tsPaused; +// else state = tsProcessing; + emit stateUpdated(); } void FileTransferInstance::pauseResumeSend() { - Widget::getInstance()->getCore()->pauseResumeFileSend(friendId, fileNum); - if (state == tsProcessing) - state = tsPaused; - else state = tsProcessing; + if (!(state == tsProcessing || state == tsPaused)) + return; + + if (remotePaused) + return; + + Core::getInstance()->pauseResumeFileSend(friendId, fileNum); +// if (state == tsProcessing) +// state = tsPaused; +// else state = tsProcessing; + emit stateUpdated(); } @@ -223,7 +266,15 @@ QString FileTransferInstance::getHtmlImage() else if (state == tsPaused) rightBtnImg = QImage(":/ui/fileTransferInstance/resumeFileButton.png"); 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); } else if (state == tsCanceled) diff --git a/filetransferinstance.h b/filetransferinstance.h index ff5d85937..b81b03102 100644 --- a/filetransferinstance.h +++ b/filetransferinstance.h @@ -17,29 +17,32 @@ #define FILETRANSFERINSTANCE_H #include -#include -#include -#include -#include -#include #include +#include -#include "core.h" +#include "corestructs.h" struct ToxFile; class FileTransferInstance : public QObject { Q_OBJECT +public: + enum TransfState {tsPending, tsProcessing, tsPaused, tsFinished, tsCanceled}; + public: explicit FileTransferInstance(ToxFile File); QString getHtmlImage(); uint getId(){return id;} + TransfState getState() {return state;} public slots: 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 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); signals: @@ -61,12 +64,11 @@ private: QString wrapIntoForm(const QString &content, const QString &type, const QString &imgAstr, const QString &imgBstr); private: - enum TransfState {tsPending, tsProcessing, tsPaused, tsFinished, tsCanceled}; - static uint Idconter; uint id; TransfState state; + bool remotePaused; QImage pic; QString filename, size, speed, eta; QDateTime lastUpdate; diff --git a/friend.cpp b/friend.cpp index ec8dd3860..6676cea81 100644 --- a/friend.cpp +++ b/friend.cpp @@ -17,6 +17,7 @@ #include "friend.h" #include "friendlist.h" #include "widget/friendwidget.h" +#include "widget/form/chatform.h" Friend::Friend(int FriendId, QString UserId) : friendId(FriendId), userId(UserId) diff --git a/friend.h b/friend.h index 8a3a2427a..390235657 100644 --- a/friend.h +++ b/friend.h @@ -18,9 +18,10 @@ #define FRIEND_H #include -#include "widget/form/chatform.h" +#include "corestructs.h" struct FriendWidget; +class ChatForm; struct Friend { @@ -38,7 +39,6 @@ public: ChatForm* chatForm; int hasNewEvents; Status friendStatus; - QPixmap avatar; }; #endif // FRIEND_H diff --git a/friendlist.cpp b/friendlist.cpp index 6547c408c..1c16c77d4 100644 --- a/friendlist.cpp +++ b/friendlist.cpp @@ -21,7 +21,7 @@ QList FriendList::friendList; -Friend* FriendList::addFriend(int friendId, QString userId) +Friend* FriendList::addFriend(int friendId, const QString& userId) { for (Friend* f : friendList) if (f->friendId == friendId) diff --git a/friendlist.h b/friendlist.h index b0f1279b7..bde30526d 100644 --- a/friendlist.h +++ b/friendlist.h @@ -17,16 +17,15 @@ #ifndef FRIENDLIST_H #define FRIENDLIST_H -#include -#include - +template class QList; struct Friend; +class QString; class FriendList { public: FriendList(); - static Friend* addFriend(int friendId, QString userId); + static Friend* addFriend(int friendId, const QString& userId); static Friend* findFriend(int friendId); static void removeFriend(int friendId); diff --git a/group.cpp b/group.cpp index 88e8a13a7..4898f525a 100644 --- a/group.cpp +++ b/group.cpp @@ -19,18 +19,18 @@ #include "widget/form/groupchatform.h" #include "friendlist.h" #include "friend.h" -#include "widget/widget.h" #include "core.h" #include +#include 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); chatForm = new GroupChatForm(this); - connect(&peerInfoTimer, SIGNAL(timeout()), this, SLOT(queryPeerInfo())); - peerInfoTimer.setInterval(500); - peerInfoTimer.setSingleShot(false); + connect(peerInfoTimer, SIGNAL(timeout()), this, SLOT(queryPeerInfo())); + peerInfoTimer->setInterval(500); + peerInfoTimer->setSingleShot(false); //peerInfoTimer.start(); //in groupchats, we only notify on messages containing your name @@ -42,11 +42,12 @@ Group::~Group() { delete chatForm; delete widget; + delete peerInfoTimer; } void Group::queryPeerInfo() { - const Core* core = Widget::getInstance()->getCore(); + const Core* core = Core::getInstance(); int nPeersResult = core->getGroupNumberPeers(groupId); if (nPeersResult == -1) { @@ -86,7 +87,7 @@ void Group::queryPeerInfo() { qDebug() << "Group::queryPeerInfo: Successfully loaded names"; hasPeerInfo = true; - peerInfoTimer.stop(); + peerInfoTimer->stop(); } } diff --git a/group.h b/group.h index aa996978e..fed4b11ee 100644 --- a/group.h +++ b/group.h @@ -17,15 +17,15 @@ #ifndef GROUP_H #define GROUP_H -#include #include -#include +#include #define RETRY_PEER_INFO_INTERVAL 500 struct Friend; class GroupWidget; class GroupChatForm; +class QTimer; class Group : public QObject { @@ -47,7 +47,7 @@ public: GroupWidget* widget; GroupChatForm* chatForm; bool hasPeerInfo; - QTimer peerInfoTimer; + QTimer* peerInfoTimer; int hasNewMessages, userWasMentioned; }; diff --git a/grouplist.cpp b/grouplist.cpp index 767faa88f..851ae5b37 100644 --- a/grouplist.cpp +++ b/grouplist.cpp @@ -19,7 +19,7 @@ QList GroupList::groupList; -Group* GroupList::addGroup(int groupId, QString name) +Group* GroupList::addGroup(int groupId, const QString& name) { Group* newGroup = new Group(groupId, name); groupList.append(newGroup); diff --git a/grouplist.h b/grouplist.h index 313ec9b0d..a2bd5a887 100644 --- a/grouplist.h +++ b/grouplist.h @@ -17,17 +17,16 @@ #ifndef GROUPLIST_H #define GROUPLIST_H -#include -#include -#include - +template +class QList; class Group; +class QString; class GroupList { public: GroupList(); - static Group* addGroup(int groupId, QString name); + static Group* addGroup(int groupId, const QString& name); static Group* findGroup(int groupId); static void removeGroup(int groupId); diff --git a/main.cpp b/main.cpp index d2d34b138..1cdac827e 100644 --- a/main.cpp +++ b/main.cpp @@ -19,6 +19,7 @@ #include #include #include +#include int main(int argc, char *argv[]) { @@ -31,7 +32,7 @@ int main(int argc, char *argv[]) if (Settings::getInstance().getUseTranslations()) { QString locale = QLocale::system().name().section('_', 0, 0); - if (translator.load(locale,":translations/")) + if (locale=="en" || translator.load(locale,":translations/")) qDebug() << "Loaded translation "+locale; else qDebug() << "Error loading translation "+locale; @@ -50,45 +51,3 @@ int main(int argc, char *argv[]) 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 - */ diff --git a/qtox.pro b/qtox.pro index 607d25791..7b52d779c 100644 --- a/qtox.pro +++ b/qtox.pro @@ -107,7 +107,10 @@ HEADERS += widget/form/addfriendform.h \ widget/form/genericchatform.h \ widget/tool/chataction.h \ widget/chatareawidget.h \ - filetransferinstance.h + filetransferinstance.h \ + corestructs.h \ + coredefines.h \ + coreav.h SOURCES += \ widget/form/addfriendform.cpp \ @@ -143,4 +146,5 @@ SOURCES += \ widget/form/genericchatform.cpp \ widget/tool/chataction.cpp \ widget/chatareawidget.cpp \ - filetransferinstance.cpp + filetransferinstance.cpp \ + corestructs.cpp diff --git a/res.qrc b/res.qrc index 508fbef28..cbf038a58 100644 --- a/res.qrc +++ b/res.qrc @@ -6,7 +6,6 @@ res/DejaVuSans.ttf - audio/notification.wav img/icon.png img/contact.png img/contact_dark.png @@ -128,11 +127,13 @@ ui/volButton/volButton.css ui/fileTransferInstance/acceptFileButton.png ui/fileTransferInstance/pauseFileButton.png + ui/fileTransferInstance/pauseGreyFileButton.png ui/fileTransferInstance/resumeFileButton.png ui/fileTransferInstance/stopFileButton.png ui/fileTransferInstance/emptyLGreenFileButton.png ui/fileTransferInstance/emptyLRedFileButton.png ui/fileTransferInstance/emptyRGreenFileButton.png ui/fileTransferInstance/emptyRRedFileButton.png + audio/notification.pcm diff --git a/settings.cpp b/settings.cpp index f2fcf58c0..2390257e6 100644 --- a/settings.cpp +++ b/settings.cpp @@ -16,8 +16,8 @@ #include "settings.h" #include "smileypack.h" -#include "widget/widget.h" +#include #include #include #include diff --git a/settings.h b/settings.h index 6533329dc..291c09270 100644 --- a/settings.h +++ b/settings.h @@ -18,8 +18,7 @@ #define SETTINGS_HPP #include -#include -#include +#include class Settings : public QObject { diff --git a/simple_make.sh b/simple_make.sh new file mode 100755 index 000000000..cf2b0234c --- /dev/null +++ b/simple_make.sh @@ -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 diff --git a/smileypack.cpp b/smileypack.cpp index cca56583c..5af07194f 100644 --- a/smileypack.cpp +++ b/smileypack.cpp @@ -19,8 +19,14 @@ #include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include SmileyPack::SmileyPack() { diff --git a/style.h b/style.h index 77a09ce25..4bd42d77f 100644 --- a/style.h +++ b/style.h @@ -17,7 +17,7 @@ #ifndef STYLE_H #define STYLE_H -#include +class QString; class Style { diff --git a/ui/fileTransferInstance/pauseGreyFileButton.png b/ui/fileTransferInstance/pauseGreyFileButton.png new file mode 100644 index 000000000..4bf1efd12 Binary files /dev/null and b/ui/fileTransferInstance/pauseGreyFileButton.png differ diff --git a/ui/fileTransferInstance/resumeFileButton.png b/ui/fileTransferInstance/resumeFileButton.png index 4bf1efd12..1b823d26d 100644 Binary files a/ui/fileTransferInstance/resumeFileButton.png and b/ui/fileTransferInstance/resumeFileButton.png differ diff --git a/widget/camera.cpp b/widget/camera.cpp index e4a6010c7..dab371005 100644 --- a/widget/camera.cpp +++ b/widget/camera.cpp @@ -15,7 +15,7 @@ */ #include "camera.h" -#include +#include "widget.h" using namespace cv; @@ -114,3 +114,8 @@ vpx_image Camera::getLastVPXImage() } return img; } + +Camera* Camera::getInstance() +{ + return Widget::getInstance()->getCamera(); +} diff --git a/widget/camera.h b/widget/camera.h index e717c5c1a..e48307d41 100644 --- a/widget/camera.h +++ b/widget/camera.h @@ -31,6 +31,7 @@ class Camera { public: Camera(); + static Camera* getInstance(); ///< Returns the global widget's Camera instance void suscribe(); ///< Call this once before trying to get frames void unsuscribe(); ///< Call this once when you don't need frames anymore cv::Mat getLastFrame(); ///< Get the last captured frame diff --git a/widget/chatareawidget.cpp b/widget/chatareawidget.cpp index 9f8633b97..203633386 100644 --- a/widget/chatareawidget.cpp +++ b/widget/chatareawidget.cpp @@ -15,23 +15,49 @@ */ #include "chatareawidget.h" -#include -#include +#include "widget/tool/chataction.h" #include +#include +#include +#include ChatAreaWidget::ChatAreaWidget(QWidget *parent) : - QTextEdit(parent) + QTextBrowser(parent) { setReadOnly(true); viewport()->setCursor(Qt::ArrowCursor); setContextMenuPolicy(Qt::CustomContextMenu); 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() { - for (ChatAction *it : messages) - delete it; + for (ChatAction* action : messages) + delete action; + messages.clear(); } 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("\n"); - - for (ChatAction *it : messages) - { - res += it->getHtml(); - } - res += "
"; - return res; + QDesktopServices::openUrl(url); } void ChatAreaWidget::insertMessage(ChatAction *msgAction) @@ -82,31 +101,33 @@ void ChatAreaWidget::insertMessage(ChatAction *msgAction) if (msgAction == nullptr) return; - messages.append(msgAction); - //updateChatContent(); + checkSlider(); - moveCursor(QTextCursor::End); - moveCursor(QTextCursor::PreviousCell); - insertHtml(msgAction->getHtml()); + int row = chatTextTable->rows() - 1; + chatTextTable->cellAt(row,0).firstCursorPosition().setBlockFormat(nameFormat); + 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(); 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(); } diff --git a/widget/chatareawidget.h b/widget/chatareawidget.h index 2d85fc453..c30b12c61 100644 --- a/widget/chatareawidget.h +++ b/widget/chatareawidget.h @@ -17,18 +17,19 @@ #ifndef CHATAREAWIDGET_H #define CHATAREAWIDGET_H -#include +#include #include -#include "widget/tool/chataction.h" -class ChatAreaWidget : public QTextEdit +class ChatAction; +class QTextTable; + +class ChatAreaWidget : public QTextBrowser { Q_OBJECT public: explicit ChatAreaWidget(QWidget *parent = 0); virtual ~ChatAreaWidget(); void insertMessage(ChatAction *msgAction); - void clearMessages(); signals: void onFileTranfertInterract(QString widgetName, QString buttonName); @@ -36,14 +37,18 @@ signals: protected: void mouseReleaseEvent(QMouseEvent * event); -public slots: - void updateChatContent(); +private slots: + void onAnchorClicked(const QUrl& url); + void onSliderRangeChanged(); private: - QString getHtmledMessages(); + void checkSlider(); + QList messages; bool lockSliderToBottom; int sliderPosition; + QTextTable *chatTextTable; + QTextBlockFormat nameFormat, dateFormat; }; #endif // CHATAREAWIDGET_H diff --git a/widget/croppinglabel.cpp b/widget/croppinglabel.cpp index 47b324d1e..d9022402a 100644 --- a/widget/croppinglabel.cpp +++ b/widget/croppinglabel.cpp @@ -16,6 +16,7 @@ #include "croppinglabel.h" #include +#include CroppingLabel::CroppingLabel(QWidget* parent) : QLabel(parent) diff --git a/widget/croppinglabel.h b/widget/croppinglabel.h index aeca082b1..678829cbe 100644 --- a/widget/croppinglabel.h +++ b/widget/croppinglabel.h @@ -18,7 +18,8 @@ #define CROPPINGLABEL_H #include -#include + +class QLineEdit; class CroppingLabel : public QLabel { diff --git a/widget/form/addfriendform.cpp b/widget/form/addfriendform.cpp index 9d09e0682..3a44ae672 100644 --- a/widget/form/addfriendform.cpp +++ b/widget/form/addfriendform.cpp @@ -19,6 +19,8 @@ #include #include #include +#include "ui_mainwindow.h" +#include "core.h" #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 { QMessageBox warning(main); + warning.setWindowTitle("Tox"); warning.setText(message); warning.setIcon(QMessageBox::Warning); warning.exec(); @@ -92,7 +95,10 @@ void AddFriendForm::onSendTriggered() if (id.isEmpty()) { 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)) { - 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->message.setText(""); } else { diff --git a/widget/form/addfriendform.h b/widget/form/addfriendform.h index 0edcf2214..6fd9d736c 100644 --- a/widget/form/addfriendform.h +++ b/widget/form/addfriendform.h @@ -17,8 +17,6 @@ #ifndef ADDFRIENDFORM_H #define ADDFRIENDFORM_H -#include "ui_mainwindow.h" - #include #include #include @@ -26,6 +24,8 @@ #include #include +namespace Ui {class MainWindow;} + class AddFriendForm : public QObject { Q_OBJECT @@ -42,8 +42,8 @@ signals: void friendRequested(const QString& friendAddress, const QString& message); private slots: - void onSendTriggered(); - void handleDnsLookup(); + void onSendTriggered(); + void handleDnsLookup(); private: QLabel headLabel, toxIdLabel, messageLabel; diff --git a/widget/form/chatform.cpp b/widget/form/chatform.cpp index 229d6c8d4..0114a92db 100644 --- a/widget/form/chatform.cpp +++ b/widget/form/chatform.cpp @@ -14,14 +14,21 @@ See the COPYING file for more details. */ +#include +#include +#include +#include +#include #include "chatform.h" #include "friend.h" #include "widget/friendwidget.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 -#include -#include ChatForm::ChatForm(Friend* chatFriend) : f(chatFriend) @@ -35,15 +42,15 @@ ChatForm::ChatForm(Friend* chatFriend) headTextLayout->addWidget(statusMessageLabel); headTextLayout->addStretch(); - connect(Widget::getInstance()->getCore(), &Core::fileSendStarted, this, &ChatForm::startFileSend); - connect(Widget::getInstance()->getCore(), &Core::videoFrameReceived, netcam, &NetCamView::updateDisplay); + connect(Core::getInstance(), &Core::fileSendStarted, this, &ChatForm::startFileSend); + connect(Core::getInstance(), &Core::videoFrameReceived, netcam, &NetCamView::updateDisplay); connect(sendButton, &QPushButton::clicked, this, &ChatForm::onSendTriggered); connect(fileButton, &QPushButton::clicked, this, &ChatForm::onAttachClicked); connect(callButton, &QPushButton::clicked, this, &ChatForm::onCallTriggered); connect(videoButton, &QPushButton::clicked, this, &ChatForm::onVideoCallTriggered); connect(msgEdit, &ChatTextEdit::enterPressed, this, &ChatForm::onSendTriggered); 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() @@ -98,10 +105,12 @@ void ChatForm::startFileSend(ToxFile file) FileTransferInstance* fileTrans = new FileTransferInstance(file); ftransWidgets.insert(fileTrans->getId(), fileTrans); - connect(Widget::getInstance()->getCore(), &Core::fileTransferInfo, fileTrans, &FileTransferInstance::onFileTransferInfo); - connect(Widget::getInstance()->getCore(), &Core::fileTransferCancelled, fileTrans, &FileTransferInstance::onFileTransferCancelled); - connect(Widget::getInstance()->getCore(), &Core::fileTransferFinished, fileTrans, &FileTransferInstance::onFileTransferFinished); - connect(fileTrans, SIGNAL(stateUpdated()), chatWidget, SLOT(updateChatContent())); + connect(Core::getInstance(), &Core::fileTransferInfo, fileTrans, &FileTransferInstance::onFileTransferInfo); + connect(Core::getInstance(), &Core::fileTransferCancelled, fileTrans, &FileTransferInstance::onFileTransferCancelled); + connect(Core::getInstance(), &Core::fileTransferFinished, fileTrans, &FileTransferInstance::onFileTransferFinished); + 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(); if (name == previousName) @@ -119,10 +128,12 @@ void ChatForm::onFileRecvRequest(ToxFile file) FileTransferInstance* fileTrans = new FileTransferInstance(file); ftransWidgets.insert(fileTrans->getId(), fileTrans); - connect(Widget::getInstance()->getCore(), &Core::fileTransferInfo, fileTrans, &FileTransferInstance::onFileTransferInfo); - connect(Widget::getInstance()->getCore(), &Core::fileTransferCancelled, fileTrans, &FileTransferInstance::onFileTransferCancelled); - connect(Widget::getInstance()->getCore(), &Core::fileTransferFinished, fileTrans, &FileTransferInstance::onFileTransferFinished); - connect(fileTrans, SIGNAL(stateUpdated()), chatWidget, SLOT(updateChatContent())); + connect(Core::getInstance(), &Core::fileTransferInfo, fileTrans, &FileTransferInstance::onFileTransferInfo); + connect(Core::getInstance(), &Core::fileTransferCancelled, fileTrans, &FileTransferInstance::onFileTransferCancelled); + connect(Core::getInstance(), &Core::fileTransferFinished, fileTrans, &FileTransferInstance::onFileTransferFinished); + 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(); if (!w->isFriendWidgetCurActiveWidget(f)|| w->getIsWindowMinimized() || !w->isActiveWindow()) diff --git a/widget/form/chatform.h b/widget/form/chatform.h index 9407f1c11..93bc2d6b4 100644 --- a/widget/form/chatform.h +++ b/widget/form/chatform.h @@ -18,11 +18,11 @@ #define CHATFORM_H #include "genericchatform.h" -#include "core.h" -#include "widget/netcamview.h" +#include "corestructs.h" struct Friend; class FileTransferInstance; +class NetCamView; class ChatForm : public GenericChatForm { diff --git a/widget/form/filesform.cpp b/widget/form/filesform.cpp index 6d69c1f5a..8aaa314b2 100644 --- a/widget/form/filesform.cpp +++ b/widget/form/filesform.cpp @@ -15,6 +15,11 @@ */ #include "filesform.h" +#include "ui_mainwindow.h" +#include +#include +#include +#include FilesForm::FilesForm() : QObject() diff --git a/widget/form/filesform.h b/widget/form/filesform.h index 0f1a2b1d8..c3efdaacf 100644 --- a/widget/form/filesform.h +++ b/widget/form/filesform.h @@ -17,17 +17,14 @@ #ifndef FILESFORM_H #define FILESFORM_H -#include "ui_mainwindow.h" - -#include +#include #include #include -#include #include #include -#include -#include -#include + +namespace Ui {class MainWindow;} +class QListWidget; class FilesForm : public QObject { diff --git a/widget/form/genericchatform.cpp b/widget/form/genericchatform.cpp index fcffb2385..f5681f1c6 100644 --- a/widget/form/genericchatform.cpp +++ b/widget/form/genericchatform.cpp @@ -22,6 +22,9 @@ #include "style.h" #include "widget/widget.h" #include "settings.h" +#include "widget/tool/chataction.h" +#include "widget/chatareawidget.h" +#include "widget/tool/chattextedit.h" GenericChatForm::GenericChatForm(QObject *parent) : QObject(parent) @@ -200,3 +203,8 @@ void GenericChatForm::onEmoteInsertRequested(QString str) msgEdit->setFocus(); // refocus so that we can continue typing } + +void GenericChatForm::focusInput() +{ + msgEdit->setFocus(); +} diff --git a/widget/form/genericchatform.h b/widget/form/genericchatform.h index d8b20281d..95940cda5 100644 --- a/widget/form/genericchatform.h +++ b/widget/form/genericchatform.h @@ -19,19 +19,18 @@ #include #include -#include -#include -#include -#include -#include - -#include "widget/croppinglabel.h" -#include "widget/chatareawidget.h" -#include "widget/tool/chattextedit.h" +#include // Spacing in px inserted when the author of the last message changes #define AUTHOR_CHANGE_SPACING 5 +class QLabel; +class QVBoxLayout; +class QPushButton; +class CroppingLabel; +class ChatTextEdit; +class ChatAreaWidget; + namespace Ui { class MainWindow; } @@ -51,6 +50,7 @@ signals: void sendMessage(int, QString); public slots: + void focusInput(); protected slots: void onChatContextMenuRequested(QPoint pos); diff --git a/widget/form/groupchatform.cpp b/widget/form/groupchatform.cpp index ca355e3db..907787fd3 100644 --- a/widget/form/groupchatform.cpp +++ b/widget/form/groupchatform.cpp @@ -17,7 +17,9 @@ #include "groupchatform.h" #include "group.h" #include "widget/groupwidget.h" -#include "widget/widget.h" +#include "widget/tool/chattextedit.h" +#include "widget/croppinglabel.h" +#include GroupChatForm::GroupChatForm(Group* chatGroup) : group(chatGroup) diff --git a/widget/form/groupchatform.h b/widget/form/groupchatform.h index 9b4766180..cdf20a113 100644 --- a/widget/form/groupchatform.h +++ b/widget/form/groupchatform.h @@ -18,9 +18,8 @@ #define GROUPCHATFORM_H #include "genericchatform.h" -#include "widget/tool/chattextedit.h" -#include "ui_mainwindow.h" +namespace Ui {class MainWindow;} class Group; class GroupChatForm : public GenericChatForm diff --git a/widget/form/settingsform.cpp b/widget/form/settingsform.cpp index e3f1660a0..4d5dc3114 100644 --- a/widget/form/settingsform.cpp +++ b/widget/form/settingsform.cpp @@ -18,11 +18,14 @@ #include "widget/widget.h" #include "settings.h" #include "smileypack.h" +#include "ui_mainwindow.h" #include #include #include #include #include +#include +#include "core.h" SettingsForm::SettingsForm() : QObject() @@ -32,6 +35,7 @@ SettingsForm::SettingsForm() QFont bold, small; bold.setBold(true); small.setPixelSize(13); + small.setKerning(false); headLabel.setText(tr("User Settings","\"Headline\" of the window")); headLabel.setFont(bold); @@ -41,7 +45,7 @@ SettingsForm::SettingsForm() id.setReadOnly(true); id.setFrameStyle(QFrame::NoFrame); 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")); loadConf.setText(tr("Load profile", "button to load selected profile")); @@ -120,12 +124,14 @@ QList SettingsForm::searchProfiles() 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) { - id.setText(friendAddress); + QString txt{friendAddress}; + txt.insert(38,'\n'); + id.setText(txt); } void SettingsForm::show(Ui::MainWindow &ui) @@ -143,13 +149,13 @@ void SettingsForm::show(Ui::MainWindow &ui) void SettingsForm::onLoadClicked() { - Widget::getInstance()->getCore()->switchConfiguration(profiles.currentText()); + Core::getInstance()->switchConfiguration(profiles.currentText()); } void SettingsForm::onExportClicked() { 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); } @@ -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")); QFileInfo info(path); 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); QFile::copy(path, profilePath); profiles.addItem(profile); - Widget::getInstance()->getCore()->switchConfiguration(profile); + Core::getInstance()->switchConfiguration(profile); } void SettingsForm::onTestVideoClicked() @@ -195,8 +201,10 @@ void SettingsForm::onEnableIPv6Updated() void SettingsForm::copyIdClicked() { - id.selectAll();; - QApplication::clipboard()->setText(id.toPlainText()); + id.selectAll(); + QString txt = id.toPlainText(); + txt.replace('\n',""); + QApplication::clipboard()->setText(txt); } void SettingsForm::onUseTranslationUpdated() diff --git a/widget/form/settingsform.h b/widget/form/settingsform.h index 8e012c5ee..e35f588da 100644 --- a/widget/form/settingsform.h +++ b/widget/form/settingsform.h @@ -20,21 +20,16 @@ #include #include #include -#include #include -#include #include #include #include #include -#include -#include #include -#include -#include "ui_mainwindow.h" -#include "widget/selfcamview.h" #include "widget/croppinglabel.h" -#include "core.h" + +namespace Ui {class MainWindow;} +class QString; class SettingsForm : public QObject { diff --git a/widget/friendlistwidget.cpp b/widget/friendlistwidget.cpp index aced0f297..176850e82 100644 --- a/widget/friendlistwidget.cpp +++ b/widget/friendlistwidget.cpp @@ -15,6 +15,7 @@ */ #include "friendlistwidget.h" #include +#include FriendListWidget::FriendListWidget(QWidget *parent) : QWidget(parent) diff --git a/widget/friendlistwidget.h b/widget/friendlistwidget.h index 02baa3f94..dae6b1c61 100644 --- a/widget/friendlistwidget.h +++ b/widget/friendlistwidget.h @@ -18,8 +18,11 @@ #define FRIENDLISTWIDGET_H #include -#include -#include "core.h" +#include +#include "corestructs.h" + +class QLayout; +class QGridLayout; class FriendListWidget : public QWidget { diff --git a/widget/friendwidget.cpp b/widget/friendwidget.cpp index 97c7b9c77..e1744002d 100644 --- a/widget/friendwidget.cpp +++ b/widget/friendwidget.cpp @@ -18,9 +18,10 @@ #include "group.h" #include "grouplist.h" #include "groupwidget.h" -#include "widget.h" #include "friendlist.h" #include "friend.h" +#include "core.h" +#include "widget/form/chatform.h" #include #include @@ -112,7 +113,7 @@ void FriendWidget::contextMenuEvent(QContextMenuEvent * event) else if (groupActions.contains(selectedItem)) { Group* group = groupActions[selectedItem]; - Widget::getInstance()->getCore()->groupInviteFriend(friendId, group->groupId); + Core::getInstance()->groupInviteFriend(friendId, group->groupId); } } } diff --git a/widget/friendwidget.h b/widget/friendwidget.h index 257d48a24..da158e68d 100644 --- a/widget/friendwidget.h +++ b/widget/friendwidget.h @@ -17,10 +17,7 @@ #ifndef FRIENDWIDGET_H #define FRIENDWIDGET_H -#include #include -#include -#include #include "genericchatroomwidget.h" #include "croppinglabel.h" diff --git a/widget/groupwidget.h b/widget/groupwidget.h index c32db80a6..54d1ee533 100644 --- a/widget/groupwidget.h +++ b/widget/groupwidget.h @@ -17,7 +17,6 @@ #ifndef GROUPWIDGET_H #define GROUPWIDGET_H -#include #include #include "genericchatroomwidget.h" diff --git a/widget/netcamview.cpp b/widget/netcamview.cpp index cd9e78fda..4268ea8dd 100644 --- a/widget/netcamview.cpp +++ b/widget/netcamview.cpp @@ -16,9 +16,8 @@ #include "netcamview.h" #include "core.h" -#include "widget.h" -#include -#include +#include +#include static inline void fromYCbCrToRGB( uint8_t Y, uint8_t Cb, uint8_t Cr, @@ -70,7 +69,7 @@ void NetCamView::updateDisplay(vpx_image* frame) if (!frame->w || !frame->h) return; - Core* core = Widget::getInstance()->getCore(); + Core* core = Core::getInstance(); core->increaseVideoBusyness(); diff --git a/widget/netcamview.h b/widget/netcamview.h index 7552dd267..0aba0edd9 100644 --- a/widget/netcamview.h +++ b/widget/netcamview.h @@ -18,14 +18,13 @@ #define NETCAMVIEW_H #include -#include -#include -#include -#include class QCloseEvent; class QShowEvent; class QPainter; +class QLabel; +class QHBoxLayout; +class vpx_image; class NetCamView : public QWidget { diff --git a/widget/selfcamview.cpp b/widget/selfcamview.cpp index 2d46e99bb..6436e24d9 100644 --- a/widget/selfcamview.cpp +++ b/widget/selfcamview.cpp @@ -15,46 +15,45 @@ */ #include "selfcamview.h" +#include "camera.h" #include #include - -#include "widget.h" +#include +#include +#include +#include using namespace cv; SelfCamView::SelfCamView(Camera* Cam, QWidget* parent) : QWidget(parent), displayLabel{new QLabel}, - mainLayout{new QHBoxLayout()}, cam(Cam) + mainLayout{new QHBoxLayout()}, cam(Cam), updateDisplayTimer{new QTimer} { setLayout(mainLayout); setWindowTitle(SelfCamView::tr("Tox video test","Title of the window to test the video/webcam")); setMinimumSize(320,240); - updateDisplayTimer.setInterval(5); - updateDisplayTimer.setSingleShot(false); + updateDisplayTimer->setInterval(5); + updateDisplayTimer->setSingleShot(false); displayLabel->setScaledContents(true); mainLayout->addWidget(displayLabel); - connect(&updateDisplayTimer, SIGNAL(timeout()), this, SLOT(updateDisplay())); -} - -SelfCamView::~SelfCamView() -{ + connect(updateDisplayTimer, SIGNAL(timeout()), this, SLOT(updateDisplay())); } void SelfCamView::closeEvent(QCloseEvent* event) { cam->unsuscribe(); - updateDisplayTimer.stop(); + updateDisplayTimer->stop(); event->accept(); } void SelfCamView::showEvent(QShowEvent* event) { cam->suscribe(); - updateDisplayTimer.start(); + updateDisplayTimer->start(); event->accept(); } diff --git a/widget/selfcamview.h b/widget/selfcamview.h index 328168299..a8cc29679 100644 --- a/widget/selfcamview.h +++ b/widget/selfcamview.h @@ -18,14 +18,14 @@ #define SELFCAMVIEW_H #include -#include -#include -#include -#include "camera.h" class QCloseEvent; class QShowEvent; class QPainter; +class Camera; +class QLabel; +class QHBoxLayout; +class QTimer; class SelfCamView : public QWidget { @@ -33,7 +33,6 @@ class SelfCamView : public QWidget public: SelfCamView(Camera* Cam, QWidget *parent=0); - ~SelfCamView(); private slots: void updateDisplay(); @@ -47,7 +46,7 @@ private: QLabel *displayLabel; QHBoxLayout* mainLayout; Camera* cam; - QTimer updateDisplayTimer; + QTimer* updateDisplayTimer; }; #endif // SELFCAMVIEW_H diff --git a/widget/tool/chataction.cpp b/widget/tool/chataction.cpp index c1db67b46..0847abdda 100644 --- a/widget/tool/chataction.cpp +++ b/widget/tool/chataction.cpp @@ -18,10 +18,11 @@ #include "smileypack.h" #include #include +#include "filetransferinstance.h" QString ChatAction::toHtmlChars(const QString &str) { - static QList> replaceList = {{"&","&"}, {" "," "}, {">",">"}, {"<","<"}}; + static QList> replaceList = {{"&","&"}, {">",">"}, {"<","<"}}; QString res = str; for (auto &it : replaceList) @@ -39,37 +40,63 @@ QString ChatAction::QImage2base64(const QImage &img) return ba.toBase64(); } -QString ChatAction::wrapName(const QString &name) +QString ChatAction::getName() { if (isMe) - return QString("
" + name + "
\n"); + return QString("
" + toHtmlChars(name) + "
"); else - return QString("
" + name + "
\n"); + return QString("
" + toHtmlChars(name) + "
"); } -QString ChatAction::wrapDate(const QString &date) +QString ChatAction::getDate() { - QString res = "
" + date + "
\n"; - return res; -} - -QString ChatAction::wrapMessage(const QString &message) -{ - QString res = "
" + message + "
\n"; - return res; -} - -QString ChatAction::wrapWholeLine(const QString &line) -{ - QString res = "\n" + line + "\n"; + QString res = "
" + date + "
"; return res; } 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)); + // 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("%1").arg(url); + message_.replace(offset, exp.cap().length(), htmledUrl); + + offset += htmledUrl.length(); + } + + // detect text quotes QStringList messageLines = message_.split("\n"); message_ = ""; for (QString& s : messageLines) @@ -81,40 +108,62 @@ MessageAction::MessageAction(const QString &author, const QString &message, cons } message_ = message_.left(message_.length()-4); - content = wrapWholeLine(wrapName(author) + wrapMessage(message_) + wrapDate(date)); -} - -QString MessageAction::getHtml() -{ - return content; + return QString("
" + message_ + "
"); } FileTransferAction::FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me) : - ChatAction(me), - sender(author), - timestamp(date) + ChatAction(me, author, date) { w = widget; + + connect(w, &FileTransferInstance::stateUpdated, this, &FileTransferAction::updateHtml); } FileTransferAction::~FileTransferAction() { - } -QString FileTransferAction::getHtml() +QString FileTransferAction::getMessage() { QString widgetHtml; if (w != nullptr) widgetHtml = w->getHtmlImage(); else widgetHtml = "
EMPTY CONTENT
"; - QString res = wrapWholeLine(wrapName(sender) + wrapMessage(widgetHtml) + wrapDate(timestamp));; - return res; + return widgetHtml; } -QString FileTransferAction::wrapMessage(const QString &message) +void FileTransferAction::setTextCursor(QTextCursor cursor) { - QString res = "" + message + "\n"; - return res; + cur = cursor; + 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(); + } } diff --git a/widget/tool/chataction.h b/widget/tool/chataction.h index 0e6d8ac87..a324a41c6 100644 --- a/widget/tool/chataction.h +++ b/widget/tool/chataction.h @@ -18,26 +18,28 @@ #define CHATACTION_H #include -#include "filetransferinstance.h" +#include -class ChatAction +class FileTransferInstance; + +class ChatAction : public QObject { 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 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: QString toHtmlChars(const QString &str); QString QImage2base64(const QImage &img); - virtual QString wrapName(const QString &name); - virtual QString wrapDate(const QString &date); - virtual QString wrapMessage(const QString &message); - virtual QString wrapWholeLine(const QString &line); - -private: +protected: bool isMe; + QString name, date; }; class MessageAction : public ChatAction @@ -45,23 +47,28 @@ class MessageAction : public ChatAction public: MessageAction(const QString &author, const QString &message, const QString &date, const bool &me); virtual ~MessageAction(){;} - virtual QString getHtml(); + virtual QString getMessage(); + virtual void setTextCursor(QTextCursor cursor) final; private: - QString content; + QString message; }; class FileTransferAction : public ChatAction { + Q_OBJECT public: FileTransferAction(FileTransferInstance *widget, const QString &author, const QString &date, const bool &me); virtual ~FileTransferAction(); - virtual QString getHtml(); - virtual QString wrapMessage(const QString &message); + virtual QString getMessage(); + virtual void setTextCursor(QTextCursor cursor) final; + +private slots: + void updateHtml(); private: FileTransferInstance *w; - QString sender, timestamp; + QTextCursor cur; }; #endif // CHATACTION_H diff --git a/widget/tool/chattextedit.cpp b/widget/tool/chattextedit.cpp index 8f727cfbb..9b51b8fba 100644 --- a/widget/tool/chattextedit.cpp +++ b/widget/tool/chattextedit.cpp @@ -21,6 +21,7 @@ ChatTextEdit::ChatTextEdit(QWidget *parent) : QTextEdit(parent) { setPlaceholderText("Type your message here..."); + setAcceptRichText(false); } void ChatTextEdit::keyPressEvent(QKeyEvent * event) diff --git a/widget/widget.cpp b/widget/widget.cpp index c6f01510b..f2c20cb23 100644 --- a/widget/widget.cpp +++ b/widget/widget.cpp @@ -16,6 +16,7 @@ #include "widget.h" #include "ui_mainwindow.h" +#include "core.h" #include "settings.h" #include "friend.h" #include "friendlist.h" @@ -26,17 +27,19 @@ #include "widget/groupwidget.h" #include "widget/form/groupchatform.h" #include "style.h" +#include "selfcamview.h" +#include "widget/friendlistwidget.h" +#include "camera.h" +#include "widget/form/chatform.h" #include #include -#include #include #include #include #include -#include -#include -#include #include +#include +#include Widget *Widget::instance{nullptr}; @@ -382,13 +385,15 @@ void Widget::setStatusMessage(const QString &statusMessage) 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); QLayout* layout = contactListWidget->getFriendLayout(Status::Offline); layout->addWidget(newfriend->widget); connect(newfriend->widget, SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), this, SLOT(onChatroomWidgetClicked(GenericChatroomWidget*))); connect(newfriend->widget, SIGNAL(removeFriend(int)), this, SLOT(removeFriend(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(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))); @@ -510,7 +515,7 @@ void Widget::newMessageAlert() { QApplication::alert(this); - static QFile sndFile(":audio/notification.wav"); + static QFile sndFile(":audio/notification.pcm"); static QByteArray sndData; if (sndData.isEmpty()) { @@ -521,7 +526,7 @@ void Widget::newMessageAlert() ALuint 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); alSourcePlay(core->alMainSource); } @@ -608,7 +613,12 @@ void Widget::onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t Cha TOX_CHAT_CHANGE change = static_cast(Change); if (change == TOX_CHAT_CHANGE_PEER_ADD) - g->addPeer(peernumber,""); + { + QString name = core->getGroupPeerName(groupnumber, peernumber); + if (name.isEmpty()) + name = tr("", "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) g->removePeer(peernumber); 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(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))); return newgroup; } diff --git a/widget/widget.h b/widget/widget.h index 54f2e9676..206ae30fd 100644 --- a/widget/widget.h +++ b/widget/widget.h @@ -17,17 +17,11 @@ #ifndef WIDGET_H #define WIDGET_H -#include #include -#include -#include -#include -#include "core.h" #include "widget/form/addfriendform.h" #include "widget/form/settingsform.h" #include "widget/form/filesform.h" -#include "camera.h" -#include "friendlistwidget.h" +#include "corestructs.h" #define PIXELS_TO_ACT 7 @@ -38,6 +32,12 @@ class MainWindow; class GenericChatroomWidget; class Group; struct Friend; +class QSplitter; +class SelfCamView; +class QMenu; +class Core; +class Camera; +class FriendListWidget; class Widget : public QMainWindow {