diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f8bc03c..c65eb23 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,43 +1,43 @@ # set Kaidans sources (used in main cmake file) set(KAIDAN_SOURCES src/main.cpp src/Kaidan.cpp src/ClientWorker.cpp src/AvatarFileStorage.cpp src/Database.cpp src/RosterModel.cpp src/RosterManager.cpp src/RegistrationManager.cpp src/MessageHandler.cpp src/MessageModel.cpp src/Notifications.cpp src/PresenceCache.cpp src/DiscoveryManager.cpp src/VCardManager.cpp src/LogHandler.cpp src/StatusBar.cpp src/UploadManager.cpp src/EmojiModel.cpp src/TransferCache.cpp src/DownloadManager.cpp - src/Utils.cpp + src/QmlUtils.cpp # needed to trigger moc generation src/Enums.h # kaidan QXmpp extensions (need to be merged into QXmpp upstream) src/qxmpp-exts/QXmppHttpUploadIq.cpp src/qxmpp-exts/QXmppUploadRequestManager.cpp src/qxmpp-exts/QXmppUploadManager.cpp src/qxmpp-exts/QXmppColorGenerator.cpp # hsluv-c required for color generation src/hsluv-c/hsluv.c ) if(NOT ANDROID AND NOT IOS) set(KAIDAN_SOURCES ${KAIDAN_SOURCES} src/singleapp/singleapplication.cpp src/singleapp/singleapplication_p.cpp ) endif() diff --git a/src/Kaidan.cpp b/src/Kaidan.cpp index cca3c81..5c56abf 100644 --- a/src/Kaidan.cpp +++ b/src/Kaidan.cpp @@ -1,221 +1,221 @@ /* * Kaidan - A user-friendly XMPP client for every device! * * Copyright (C) 2016-2019 Kaidan developers and contributors * (see the LICENSE file for a full list of copyright authors) * * Kaidan is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * In addition, as a special exception, the author of Kaidan gives * permission to link the code of its release with the OpenSSL * project's "OpenSSL" library (or with modified versions of it that * use the same license as the "OpenSSL" library), and distribute the * linked executables. You must obey the GNU General Public License in * all respects for all of the code used other than "OpenSSL". If you * modify this file, you may extend this exception to your version of * the file, but you are not obligated to do so. If you do not wish to * do so, delete this exception statement from your version. * * Kaidan is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Kaidan. If not, see . */ #include "Kaidan.h" // Qt #include #include #include // QXmpp #include #include "qxmpp-exts/QXmppColorGenerator.h" // Kaidan #include "AvatarFileStorage.h" #include "Database.h" #include "RosterModel.h" #include "MessageModel.h" #include "PresenceCache.h" -#include "Utils.h" +#include "QmlUtils.h" Kaidan *Kaidan::s_instance = nullptr; Kaidan::Kaidan(QGuiApplication *app, bool enableLogging, QObject *parent) - : QObject(parent), utils(new Utils(this)), database(new Database()) + : QObject(parent), m_utils(new QmlUtils(this)), database(new Database()) { Q_ASSERT(!Kaidan::s_instance); Kaidan::s_instance = this; // Database setup database->openDatabase(); if (database->needToConvert()) database->convertDatabase(); // Caching components caches = new ClientWorker::Caches(database, this); // Connect the avatar changed signal of the avatarStorage with the NOTIFY signal // of the Q_PROPERTY for the avatar storage (so all avatars are updated in QML) connect(caches->avatarStorage, &AvatarFileStorage::avatarIdsChanged, this, &Kaidan::avatarStorageChanged); // // Load settings // creds.jid = caches->settings->value(KAIDAN_SETTINGS_AUTH_JID).toString(); creds.jidResource = caches->settings->value(KAIDAN_SETTINGS_AUTH_RESOURCE) .toString(); creds.password = QString(QByteArray::fromBase64(caches->settings->value( KAIDAN_SETTINGS_AUTH_PASSWD).toString().toUtf8())); // use Kaidan as resource, if no set if (creds.jidResource.isEmpty()) setJidResource(APPLICATION_DISPLAY_NAME); creds.isFirstTry = false; // // Start ClientWorker on new thread // cltThrd = new ClientThread(); client = new ClientWorker(caches, this, enableLogging, app); client->setCredentials(creds); connect(client, &ClientWorker::disconnReasonChanged, this, &Kaidan::setDisconnReason); client->moveToThread(cltThrd); connect(cltThrd, &QThread::started, client, &ClientWorker::main); cltThrd->start(); } Kaidan::~Kaidan() { delete caches; delete database; Kaidan::s_instance = nullptr; } void Kaidan::start() { if (creds.jid.isEmpty() || creds.password.isEmpty()) emit newCredentialsNeeded(); else mainConnect(); } void Kaidan::mainConnect() { if (connectionState != ConnectionState::StateDisconnected) { qWarning() << "[main] Tried to connect, even if still connected!" << "Requesting disconnect."; emit client->disconnectRequested(); } emit client->credentialsUpdated(creds); emit client->connectRequested(); // update own JID to display correct messages caches->msgModel->setOwnJid(creds.jid); } void Kaidan::mainDisconnect(bool openLogInPage) { // disconnect the client if connected or connecting if (connectionState != ConnectionState::StateDisconnected) emit client->disconnectRequested(); if (openLogInPage) { // clear password caches->settings->remove(KAIDAN_SETTINGS_AUTH_PASSWD); setPassword(QString()); // trigger log in page emit newCredentialsNeeded(); } } void Kaidan::setConnectionState(QXmppClient::State state) { this->connectionState = (ConnectionState) state; emit connectionStateChanged(); // Open the possibly cached URI when connected. // This is needed because the XMPP URIs can't be opened when Kaidan is not connected. if (connectionState == ConnectionState::StateConnected && !openUriCache.isEmpty()) { // delay is needed because sometimes the RosterPage needs to be loaded first QTimer::singleShot(300, [=] () { emit xmppUriReceived(openUriCache); openUriCache = ""; }); } } void Kaidan::setDisconnReason(DisconnectionReason reason) { disconnReason = reason; emit disconnReasonChanged(); } void Kaidan::setJid(const QString &jid) { creds.jid = jid; // credentials were modified -> first try creds.isFirstTry = true; } void Kaidan::setJidResource(const QString &jidResource) { // JID resource won't influence the authentication, so we don't need // to set the first try flag and can save it. creds.jidResource = jidResource; caches->settings->setValue(KAIDAN_SETTINGS_AUTH_RESOURCE, jidResource); } void Kaidan::setPassword(const QString &password) { creds.password = password; // credentials were modified -> first try creds.isFirstTry = true; } void Kaidan::setChatPartner(const QString &chatPartner) { // check if different if (this->chatPartner == chatPartner) return; this->chatPartner = chatPartner; emit chatPartnerChanged(chatPartner); caches->msgModel->applyRecipientFilter(chatPartner); } quint8 Kaidan::getDisconnReason() const { return static_cast(disconnReason); } void Kaidan::addOpenUri(const QByteArray &uri) { qDebug() << "[main]" << uri; if (!uri.startsWith("xmpp:") || !uri.contains("@")) return; if (connectionState == ConnectionState::StateConnected) { emit xmppUriReceived(QString::fromUtf8(uri)); } else { //: The link is an XMPP-URI (i.e. 'xmpp:kaidan@muc.kaidan.im?join' for joining a chat) emit passiveNotificationRequested(tr("The link will be opened after you have connected.")); openUriCache = QString::fromUtf8(uri); } } Kaidan *Kaidan::instance() { return s_instance; } diff --git a/src/Kaidan.h b/src/Kaidan.h index 5f23345..f7bf5b5 100644 --- a/src/Kaidan.h +++ b/src/Kaidan.h @@ -1,425 +1,425 @@ /* * Kaidan - A user-friendly XMPP client for every device! * * Copyright (C) 2016-2019 Kaidan developers and contributors * (see the LICENSE file for a full list of copyright authors) * * Kaidan is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * In addition, as a special exception, the author of Kaidan gives * permission to link the code of its release with the OpenSSL * project's "OpenSSL" library (or with modified versions of it that * use the same license as the "OpenSSL" library), and distribute the * linked executables. You must obey the GNU General Public License in * all respects for all of the code used other than "OpenSSL". If you * modify this file, you may extend this exception to your version of * the file, but you are not obligated to do so. If you do not wish to * do so, delete this exception statement from your version. * * Kaidan is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Kaidan. If not, see . */ #ifndef KAIDAN_H #define KAIDAN_H // Qt #include #include #include // Kaidan #include "ClientWorker.h" #include "Globals.h" #include "Enums.h" class QGuiApplication; class Database; class QXmppClient; -class Utils; +class QmlUtils; using namespace Enums; /** * @class Kaidan Kaidan's Back-End Class * * @brief This class will initiate the complete back-end, including the @see Database * connection, viewing models (@see MessageModel, @see RosterModel), etc. * * This class will run in the main thread, only the XMPP connection runs in another * thread (@see ClientThread). */ class Kaidan : public QObject { Q_OBJECT - Q_PROPERTY(Utils* utils READ getUtils CONSTANT) + Q_PROPERTY(QmlUtils* utils READ getUtils CONSTANT) Q_PROPERTY(RosterModel* rosterModel READ getRosterModel CONSTANT) Q_PROPERTY(MessageModel* messageModel READ getMessageModel CONSTANT) Q_PROPERTY(AvatarFileStorage* avatarStorage READ getAvatarStorage NOTIFY avatarStorageChanged) Q_PROPERTY(PresenceCache* presenceCache READ getPresenceCache CONSTANT) Q_PROPERTY(TransferCache* transferCache READ getTransferCache CONSTANT) Q_PROPERTY(QSettings* settings READ getSettings CONSTANT) Q_PROPERTY(quint8 connectionState READ getConnectionState NOTIFY connectionStateChanged) Q_PROPERTY(quint8 disconnReason READ getDisconnReason NOTIFY disconnReasonChanged) Q_PROPERTY(QString jid READ getJid WRITE setJid NOTIFY jidChanged) Q_PROPERTY(QString jidResource READ getJidResource WRITE setJidResource NOTIFY jidResourceChanged) Q_PROPERTY(QString password READ getPassword WRITE setPassword NOTIFY passwordChanged) Q_PROPERTY(QString chatPartner READ getChatPartner WRITE setChatPartner NOTIFY chatPartnerChanged) Q_PROPERTY(bool uploadServiceFound READ getUploadServiceFound NOTIFY uploadServiceFoundChanged) public: Kaidan(QGuiApplication *app, bool enableLogging = true, QObject *parent = nullptr); ~Kaidan(); /** * Start connection (called from QML when ready) */ Q_INVOKABLE void start(); /** * Connect to the XMPP server * * If you haven't set a username and password, they are used from the * last successful login (the settings file). */ Q_INVOKABLE void mainConnect(); /** * Disconnect from XMPP server * * This will disconnect the client from the server. When disconnected, * the connectionStateChanged signal will be emitted. * * @param openLogInPage If true, the newCredentialsNeeded signal will be * emitted. */ Q_INVOKABLE void mainDisconnect(bool openLogInPage = false); /** * Returns the current ConnectionState */ Q_INVOKABLE quint8 getConnectionState() const { return (quint8) connectionState; } /** * Returns the last disconnection reason */ Q_INVOKABLE quint8 getDisconnReason() const; /** * Set own JID used for connection * * To really change the JID of the current connection, you'll need to * reconnect. */ void setJid(const QString &jid); /** * Get the current JID */ QString getJid() const { return creds.jid; } /** * Set a optional custom JID resource (device name) */ void setJidResource(const QString &jidResource); /** * Get the JID resoruce */ QString getJidResource() const { return creds.jidResource; } /** * Set the password for next connection */ void setPassword(const QString &password); /** * Get the currently used password */ QString getPassword() const { return creds.password; } /** * Set the currently opened chat * * This will set a filter on the database to only view the related messages. */ void setChatPartner(const QString &jid); /** * Get the currrently opened chat */ QString getChatPartner() const { return chatPartner; } RosterModel* getRosterModel() const { return caches->rosterModel; } MessageModel* getMessageModel() const { return caches->msgModel; } AvatarFileStorage* getAvatarStorage() const { return caches->avatarStorage; } PresenceCache* getPresenceCache() const { return caches->presCache; } TransferCache* getTransferCache() const { return caches->transferCache; } QSettings* getSettings() const { return caches->settings; } - Utils* getUtils() const + QmlUtils* getUtils() const { - return utils; + return m_utils; } /** * Adds XMPP URI to open as soon as possible */ void addOpenUri(const QByteArray &uri); /** * Returns whether an HTTP File Upload service has been found */ bool getUploadServiceFound() const { return uploadServiceFound; } static Kaidan *instance(); signals: void avatarStorageChanged(); /** * Emitted, when the client's connection state has changed (e.g. when * successfully connected or when disconnected) */ void connectionStateChanged(); /** * Emitted, when the client failed to connect and gives the reason in * a DisconnectionReason enumatrion. */ void disconnReasonChanged(); /** * Emitted when the JID was changed */ void jidChanged(); /** * Emitted when the JID resouce (device name) has changed */ void jidResourceChanged(); /** * Emitted when the used password for logging in has changed */ void passwordChanged(); /** * Emitted when the currently opnened chat has changed */ void chatPartnerChanged(QString chatPartner); /** * Emitted when there are no (correct) credentials and new are needed * * The client will be in disconnected state, when this is emitted. */ void newCredentialsNeeded(); /** * Emitted when log in worked with new credentials * * The client will be in connected state, when this is emitted. */ void logInWorked(); /** * Show passive notification */ void passiveNotificationRequested(QString text); /** * Emitted, whan a subscription request was received */ void subscriptionRequestReceived(QString from, QString msg); /** * Incoming subscription request was accepted or declined by the user */ void subscriptionRequestAnswered(QString jid, bool accepted); /** * Request vCard of any JID * * Is required when the avatar (or other information) of a JID are * requested and the JID is not in the roster. */ void vCardRequested(QString jid); /** * XMPP URI received * * Is called when Kaidan was used to open an XMPP URI (i.e. 'xmpp:kaidan@muc.kaidan.im?join') */ void xmppUriReceived(QString uri); /** * The upload progress of a file upload has changed */ void uploadProgressMade(QString msgId, unsigned long sent, unsigned long total); /** * An HTTP File Upload service was discovered */ void uploadServiceFoundChanged(); /** * Send a text message to any JID * * Currently only contacts are displayed on the RosterPage (there is no * way to view a list of all chats -> for contacts and non-contacts), so * you should only send messages to JIDs from your roster, otherwise you * won't be able to see the message history. */ void sendMessage(QString jid, QString message, bool isSpoiler, QString spoilerHint); /** * Correct the last message * * To get/check the last message id, use `kaidan.messageModel.lastMessageId(jid)` */ void correctMessage(QString toJid, QString msgId, QString message); /** * Upload and send file */ void sendFile(QString jid, QString filePath, QString message); /** * Add a contact to your roster * * @param nick A simple nick name for the new contact, which should be * used to display in the roster. */ void addContact(QString jid, QString nick, QString msg); /** * Remove a contact from your roster * * Only the JID is needed. */ void removeContact(QString jid); /** * Downloads an attached media file of a message * * @param msgId The message * @param url the media url from the message */ void downloadMedia(QString msgId, QString url); /** * Changes the user's password on the server * * @param newPassword The new password */ void changePassword(const QString &newPassword); /** * Emitted, when changing the password has succeeded. */ void passwordChangeSucceeded(); /** * Emitted, when changing the password has failed. */ void passwordChangeFailed(); public slots: /** * Set current connection state */ void setConnectionState(QXmppClient::State state); /** * Sets the disconnection error/reason */ void setDisconnReason(DisconnectionReason reason); /** * Receives messages from another instance of the application */ void receiveMessage(quint32, QByteArray msg) { // currently we only send XMPP URIs addOpenUri(msg); } /** * Enables HTTP File Upload to be used (will be called from UploadManager) */ void setUploadServiceFound(bool enabled) { uploadServiceFound = enabled; emit uploadServiceFoundChanged(); } private: void connectDatabases(); - Utils *utils; + QmlUtils *m_utils; Database *database; ClientWorker::Caches *caches; ClientThread *cltThrd; ClientWorker *client; ClientWorker::Credentials creds; QString chatPartner; QString openUriCache; bool uploadServiceFound = false; ConnectionState connectionState = ConnectionState::StateDisconnected; DisconnReason disconnReason = DisconnReason::ConnNoError; static Kaidan *s_instance; }; #endif diff --git a/src/Utils.cpp b/src/QmlUtils.cpp similarity index 88% rename from src/Utils.cpp rename to src/QmlUtils.cpp index 2aff763..fb9fe79 100644 --- a/src/Utils.cpp +++ b/src/QmlUtils.cpp @@ -1,140 +1,140 @@ /* * Kaidan - A user-friendly XMPP client for every device! * * Copyright (C) 2016-2019 Kaidan developers and contributors * (see the LICENSE file for a full list of copyright authors) * * Kaidan is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * In addition, as a special exception, the author of Kaidan gives * permission to link the code of its release with the OpenSSL * project's "OpenSSL" library (or with modified versions of it that * use the same license as the "OpenSSL" library), and distribute the * linked executables. You must obey the GNU General Public License in * all respects for all of the code used other than "OpenSSL". If you * modify this file, you may extend this exception to your version of * the file, but you are not obligated to do so. If you do not wish to * do so, delete this exception statement from your version. * * Kaidan is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Kaidan. If not, see . */ -#include "Utils.h" +#include "QmlUtils.h" #include #include #include #include #include #include #include #include #include #include #include "qxmpp-exts/QXmppColorGenerator.h" -Utils::Utils(QObject *parent) +QmlUtils::QmlUtils(QObject *parent) : QObject(parent) { } -QString Utils::getResourcePath(const QString &name) const +QString QmlUtils::getResourcePath(const QString &name) const { // We generally prefer to first search for files in application resources if (QFile::exists(":/" + name)) return QString("qrc:/" + name); // list of file paths where to search for the resource file QStringList pathList; // add relative path from binary (only works if installed) pathList << QCoreApplication::applicationDirPath() + QString("/../share/") + QString(APPLICATION_NAME); // get the standard app data locations for current platform pathList << QStandardPaths::standardLocations(QStandardPaths::AppDataLocation); #ifdef UBUNTU_TOUCH pathList << QString("./share/") + QString(APPLICATION_NAME); #endif #ifndef NDEBUG #ifdef DEBUG_SOURCE_PATH // add source directory (only for debug builds) pathList << QString(DEBUG_SOURCE_PATH) + QString("/data"); #endif #endif // search for file in directories for (int i = 0; i < pathList.size(); i++) { // open directory QDir directory(pathList.at(i)); // look up the file if (directory.exists(name)) { // found the file, return the path return QUrl::fromLocalFile(directory.absoluteFilePath(name)).toString(); } } // no file found qWarning() << "[main] Could NOT find media file:" << name; return ""; } -bool Utils::isImageFile(const QUrl &fileUrl) const +bool QmlUtils::isImageFile(const QUrl &fileUrl) const { QMimeType type = QMimeDatabase().mimeTypeForUrl(fileUrl); return type.inherits("image/jpeg") || type.inherits("image/png"); } -void Utils::copyToClipboard(const QString &text) const +void QmlUtils::copyToClipboard(const QString &text) const { QGuiApplication::clipboard()->setText(text); } -QString Utils::fileNameFromUrl(const QUrl &url) const +QString QmlUtils::fileNameFromUrl(const QUrl &url) const { return QUrl(url).fileName(); } -QString Utils::fileSizeFromUrl(const QUrl &url) const +QString QmlUtils::fileSizeFromUrl(const QUrl &url) const { #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) // Qt 5.10 or later return QLocale::system().formattedDataSize(QFileInfo(QUrl(url).toLocalFile()) .size()); #else // before Qt 5.10 there was no formattedDataSize() method: // sizes will always be in MiB double size = QFileInfo(QUrl(url).toLocalFile()).size(); return QString::number(qRound(size / 1024.0 / 10.24) / 100.0).append(" MiB"); #endif } -QString Utils::formatMessage(const QString &message) const +QString QmlUtils::formatMessage(const QString &message) const { // escape all special XML chars (like '<' and '>') // and spilt into words for processing return processMsgFormatting(message.toHtmlEscaped().split(" ")); } -QColor Utils::getUserColor(const QString &nickName) const +QColor QmlUtils::getUserColor(const QString &nickName) const { QXmppColorGenerator::RGBColor color = QXmppColorGenerator::generateColor(nickName); return QColor(color.red, color.green, color.blue); } -QString Utils::processMsgFormatting(const QStringList &list, bool isFirst) const +QString QmlUtils::processMsgFormatting(const QStringList &list, bool isFirst) const { if (list.isEmpty()) return ""; // link highlighting if (list.first().startsWith("https://") || list.first().startsWith("http://")) return (isFirst ? "" : " ") + QString("%1").arg(list.first()) + processMsgFormatting(list.mid(1), false); return (isFirst ? "" : " ") + list.first() + processMsgFormatting(list.mid(1), false); } diff --git a/src/Utils.h b/src/QmlUtils.h similarity index 97% rename from src/Utils.h rename to src/QmlUtils.h index 132633b..cbc78a0 100644 --- a/src/Utils.h +++ b/src/QmlUtils.h @@ -1,118 +1,118 @@ /* * Kaidan - A user-friendly XMPP client for every device! * * Copyright (C) 2016-2019 Kaidan developers and contributors * (see the LICENSE file for a full list of copyright authors) * * Kaidan is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * In addition, as a special exception, the author of Kaidan gives * permission to link the code of its release with the OpenSSL * project's "OpenSSL" library (or with modified versions of it that * use the same license as the "OpenSSL" library), and distribute the * linked executables. You must obey the GNU General Public License in * all respects for all of the code used other than "OpenSSL". If you * modify this file, you may extend this exception to your version of * the file, but you are not obligated to do so. If you do not wish to * do so, delete this exception statement from your version. * * Kaidan is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Kaidan. If not, see . */ #ifndef UTILS_H #define UTILS_H #include #include "Globals.h" /** * @brief C++ utitlities to be used in QML * * The methods are not static, because they need to be used from QML and registered in * Qt. */ -class Utils : public QObject +class QmlUtils : public QObject { Q_OBJECT public: - Utils(QObject *parent = nullptr); + QmlUtils(QObject *parent = nullptr); public slots: /** * Returns a URL to a given resource file name * * This will check various paths which could contain the searched file. * If the file was found, it'll return a `file://` or a `qrc:/` url to * the file. */ QString getResourcePath(const QString &resourceName) const; /** * Returns a string of this build's Kaidan version */ QString getVersionString() const { return VERSION_STRING; } /** * Returns a string without new lines, unneeded spaces, etc. * * See QString::simplified for more information. */ QString removeNewLinesFromString(const QString &input) const { return input.simplified(); } /** * Checks whether a file is an image and could be displayed as such. * @param fileUrl URL to the possible image file */ bool isImageFile(const QUrl &fileUrl) const; /** * Copy text to the clipboard */ void copyToClipboard(const QString &text) const; /** * Returns the file name from a URL */ QString fileNameFromUrl(const QUrl &url) const; /** * Returns the file size from a URL */ QString fileSizeFromUrl(const QUrl &url) const; /** * Styles/formats a message for displaying * * This currently only adds some link highlighting */ QString formatMessage(const QString &message) const; /** * Returns a consistent user color generated from the nickname. */ QColor getUserColor(const QString &nickName) const; private: /** * Highlights links in a list of words */ QString processMsgFormatting(const QStringList &words, bool isFirst = true) const; }; #endif // UTILS_H diff --git a/src/main.cpp b/src/main.cpp index 8222652..709128f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,283 +1,283 @@ /* * Kaidan - A user-friendly XMPP client for every device! * * Copyright (C) 2016-2019 Kaidan developers and contributors * (see the LICENSE file for a full list of copyright authors) * * Kaidan is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * In addition, as a special exception, the author of Kaidan gives * permission to link the code of its release with the OpenSSL * project's "OpenSSL" library (or with modified versions of it that * use the same license as the "OpenSSL" library), and distribute the * linked executables. You must obey the GNU General Public License in * all respects for all of the code used other than "OpenSSL". If you * modify this file, you may extend this exception to your version of * the file, but you are not obligated to do so. If you do not wish to * do so, delete this exception statement from your version. * * Kaidan is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Kaidan. If not, see . */ // Qt #include #include #include #include #include #include #include #include #include #include // QXmpp #include #include "qxmpp-exts/QXmppUploadManager.h" // Kaidan #include "Kaidan.h" #include "RosterModel.h" #include "MessageModel.h" #include "AvatarFileStorage.h" #include "PresenceCache.h" #include "UploadManager.h" #include "Globals.h" #include "Enums.h" #include "StatusBar.h" #include "EmojiModel.h" -#include "Utils.h" +#include "QmlUtils.h" #ifdef STATIC_BUILD #include "static_plugins.h" #endif #ifndef QAPPLICATION_CLASS #define QAPPLICATION_CLASS QApplication #endif #include QT_STRINGIFY(QAPPLICATION_CLASS) #if !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID) // SingleApplication (Qt5 replacement for QtSingleApplication) #include "singleapp/singleapplication.h" #endif #ifdef STATIC_BUILD #define KIRIGAMI_BUILD_TYPE_STATIC #include "./3rdparty/kirigami/src/kirigamiplugin.h" #endif #ifdef Q_OS_ANDROID #include #endif #ifdef Q_OS_WIN #include #endif enum CommandLineParseResult { CommandLineOk, CommandLineError, CommandLineVersionRequested, CommandLineHelpRequested }; CommandLineParseResult parseCommandLine(QCommandLineParser &parser, QString *errorMessage) { // application description parser.setApplicationDescription(QString(APPLICATION_DISPLAY_NAME) + " - " + QString(APPLICATION_DESCRIPTION)); // add all possible arguments QCommandLineOption helpOption = parser.addHelpOption(); QCommandLineOption versionOption = parser.addVersionOption(); parser.addOption({"disable-xml-log", "Disable output of full XMPP XML stream."}); parser.addOption({{"m", "multiple"}, "Allow multiple instances to be started."}); parser.addPositionalArgument("xmpp-uri", "An XMPP-URI to open (i.e. join a chat).", "[xmpp-uri]"); // parse arguments if (!parser.parse(QGuiApplication::arguments())) { *errorMessage = parser.errorText(); return CommandLineError; } // check for special cases if (parser.isSet(versionOption)) return CommandLineVersionRequested; if (parser.isSet(helpOption)) return CommandLineHelpRequested; // if nothing special happened, return OK return CommandLineOk; } Q_DECL_EXPORT int main(int argc, char *argv[]) { #ifdef Q_OS_WIN if (AttachConsole(ATTACH_PARENT_PROCESS)) { freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stderr); } #endif // initialize random generator qsrand(time(nullptr)); // // App // #ifdef UBUNTU_TOUCH qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "true"); qputenv("QT_QUICK_CONTROLS_MOBILE", "true"); #endif // name, display name, description QGuiApplication::setApplicationName(APPLICATION_NAME); QGuiApplication::setApplicationDisplayName(APPLICATION_DISPLAY_NAME); QGuiApplication::setApplicationVersion(VERSION_STRING); // attributes QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // create a qt app #if defined(Q_OS_IOS) || defined(Q_OS_ANDROID) QGuiApplication app(argc, argv); #else SingleApplication app(argc, argv, true); #endif // register qMetaTypes qRegisterMetaType("RosterModel*"); qRegisterMetaType("MessageModel*"); qRegisterMetaType("Message"); qRegisterMetaType("AvatarFileStorage*"); qRegisterMetaType("ContactMap"); qRegisterMetaType("PresenceCache*"); qRegisterMetaType("QXmppPresence"); qRegisterMetaType("Credentials"); qRegisterMetaType("Qt::ApplicationState"); qRegisterMetaType("QXmppClient::State"); qRegisterMetaType("MessageType"); qRegisterMetaType("DisconnectionReason"); qRegisterMetaType("TransferJob*"); - qRegisterMetaType("Utils*"); + qRegisterMetaType("QmlUtils*"); // Qt-Translator QTranslator qtTranslator; qtTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); app.installTranslator(&qtTranslator); // Kaidan-Translator QTranslator kaidanTranslator; // load the systems locale or none from resources kaidanTranslator.load(QLocale::system().name(), ":/i18n"); app.installTranslator(&kaidanTranslator); // // Command line arguments // // create parser and add a description QCommandLineParser parser; // parse the arguments QString commandLineErrorMessage; switch (parseCommandLine(parser, &commandLineErrorMessage)) { case CommandLineError: qWarning() << commandLineErrorMessage; return 1; case CommandLineVersionRequested: parser.showVersion(); return 0; case CommandLineHelpRequested: parser.showHelp(); return 0; case CommandLineOk: break; } #if !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID) // check if another instance already runs if (app.isSecondary() && !parser.isSet("multiple")) { qDebug().noquote() << QString("Another instance of %1 is already running.") .arg(APPLICATION_DISPLAY_NAME) << "You can enable multiple instances by specifying '--multiple'."; // send a possible link to the primary instance if (!parser.positionalArguments().isEmpty()) app.sendMessage(parser.positionalArguments()[0].toUtf8()); return 0; } #endif // // Kaidan back-end // Kaidan kaidan(&app, !parser.isSet("disable-xml-log")); #if !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID) // receive messages from other instances of Kaidan kaidan.connect(&app, &SingleApplication::receivedMessage, &kaidan, &Kaidan::receiveMessage); #endif // open the XMPP-URI/link (if given) if (!parser.positionalArguments().isEmpty()) kaidan.addOpenUri(parser.positionalArguments()[0].toUtf8()); // // QML-GUI // if (QIcon::themeName().isEmpty()) { QIcon::setThemeName("breeze"); } QQmlApplicationEngine engine; // QtQuickControls2 Style if (qgetenv("QT_QUICK_CONTROLS_STYLE").isEmpty()) { #ifdef Q_OS_WIN QString defaultStyle = "Universal"; #else QString defaultStyle = "Material"; #endif qDebug() << "QT_QUICK_CONTROLS_STYLE not set, setting to" << defaultStyle; qputenv("QT_QUICK_CONTROLS_STYLE", defaultStyle.toLatin1()); } // QML type bindings #ifdef STATIC_BUILD KirigamiPlugin::getInstance().registerTypes(); #endif qmlRegisterType("StatusBar", 0, 1, "StatusBar"); qmlRegisterType("EmojiModel", 0, 1, "EmojiModel"); qmlRegisterType("EmojiModel", 0, 1, "EmojiProxyModel"); qmlRegisterUncreatableType("EmojiModel", 0, 1, "QAbstractItemModel", "Used by proxy models"); qmlRegisterUncreatableType("EmojiModel", 0, 1, "Emoji", "Used by emoji models"); qmlRegisterUncreatableMetaObject(Enums::staticMetaObject, APPLICATION_ID, 1, 0, "Enums", "Can't create object; only enums defined!"); engine.rootContext()->setContextProperty("kaidan", &kaidan); engine.load(QUrl("qrc:/qml/main.qml")); if(engine.rootObjects().isEmpty()) return -1; #ifdef Q_OS_ANDROID QtAndroid::hideSplashScreen(); #endif // enter qt main loop return app.exec(); }