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

Merge branch 'android'

This commit is contained in:
Tux3 / Mlkj / !Lev.uXFMLA 2015-02-06 20:00:22 +01:00
commit 6286e4a11f
No known key found for this signature in database
GPG Key ID: 7E086DD661263264
26 changed files with 865 additions and 243 deletions

View File

@ -0,0 +1,56 @@
<?xml version="1.0"?>
<manifest package="im.tox.qtox" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto">
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="qtox">
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="qTox" android:screenOrientation="unspecified" android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data android:name="android.app.lib_name" android:value="qtox"/>
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
<meta-data android:name="android.app.repository" android:value="default"/>
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
<!-- Deploy Qt libs as part of package -->
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
<!-- Run with local libs -->
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
<meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
<!-- Messages maps -->
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
<!-- Messages maps -->
<!-- Splash screen -->
<!--
<meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/>
-->
<!-- Splash screen -->
<!-- Background running -->
<!-- Warning: changing this value to true may cause unexpected crashes if the
application still try to draw after
"applicationStateChanged(Qt::ApplicationSuspended)"
signal is sent! -->
<meta-data android:name="android.app.background_running" android:value="false"/>
<!-- Background running -->
</activity>
</application>
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="20"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
Remove the comment if you do not require these default permissions. -->
<!-- %%INSERT_PERMISSIONS -->
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
Remove the comment if you do not require these default features. -->
<!-- %%INSERT_FEATURES -->
</manifest>

View File

@ -69,6 +69,23 @@ contains(ENABLE_SYSTRAY_UNITY_BACKEND, YES) {
LIBS += -lgobject-2.0 -lappindicator -lgtk-x11-2.0
}
android {
ANDROID_TOOLCHAIN=/opt/android/toolchain-r9d-17/
INCLUDEPATH += $$ANDROID_TOOLCHAIN/include/
LIBS += -L$$ANDROID_TOOLCHAIN/lib
DISABLE_PLATFORM_EXT=YES
DISABLE_FILTER_AUDIO=YES
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
contains(ANDROID_TARGET_ARCH,armeabi) {
ANDROID_EXTRA_LIBS = \
$$ANDROID_TOOLCHAIN/lib/libopenal.so \
$$ANDROID_TOOLCHAIN/lib/libsodium.so
}
}
contains(DISABLE_PLATFORM_EXT, YES) {
} else {
@ -90,7 +107,7 @@ contains(JENKINS,YES) {
# Rules for Windows, Mac OSX, and Linux
win32 {
RC_FILE = windows/qtox.rc
LIBS += -L$$PWD/libs/lib -ltoxav -ltoxcore -ltoxencryptsave -ltoxdns -lsodium -lvpx -lpthread
LIBS += -L$$PWD/libs/lib -ltoxav -ltoxcore -ltoxencryptsave -ltoxdns -lsodium -lvpx -lpthread
LIBS += -L$$PWD/libs/lib -lopencv_core249 -lopencv_highgui249 -lopencv_imgproc249 -lOpenAL32 -lopus
LIBS += -lopengl32 -lole32 -loleaut32 -luuid -lvfw32 -lws2_32 -liphlpapi -lz
@ -110,31 +127,38 @@ win32 {
contains(DEFINES, QTOX_PLATFORM_EXT) { LIBS += -framework IOKit -framework CoreFoundation }
contains(DEFINES, QTOX_FILTER_AUDIO) { LIBS += -lfilteraudio }
} else {
# If we're building a package, static link libtox[core,av] and libsodium, since they are not provided by any package
contains(STATICPKG, YES) {
target.path = /usr/bin
INSTALLS += target
LIBS += -L$$PWD/libs/lib/ -lopus -lvpx -lopenal -Wl,-Bstatic -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lopencv_highgui -lopencv_imgproc -lopencv_core -lz -Wl,-Bdynamic
LIBS += -Wl,-Bstatic -ljpeg -ltiff -lpng -ljasper -lIlmImf -lIlmThread -lIex -ldc1394 -lraw1394 -lHalf -lz -llzma -ljbig
LIBS += -Wl,-Bdynamic -lv4l1 -lv4l2 -lavformat -lavcodec -lavutil -lswscale -lusb-1.0
android {
LIBS += -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns
LIBS += -lopencv_videoio -lopencv_imgcodecs -lopencv_highgui -lopencv_imgproc -lopencv_androidcamera
LIBS += -llibjpeg -llibwebp -llibpng -llibtiff -llibjasper -lIlmImf -lopencv_core
LIBS += -lopus -lvpx -lsodium -lopenal
} else {
LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lvpx -lsodium -lopenal -lopencv_core -lopencv_highgui -lopencv_imgproc
}
contains(DEFINES, QTOX_PLATFORM_EXT) {
LIBS += -lX11 -lXss
}
contains(DEFINES, QTOX_FILTER_AUDIO) {
# If we're building a package, static link libtox[core,av] and libsodium, since they are not provided by any package
contains(STATICPKG, YES) {
LIBS += -Wl,-Bstatic -lfilteraudio
target.path = /usr/bin
INSTALLS += target
LIBS += -L$$PWD/libs/lib/ -lopus -lvpx -lopenal -Wl,-Bstatic -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lsodium -lopencv_highgui -lopencv_imgproc -lopencv_core -lz -Wl,-Bdynamic
LIBS += -Wl,-Bstatic -ljpeg -ltiff -lpng -ljasper -lIlmImf -lIlmThread -lIex -ldc1394 -lraw1394 -lHalf -lz -llzma -ljbig
LIBS += -Wl,-Bdynamic -lv4l1 -lv4l2 -lavformat -lavcodec -lavutil -lswscale -lusb-1.0
} else {
LIBS += -lfilteraudio
LIBS += -L$$PWD/libs/lib/ -ltoxcore -ltoxav -ltoxencryptsave -ltoxdns -lvpx -lsodium -lopenal -lopencv_core -lopencv_highgui -lopencv_imgproc
}
}
contains(JENKINS, YES) {
LIBS = ./libs/lib/libtoxav.a ./libs/lib/libvpx.a ./libs/lib/libopus.a ./libs/lib/libtoxdns.a ./libs/lib/libtoxencryptsave.a ./libs/lib/libtoxcore.a ./libs/lib/libsodium.a ./libs/lib/libfilteraudio.a /usr/lib/libopencv_core.so /usr/lib/libopencv_highgui.so /usr/lib/libopencv_imgproc.so -lopenal -lX11 -lXss -s
contains(DEFINES, QTOX_PLATFORM_EXT) {
LIBS += -lX11 -lXss
}
contains(DEFINES, QTOX_FILTER_AUDIO) {
contains(STATICPKG, YES) {
LIBS += -Wl,-Bstatic -lfilteraudio
} else {
LIBS += -lfilteraudio
}
}
contains(JENKINS, YES) {
LIBS = ./libs/lib/libtoxav.a ./libs/lib/libvpx.a ./libs/lib/libopus.a ./libs/lib/libtoxdns.a ./libs/lib/libtoxencryptsave.a ./libs/lib/libtoxcore.a ./libs/lib/libsodium.a ./libs/lib/libfilteraudio.a /usr/lib/libopencv_core.so /usr/lib/libopencv_highgui.so /usr/lib/libopencv_imgproc.so -lopenal -lX11 -lXss -s
}
}
}
}
@ -206,7 +230,10 @@ HEADERS += src/widget/form/addfriendform.h \
src/audio.h \
src/widget/callconfirmwidget.h \
src/widget/systemtrayicon.h \
src/widget/systemtrayicon_private.h
src/widget/systemtrayicon_private.h \
src/nexus.h \
src/widget/gui.h \
src/widget/androidgui.h
SOURCES += \
src/widget/form/addfriendform.cpp \
@ -275,7 +302,10 @@ SOURCES += \
src/widget/form/settings/advancedform.cpp \
src/audio.cpp \
src/widget/callconfirmwidget.cpp \
src/widget/systemtrayicon.cpp
src/widget/systemtrayicon.cpp \
src/nexus.cpp \
src/widget/gui.cpp \
src/widget/androidgui.cpp
contains(DEFINES, QTOX_FILTER_AUDIO) {
HEADERS += src/audiofilterer.h

View File

@ -19,6 +19,7 @@
#include "src/misc/serialize.h"
#include "src/misc/settings.h"
#include "src/widget/widget.h"
#include "src/widget/gui.h"
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QCoreApplication>
@ -490,7 +491,7 @@ void AutoUpdater::checkUpdatesAsyncInteractiveWorker()
QDir updateDir(updateDirStr);
if ((updateDir.exists() && QFile(updateDirStr+"flist").exists())
|| Widget::getInstance()->askQuestion(QObject::tr("Update", "The title of a message box"),
|| GUI::askQuestion(QObject::tr("Update", "The title of a message box"),
QObject::tr("An update is available, do you want to download it now?\nIt will be installed when qTox restarts."), true, false))
{
downloadUpdate();

View File

@ -15,10 +15,11 @@
*/
#include "core.h"
#include "nexus.h"
#include "misc/cdata.h"
#include "misc/cstring.h"
#include "misc/settings.h"
#include "widget/widget.h"
#include "widget/gui.h"
#include "historykeeper.h"
#include "src/audio.h"
@ -106,6 +107,7 @@ Core::~Core()
{
qDebug() << "Deleting Core";
saveConfiguration();
toxTimer->stop();
coreThread->exit(0);
while (coreThread->isRunning())
@ -128,7 +130,7 @@ Core::~Core()
Core* Core::getInstance()
{
return Widget::getInstance()->getCore();
return Nexus::getCore();
}
void Core::make_tox()
@ -223,6 +225,8 @@ void Core::make_tox()
void Core::start()
{
qDebug() << "Core: Starting up";
make_tox();
qsrand(time(nullptr));
@ -255,7 +259,6 @@ void Core::start()
{
setStatusMessage(tr("Toxing on qTox")); // this also solves the not updating issue
setUsername(tr("qTox User"));
QMetaObject::invokeMethod(Widget::getInstance(), "onSettingsClicked"); // update ui with new profile
}
tox_callback_friend_request(tox, onFriendRequest, this);
@ -1202,8 +1205,7 @@ bool Core::loadConfiguration(QString path)
{
configurationFile.close();
QString profile;
QMetaObject::invokeMethod(Widget::getInstance(), "askProfiles", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, profile));
QString profile = Settings::getInstance().askProfiles();
if (!profile.isEmpty())
{
@ -1281,7 +1283,7 @@ void Core::switchConfiguration(const QString& profile)
saveCurrentInformation(); // part of a hack, see core.h
ready = false;
Widget::getInstance()->setEnabledThreadsafe(false);
GUI::setEnabled(false);
clearPassword(ptMain);
clearPassword(ptHistory);
@ -1301,7 +1303,7 @@ void Core::switchConfiguration(const QString& profile)
start();
if (isReady())
Widget::getInstance()->setEnabledThreadsafe(true);
GUI::setEnabled(true);
}
void Core::loadFriends()

View File

@ -19,7 +19,7 @@
/* was permanently moved here to handle encryption */
#include "core.h"
#include "src/widget/widget.h"
#include "src/widget/gui.h"
#include <tox/tox.h>
#include <tox/toxencryptsave.h>
#include "src/misc/settings.h"
@ -165,7 +165,7 @@ QByteArray Core::getSaltFromFile(QString filename)
bool Core::loadEncryptedSave(QByteArray& data)
{
if (!Settings::getInstance().getEncryptTox())
Widget::getInstance()->showWarningMsgBox(tr("Encryption error"), tr("The .tox file is encrypted, but encryption was not checked, continuing regardless."));
GUI::showWarning(tr("Encryption error"), tr("The .tox file is encrypted, but encryption was not checked, continuing regardless."));
int error = -1;
QString a(tr("Please enter the password for the %1 profile.", "used in load() when no pw is already set").arg(Settings::getInstance().getCurrentProfile()));
@ -190,7 +190,7 @@ bool Core::loadEncryptedSave(QByteArray& data)
do
{
QString pw = Widget::getInstance()->passwordDialog(tr("Change profile"), dialogtxt);
QString pw = GUI::passwordDialog(tr("Change profile"), dialogtxt);
if (pw.isEmpty())
{
@ -216,7 +216,7 @@ void Core::checkEncryptedHistory()
QByteArray salt = getSaltFromFile(path);
if (exists && salt.size() == 0)
{ // maybe we should handle this better
Widget::getInstance()->showWarningMsgBox(tr("Encrypted chat history"), tr("No encrypted chat history file found, or it was corrupted.\nHistory will be disabled!"));
GUI::showWarning(tr("Encrypted chat history"), tr("No encrypted chat history file found, or it was corrupted.\nHistory will be disabled!"));
Settings::getInstance().setEncryptLogs(false);
Settings::getInstance().setEnableLogging(false);
HistoryKeeper::resetInstance();
@ -252,7 +252,7 @@ void Core::checkEncryptedHistory()
bool error = true;
do
{
QString pw = Widget::getInstance()->passwordDialog(tr("Disable chat history"), dialogtxt);
QString pw = GUI::passwordDialog(tr("Disable chat history"), dialogtxt);
if (pw.isEmpty())
{
@ -295,7 +295,7 @@ void Core::saveConfiguration(const QString& path)
else
fileSize = tox_size(tox);
if (fileSize > 0 && fileSize <= INT32_MAX) {
if (fileSize > 0 && fileSize <= std::numeric_limits<int32_t>::max()) {
uint8_t *data = new uint8_t[fileSize];
if (encrypt)
@ -303,7 +303,7 @@ void Core::saveConfiguration(const QString& path)
if (!pwsaltedkeys[ptMain])
{
// probably zero chance event
Widget::getInstance()->showWarningMsgBox(tr("NO Password"), tr("Encryption is enabled, but there is no password! Encryption will be disabled."));
GUI::showWarning(tr("NO Password"), tr("Encryption is enabled, but there is no password! Encryption will be disabled."));
Settings::getInstance().setEncryptTox(false);
tox_save(tox, data);
}

View File

@ -18,7 +18,7 @@
#include "friendlist.h"
#include "widget/friendwidget.h"
#include "widget/form/chatform.h"
#include "widget/widget.h"
#include "widget/gui.h"
#include "src/core.h"
#include "src/misc/settings.h"
@ -52,7 +52,7 @@ void Friend::setName(QString name)
chatForm->setName(name);
if (widget->isActive())
Widget::getInstance()->setWindowTitle(name);
GUI::setWindowTitle(name);
}
}
@ -65,7 +65,7 @@ void Friend::setAlias(QString name)
chatForm->setName(dispName);
if (widget->isActive())
Widget::getInstance()->setWindowTitle(dispName);
GUI::setWindowTitle(dispName);
}
void Friend::setStatusMessage(QString message)

View File

@ -20,7 +20,7 @@
#include "friendlist.h"
#include "friend.h"
#include "core.h"
#include "widget/widget.h"
#include "widget/gui.h"
#include <QDebug>
#include <QTimer>
@ -90,7 +90,7 @@ void Group::setName(const QString& name)
chatForm->setName(name);
if (widget->isActive())
Widget::getInstance()->setWindowTitle(name);
GUI::setWindowTitle(name);
}
void Group::regeneratePeerList()

View File

@ -16,6 +16,7 @@
#include "widget/widget.h"
#include "misc/settings.h"
#include "src/nexus.h"
#include "src/ipc.h"
#include "src/widget/toxuri.h"
#include "src/widget/toxsave.h"
@ -70,6 +71,7 @@ int main(int argc, char *argv[])
parser.process(a);
Settings::getInstance(); // Build our Settings singleton as soon as QApplication is ready, not before
if (parser.isSet("p"))
{
QString profile = parser.value("p");
@ -121,6 +123,9 @@ int main(int argc, char *argv[])
AutoUpdater::installLocalUpdate(); ///< NORETURN
#endif
Nexus::getInstance().start();
#ifndef Q_OS_ANDROID
// Inter-process communication
IPC ipc;
ipc.registerEventHandler(&toxURIEventHandler);
@ -175,17 +180,18 @@ int main(int argc, char *argv[])
if (!ipc.isCurrentOwner())
return EXIT_SUCCESS;
}
#endif
// Run
a.setQuitOnLastWindowClosed(false);
Widget* w = Widget::getInstance();
int errorcode = a.exec();
delete w;
#ifdef LOG_TO_FILE
delete logFile;
logFile = nullptr;
#endif
Nexus::destroyInstance();
return errorcode;
}

View File

@ -18,6 +18,8 @@
#include "smileypack.h"
#include "src/corestructs.h"
#include "src/misc/db/plaindb.h"
#include "src/core.h"
#include "src/widget/gui.h"
#include <QFont>
#include <QApplication>
@ -65,6 +67,70 @@ void Settings::switchProfile(const QString& profile)
resetInstance();
}
QString Settings::detectProfile()
{
QDir dir(getSettingsDirPath());
QString path, profile = getCurrentProfile();
path = dir.filePath(profile + Core::TOX_EXT);
QFile file(path);
if (profile.isEmpty() || !file.exists())
{
setCurrentProfile("");
#if 1 // deprecation attempt
// if the last profile doesn't exist, fall back to old "data"
path = dir.filePath(Core::CONFIG_FILE_NAME);
QFile file(path);
if (file.exists())
return path;
else if (QFile(path = dir.filePath("tox_save")).exists()) // also import tox_save if no data
return path;
else
#endif
{
profile = askProfiles();
if (profile.isEmpty())
return "";
else
{
switchProfile(profile);
return dir.filePath(profile + Core::TOX_EXT);
}
}
}
else
return path;
}
QList<QString> Settings::searchProfiles()
{
QList<QString> out;
QDir dir(getSettingsDirPath());
dir.setFilter(QDir::Files | QDir::NoDotAndDotDot);
dir.setNameFilters(QStringList("*.tox"));
for (QFileInfo file : dir.entryInfoList())
out += file.completeBaseName();
return out;
}
QString Settings::askProfiles()
{ // TODO: allow user to create new Tox ID, even if a profile already exists
QList<QString> profiles = searchProfiles();
if (profiles.empty()) return "";
bool ok;
QString profile = GUI::itemInputDialog(nullptr,
tr("Choose a profile"),
tr("Please choose which identity to use"),
profiles,
0, // which slot to start on
false, // if the user can enter their own input
&ok);
if (!ok) // user cancelled
return "";
else
return profile;
}
void Settings::load()
{
if (loaded)

View File

@ -33,6 +33,9 @@ public:
static Settings& getInstance();
static void resetInstance();
void switchProfile(const QString& profile);
QString detectProfile();
QList<QString> searchProfiles();
QString askProfiles();
~Settings() = default;
void executeSettingsDialog(QWidget* parent);

View File

@ -16,10 +16,7 @@
#include "style.h"
#include "settings.h"
#include "src/widget/widget.h"
#include "ui_mainwindow.h"
#include "src/widget/genericchatroomwidget.h"
#include "src/widget/gui.h"
#include <QFile>
#include <QDebug>
@ -198,11 +195,9 @@ void Style::setThemeColor(QColor color)
dict["@themeMediumDark"] = getColor(ThemeMediumDark).name();
dict["@themeMedium"] = getColor(ThemeMedium).name();
dict["@themeLight"] = getColor(ThemeLight).name();
applyTheme();
}
void Style::applyTheme()
{
Widget::getInstance()->reloadTheme();
GUI::reloadTheme();
}

142
src/nexus.cpp Normal file
View File

@ -0,0 +1,142 @@
#include "nexus.h"
#include "core.h"
#include "misc/settings.h"
#include "video/camera.h"
#include "widget/gui.h"
#include <QThread>
#include <QDebug>
#ifdef Q_OS_ANDROID
#include <src/widget/androidgui.h>
#else
#include <src/widget/widget.h>
#endif
static Nexus* nexus{nullptr};
Nexus::Nexus(QObject *parent) :
QObject(parent),
core{nullptr},
coreThread{nullptr},
widget{nullptr},
androidgui{nullptr},
started{false}
{
}
Nexus::~Nexus()
{
delete core;
delete coreThread;
#ifdef Q_OS_ANDROID
delete androidgui;
#else
delete widget;
#endif
}
void Nexus::start()
{
if (started)
return;
qDebug() << "Nexus: Starting up";
// Setup the environment
qRegisterMetaType<Status>("Status");
qRegisterMetaType<vpx_image>("vpx_image");
qRegisterMetaType<uint8_t>("uint8_t");
qRegisterMetaType<uint16_t>("uint16_t");
qRegisterMetaType<const int16_t*>("const int16_t*");
qRegisterMetaType<int32_t>("int32_t");
qRegisterMetaType<int64_t>("int64_t");
qRegisterMetaType<QPixmap>("QPixmap");
qRegisterMetaType<ToxFile>("ToxFile");
qRegisterMetaType<ToxFile::FileDirection>("ToxFile::FileDirection");
qRegisterMetaType<Core::PasswordType>("Core::PasswordType");
// Create Core
QString profilePath = Settings::getInstance().detectProfile();
coreThread = new QThread(this);
coreThread->setObjectName("qTox Core");
core = new Core(Camera::getInstance(), coreThread, profilePath);
core->moveToThread(coreThread);
connect(coreThread, &QThread::started, core, &Core::start);
// Start GUI
#ifdef Q_OS_ANDROID
androidgui = new AndroidGUI;
androidgui->show();
#else
widget = Widget::getInstance();
#endif
GUI::getInstance();
// Connections
#ifndef Q_OS_ANDROID
connect(core, &Core::connected, widget, &Widget::onConnected);
connect(core, &Core::disconnected, widget, &Widget::onDisconnected);
connect(core, &Core::failedToStart, widget, &Widget::onFailedToStartCore);
connect(core, &Core::badProxy, widget, &Widget::onBadProxyCore);
connect(core, &Core::statusSet, widget, &Widget::onStatusSet);
connect(core, &Core::usernameSet, widget, &Widget::setUsername);
connect(core, &Core::statusMessageSet, widget, &Widget::setStatusMessage);
connect(core, &Core::selfAvatarChanged, widget, &Widget::onSelfAvatarLoaded);
connect(core, &Core::friendAdded, widget, &Widget::addFriend);
connect(core, &Core::failedToAddFriend, widget, &Widget::addFriendFailed);
connect(core, &Core::friendUsernameChanged, widget, &Widget::onFriendUsernameChanged);
connect(core, &Core::friendStatusChanged, widget, &Widget::onFriendStatusChanged);
connect(core, &Core::friendStatusMessageChanged, widget, &Widget::onFriendStatusMessageChanged);
connect(core, &Core::friendRequestReceived, widget, &Widget::onFriendRequestReceived);
connect(core, &Core::friendMessageReceived, widget, &Widget::onFriendMessageReceived);
connect(core, &Core::receiptRecieved, widget, &Widget::onReceiptRecieved);
connect(core, &Core::groupInviteReceived, widget, &Widget::onGroupInviteReceived);
connect(core, &Core::groupMessageReceived, widget, &Widget::onGroupMessageReceived);
connect(core, &Core::groupNamelistChanged, widget, &Widget::onGroupNamelistChanged);
connect(core, &Core::groupTitleChanged, widget, &Widget::onGroupTitleChanged);
connect(core, &Core::emptyGroupCreated, widget, &Widget::onEmptyGroupCreated);
connect(core, &Core::avInvite, widget, &Widget::playRingtone);
connect(core, &Core::blockingClearContacts, widget, &Widget::clearContactsList, Qt::BlockingQueuedConnection);
connect(core, &Core::friendTypingChanged, widget, &Widget::onFriendTypingChanged);
connect(core, SIGNAL(messageSentResult(int,QString,int)), widget, SLOT(onMessageSendResult(int,QString,int)));
connect(core, SIGNAL(groupSentResult(int,QString,int)), widget, SLOT(onGroupSendResult(int,QString,int)));
connect(widget, &Widget::statusSet, core, &Core::setStatus);
connect(widget, &Widget::friendRequested, core, &Core::requestFriendship);
connect(widget, &Widget::friendRequestAccepted, core, &Core::acceptFriendRequest);
connect(widget, &Widget::changeProfile, core, &Core::switchConfiguration);
#endif
// Start Core
coreThread->start();
started = true;
}
Nexus& Nexus::getInstance()
{
if (!nexus)
nexus = new Nexus;
return *nexus;
}
void Nexus::destroyInstance()
{
delete nexus;
nexus = nullptr;
}
Core* Nexus::getCore()
{
return getInstance().core;
}
AndroidGUI* Nexus::getAndroidGUI()
{
return getInstance().androidgui;
}
Widget* Nexus::getDesktopGUI()
{
return getInstance().widget;
}

38
src/nexus.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef NEXUS_H
#define NEXUS_H
#include <QObject>
class QThread;
class Core;
class Widget;
class AndroidGUI;
/// This class is in charge of connecting various systems together
/// and forwarding signals appropriately to the right objects
/// It is in charge of starting the GUI and the Core
class Nexus : public QObject
{
Q_OBJECT
public:
void start(); ///< Will initialise the systems (GUI, Core, ...)
static Nexus& getInstance();
static void destroyInstance();
static Core* getCore(); ///< Will return 0 if not started
static AndroidGUI* getAndroidGUI(); ///< Will return 0 if not started
static Widget* getDesktopGUI(); ///< Will return 0 if not started
private:
explicit Nexus(QObject *parent = 0);
~Nexus();
private:
Core* core;
QThread* coreThread;
Widget* widget;
AndroidGUI* androidgui;
bool started;
};
#endif // NEXUS_H

13
src/widget/androidgui.cpp Normal file
View File

@ -0,0 +1,13 @@
#include "androidgui.h"
#include <QLabel>
AndroidGUI::AndroidGUI(QWidget *parent) :
QWidget(parent)
{
l = new QLabel("qTox Android", this);
}
AndroidGUI::~AndroidGUI()
{
delete l;
}

19
src/widget/androidgui.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef ANDROIDGUI_H
#define ANDROIDGUI_H
#include <QWidget>
class QLabel;
class AndroidGUI : public QWidget
{
Q_OBJECT
public:
explicit AndroidGUI(QWidget *parent = 0);
~AndroidGUI();
private:
QLabel* l;
};
#endif // ANDROIDGUI_H

View File

@ -1,5 +1,6 @@
#include "callconfirmwidget.h"
#include "widget.h"
#include "gui.h"
#include <assert.h>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
@ -11,7 +12,7 @@
#include <QPalette>
CallConfirmWidget::CallConfirmWidget(const QWidget *Anchor) :
QWidget(Widget::getInstance()), anchor(Anchor),
QWidget(GUI::getMainWidget()), anchor(Anchor),
rectW{120}, rectH{85},
spikeW{30}, spikeH{15},
roundedFactor{20},
@ -43,7 +44,7 @@ CallConfirmWidget::CallConfirmWidget(const QWidget *Anchor) :
connect(buttonBox, &QDialogButtonBox::accepted, this, &CallConfirmWidget::accepted);
connect(buttonBox, &QDialogButtonBox::rejected, this, &CallConfirmWidget::rejected);
connect(Widget::getInstance(), &Widget::resized, this, &CallConfirmWidget::reposition);
connect(&GUI::getInstance(), &GUI::resized, this, &CallConfirmWidget::reposition);
layout->setMargin(12);
layout->addSpacing(spikeH);
@ -56,7 +57,7 @@ CallConfirmWidget::CallConfirmWidget(const QWidget *Anchor) :
void CallConfirmWidget::reposition()
{
Widget* w = Widget::getInstance();
QWidget* w = GUI::getMainWidget();
QPoint pos = anchor->mapToGlobal({(anchor->width()-rectW)/2,anchor->height()})-w->mapToGlobal({0,0});
// We don't want the widget to overflow past the right of the screen

View File

@ -27,6 +27,10 @@
#include <AL/al.h>
#endif
#ifndef ALC_ALL_DEVICES_SPECIFIER
#define ALC_ALL_DEVICES_SPECIFIER ALC_DEVICE_SPECIFIER
#endif
AVForm::AVForm() :
GenericForm(tr("Audio/Video"), QPixmap(":/img/settings/av.png"))
{

View File

@ -359,4 +359,5 @@ void GeneralForm::onThemeColorChanged(int)
int index = bodyUI->themeColorCBox->currentIndex();
Settings::getInstance().setThemeColor(index);
Style::setThemeColor(index);
Style::applyTheme();
}

View File

@ -111,7 +111,7 @@ void IdentityForm::present()
toxId->setText(Core::getInstance()->getSelfId().toString());
toxId->setCursorPosition(0);
bodyUI->profiles->clear();
for (QString profile : Widget::searchProfiles())
for (QString profile : Settings::getInstance().searchProfiles())
bodyUI->profiles->addItem(profile);
QString current = Settings::getInstance().getCurrentProfile();
if (current != "")

290
src/widget/gui.cpp Normal file
View File

@ -0,0 +1,290 @@
#include "gui.h"
#include "src/nexus.h"
#include <assert.h>
#include <QCoreApplication>
#include <QDebug>
#include <QDialogButtonBox>
#include <QInputDialog>
#include <QLabel>
#include <QMessageBox>
#include <QPushButton>
#include <QThread>
#ifdef Q_OS_ANDROID
#include "androidgui.h"
#else
#include "widget.h"
#endif
GUI::GUI(QObject *parent) :
QObject(parent)
{
assert(QThread::currentThread() == qApp->thread());
#ifndef Q_OS_ANDROID
assert(Nexus::getDesktopGUI());
connect(Nexus::getDesktopGUI(), &Widget::resized, this, &GUI::resized);
#endif
}
GUI& GUI::getInstance()
{
static GUI gui;
return gui;
}
// Implementation of the public clean interface
void GUI::setEnabled(bool state)
{
if (QThread::currentThread() == qApp->thread())
{
getInstance()._setEnabled(state);
}
else
{
QMetaObject::invokeMethod(&getInstance(), "_setEnabled", Qt::BlockingQueuedConnection,
Q_ARG(bool, state));
}
}
void GUI::setWindowTitle(const QString& title)
{
if (QThread::currentThread() == qApp->thread())
{
getInstance()._setWindowTitle(title);
}
else
{
QMetaObject::invokeMethod(&getInstance(), "_setWindowTitle", Qt::BlockingQueuedConnection,
Q_ARG(const QString&, title));
}
}
void GUI::reloadTheme()
{
if (QThread::currentThread() == qApp->thread())
{
getInstance()._reloadTheme();
}
else
{
QMetaObject::invokeMethod(&getInstance(), "_reloadTheme", Qt::BlockingQueuedConnection);
}
}
void GUI::showWarning(const QString& title, const QString& msg)
{
if (QThread::currentThread() == qApp->thread())
{
getInstance()._showWarning(title, msg);
}
else
{
QMetaObject::invokeMethod(&getInstance(), "_showWarning", Qt::BlockingQueuedConnection,
Q_ARG(const QString&, title), Q_ARG(const QString&, msg));
}
}
void GUI::showInfo(const QString& title, const QString& msg)
{
if (QThread::currentThread() == qApp->thread())
{
getInstance()._showInfo(title, msg);
}
else
{
QMetaObject::invokeMethod(&getInstance(), "_showInfo", Qt::BlockingQueuedConnection,
Q_ARG(const QString&, title), Q_ARG(const QString&, msg));
}
}
bool GUI::askQuestion(const QString& title, const QString& msg,
bool defaultAns, bool warning)
{
if (QThread::currentThread() == qApp->thread())
{
return getInstance()._askQuestion(title, msg, defaultAns, warning);
}
else
{
bool ret;
QMetaObject::invokeMethod(&getInstance(), "_askQuestion", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, ret),
Q_ARG(const QString&, title), Q_ARG(const QString&, msg),
Q_ARG(bool, defaultAns), Q_ARG(bool, warning));
return ret;
}
}
QString GUI::itemInputDialog(QWidget * parent, const QString & title,
const QString & label, const QStringList & items,
int current, bool editable, bool * ok,
Qt::WindowFlags flags,
Qt::InputMethodHints hints)
{
if (QThread::currentThread() == qApp->thread())
{
return getInstance()._itemInputDialog(parent, title, label, items, current, editable, ok, flags, hints);
}
else
{
QString r;
QMetaObject::invokeMethod(&getInstance(), "_itemInputDialog", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QString, r),
Q_ARG(QWidget*, parent), Q_ARG(const QString&, title),
Q_ARG(const QString&,label), Q_ARG(const QStringList&, items),
Q_ARG(int, current), Q_ARG(bool, editable), Q_ARG(bool*, ok),
Q_ARG(Qt::WindowFlags, flags), Q_ARG(Qt::InputMethodHints, hints));
return r;
}
}
QString GUI::passwordDialog(const QString& cancel, const QString& body)
{
if (QThread::currentThread() == qApp->thread())
{
return getInstance()._passwordDialog(cancel, body);
}
else
{
QString r;
QMetaObject::invokeMethod(&getInstance(), "_passwordDialog", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QString, r),
Q_ARG(const QString&, cancel), Q_ARG(const QString&, body));
return r;
}
}
// Private implementations
void GUI::_setEnabled(bool state)
{
#ifdef Q_OS_ANDROID
Nexus::getAndroidGUI()->setEnabled(state);
#else
Nexus::getDesktopGUI()->setEnabled(state);
#endif
}
void GUI::_setWindowTitle(const QString& title)
{
if (title.isEmpty())
getMainWidget()->setWindowTitle("qTox");
else
getMainWidget()->setWindowTitle("qTox - " +title);
}
void GUI::_reloadTheme()
{
#ifndef Q_OS_ANDROID
Nexus::getDesktopGUI()->reloadTheme();
#endif
}
void GUI::_showWarning(const QString& title, const QString& msg)
{
QMessageBox::warning(getMainWidget(), title, msg);
}
void GUI::_showInfo(const QString& title, const QString& msg)
{
QMessageBox::information(getMainWidget(), title, msg);
}
bool GUI::_askQuestion(const QString& title, const QString& msg,
bool defaultAns, bool warning)
{
if (warning)
{
QMessageBox::StandardButton def = QMessageBox::Cancel;
if (defaultAns)
def = QMessageBox::Ok;
return QMessageBox::warning(getMainWidget(), title, msg, QMessageBox::Ok | QMessageBox::Cancel, def) == QMessageBox::Ok;
}
else
{
QMessageBox::StandardButton def = QMessageBox::No;
if (defaultAns)
def = QMessageBox::Yes;
return QMessageBox::question(getMainWidget(), title, msg, QMessageBox::Yes | QMessageBox::No, def) == QMessageBox::Yes;
}
}
QString GUI::_itemInputDialog(QWidget * parent, const QString & title,
const QString & label, const QStringList & items,
int current, bool editable, bool * ok,
Qt::WindowFlags flags,
Qt::InputMethodHints hints)
{
return QInputDialog::getItem(parent, title, label, items, current, editable, ok, flags, hints);
}
QString GUI::_passwordDialog(const QString& cancel, const QString& body)
{
// we use a hack. It is considered that closing the dialog without explicitly clicking
// disable history is confusing. But we can't distinguish between clicking the cancel
// button and closing the dialog. So instead, we reverse the Ok and Cancel roles,
// so that nothing but explicitly clicking disable history closes the dialog
QString ret;
QInputDialog dialog;
dialog.setWindowTitle(tr("Enter your password"));
dialog.setOkButtonText(cancel);
dialog.setCancelButtonText(tr("Decrypt"));
dialog.setInputMode(QInputDialog::TextInput);
dialog.setTextEchoMode(QLineEdit::Password);
dialog.setLabelText(body);
// problem with previous hack: the default button is disable history, not decrypt.
// use another hack to reverse the default buttons.
// http://www.qtcentre.org/threads/49924-Change-property-of-QInputDialog-button
QList<QDialogButtonBox*> l = dialog.findChildren<QDialogButtonBox*>();
if (!l.isEmpty())
{
QPushButton* ok = l.first()->button(QDialogButtonBox::Ok);
QPushButton* cancel = l.first()->button(QDialogButtonBox::Cancel);
if (ok && cancel)
{
ok->setAutoDefault(false);
ok->setDefault(false);
cancel->setAutoDefault(true);
cancel->setDefault(true);
}
else
qWarning() << "PasswordDialog: Missing button!";
}
else
qWarning() << "PasswordDialog: No QDialogButtonBox!";
// using similar code, set QLabels to wrap
for (auto* label : dialog.findChildren<QLabel*>())
label->setWordWrap(true);
while (true)
{
int val = dialog.exec();
if (val == QDialog::Accepted)
return QString();
else
{
ret = dialog.textValue();
if (!ret.isEmpty())
return ret;
}
dialog.setTextValue("");
dialog.setLabelText(body + "\n\n" + tr("You must enter a non-empty password:"));
}
}
// Other
QWidget* GUI::getMainWidget()
{
QWidget* maingui{nullptr};
#ifdef Q_OS_ANDROID
maingui = Nexus::getAndroidGUI();
#else
maingui = Nexus::getDesktopGUI();
#endif
return maingui;
}

72
src/widget/gui.h Normal file
View File

@ -0,0 +1,72 @@
#ifndef GUI_H
#define GUI_H
#include <QObject>
class QWidget;
/// Abstracts the GUI from the target backend (AndroidGUI, DesktopGUI, ...)
/// All the functions exposed here are thread-safe
/// Prefer calling this class to calling a GUI backend directly
class GUI : public QObject
{
Q_OBJECT
public:
static GUI& getInstance();
/// Returns the main QWidget* of the application
static QWidget* getMainWidget();
/// Will enable or disable the GUI.
/// A disabled GUI can't be interacted with by the user
static void setEnabled(bool state);
/// Change the title of the main window
/// This is usually always visible to the user
static void setWindowTitle(const QString& title);
/// Reloads the application theme and redraw the window
static void reloadTheme();
/// Show a warning to the user, for example in a message box
static void showWarning(const QString& title, const QString& msg);
/// Show some text to the user, for example in a message box
static void showInfo(const QString& title, const QString& msg);
/// Asks the user a question, for example in a message box.
/// If warning is true, we will use a special warning style.
/// Returns the answer.
static bool askQuestion(const QString& title, const QString& msg,
bool defaultAns = false, bool warning = true);
/// Asks the user to input text and returns the answer.
/// The interface is equivalent to QInputDialog::getItem()
static QString itemInputDialog(QWidget * parent, const QString & title,
const QString & label, const QStringList & items,
int current = 0, bool editable = true, bool * ok = 0,
Qt::WindowFlags flags = 0,
Qt::InputMethodHints hints = Qt::ImhNone);
/// Asks the user to answer a password
/// cancel is the text on the cancel button and body
/// is descriptive text that will be shown to the user
static QString passwordDialog(const QString& cancel, const QString& body);
signals:
/// Emitted when the GUI is resized on supported platforms
/// Guaranteed to work on desktop platforms
void resized();
private:
explicit GUI(QObject *parent = 0);
// Private implementation, those must be called from the GUI thread
private slots:
void _setEnabled(bool state);
void _setWindowTitle(const QString& title);
void _reloadTheme();
void _showWarning(const QString& title, const QString& msg);
void _showInfo(const QString& title, const QString& msg);
bool _askQuestion(const QString& title, const QString& msg,
bool defaultAns = false, bool warning = true);
QString _itemInputDialog(QWidget * parent, const QString & title,
const QString & label, const QStringList & items,
int current = 0, bool editable = true, bool * ok = 0,
Qt::WindowFlags flags = 0,
Qt::InputMethodHints inputMethodHints = Qt::ImhNone);
QString _passwordDialog(const QString& cancel, const QString& body);
};
#endif // GUI_H

View File

@ -42,6 +42,11 @@ SystemTrayIcon::SystemTrayIcon()
}
}
SystemTrayIcon::~SystemTrayIcon()
{
qDebug() << "Deleting SystemTrayIcon";
}
QString SystemTrayIcon::extractIconToFile(QIcon icon, QString name)
{
QString iconPath;

View File

@ -12,6 +12,7 @@ class SystemTrayIcon : public QObject
Q_OBJECT
public:
SystemTrayIcon();
~SystemTrayIcon();
void setContextMenu(QMenu* menu);
void show();
void hide();

View File

@ -15,7 +15,7 @@
*/
#include "toxsave.h"
#include "widget.h"
#include "gui.h"
#include "src/core.h"
#include "src/misc/settings.h"
#include <QCoreApplication>
@ -53,20 +53,19 @@ void handleToxSave(const QString& path)
if (info.suffix() != "tox")
{
QMessageBox::warning(Widget::getInstance(),
QObject::tr("Ignoring non-Tox file", "popup title"),
QObject::tr("Warning: you've chosen a file that is not a Tox save file; ignoring.", "popup text"));
GUI::showWarning(QObject::tr("Ignoring non-Tox file", "popup title"),
QObject::tr("Warning: you've chosen a file that is not a Tox save file; ignoring.", "popup text"));
return;
}
QString profilePath = QDir(Settings::getSettingsDirPath()).filePath(profile + Core::TOX_EXT);
if (QFileInfo(profilePath).exists() && !Widget::getInstance()->askQuestion(QObject::tr("Profile already exists", "import confirm title"),
if (QFileInfo(profilePath).exists() && !GUI::askQuestion(QObject::tr("Profile already exists", "import confirm title"),
QObject::tr("A profile named \"%1\" already exists. Do you want to erase it?", "import confirm text").arg(profile)))
return;
QFile::copy(path, profilePath);
// no good way to update the ui from here... maybe we need a Widget:refreshUi() function...
// such a thing would simplify other code as well I believe
QMessageBox::information(Widget::getInstance(), QObject::tr("Profile imported"), QObject::tr("%1.tox was successfully imported").arg(profile));
GUI::showInfo(QObject::tr("Profile imported"), QObject::tr("%1.tox was successfully imported").arg(profile));
}

View File

@ -36,6 +36,8 @@
#include "src/audio.h"
#include "src/platform/timer.h"
#include "systemtrayicon.h"
#include "src/nexus.h"
#include <cassert>
#include <QMessageBox>
#include <QDebug>
#include <QFile>
@ -53,6 +55,12 @@
#include <QTranslator>
#include <tox/tox.h>
#ifdef Q_OS_ANDROID
#define IS_ON_DESKTOP_GUI 0
#else
#define IS_ON_DESKTOP_GUI 1
#endif
void toxActivateEventHandler(const QByteArray& data)
{
if (data != "$activate")
@ -64,11 +72,11 @@ Widget *Widget::instance{nullptr};
Widget::Widget(QWidget *parent)
: QMainWindow(parent),
icon{nullptr},
ui(new Ui::MainWindow),
activeChatroomWidget{nullptr},
eventFlag(false),
eventIcon(false),
icon{nullptr}
eventIcon(false)
{
translator = new QTranslator;
setTranslation();
@ -116,6 +124,9 @@ void Widget::init()
this,
SLOT(onIconClick(QSystemTrayIcon::ActivationReason)));
icon->show();
icon->hide();
if (Settings::getInstance().getShowSystemTray())
{
icon->show();
@ -124,7 +135,6 @@ void Widget::init()
}
else
this->show();
}
else
{
@ -193,68 +203,16 @@ void Widget::init()
ui->statusButton->setEnabled(false);
Style::setThemeColor(Settings::getInstance().getThemeColor());
Style::applyTheme();
qRegisterMetaType<Status>("Status");
qRegisterMetaType<vpx_image>("vpx_image");
qRegisterMetaType<uint8_t>("uint8_t");
qRegisterMetaType<uint16_t>("uint16_t");
qRegisterMetaType<const int16_t*>("const int16_t*");
qRegisterMetaType<int32_t>("int32_t");
qRegisterMetaType<int64_t>("int64_t");
qRegisterMetaType<QPixmap>("QPixmap");
qRegisterMetaType<ToxFile>("ToxFile");
qRegisterMetaType<ToxFile::FileDirection>("ToxFile::FileDirection");
qRegisterMetaType<Core::PasswordType>("Core::PasswordType");
QString profilePath = detectProfile();
coreThread = new QThread(this);
coreThread->setObjectName("qTox Core");
core = new Core(Camera::getInstance(), coreThread, profilePath);
core->moveToThread(coreThread);
connect(coreThread, &QThread::started, core, &Core::start);
reloadTheme();
filesForm = new FilesForm();
addFriendForm = new AddFriendForm;
settingsWidget = new SettingsWidget();
connect(settingsWidget, &SettingsWidget::setShowSystemTray, this, &Widget::onSetShowSystemTray);
connect(core, &Core::connected, this, &Widget::onConnected);
connect(core, &Core::disconnected, this, &Widget::onDisconnected);
connect(core, &Core::failedToStart, this, &Widget::onFailedToStartCore);
connect(core, &Core::badProxy, this, &Widget::onBadProxyCore);
connect(core, &Core::statusSet, this, &Widget::onStatusSet);
connect(core, &Core::usernameSet, this, &Widget::setUsername);
connect(core, &Core::statusMessageSet, this, &Widget::setStatusMessage);
connect(core, &Core::selfAvatarChanged, this, &Widget::onSelfAvatarLoaded);
Core* core = Nexus::getCore();
connect(core, SIGNAL(fileDownloadFinished(const QString&)), filesForm, SLOT(onFileDownloadComplete(const QString&)));
connect(core, SIGNAL(fileUploadFinished(const QString&)), filesForm, SLOT(onFileUploadComplete(const QString&)));
connect(core, &Core::friendAdded, this, &Widget::addFriend);
connect(core, &Core::failedToAddFriend, this, &Widget::addFriendFailed);
connect(core, &Core::friendUsernameChanged, this, &Widget::onFriendUsernameChanged);
connect(core, &Core::friendStatusChanged, this, &Widget::onFriendStatusChanged);
connect(core, &Core::friendStatusMessageChanged, this, &Widget::onFriendStatusMessageChanged);
connect(core, &Core::friendRequestReceived, this, &Widget::onFriendRequestReceived);
connect(core, &Core::friendMessageReceived, this, &Widget::onFriendMessageReceived);
connect(core, &Core::receiptRecieved, this, &Widget::onReceiptRecieved);
connect(core, &Core::groupInviteReceived, this, &Widget::onGroupInviteReceived);
connect(core, &Core::groupMessageReceived, this, &Widget::onGroupMessageReceived);
connect(core, &Core::groupNamelistChanged, this, &Widget::onGroupNamelistChanged);
connect(core, &Core::groupTitleChanged, this, &Widget::onGroupTitleChanged);
connect(core, &Core::emptyGroupCreated, this, &Widget::onEmptyGroupCreated);
connect(core, &Core::avInvite, this, &Widget::playRingtone);
connect(core, &Core::blockingClearContacts, this, &Widget::clearContactsList, Qt::BlockingQueuedConnection);
connect(core, &Core::friendTypingChanged, this, &Widget::onFriendTypingChanged);
connect(core, SIGNAL(messageSentResult(int,QString,int)), this, SLOT(onMessageSendResult(int,QString,int)));
connect(core, SIGNAL(groupSentResult(int,QString,int)), this, SLOT(onGroupSendResult(int,QString,int)));
connect(this, &Widget::statusSet, core, &Core::setStatus);
connect(this, &Widget::friendRequested, core, &Core::requestFriendship);
connect(this, &Widget::friendRequestAccepted, core, &Core::acceptFriendRequest);
connect(this, &Widget::changeProfile, core, &Core::switchConfiguration);
connect(settingsWidget, &SettingsWidget::setShowSystemTray, this, &Widget::onSetShowSystemTray);
connect(ui->addButton, SIGNAL(clicked()), this, SLOT(onAddClicked()));
connect(ui->groupButton, SIGNAL(clicked()), this, SLOT(onGroupClicked()));
connect(ui->transferButton, SIGNAL(clicked()), this, SLOT(onTransferClicked()));
@ -270,8 +228,6 @@ void Widget::init()
connect(timer, &QTimer::timeout, this, &Widget::onUserAwayCheck);
connect(timer, &QTimer::timeout, this, &Widget::onEventIconTick);
coreThread->start();
addFriendForm->show(*ui);
#if (AUTOUPDATE_ENABLED)
@ -317,10 +273,8 @@ void Widget::updateTrayIcon()
Widget::~Widget()
{
qDebug() << "Deleting Widget";
core->saveConfiguration();
qDebug() << "Widget: Deleting Widget";
AutoUpdater::abortUpdates();
delete core;
icon->hide();
hideMainForms();
delete settingsWidget;
@ -338,6 +292,8 @@ Widget::~Widget()
Widget* Widget::getInstance()
{
assert(IS_ON_DESKTOP_GUI); // Widget must only be used on Desktop platforms
if (!instance)
{
instance = new Widget();
@ -346,11 +302,6 @@ Widget* Widget::getInstance()
return instance;
}
QThread* Widget::getCoreThread()
{
return coreThread;
}
void Widget::closeEvent(QCloseEvent *event)
{
if (Settings::getInstance().getShowSystemTray() && Settings::getInstance().getCloseToTray() == true)
@ -386,72 +337,9 @@ void Widget::resizeEvent(QResizeEvent *event)
emit resized();
}
QString Widget::detectProfile()
{
QDir dir(Settings::getSettingsDirPath());
QString path, profile = Settings::getInstance().getCurrentProfile();
path = dir.filePath(profile + Core::TOX_EXT);
QFile file(path);
if (profile.isEmpty() || !file.exists())
{
Settings::getInstance().setCurrentProfile("");
#if 1 // deprecation attempt
// if the last profile doesn't exist, fall back to old "data"
path = dir.filePath(Core::CONFIG_FILE_NAME);
QFile file(path);
if (file.exists())
return path;
else if (QFile(path = dir.filePath("tox_save")).exists()) // also import tox_save if no data
return path;
else
#endif
{
profile = askProfiles();
if (profile.isEmpty())
return "";
else
{
Settings::getInstance().switchProfile(profile);
return dir.filePath(profile + Core::TOX_EXT);
}
}
}
else
return path;
}
QList<QString> Widget::searchProfiles()
{
QList<QString> out;
QDir dir(Settings::getSettingsDirPath());
dir.setFilter(QDir::Files | QDir::NoDotAndDotDot);
dir.setNameFilters(QStringList("*.tox"));
for (QFileInfo file : dir.entryInfoList())
out += file.completeBaseName();
return out;
}
QString Widget::askProfiles()
{ // TODO: allow user to create new Tox ID, even if a profile already exists
QList<QString> profiles = searchProfiles();
if (profiles.empty()) return "";
bool ok;
QString profile = QInputDialog::getItem(this,
tr("Choose a profile"),
tr("Please choose which identity to use"),
profiles,
0, // which slot to start on
false, // if the user can enter their own input
&ok);
if (!ok) // user cancelled
return "";
else
return profile;
}
QString Widget::getUsername()
{
return core->getUsername();
return Nexus::getCore()->getUsername();
}
void Widget::onAvatarClicked()
@ -495,7 +383,7 @@ void Widget::onAvatarClicked()
return;
}
core->setAvatar(TOX_AVATAR_FORMAT_PNG, bytes);
Nexus::getCore()->setAvatar(TOX_AVATAR_FORMAT_PNG, bytes);
}
void Widget::onSelfAvatarLoaded(const QPixmap& pic)
@ -591,7 +479,7 @@ void Widget::onAddClicked()
void Widget::onGroupClicked()
{
core->createGroup();
Nexus::getCore()->createGroup();
}
void Widget::onTransferClicked()
@ -664,7 +552,7 @@ void Widget::hideMainForms()
void Widget::onUsernameChanged(const QString& newUsername, const QString& oldUsername)
{
setUsername(oldUsername); // restore old username until Core tells us to set it
core->setUsername(newUsername);
Nexus::getCore()->setUsername(newUsername);
}
void Widget::setUsername(const QString& username)
@ -681,7 +569,7 @@ void Widget::onStatusMessageChanged(const QString& newStatusMessage, const QStri
{
ui->statusLabel->setText(oldStatusMessage); // restore old status message until Core tells us to set it
ui->statusLabel->setToolTip(oldStatusMessage); // for overlength messsages
core->setStatusMessage(newStatusMessage);
Nexus::getCore()->setStatusMessage(newStatusMessage);
}
void Widget::setStatusMessage(const QString &statusMessage)
@ -707,6 +595,7 @@ void Widget::addFriend(int friendId, const QString &userId)
if (Settings::getInstance().getEnableLogging())
newfriend->getChatForm()->loadHistory(QDateTime::currentDateTime().addDays(-7), true);
Core* core = Nexus::getCore();
connect(settingsWidget, &SettingsWidget::compactToggled, newfriend->getFriendWidget(), &GenericChatroomWidget::onCompactChanged);
connect(newfriend->getFriendWidget(), SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), this, SLOT(onChatroomWidgetClicked(GenericChatroomWidget*)));
connect(newfriend->getFriendWidget(), SIGNAL(removeFriend(int)), this, SLOT(removeFriend(int)));
@ -928,7 +817,7 @@ void Widget::removeFriend(Friend* f, bool fake)
onAddClicked();
}
FriendList::removeFriend(f->getFriendID(), fake);
core->removeFriend(f->getFriendID(), fake);
Nexus::getCore()->removeFriend(f->getFriendID(), fake);
delete f;
if (ui->mainHead->layout()->isEmpty())
onAddClicked();
@ -959,7 +848,7 @@ void Widget::copyFriendIdToClipboard(int friendId)
if (f != nullptr)
{
QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(core->getFriendAddress(f->getFriendID()), QClipboard::Clipboard);
clipboard->setText(Nexus::getCore()->getFriendAddress(f->getFriendID()), QClipboard::Clipboard);
}
}
@ -967,7 +856,7 @@ void Widget::onGroupInviteReceived(int32_t friendId, uint8_t type, QByteArray in
{
if (type == TOX_GROUPCHAT_TYPE_TEXT || type == TOX_GROUPCHAT_TYPE_AV)
{
int groupId = core->joinGroupchat(friendId, type, (uint8_t*)invite.data(), invite.length());
int groupId = Nexus::getCore()->joinGroupchat(friendId, type, (uint8_t*)invite.data(), invite.length());
if (groupId < 0)
{
qWarning() << "Widget::onGroupInviteReceived: Unable to accept group invite";
@ -1014,7 +903,7 @@ void Widget::onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t Cha
g = createGroup(groupnumber);
}
QString name = core->getGroupPeerName(groupnumber, peernumber);
QString name = Nexus::getCore()->getGroupPeerName(groupnumber, peernumber);
TOX_CHAT_CHANGE change = static_cast<TOX_CHAT_CHANGE>(Change);
if (change == TOX_CHAT_CHANGE_PEER_ADD)
{
@ -1033,7 +922,7 @@ void Widget::onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t Cha
//g->chatForm->addSystemInfoMessage(tr("%1 has left the chat").arg(name), "silver");
}
else if (change == TOX_CHAT_CHANGE_PEER_NAME) // core overwrites old name before telling us it changed...
g->updatePeer(peernumber,core->getGroupPeerName(groupnumber, peernumber));
g->updatePeer(peernumber,Nexus::getCore()->getGroupPeerName(groupnumber, peernumber));
}
void Widget::onGroupTitleChanged(int groupnumber, const QString& author, const QString& title)
@ -1056,7 +945,7 @@ void Widget::removeGroup(Group* g, bool fake)
onAddClicked();
}
GroupList::removeGroup(g->getGroupId(), fake);
core->removeGroup(g->getGroupId(), fake);
Nexus::getCore()->removeGroup(g->getGroupId(), fake);
delete g;
if (ui->mainHead->layout()->isEmpty())
onAddClicked();
@ -1070,11 +959,6 @@ void Widget::removeGroup(int groupId)
removeGroup(GroupList::findGroup(groupId));
}
Core *Widget::getCore()
{
return core;
}
Group *Widget::createGroup(int groupId)
{
Group* g = GroupList::findGroup(groupId);
@ -1090,6 +974,7 @@ Group *Widget::createGroup(int groupId)
layout->addWidget(newgroup->getGroupWidget());
newgroup->getGroupWidget()->updateStatusLight();
Core* core = Nexus::getCore();
connect(newgroup->getGroupWidget(), SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), this, SLOT(onChatroomWidgetClicked(GenericChatroomWidget*)));
connect(newgroup->getGroupWidget(), SIGNAL(removeGroup(int)), this, SLOT(removeGroup(int)));
connect(newgroup->getGroupWidget(), SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), newgroup->getChatForm(), SLOT(focusInput()));
@ -1174,17 +1059,17 @@ void Widget::onEventIconTick()
void Widget::setStatusOnline()
{
core->setStatus(Status::Online);
Nexus::getCore()->setStatus(Status::Online);
}
void Widget::setStatusAway()
{
core->setStatus(Status::Away);
Nexus::getCore()->setStatus(Status::Away);
}
void Widget::setStatusBusy()
{
core->setStatus(Status::Busy);
Nexus::getCore()->setStatus(Status::Busy);
}
void Widget::onMessageSendResult(int friendId, const QString& message, int messageId)

View File

@ -54,14 +54,11 @@ public:
explicit Widget(QWidget *parent = 0);
void setCentralWidget(QWidget *widget, const QString &widgetName);
QString getUsername();
Core* getCore();
QThread* getCoreThread();
Camera* getCamera();
static Widget* getInstance();
void newMessageAlert(GenericChatroomWidget* chat);
bool isFriendWidgetCurActiveWidget(Friend* f);
bool getIsWindowMinimized();
static QList<QString> searchProfiles();
void clearContactsList();
void setTranslation();
void updateTrayIcon();
@ -69,7 +66,6 @@ public:
Q_INVOKABLE void setEnabledThreadsafe(bool enabled);
Q_INVOKABLE bool askQuestion(const QString& title, const QString& msg, bool defaultAns = false, bool warning = true);
Q_INVOKABLE QString passwordDialog(const QString& cancel, const QString& body);
Q_INVOKABLE QString askProfiles();
// hooray for threading hacks
~Widget();
@ -86,6 +82,29 @@ public slots:
void onSettingsClicked();
void setWindowTitle(const QString& title);
void forceShow();
void onConnected();
void onDisconnected();
void onStatusSet(Status status);
void onFailedToStartCore();
void onBadProxyCore();
void onSelfAvatarLoaded(const QPixmap &pic);
void setUsername(const QString& username);
void setStatusMessage(const QString &statusMessage);
void addFriend(int friendId, const QString& userId);
void addFriendFailed(const QString& userId, const QString& errorInfo = QString());
void onFriendStatusChanged(int friendId, Status status);
void onFriendStatusMessageChanged(int friendId, const QString& message);
void onFriendUsernameChanged(int friendId, const QString& username);
void onFriendMessageReceived(int friendId, const QString& message, bool isAction);
void onFriendRequestReceived(const QString& userId, const QString& message);
void onReceiptRecieved(int friendId, int receipt);
void onEmptyGroupCreated(int groupId);
void onGroupInviteReceived(int32_t friendId, uint8_t type, QByteArray invite);
void onGroupMessageReceived(int groupnumber, int peernumber, const QString& message, bool isAction);
void onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t change);
void onGroupTitleChanged(int groupnumber, const QString& author, const QString& title);
void playRingtone();
void onFriendTypingChanged(int friendId, bool isTyping);
signals:
void friendRequestAccepted(const QString& userId);
@ -98,34 +117,13 @@ signals:
void resized();
private slots:
void onConnected();
void onDisconnected();
void onStatusSet(Status status);
void onAddClicked();
void onGroupClicked();
void onTransferClicked();
void onFailedToStartCore();
void onBadProxyCore();
void onAvatarClicked();
void onSelfAvatarLoaded(const QPixmap &pic);
void onUsernameChanged(const QString& newUsername, const QString& oldUsername);
void onStatusMessageChanged(const QString& newStatusMessage, const QString& oldStatusMessage);
void setUsername(const QString& username);
void setStatusMessage(const QString &statusMessage);
void addFriend(int friendId, const QString& userId);
void addFriendFailed(const QString& userId, const QString& errorInfo = QString());
void onFriendStatusChanged(int friendId, Status status);
void onFriendStatusMessageChanged(int friendId, const QString& message);
void onFriendUsernameChanged(int friendId, const QString& username);
void onChatroomWidgetClicked(GenericChatroomWidget *);
void onFriendMessageReceived(int friendId, const QString& message, bool isAction);
void onFriendRequestReceived(const QString& userId, const QString& message);
void onReceiptRecieved(int friendId, int receipt);
void onEmptyGroupCreated(int groupId);
void onGroupInviteReceived(int32_t friendId, uint8_t type, QByteArray invite);
void onGroupMessageReceived(int groupnumber, int peernumber, const QString& message, bool isAction);
void onGroupNamelistChanged(int groupnumber, int peernumber, uint8_t change);
void onGroupTitleChanged(int groupnumber, const QString& author, const QString& title);
void removeFriend(int friendId);
void copyFriendIdToClipboard(int friendId);
void removeGroup(int groupId);
@ -134,11 +132,9 @@ private slots:
void setStatusBusy();
void onMessageSendResult(int friendId, const QString& message, int messageId);
void onGroupSendResult(int groupId, const QString& message, int result);
void playRingtone();
void onIconClick(QSystemTrayIcon::ActivationReason);
void onUserAwayCheck();
void onEventIconTick();
void onFriendTypingChanged(int friendId, bool isTyping);
void onSetShowSystemTray(bool newValue);
void onSplitterMoved(int pos, int index);
@ -151,7 +147,6 @@ private:
void removeGroup(Group* g, bool fake = false);
void saveWindowGeometry();
void saveSplitterGeometry();
QString detectProfile();
SystemTrayIcon *icon;
QMenu *trayMenu;
QAction *statusOnline,
@ -162,8 +157,6 @@ private:
Ui::MainWindow *ui;
QSplitter *centralLayout;
QPoint dragPosition;
Core* core;
QThread* coreThread;
AddFriendForm* addFriendForm;
SettingsWidget* settingsWidget;
FilesForm* filesForm;