From: Manuel Nickschas Date: Wed, 11 Mar 2015 19:10:41 +0000 (+0100) Subject: Merge pull request #110 from mamarley/passhash X-Git-Tag: 0.12-rc1~6 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=d82f98b8cf9c7c83f3aab1d7f010ccf8bdd2c003;hp=07b0587b932ccbfb0d93f59109b23b97ba85f4cf Merge pull request #110 from mamarley/passhash Introduce new password hash versioning system and new salted SHA2-512 hash --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fe8bf55..baf926d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,14 +6,13 @@ # General setup ##################################################################### -cmake_minimum_required(VERSION 2.8.9) # You'll need at least 2.8.12 for KDE Frameworks integration project(QuasselIRC) # Versions set(QUASSEL_MAJOR 0) set(QUASSEL_MINOR 12) set(QUASSEL_PATCH 0) -set(QUASSEL_VERSION_STRING "0.12-pre") +set(QUASSEL_VERSION_STRING "0.12-beta1") # Tell CMake about or own modules set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) @@ -34,11 +33,6 @@ include(FeatureSummary) include(QuasselCompileSettings) include(QuasselMacros) -# Setting COMPILE_DEFINITIONS_ is deprecated since CMake 3.0 in favor of generator expressions. -# These have existed since CMake 2.8.10; until we depend on that, we have to explicitly enable the old policy. -if (CMAKE_MAJOR_VERSION GREATER 2) - cmake_policy(SET CMP0043 OLD) -endif() # Options and variables that can be set on the command line ##################################################################### @@ -119,6 +113,22 @@ if (LINK_EXTRA) endif() +# Setup CMake +##################################################################### + +if (USE_QT5 AND WITH_KDE) + cmake_minimum_required(VERSION 2.8.12) +else() + cmake_minimum_required(VERSION 2.8.9) +endif() + +# Setting COMPILE_DEFINITIONS_ is deprecated since CMake 3.0 in favor of generator expressions. +# These have existed since CMake 2.8.10; until we depend on that, we have to explicitly enable the old policy. +if (CMAKE_MAJOR_VERSION GREATER 2) + cmake_policy(SET CMP0043 OLD) +endif() + + # Simplify later checks ##################################################################### @@ -252,23 +262,17 @@ if (USE_QT5) endif() if (WITH_KDE) - find_package(KF5CoreAddons QUIET) - set_package_properties(KF5CoreAddons PROPERTIES TYPE REQUIRED - URL "http://inqlude.org/libraries/kcoreaddons.html" - DESCRIPTION "framework for solving common problems such as caching, randomization, and more" - PURPOSE "Required for KDE Frameworks integration" - ) - - find_package(KF5TextWidgets QUIET) - set_package_properties(KF5TextWidgets PROPERTIES TYPE REQUIRED - URL "http://inqlude.org/libraries/ktextwidgets.html" - DESCRIPTION "framework providing an assortment of widgets for displaying and editing text" - PURPOSE "Allows to use extra features provided by KDE Frameworks in input widgets" + find_package(KF5 COMPONENTS ConfigWidgets CoreAddons Notifications NotifyConfig TextWidgets WidgetsAddons XmlGui QUIET) + set_package_properties(KF5 PROPERTIES TYPE REQUIRED + URL "http://www.kde.org" + DESCRIPTION "KDE Frameworks" + PURPOSE "Required for integration into the Plasma desktop" ) endif() endif(BUILD_GUI) + if (BUILD_CORE) find_package(Qt5Script QUIET) set_package_properties(Qt5Script PROPERTIES TYPE REQUIRED @@ -293,6 +297,7 @@ if (USE_QT5) DESCRIPTION "contains tools for handling translation files" PURPOSE "Required for having translations" ) + # Some Qt5 versions do not define a target for lconvert, so we need to find it ourselves if (Qt5LinguistTools_FOUND) if (NOT TARGET Qt5::lconvert AND TARGET Qt5::lrelease) @@ -425,6 +430,11 @@ if (MINGW AND NOT KDE4_FOUND) add_definitions(-U__STRICT_ANSI__) endif() +# Sanitize compiler flags - old versions of KDE set -ansi, which breaks -std=c++11 +if (CMAKE_COMPILER_IS_GNUCXX) + string(REPLACE "-ansi" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) +endif() + # Setup KDE / KDE Frameworks ##################################################################### @@ -553,6 +563,17 @@ include(GetGitRevisionDescription) get_git_head_revision(GIT_REFSPEC GIT_HEAD) git_describe(GIT_DESCRIBE --long) +# If not in a Git repo try to read GIT_HEAD and GIT_DESCRIBE from +# enviroment +if (NOT GIT_HEAD OR NOT GIT_DESCRIBE) + if (DEFINED ENV{GIT_HEAD}) + set(GIT_HEAD ${GIT_HEAD}) + endif () + if (DEFINED ENV{GIT_DESCRIBE}) + set(GIT_DESCRIBE ${GIT_DESCRIBE}) + endif() +endif() + # Sanitize things if we're not in a Git repo if (NOT GIT_HEAD OR NOT GIT_DESCRIBE) set(GIT_HEAD "") diff --git a/ChangeLog b/ChangeLog index 562928d0..617cd84e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,18 @@ changes, the git history at is your friend. Without further ado, let's start: +Version 0.12.0 (TBA) +==================== + +* Full support for KDE Frameworks +* Remote password change +* Core connection improvements +* Build system improvements +* PostgreSQL connection improvements +* Improve Qt5 support +* Qt 4.8+ or Qt 5.2+ now required +* Several tweaks and fixes + Version 0.11.0 (2014-09-23) =========================== diff --git a/INSTALL b/INSTALL index a9dc9e2b..d4e39209 100644 --- a/INSTALL +++ b/INSTALL @@ -27,14 +27,14 @@ example a compiler. As we use a subset of the C++11 standard, we require a fairly recent compiler: - gcc 4.7+ (available for most platforms), or -- Clang 3.2+ (available for most platforms, or +- Clang 3.2+ (available for most platforms), or - XCode 4.6+ (available for Max OS X and based on Clang), or -- Visual C++ 2013 (available for Windows™), or +- Visual C++ Nov 2013 CTP (available for Windows™), or - any other compiler with decent C++11 support -Furthermore, CMake 2.8.9 or later is required. +Furthermore, CMake 2.8.9 or later is required (2.8.12 for KDE Frameworks). -As Quassel is a Qt application, you need the Qt SDK, either Qt 4.6+ or Qt 5.2+. +As Quassel is a Qt application, you need the Qt SDK, either Qt 4.8+ or Qt 5.2+. There are several optional dependencies; we will talk about that later. @@ -58,7 +58,7 @@ First of all, it is highly recommended for any CMake-based project to be built in a separate build directory rather than in-source. That way, your source checkout remains pristine, and you can easily remove any build artifacts by just deleting the build directory. This directory can be located anywhere; in the -short example above, we just created a directory called "build" inside the +short example above, we've just created a directory called "build" inside the source checkout. From inside the build directory, you can then run the "cmake" command, followed @@ -80,7 +80,7 @@ options here: things may happen. -DWITH_KDE=ON - Enable integration into KDE4; only available if -DUSE_QT5=OFF + Enable integration into KDE4 (with Qt4) or KDE Frameworks (with Qt5). -DWITH_OXYGEN=(ON|OFF) Install the parts of the Oxygen icon set Quassel uses. Oxygen is the default @@ -92,7 +92,8 @@ options here: -DWITH_WEBKIT=OFF Use Webkit for showing previews of webpages linked in the chat. Requires the QtWebkit module to be available, and increases the client's RAM usage - by *a lot* if enabled at runtime. + by *a lot* if enabled at runtime. Note also that Webkit frequently crashes + especially on Windows. -DEMBED_DATA=(ON|OFF) Specifies whether Quassel's data files (icons, translations and so on) diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 04b322b3..5c6762d5 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -8,9 +8,13 @@ if (BUILD_GUI) install(FILES quassel.desktop DESTINATION ${CMAKE_INSTALL_APPDIR}) endif() - if (KDE4_FOUND) + if (WITH_KDE4) install(FILES quassel.notifyrc DESTINATION ${CMAKE_INSTALL_DATADIR}/quassel) endif() + + if (WITH_KF5) + install(FILES quassel.notifyrc DESTINATION ${CMAKE_INSTALL_KNOTIFY5RCDIR}) + endif() endif() if (EMBED_DATA) diff --git a/icons/import/import_oxygen.pl b/icons/import/import_oxygen.pl index c6132d01..c6fb8177 100755 --- a/icons/import/import_oxygen.pl +++ b/icons/import/import_oxygen.pl @@ -72,8 +72,6 @@ foreach my $sizestr (readdir BASEDIR) { opendir (SIZEDIR, "$oxygen/$sizestr") or die "Could not open dir $sizestr\n"; foreach my $cat (readdir SIZEDIR) { next if $cat eq '.' or $cat eq '..'; - #system "mkdir -p $output/$sizestr/$cat" and die "Could not create category dir\n"; - system "mkdir -p $output/scalable/$cat" and die "Could not create category dir\n"; opendir (CATDIR, "$oxygen/$sizestr/$cat") or die "Could not open category dir\n"; foreach my $icon (readdir CATDIR) { $icon =~ s/\.png$//; @@ -105,13 +103,13 @@ foreach my $icon (keys %req_icons) { print "Warning: Missing icon $icon\n"; } +# Copy license etc. +system "cp $oxygen/AUTHORS $oxygen/CONTRIBUTING $oxygen/COPYING $oxygen/index.theme $output/"; + # Generate .qrc my @file_list; generate_qrc($output, $qrcfile_kde); -# Copy license etc. -system "cp $oxygen/AUTHORS $oxygen/CONTRIBUTING $oxygen/COPYING $oxygen/index.theme $output/"; - print "Done.\n"; ######################################################################################## @@ -135,7 +133,7 @@ sub generate_qrc { } sub push_icon_path { - return unless /\.png$/; + return unless /\.png$/ or /^index.theme$/; push @file_list, " $File::Find::name"; } diff --git a/icons/oxygen.qrc b/icons/oxygen.qrc index 3b019426..b451269f 100644 --- a/icons/oxygen.qrc +++ b/icons/oxygen.qrc @@ -1,5 +1,6 @@ + oxygen/index.theme oxygen/22x22/actions/irc-voice.png oxygen/22x22/actions/go-next.png oxygen/22x22/actions/im-user.png diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 4f0106c4..4eef7d54 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -38,11 +38,6 @@ set(SOURCES clientcoreinfo.h ) -if (KDE4_FOUND) - include_directories(${KDE4_INCLUDES}) - add_definitions(-DHAVE_KDE ${KDE4_DEFINITIONS}) -endif() - if (USE_QT5) list(APPEND qt_modules Widgets) endif() @@ -53,7 +48,3 @@ add_library(mod_client STATIC ${SOURCES}) qt_use_modules(mod_client Network Core Gui ${qt_modules}) target_link_libraries(mod_client mod_common) - -if (KDE4_FOUND) - target_link_libraries(mod_client ${KDE4_SOLID_LIBS}) -endif() diff --git a/src/client/client.cpp b/src/client/client.cpp index 7bbbefe7..54a93fb3 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -48,6 +48,7 @@ #include "quassel.h" #include "signalproxy.h" #include "util.h" +#include "clientauthhandler.h" #include #include @@ -152,6 +153,9 @@ void Client::init() p->attachSlot(SIGNAL(networkCreated(NetworkId)), this, SLOT(coreNetworkCreated(NetworkId))); p->attachSlot(SIGNAL(networkRemoved(NetworkId)), this, SLOT(coreNetworkRemoved(NetworkId))); + p->attachSignal(this, SIGNAL(requestPasswordChange(PeerPtr,QString,QString,QString)), SIGNAL(changePassword(PeerPtr,QString,QString,QString))); + p->attachSlot(SIGNAL(passwordChanged(PeerPtr,bool)), this, SLOT(corePasswordChanged(PeerPtr,bool))); + //connect(mainUi(), SIGNAL(connectToCore(const QVariantMap &)), this, SLOT(connectToCore(const QVariantMap &))); connect(mainUi(), SIGNAL(disconnectFromCore()), this, SLOT(disconnectFromCore())); connect(this, SIGNAL(connected()), mainUi(), SLOT(connectedToCore())); @@ -383,32 +387,34 @@ void Client::setSyncedToCore() connect(bufferSyncer(), SIGNAL(buffersPermanentlyMerged(BufferId, BufferId)), _messageModel, SLOT(buffersPermanentlyMerged(BufferId, BufferId))); connect(bufferSyncer(), SIGNAL(bufferMarkedAsRead(BufferId)), SIGNAL(bufferMarkedAsRead(BufferId))); connect(networkModel(), SIGNAL(requestSetLastSeenMsg(BufferId, MsgId)), bufferSyncer(), SLOT(requestSetLastSeenMsg(BufferId, const MsgId &))); - signalProxy()->synchronize(bufferSyncer()); + + SignalProxy *p = signalProxy(); + p->synchronize(bufferSyncer()); // create a new BufferViewManager Q_ASSERT(!_bufferViewManager); - _bufferViewManager = new ClientBufferViewManager(signalProxy(), this); + _bufferViewManager = new ClientBufferViewManager(p, this); connect(_bufferViewManager, SIGNAL(initDone()), _bufferViewOverlay, SLOT(restore())); // create AliasManager Q_ASSERT(!_aliasManager); _aliasManager = new ClientAliasManager(this); connect(aliasManager(), SIGNAL(initDone()), SLOT(sendBufferedUserInput())); - signalProxy()->synchronize(aliasManager()); + p->synchronize(aliasManager()); // create NetworkConfig Q_ASSERT(!_networkConfig); _networkConfig = new NetworkConfig("GlobalNetworkConfig", this); - signalProxy()->synchronize(networkConfig()); + p->synchronize(networkConfig()); // create IgnoreListManager Q_ASSERT(!_ignoreListManager); _ignoreListManager = new ClientIgnoreListManager(this); - signalProxy()->synchronize(ignoreListManager()); + p->synchronize(ignoreListManager()); Q_ASSERT(!_transferManager); _transferManager = new ClientTransferManager(this); - signalProxy()->synchronize(transferManager()); + p->synchronize(transferManager()); // trigger backlog request once all active bufferviews are initialized connect(bufferViewOverlay(), SIGNAL(initDone()), this, SLOT(requestInitialBacklog())); @@ -646,6 +652,22 @@ void Client::markBufferAsRead(BufferId id) } +void Client::changePassword(const QString &oldPassword, const QString &newPassword) { + CoreAccount account = currentCoreAccount(); + account.setPassword(newPassword); + coreAccountModel()->createOrUpdateAccount(account); + emit instance()->requestPasswordChange(nullptr, account.user(), oldPassword, newPassword); +} + + +void Client::corePasswordChanged(PeerPtr, bool success) +{ + if (success) + coreAccountModel()->save(); + emit passwordChanged(success); +} + + #if QT_VERSION < 0x050000 void Client::logMessage(QtMsgType type, const char *msg) { diff --git a/src/client/client.h b/src/client/client.h index 8c707f34..6d224cf9 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -142,6 +142,8 @@ public: static void mergeBuffersPermanently(BufferId bufferId1, BufferId bufferId2); static void purgeKnownBufferIds(); + static void changePassword(const QString &oldPassword, const QString &newPassword); + #if QT_VERSION < 0x050000 static void logMessage(QtMsgType type, const char *msg); #else @@ -191,6 +193,10 @@ signals: */ void bufferMarkedAsRead(BufferId id); + //! Requests a password change (user name must match the currently logged in user) + void requestPasswordChange(PeerPtr peer, const QString &userName, const QString &oldPassword, const QString &newPassword); + void passwordChanged(bool success); + public slots: void disconnectFromCore(); @@ -214,6 +220,8 @@ private slots: void coreNetworkCreated(NetworkId); void coreNetworkRemoved(NetworkId); + void corePasswordChanged(PeerPtr, bool success); + void requestInitialBacklog(); void sendBufferedUserInput(); diff --git a/src/client/clientsettings.cpp b/src/client/clientsettings.cpp index 1023efb0..dc8e5c18 100644 --- a/src/client/clientsettings.cpp +++ b/src/client/clientsettings.cpp @@ -249,12 +249,10 @@ void CoreConnectionSettings::setNetworkDetectionMode(NetworkDetectionMode mode) CoreConnectionSettings::NetworkDetectionMode CoreConnectionSettings::networkDetectionMode() { -#ifdef HAVE_KDE4 - NetworkDetectionMode def = UseSolid; -#else - NetworkDetectionMode def = UseQNetworkConfigurationManager; -#endif - return (NetworkDetectionMode)localValue("NetworkDetectionMode", def).toInt(); + auto mode = localValue("NetworkDetectionMode", UseQNetworkConfigurationManager).toInt(); + if (mode == 0) + mode = UseQNetworkConfigurationManager; // UseSolid is gone, map that to the new default + return static_cast(mode); } diff --git a/src/client/clientsettings.h b/src/client/clientsettings.h index ed02efd1..dd413e0d 100644 --- a/src/client/clientsettings.h +++ b/src/client/clientsettings.h @@ -124,8 +124,7 @@ class CoreConnectionSettings : public ClientSettings { public: enum NetworkDetectionMode { - UseSolid, - UseQNetworkConfigurationManager, + UseQNetworkConfigurationManager = 1, // UseSolid is gone UsePingTimeout, NoActiveDetection }; diff --git a/src/client/coreconnection.cpp b/src/client/coreconnection.cpp index 735fab46..0e4b4f94 100644 --- a/src/client/coreconnection.cpp +++ b/src/client/coreconnection.cpp @@ -43,8 +43,7 @@ CoreConnection::CoreConnection(QObject *parent) _progressMinimum(0), _progressMaximum(-1), _progressValue(-1), - _resetting(false), - _qNetworkConfigurationManager(0) + _resetting(false) { qRegisterMetaType("CoreConnection::ConnectionState"); } @@ -58,10 +57,6 @@ void CoreConnection::init() _reconnectTimer.setSingleShot(true); connect(&_reconnectTimer, SIGNAL(timeout()), SLOT(reconnectTimeout())); -#ifdef HAVE_KDE4 - connect(Solid::Networking::notifier(), SIGNAL(statusChanged(Solid::Networking::Status)), - SLOT(solidNetworkStatusChanged(Solid::Networking::Status))); -#endif _qNetworkConfigurationManager = new QNetworkConfigurationManager(this); connect(_qNetworkConfigurationManager, SIGNAL(onlineStateChanged(bool)), SLOT(onlineStateChanged(bool))); @@ -130,22 +125,12 @@ void CoreConnection::reconnectTimeout() if (!_peer) { CoreConnectionSettings s; if (_wantReconnect && s.autoReconnect()) { -#ifdef HAVE_KDE4 - // If using Solid, we don't want to reconnect if we're offline - if (s.networkDetectionMode() == CoreConnectionSettings::UseSolid) { - if (Solid::Networking::status() != Solid::Networking::Connected - && Solid::Networking::status() != Solid::Networking::Unknown) { - return; - } - } -#endif /* HAVE_KDE4 */ - // If using QNetworkConfigurationManager, ditto + // If using QNetworkConfigurationManager, we don't want to reconnect if we're offline if (s.networkDetectionMode() == CoreConnectionSettings::UseQNetworkConfigurationManager) { if (!_qNetworkConfigurationManager->isOnline()) { return; } } - reconnectToCore(); } } @@ -178,36 +163,6 @@ void CoreConnection::reconnectIntervalChanged(const QVariant &interval) } -#ifdef HAVE_KDE4 - -void CoreConnection::solidNetworkStatusChanged(Solid::Networking::Status status) -{ - CoreConnectionSettings s; - if (s.networkDetectionMode() != CoreConnectionSettings::UseSolid) - return; - - switch (status) { - case Solid::Networking::Unknown: - case Solid::Networking::Connected: - //qDebug() << "Solid: Network status changed to connected or unknown"; - if (state() == Disconnected) { - if (_wantReconnect && s.autoReconnect()) { - reconnectToCore(); - } - } - break; - case Solid::Networking::Disconnecting: - case Solid::Networking::Unconnected: - if (state() != Disconnected && !isLocalConnection()) - disconnectFromCore(tr("Network is down"), true); - break; - default: - break; - } -} - -#endif - void CoreConnection::onlineStateChanged(bool isOnline) { CoreConnectionSettings s; @@ -228,6 +183,7 @@ void CoreConnection::onlineStateChanged(bool isOnline) } } + bool CoreConnection::isEncrypted() const { return _peer && _peer->isSecure(); diff --git a/src/client/coreconnection.h b/src/client/coreconnection.h index 3c21b797..0019a534 100644 --- a/src/client/coreconnection.h +++ b/src/client/coreconnection.h @@ -18,11 +18,11 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#ifndef CORECONNECTION_H_ -#define CORECONNECTION_H_ +#pragma once -#include "QPointer" -#include "QTimer" +#include +#include +#include #ifdef HAVE_SSL # include @@ -30,12 +30,6 @@ # include #endif -#ifdef HAVE_KDE4 -# include -#endif - -#include - #include "coreaccount.h" #include "remotepeer.h" #include "types.h" @@ -150,9 +144,6 @@ private slots: void reconnectIntervalChanged(const QVariant &interval); void reconnectTimeout(); -#ifdef HAVE_KDE4 - void solidNetworkStatusChanged(Solid::Networking::Status status); -#endif void onlineStateChanged(bool isOnline); private: @@ -191,5 +182,3 @@ inline QString CoreConnection::progressText() const { return _progressText; } inline CoreConnection::ConnectionState CoreConnection::state() const { return _state; } inline bool CoreConnection::isConnected() const { return state() >= Connected; } inline CoreAccount CoreConnection::currentAccount() const { return _account; } - -#endif diff --git a/src/common/main.cpp b/src/common/main.cpp index 9d75da4e..6847371d 100644 --- a/src/common/main.cpp +++ b/src/common/main.cpp @@ -49,6 +49,7 @@ # include "kcmdlinewrapper.h" #elif defined HAVE_KF5 # include +# include # include "qt5cliparser.h" #elif defined HAVE_QT5 # include "qt5cliparser.h" @@ -102,6 +103,13 @@ int main(int argc, char **argv) # endif #endif + // Migrate settings from KDE4 to KF5 if appropriate +#ifdef HAVE_KF5 + Kdelibs4ConfigMigrator migrator(QCoreApplication::applicationName()); + migrator.setConfigFiles(QStringList() << "quasselrc" << "quassel.notifyrc"); + migrator.migrate(); +#endif + AbstractCliParser *cliParser; #ifdef HAVE_KDE4 @@ -190,9 +198,6 @@ int main(int argc, char **argv) } #endif - if (!app.init()) - return EXIT_FAILURE; - #ifdef HAVE_KF5 // FIXME: This should be done after loading the translation catalogue, but still in main() AboutData aboutData; @@ -200,5 +205,8 @@ int main(int argc, char **argv) KAboutData::setApplicationData(aboutData.kAboutData()); #endif + if (!app.init()) + return EXIT_FAILURE; + return app.exec(); } diff --git a/src/common/peer.cpp b/src/common/peer.cpp index 14041597..3785326c 100644 --- a/src/common/peer.cpp +++ b/src/common/peer.cpp @@ -32,3 +32,22 @@ AuthHandler *Peer::authHandler() const { return _authHandler; } + + +// Note that we need to use a fixed-size integer instead of uintptr_t, in order +// to avoid issues with different architectures for client and core. +// In practice, we'll never really have to restore the real value of a PeerPtr from +// a QVariant. +QDataStream &operator<<(QDataStream &out, PeerPtr ptr) +{ + out << reinterpret_cast(ptr); + return out; +} + +QDataStream &operator>>(QDataStream &in, PeerPtr &ptr) +{ + quint64 value; + in >> value; + ptr = reinterpret_cast(value); + return in; +} diff --git a/src/common/peer.h b/src/common/peer.h index a21e9c1b..b9dfed16 100644 --- a/src/common/peer.h +++ b/src/common/peer.h @@ -86,6 +86,9 @@ private: typedef Peer * PeerPtr; Q_DECLARE_METATYPE(PeerPtr) +QDataStream &operator<<(QDataStream &out, PeerPtr ptr); +QDataStream &operator>>(QDataStream &in, PeerPtr &ptr); + // Template method needed in the header template inline diff --git a/src/common/quassel.cpp b/src/common/quassel.cpp index c9da049c..c166ee64 100644 --- a/src/common/quassel.cpp +++ b/src/common/quassel.cpp @@ -42,6 +42,7 @@ #include "logger.h" #include "message.h" #include "network.h" +#include "peer.h" #include "protocol.h" #include "syncableobject.h" #include "types.h" @@ -203,6 +204,8 @@ void Quassel::registerMetaTypes() qRegisterMetaTypeStreamOperators("MsgId"); qRegisterMetaType("Protocol::SessionState"); + qRegisterMetaType("PeerPtr"); + qRegisterMetaTypeStreamOperators("PeerPtr"); // Versions of Qt prior to 4.7 didn't define QVariant as a meta type if (!QMetaType::type("QVariant")) { @@ -427,43 +430,50 @@ QStringList Quassel::dataDirPaths() QStringList Quassel::findDataDirPaths() const { - QStringList dataDirNames = QString(qgetenv("XDG_DATA_DIRS")).split(':', QString::SkipEmptyParts); + // We don't use QStandardPaths for now, as we still need to provide fallbacks for Qt4 and + // want to stay consistent. - if (!dataDirNames.isEmpty()) { - for (int i = 0; i < dataDirNames.count(); i++) - dataDirNames[i].append("/apps/quassel/"); - } - else { - // Provide a fallback + QStringList dataDirNames; #ifdef Q_OS_WIN - dataDirNames << qgetenv("APPDATA") + QCoreApplication::organizationDomain() + "/share/apps/quassel/" - << qgetenv("APPDATA") + QCoreApplication::organizationDomain() - << QCoreApplication::applicationDirPath(); - } + dataDirNames << qgetenv("APPDATA") + QCoreApplication::organizationDomain() + "/share/apps/quassel/" + << qgetenv("APPDATA") + QCoreApplication::organizationDomain() + << QCoreApplication::applicationDirPath(); #elif defined Q_OS_MAC - dataDirNames << QDir::homePath() + "/Library/Application Support/Quassel/" - << QCoreApplication::applicationDirPath(); - } + dataDirNames << QDir::homePath() + "/Library/Application Support/Quassel/" + << QCoreApplication::applicationDirPath(); #else - dataDirNames.append("/usr/share/apps/quassel/"); - } - // on UNIX, we always check our install prefix - QString appDir = QCoreApplication::applicationDirPath(); - int binpos = appDir.lastIndexOf("/bin"); - if (binpos >= 0) { - appDir.replace(binpos, 4, "/share"); - appDir.append("/apps/quassel/"); - if (!dataDirNames.contains(appDir)) - dataDirNames.append(appDir); - } + // Linux et al + + // XDG_DATA_HOME is the location for users to override system-installed files, usually in .local/share + // This should thus come first. + QString xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME")); + if (xdgDataHome.isEmpty()) + xdgDataHome = QDir::homePath() + QLatin1String("/.local/share"); + dataDirNames << xdgDataHome; + + // Now whatever is configured through XDG_DATA_DIRS + QString xdgDataDirs = QFile::decodeName(qgetenv("XDG_DATA_DIRS")); + if (xdgDataDirs.isEmpty()) + dataDirNames << "/usr/local/share" << "/usr/share"; + else + dataDirNames << xdgDataDirs.split(':', QString::SkipEmptyParts); + + // Just in case, also check our install prefix + dataDirNames << QCoreApplication::applicationDirPath() + "/../share"; + + // Normalize and append our application name + for (int i = 0; i < dataDirNames.count(); i++) + dataDirNames[i] = QDir::cleanPath(dataDirNames.at(i)) + "/quassel/"; + #endif - // add resource path and workdir just in case - dataDirNames << QCoreApplication::applicationDirPath() + "/data/" - << ":/data/"; + // Add resource path and workdir just in case. + // Workdir should have precedence + dataDirNames.prepend(QCoreApplication::applicationDirPath() + "/data/"); + dataDirNames.append(":/data/"); - // append trailing '/' and check for existence - QStringList::Iterator iter = dataDirNames.begin(); + // Append trailing '/' and check for existence + auto iter = dataDirNames.begin(); while (iter != dataDirNames.end()) { if (!iter->endsWith(QDir::separator()) && !iter->endsWith('/')) iter->append(QDir::separator()); @@ -473,6 +483,8 @@ QStringList Quassel::findDataDirPaths() const ++iter; } + dataDirNames.removeDuplicates(); + return dataDirNames; } diff --git a/src/common/quassel.h b/src/common/quassel.h index bcfad072..30d3d35f 100644 --- a/src/common/quassel.h +++ b/src/common/quassel.h @@ -71,8 +71,9 @@ public: SaslAuthentication = 0x0002, SaslExternal = 0x0004, HideInactiveNetworks = 0x0008, + PasswordChange = 0x0010, - NumFeatures = 0x0008 + NumFeatures = 0x0010 }; Q_DECLARE_FLAGS(Features, Feature); diff --git a/src/common/remotepeer.cpp b/src/common/remotepeer.cpp index a3fb2879..e8fa578d 100644 --- a/src/common/remotepeer.cpp +++ b/src/common/remotepeer.cpp @@ -252,11 +252,7 @@ void RemotePeer::handle(const HeartBeat &heartBeat) void RemotePeer::handle(const HeartBeatReply &heartBeatReply) { _heartBeatCount = 0; -#if QT_VERSION >= 0x040700 emit lagUpdated(heartBeatReply.timestamp.msecsTo(QDateTime::currentDateTime().toUTC()) / 2); -#else - emit lagUpdated(heartBeatReply.timestamp.time().msecsTo(QDateTime::currentDateTime().toUTC().time()) / 2); -#endif } diff --git a/src/core/core.cpp b/src/core/core.cpp index a86424f4..2049b63b 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -222,7 +222,7 @@ Core::~Core() foreach(CoreAuthHandler *handler, _connectingClients) { handler->deleteLater(); // disconnect non authed clients } - qDeleteAll(sessions); + qDeleteAll(_sessions); qDeleteAll(_storageBackends); } @@ -234,7 +234,8 @@ void Core::saveState() CoreSettings s; QVariantMap state; QVariantList activeSessions; - foreach(UserId user, instance()->sessions.keys()) activeSessions << QVariant::fromValue(user); + foreach(UserId user, instance()->_sessions.keys()) + activeSessions << QVariant::fromValue(user); state["CoreStateVersion"] = 1; state["ActiveSessions"] = activeSessions; s.setCoreState(state); @@ -247,7 +248,7 @@ void Core::restoreState() // qWarning() << qPrintable(tr("Cannot restore a state for an unconfigured core!")); return; } - if (instance()->sessions.count()) { + if (instance()->_sessions.count()) { qWarning() << qPrintable(tr("Calling restoreState() even though active sessions exist!")); return; } @@ -265,7 +266,7 @@ void Core::restoreState() quInfo() << "Restoring previous core state..."; foreach(QVariant v, activeSessions) { UserId user = v.value(); - instance()->createSession(user, true); + instance()->sessionForUser(user, true); } } } @@ -577,19 +578,7 @@ void Core::setupClientSession(RemotePeer *peer, UserId uid) handler->deleteLater(); // Find or create session for validated user - SessionThread *session; - if (sessions.contains(uid)) { - session = sessions[uid]; - } - else { - session = createSession(uid); - if (!session) { - qWarning() << qPrintable(tr("Could not initialize session for client:")) << qPrintable(peer->description()); - peer->close(); - peer->deleteLater(); - return; - } - } + sessionForUser(uid); // as we are currently handling an event triggered by incoming data on this socket // it is unsafe to directly move the socket to the client thread. @@ -610,14 +599,7 @@ void Core::customEvent(QEvent *event) void Core::addClientHelper(RemotePeer *peer, UserId uid) { // Find or create session for validated user - if (!sessions.contains(uid)) { - qWarning() << qPrintable(tr("Could not find a session for client:")) << qPrintable(peer->description()); - peer->close(); - peer->deleteLater(); - return; - } - - SessionThread *session = sessions[uid]; + SessionThread *session = sessionForUser(uid); session->addClient(peer); } @@ -643,26 +625,20 @@ void Core::setupInternalClientSession(InternalPeer *clientPeer) clientPeer->setPeer(corePeer); // Find or create session for validated user - SessionThread *sessionThread; - if (sessions.contains(uid)) - sessionThread = sessions[uid]; - else - sessionThread = createSession(uid); - + SessionThread *sessionThread = sessionForUser(uid); sessionThread->addClient(corePeer); } -SessionThread *Core::createSession(UserId uid, bool restore) +SessionThread *Core::sessionForUser(UserId uid, bool restore) { - if (sessions.contains(uid)) { - qWarning() << "Calling createSession() when a session for the user already exists!"; - return 0; - } - SessionThread *sess = new SessionThread(uid, restore, this); - sessions[uid] = sess; - sess->start(); - return sess; + if (_sessions.contains(uid)) + return _sessions[uid]; + + SessionThread *session = new SessionThread(uid, restore, this); + _sessions[uid] = session; + session->start(); + return session; } @@ -842,6 +818,15 @@ void Core::changeUserPass(const QString &username) } +bool Core::changeUserPassword(UserId userId, const QString &password) +{ + if (!isConfigured() || !userId.isValid()) + return false; + + return instance()->_storage->updateUser(userId, password); +} + + AbstractSqlMigrationReader *Core::getMigrationReader(Storage *storage) { if (!storage) diff --git a/src/core/core.h b/src/core/core.h index d544744a..e356a0fb 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -74,6 +74,15 @@ public: return instance()->_storage->validateUser(userName, password); } + + //! Change a user's password + /** + * \param userId The user's ID + * \param password The user's unencrypted new password + * \return true, if the password change was successful + */ + static bool changeUserPassword(UserId userId, const QString &password); + //! Store a user setting persistently /** * \param userId The users Id @@ -524,13 +533,15 @@ private slots: void socketError(QAbstractSocket::SocketError err, const QString &errorString); void setupClientSession(RemotePeer *, UserId); + void changeUserPass(const QString &username); + private: Core(); ~Core(); void init(); static Core *instanceptr; - SessionThread *createSession(UserId userId, bool restoreState = false); + SessionThread *sessionForUser(UserId userId, bool restoreState = false); void addClientHelper(RemotePeer *peer, UserId uid); //void processCoreSetup(QTcpSocket *socket, QVariantMap &msg); QString setupCoreForInternalUsage(); @@ -541,13 +552,12 @@ private: void unregisterStorageBackend(Storage *); bool selectBackend(const QString &backend); void createUser(); - void changeUserPass(const QString &username); void saveBackendSettings(const QString &backend, const QVariantMap &settings); QVariantMap promptForSettings(const Storage *storage); private: QSet _connectingClients; - QHash sessions; + QHash _sessions; Storage *_storage; QTimer _storageSyncTimer; diff --git a/src/core/corenetwork.cpp b/src/core/corenetwork.cpp index 1ba393fe..7e9ce268 100644 --- a/src/core/corenetwork.cpp +++ b/src/core/corenetwork.cpp @@ -232,17 +232,18 @@ void CoreNetwork::disconnectFromIrc(bool requested, const QString &reason, bool _quitReason = reason; displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Disconnecting. (%1)").arg((!requested && !withReconnect) ? tr("Core Shutdown") : _quitReason)); - switch (socket.state()) { - case QAbstractSocket::ConnectedState: - userInputHandler()->issueQuit(_quitReason); + if (socket.state() == QAbstractSocket::UnconnectedState) { + socketDisconnected(); + } else { + if (socket.state() == QAbstractSocket::ConnectedState) { + userInputHandler()->issueQuit(_quitReason); + } else { + socket.close(); + } if (requested || withReconnect) { // the irc server has 10 seconds to close the socket _socketCloseTimer.start(10000); - break; } - default: - socket.close(); - socketDisconnected(); } } @@ -416,11 +417,7 @@ void CoreNetwork::socketHasData() else if (s.endsWith("\n")) s.chop(1); NetworkDataEvent *event = new NetworkDataEvent(EventManager::NetworkIncoming, this, s); -#if QT_VERSION >= 0x040700 event->setTimestamp(QDateTime::currentDateTimeUtc()); -#else - event->setTimestamp(QDateTime::currentDateTime().toUTC()); -#endif emit newEvent(event); } } @@ -450,17 +447,15 @@ void CoreNetwork::socketInitialized() disconnectFromIrc(); return; } - + emit socketOpen(identity, localAddress(), localPort(), peerAddress(), peerPort()); - + Server server = usedServer(); #ifdef HAVE_SSL if (server.useSsl && !socket.isEncrypted()) return; #endif -#if QT_VERSION >= 0x040600 socket.setSocketOption(QAbstractSocket::KeepAliveOption, true); -#endif emit socketInitialized(identity, localAddress(), localPort(), peerAddress(), peerPort()); diff --git a/src/core/coresession.cpp b/src/core/coresession.cpp index 112aa856..5fd5bdcf 100644 --- a/src/core/coresession.cpp +++ b/src/core/coresession.cpp @@ -100,6 +100,9 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent) p->attachSlot(SIGNAL(createNetwork(const NetworkInfo &, const QStringList &)), this, SLOT(createNetwork(const NetworkInfo &, const QStringList &))); p->attachSlot(SIGNAL(removeNetwork(NetworkId)), this, SLOT(removeNetwork(NetworkId))); + p->attachSlot(SIGNAL(changePassword(PeerPtr,QString,QString,QString)), this, SLOT(changePassword(PeerPtr,QString,QString,QString))); + p->attachSignal(this, SIGNAL(passwordChanged(PeerPtr,bool))); + loadSettings(); initScriptEngine(); @@ -638,3 +641,13 @@ void CoreSession::globalAway(const QString &msg) net->userInputHandler()->issueAway(msg, false /* no force away */); } } + +void CoreSession::changePassword(PeerPtr peer, const QString &userName, const QString &oldPassword, const QString &newPassword) +{ + bool success = false; + UserId uid = Core::validateUser(userName, oldPassword); + if (uid.isValid() && uid == user()) + success = Core::changeUserPassword(uid, newPassword); + + emit passwordChanged(peer, success); +} diff --git a/src/core/coresession.h b/src/core/coresession.h index 3eecc4bb..a164ffe1 100644 --- a/src/core/coresession.h +++ b/src/core/coresession.h @@ -27,6 +27,7 @@ #include "corecoreinfo.h" #include "corealiasmanager.h" #include "coreignorelistmanager.h" +#include "peer.h" #include "protocol.h" #include "message.h" #include "storage.h" @@ -45,7 +46,6 @@ class EventManager; class EventStringifier; class InternalPeer; class IrcParser; -class Peer; class MessageEvent; class NetworkConnection; class RemotePeer; @@ -127,6 +127,8 @@ public slots: */ void renameBuffer(const NetworkId &networkId, const QString &newName, const QString &oldName); + void changePassword(PeerPtr peer, const QString &userName, const QString &oldPassword, const QString &newPassword); + QHash persistentChannels(NetworkId) const; //! Marks us away (or unaway) on all networks @@ -158,6 +160,8 @@ signals: void networkRemoved(NetworkId); void networkDisconnected(NetworkId); + void passwordChanged(PeerPtr peer, bool success); + protected: virtual void customEvent(QEvent *event); diff --git a/src/core/coreuserinputhandler.cpp b/src/core/coreuserinputhandler.cpp index 6a53cad2..33d1f67a 100644 --- a/src/core/coreuserinputhandler.cpp +++ b/src/core/coreuserinputhandler.cpp @@ -169,11 +169,7 @@ void CoreUserInputHandler::handleCtcp(const BufferInfo &bufferInfo, const QStrin QString verboseMessage = tr("sending CTCP-%1 request to %2").arg(ctcpTag).arg(nick); if (ctcpTag == "PING") { -#if QT_VERSION >= 0x040700 message = QString::number(QDateTime::currentMSecsSinceEpoch()); -#else - message = QString::number(QDateTime::currentDateTime().toTime_t()); -#endif } // FIXME make this a proper event @@ -549,6 +545,16 @@ void CoreUserInputHandler::handlePing(const BufferInfo &bufferInfo, const QStrin } +void CoreUserInputHandler::handlePrint(const BufferInfo &bufferInfo, const QString &msg) +{ + if (bufferInfo.bufferName().isEmpty() || !bufferInfo.acceptsRegularMessages()) + return; // server buffer + + QByteArray encMsg = channelEncode(bufferInfo.bufferName(), msg); + emit displayMsg(Message::Info, bufferInfo.type(), bufferInfo.bufferName(), msg, network()->myNick(), Message::Self); +} + + // TODO: implement queries void CoreUserInputHandler::handleQuery(const BufferInfo &bufferInfo, const QString &msg) { diff --git a/src/core/coreuserinputhandler.h b/src/core/coreuserinputhandler.h index dd9696c4..69a429ee 100644 --- a/src/core/coreuserinputhandler.h +++ b/src/core/coreuserinputhandler.h @@ -63,6 +63,7 @@ public slots: void handleHalfop(const BufferInfo& bufferInfo, const QString &nicks); void handlePart(const BufferInfo &bufferInfo, const QString &text); void handlePing(const BufferInfo &bufferInfo, const QString &text); + void handlePrint(const BufferInfo &bufferInfo, const QString &text); void handleQuery(const BufferInfo &bufferInfo, const QString &text); void handleQuit(const BufferInfo &bufferInfo, const QString &text); void handleQuote(const BufferInfo &bufferInfo, const QString &text); diff --git a/src/core/eventstringifier.cpp b/src/core/eventstringifier.cpp index afb70c23..943727cd 100644 --- a/src/core/eventstringifier.cpp +++ b/src/core/eventstringifier.cpp @@ -733,12 +733,7 @@ void EventStringifier::handleCtcpPing(CtcpEvent *e) if (e->ctcpType() == CtcpEvent::Query) defaultHandler(e->ctcpCmd(), e); else { -#if QT_VERSION >= 0x040700 displayMsg(e, Message::Server, tr("Received CTCP-PING answer from %1 with %2 milliseconds round trip time") .arg(nickFromMask(e->prefix())).arg(QDateTime::fromMSecsSinceEpoch(e->param().toULongLong()).msecsTo(e->timestamp()))); -#else - displayMsg(e, Message::Server, tr("Received CTCP-PING answer from %1 with %2 seconds round trip time") - .arg(nickFromMask(e->prefix())).arg(QDateTime::fromTime_t(e->param().toInt()).secsTo(e->timestamp()))); -#endif } } diff --git a/src/qtui/CMakeLists.txt b/src/qtui/CMakeLists.txt index c9274a22..be9a14b5 100644 --- a/src/qtui/CMakeLists.txt +++ b/src/qtui/CMakeLists.txt @@ -34,6 +34,7 @@ set(SOURCES markerlineitem.cpp msgprocessorstatuswidget.cpp nicklistwidget.cpp + passwordchangedlg.cpp qtui.cpp qtuiapplication.cpp qtuimessageprocessor.cpp @@ -71,6 +72,7 @@ set(FORMS inputwidget.ui msgprocessorstatuswidget.ui nicklistwidget.ui + passwordchangedlg.ui settingsdlg.ui settingspagedlg.ui simplenetworkeditor.ui @@ -81,13 +83,18 @@ set(FORMS set(LIBS ) set(QT_MODULES ) -if (KDE4_FOUND) +if (WITH_KDE4) add_definitions(-DHAVE_KDE ${KDE4_DEFINITIONS}) include_directories(${KDE4_INCLUDES}) list(APPEND SOURCES knotificationbackend.cpp) list(APPEND LIBS ${KDE4_KDECORE_LIBS} ${KDE4_KDEUI_LIBRARY} ${KDE4_KNOTIFYCONFIG_LIBRARY}) endif() +if (WITH_KF5) + list(APPEND SOURCES knotificationbackend.cpp) + list(APPEND LIBS KF5::ConfigWidgets KF5::Notifications KF5::NotifyConfig KF5::WidgetsAddons KF5::XmlGui) +endif() + if (LIBSNORE_FOUND) add_definitions(-DHAVE_LIBSNORE) include_directories(${LIBSNORE_INCLUDE_DIRS}) diff --git a/src/qtui/aboutdlg.cpp b/src/qtui/aboutdlg.cpp index 582fe932..b5b7c76d 100644 --- a/src/qtui/aboutdlg.cpp +++ b/src/qtui/aboutdlg.cpp @@ -74,7 +74,7 @@ QString AboutDlg::authors() const res.append("
" + person.prettyName() + "
"); if (!person.emailAddress().isEmpty()) res.append("" + person.emailAddress() + "
"); - res.append(person.task() + "
"); + res.append("" + person.task() + "
"); } res.append(""); return res; @@ -86,9 +86,9 @@ QString AboutDlg::contributors() const QString res; res = tr("We would like to thank the following contributors (in alphabetical order) and everybody we forgot to mention here:") + "
"; for (const auto &person : _aboutData->credits()) { - res.append("
" + person.prettyName() + "
" + person.task() + "
"); + res.append("
" + person.prettyName() + "
" + person.task() + "
"); } - res.append("

" + tr("...and anybody else finding and reporting bugs, giving feedback, helping others and being part of the community!")); + res.append("" + tr("...and anybody else finding and reporting bugs, giving feedback, helping others and being part of the community!")); return res; } @@ -100,13 +100,13 @@ QString AboutDlg::thanksTo() const res = tr("Special thanks goes to:
" "
" "
 John \"nox\" Hand
" - "
for the original Quassel icon - The All-Seeing Eye" + "
for the original Quassel icon - The All-Seeing Eye
" "
 The Oxygen Team
" - "
for creating all the artwork you see throughout Quassel
" + "
for creating all the artwork you see throughout Quassel
" "
 Qt Software formerly known as Trolltech
" - "
for creating Qt and Qtopia, and for sponsoring development of QuasselTopia with Greenphones and more
" + "
for creating Qt and Qtopia, and for sponsoring development of QuasselTopia with Greenphones and more
" "
" - "
for keeping Qt alive, and for sponsoring development of Quassel Mobile with N810s
" + "
for sponsoring development of Quassel Mobile with N810s
" ); return res; diff --git a/src/qtui/chatviewsearchcontroller.h b/src/qtui/chatviewsearchcontroller.h index 294693de..2ad0edaa 100644 --- a/src/qtui/chatviewsearchcontroller.h +++ b/src/qtui/chatviewsearchcontroller.h @@ -21,7 +21,7 @@ #ifndef CHATVIEWSEARCHCONTROLLER_H #define CHATVIEWSEARCHCONTROLLER_H -#include +#include #include #include #include @@ -87,11 +87,11 @@ private: // Highlight Items -#include - class SearchHighlightItem : public QObject, public QGraphicsItem { Q_OBJECT + +// Apparently, there are broken Qt 4.8.2 mocs around that will fail without this (otherwise useless) #if... looking at you, Wheezy! #if QT_VERSION >= 0x040600 Q_INTERFACES(QGraphicsItem) #endif diff --git a/src/qtui/knotificationbackend.cpp b/src/qtui/knotificationbackend.cpp index 41d56385..1b09927a 100644 --- a/src/qtui/knotificationbackend.cpp +++ b/src/qtui/knotificationbackend.cpp @@ -18,13 +18,19 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#include -#include +#include "knotificationbackend.h" + #include #include #include -#include "knotificationbackend.h" +#ifdef HAVE_KDE4 +# include +# include +#else +# include +# include +#endif #include "client.h" #include "mainwin.h" diff --git a/src/qtui/knotificationbackend.h b/src/qtui/knotificationbackend.h index 2f21c9ef..25abcf93 100644 --- a/src/qtui/knotificationbackend.h +++ b/src/qtui/knotificationbackend.h @@ -18,8 +18,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#ifndef KNOTIFICATIONBACKEND_H_ -#define KNOTIFICATIONBACKEND_H_ +#pragma once #include @@ -52,7 +51,7 @@ private: void removeNotificationById(uint id); void updateToolTip(); - QList > > _notifications; + QList>> _notifications; }; @@ -72,6 +71,3 @@ private slots: private: KNotifyConfigWidget *_widget; }; - - -#endif diff --git a/src/qtui/mainwin.cpp b/src/qtui/mainwin.cpp index cd4a5fe1..8f022cac 100644 --- a/src/qtui/mainwin.cpp +++ b/src/qtui/mainwin.cpp @@ -25,17 +25,23 @@ #include #include #include +#include #ifdef HAVE_KDE4 -# include -# include # include # include # include # include # include # include -# include +#endif + +#ifdef HAVE_KF5 +# include +# include +# include +# include +# include #endif #ifdef Q_WS_X11 @@ -81,6 +87,7 @@ #include "legacysystemtray.h" #include "msgprocessorstatuswidget.h" #include "nicklistwidget.h" +#include "passwordchangedlg.h" #include "qtuiapplication.h" #include "qtuimessageprocessor.h" #include "qtuisettings.h" @@ -93,7 +100,7 @@ #include "topicwidget.h" #include "verticaldock.h" -#ifndef HAVE_KDE4 +#ifndef HAVE_KDE # ifdef HAVE_PHONON # include "phononnotificationbackend.h" # endif @@ -102,9 +109,9 @@ # endif # include "systraynotificationbackend.h" # include "taskbarnotificationbackend.h" -#else /* HAVE_KDE4 */ +#else /* HAVE_KDE */ # include "knotificationbackend.h" -#endif /* HAVE_KDE4 */ +#endif /* HAVE_KDE */ #ifdef HAVE_SSL # include "sslinfodlg.h" @@ -140,14 +147,13 @@ #include "settingspages/notificationssettingspage.h" #include "settingspages/topicwidgetsettingspage.h" -#ifndef HAVE_KDE4 +#ifndef HAVE_KDE # include "settingspages/shortcutssettingspage.h" #endif MainWin::MainWin(QWidget *parent) -#ifdef HAVE_KDE4 - : KMainWindow(parent), - _kHelpMenu(new KHelpMenu(this, KGlobal::mainComponent().aboutData())), +#ifdef HAVE_KDE + : KMainWindow(parent), _kHelpMenu(new KHelpMenu(this)), #else : QMainWindow(parent), #endif @@ -214,7 +220,7 @@ void MainWin::init() setupTitleSetter(); setupHotList(); -#ifndef HAVE_KDE4 +#ifndef HAVE_KDE # ifdef HAVE_PHONON QtUi::registerNotificationBackend(new PhononNotificationBackend(this)); # endif @@ -226,9 +232,9 @@ void MainWin::init() QtUi::registerNotificationBackend(new TaskbarNotificationBackend(this)); -#else /* HAVE_KDE4 */ +#else /* HAVE_KDE */ QtUi::registerNotificationBackend(new KNotificationBackend(this)); -#endif /* HAVE_KDE4 */ +#endif /* HAVE_KDE */ #ifdef HAVE_INDICATEQT QtUi::registerNotificationBackend(new IndicatorNotificationBackend(this)); @@ -249,7 +255,7 @@ void MainWin::init() setDisconnectedState(); // Disable menus and stuff -#ifdef HAVE_KDE4 +#ifdef HAVE_KDE setAutoSaveSettings(); #endif @@ -295,7 +301,7 @@ void MainWin::saveStateToSettings(UiSettings &s) if (lastBufId.isValid()) s.setValue("LastUsedBufferId", lastBufId.toInt()); -#ifdef HAVE_KDE4 +#ifdef HAVE_KDE saveAutoSaveSettings(); #endif } @@ -307,7 +313,7 @@ void MainWin::restoreStateFromSettings(UiSettings &s) _normalPos = s.value("MainWinPos", pos()).toPoint(); bool maximized = s.value("MainWinMaximized", false).toBool(); -#ifndef HAVE_KDE4 +#ifndef HAVE_KDE restoreGeometry(s.value("MainWinGeometry").toByteArray()); if (maximized) { @@ -355,6 +361,8 @@ void MainWin::setupActions() this, SLOT(showCoreConnectionDlg()))); coll->addAction("DisconnectCore", new Action(QIcon::fromTheme("network-disconnect"), tr("&Disconnect from Core"), coll, Client::instance(), SLOT(disconnectFromCore()))); + coll->addAction("ChangePassword", new Action(QIcon::fromTheme("dialog-password"), tr("Change &Password..."), coll, + this, SLOT(showPasswordChangeDlg()))); coll->addAction("CoreInfo", new Action(QIcon::fromTheme("help-about"), tr("Core &Info..."), coll, this, SLOT(showCoreInfoDlg()))); coll->addAction("ConfigureNetworks", new Action(QIcon::fromTheme("configure"), tr("Configure &Networks..."), coll, @@ -381,14 +389,14 @@ void MainWin::setupActions() coll->addAction("ToggleStatusBar", new Action(tr("Show Status &Bar"), coll, 0, 0))->setCheckable(true); -#ifdef HAVE_KDE4 - QAction *fullScreenAct = KStandardAction::fullScreen(this, SLOT(onFullScreenToggled()), this, coll); +#ifdef HAVE_KDE + _fullScreenAction = KStandardAction::fullScreen(this, SLOT(onFullScreenToggled()), this, coll); #else - QAction *fullScreenAct = new Action(QIcon::fromTheme("view-fullscreen"), tr("&Full Screen Mode"), coll, + _fullScreenAction = new Action(QIcon::fromTheme("view-fullscreen"), tr("&Full Screen Mode"), coll, this, SLOT(onFullScreenToggled()), QKeySequence(Qt::Key_F11)); - fullScreenAct->setCheckable(true); + _fullScreenAction->setCheckable(true); + coll->addAction("ToggleFullScreen", _fullScreenAction); #endif - coll->addAction("ToggleFullScreen", fullScreenAct); // Settings QAction *configureShortcutsAct = new Action(QIcon::fromTheme("configure-shortcuts"), tr("Configure &Shortcuts..."), coll, @@ -396,14 +404,14 @@ void MainWin::setupActions() configureShortcutsAct->setMenuRole(QAction::NoRole); coll->addAction("ConfigureShortcuts", configureShortcutsAct); - #ifdef Q_OS_MAC +#ifdef Q_OS_MAC QAction *configureQuasselAct = new Action(QIcon::fromTheme("configure"), tr("&Configure Quassel..."), coll, this, SLOT(showSettingsDlg())); configureQuasselAct->setMenuRole(QAction::PreferencesRole); - #else +#else QAction *configureQuasselAct = new Action(QIcon::fromTheme("configure"), tr("&Configure Quassel..."), coll, this, SLOT(showSettingsDlg()), QKeySequence(Qt::Key_F7)); - #endif +#endif coll->addAction("ConfigureQuassel", configureQuasselAct); // Help @@ -508,7 +516,7 @@ void MainWin::setupMenus() _fileMenu = menuBar()->addMenu(tr("&File")); static const QStringList coreActions = QStringList() - << "ConnectCore" << "DisconnectCore" << "CoreInfo"; + << "ConnectCore" << "DisconnectCore" << "ChangePassword" << "CoreInfo"; QAction *coreAction; foreach(QString actionName, coreActions) { @@ -542,7 +550,7 @@ void MainWin::setupMenus() _viewMenu->addAction(coll->action("LockLayout")); _settingsMenu = menuBar()->addMenu(tr("&Settings")); -#ifdef HAVE_KDE4 +#ifdef HAVE_KDE _settingsMenu->addAction(KStandardAction::configureNotifications(this, SLOT(showNotificationsDlg()), this)); _settingsMenu->addAction(KStandardAction::keyBindings(this, SLOT(showShortcutsDlg()), this)); #else @@ -550,9 +558,11 @@ void MainWin::setupMenus() #endif _settingsMenu->addAction(coll->action("ConfigureQuassel")); + _helpMenu = menuBar()->addMenu(tr("&Help")); + _helpMenu->addAction(coll->action("AboutQuassel")); -#ifndef HAVE_KDE4 +#ifndef HAVE_KDE _helpMenu->addAction(coll->action("AboutQt")); #else _helpMenu->addAction(KStandardAction::aboutKDE(_kHelpMenu, SLOT(aboutKDE()), this)); @@ -727,6 +737,22 @@ void MainWin::changeActiveBufferView(int bufferViewId) } +void MainWin::showPasswordChangeDlg() +{ + if((Client::coreFeatures() & Quassel::PasswordChange)) { + PasswordChangeDlg dlg(this); + dlg.exec(); + } + else { + QMessageBox box(QMessageBox::Warning, tr("Feature Not Supported"), + tr("Your Quassel Core does not support this feature"), + QMessageBox::Ok, this); + box.setInformativeText(tr("You need a Quassel Core v0.12.0 or newer in order to be able to remotely change your password.")); + box.exec(); + } +} + + void MainWin::changeActiveBufferView(bool backwards) { BufferView *current = activeBufferView(); @@ -917,7 +943,7 @@ void MainWin::setupTopicWidget() void MainWin::setupViewMenuTail() { _viewMenu->addSeparator(); - _viewMenu->addAction(QtUi::actionCollection("General")->action("ToggleFullScreen")); + _viewMenu->addAction(_fullScreenAction); } @@ -998,7 +1024,7 @@ void MainWin::setupToolBars() setUnifiedTitleAndToolBarOnMac(true); #endif -#ifdef HAVE_KDE4 +#ifdef HAVE_KDE _mainToolBar = new KToolBar("MainToolBar", this, Qt::TopToolBarArea, false, true, true); #else _mainToolBar = new QToolBar(this); @@ -1049,6 +1075,7 @@ void MainWin::setConnectedState() coll->action("ConnectCore")->setEnabled(false); coll->action("DisconnectCore")->setEnabled(true); + coll->action("ChangePassword")->setEnabled(true); coll->action("CoreInfo")->setEnabled(true); foreach(QAction *action, _fileMenu->actions()) { @@ -1165,6 +1192,7 @@ void MainWin::setDisconnectedState() coll->action("ConnectCore")->setEnabled(true); coll->action("DisconnectCore")->setEnabled(false); coll->action("CoreInfo")->setEnabled(false); + coll->action("ChangePassword")->setEnabled(false); //_viewMenu->setEnabled(false); statusBar()->showMessage(tr("Not connected to core.")); if (_msgProcessorStatusWidget) @@ -1363,11 +1391,11 @@ void MainWin::showAboutDlg() void MainWin::showShortcutsDlg() { -#ifdef HAVE_KDE4 +#ifdef HAVE_KDE KShortcutsDialog dlg(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsDisallowed, this); foreach(KActionCollection *coll, QtUi::actionCollections()) dlg.addCollection(coll, coll->property("Category").toString()); - dlg.exec(); + dlg.configure(true); #else SettingsPageDlg dlg(new ShortcutsSettingsPage(QtUi::actionCollections(), this), this); dlg.exec(); @@ -1387,15 +1415,10 @@ void MainWin::onFullScreenToggled() // Relying on QWidget::isFullScreen is discouraged, see the KToggleFullScreenAction docs // Also, one should not use showFullScreen() or showNormal(), as those reset all other window flags - QAction *action = QtUi::actionCollection("General")->action("ToggleFullScreen"); - if (!action) - return; - -#ifdef HAVE_KDE4 - KToggleFullScreenAction *kAct = static_cast(action); - kAct->setFullScreen(this, kAct->isChecked()); +#ifdef HAVE_KDE + static_cast(_fullScreenAction)->setFullScreen(this, _fullScreenAction->isChecked()); #else - if (action->isChecked()) + if (_fullScreenAction->isChecked()) setWindowState(windowState() | Qt::WindowFullScreen); else setWindowState(windowState() & ~Qt::WindowFullScreen); diff --git a/src/qtui/mainwin.h b/src/qtui/mainwin.h index 30e57269..900354b1 100644 --- a/src/qtui/mainwin.h +++ b/src/qtui/mainwin.h @@ -18,11 +18,12 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#ifndef MAINWIN_H_ -#define MAINWIN_H_ +#pragma once #ifdef HAVE_KDE4 # include +#elif defined HAVE_KF5 +# include #else # include #endif @@ -56,11 +57,10 @@ class KHelpMenu; //!\brief The main window of Quassel's QtUi. class MainWin -#ifdef HAVE_KDE4 - : public KMainWindow -{ +#ifdef HAVE_KDE + : public KMainWindow { #else -: public QMainWindow { + : public QMainWindow { #endif Q_OBJECT @@ -123,6 +123,7 @@ private slots: void showNotificationsDlg(); void showIgnoreList(QString newRule = QString()); void showShortcutsDlg(); + void showPasswordChangeDlg(); void showNewTransferDlg(const ClientTransfer *transfer); void onFullScreenToggled(); @@ -169,7 +170,7 @@ signals: void disconnectFromCore(); private: -#ifdef HAVE_KDE4 +#ifdef HAVE_KDE KHelpMenu *_kHelpMenu; #endif @@ -203,6 +204,7 @@ private: ChatMonitorView *_chatMonitorView; TopicWidget *_topicWidget; + QAction *_fullScreenAction; QMenu *_fileMenu, *_networksMenu, *_viewMenu, *_bufferViewsMenu, *_settingsMenu, *_helpMenu, *_helpDebugMenu; QMenu *_toolbarMenu; QToolBar *_mainToolBar, *_chatViewToolBar, *_nickToolBar; @@ -220,6 +222,3 @@ private: friend class QtUi; }; - - -#endif diff --git a/src/qtui/passwordchangedlg.cpp b/src/qtui/passwordchangedlg.cpp new file mode 100644 index 00000000..7009adf6 --- /dev/null +++ b/src/qtui/passwordchangedlg.cpp @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (C) 2005-2015 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "passwordchangedlg.h" + +#include +#include + +#include "client.h" + +PasswordChangeDlg::PasswordChangeDlg(QWidget *parent) : QDialog(parent) +{ + ui.setupUi(this); + + CoreAccount account = Client::currentCoreAccount(); + ui.infoLabel->setText(tr("This changes the password for your username %1 " + "on the Quassel Core running at %2.") + .arg(account.user(), account.hostName())); + + connect(ui.oldPasswordEdit, SIGNAL(textChanged(QString)), SLOT(inputChanged())); + connect(ui.newPasswordEdit, SIGNAL(textChanged(QString)), SLOT(inputChanged())); + connect(ui.confirmPasswordEdit, SIGNAL(textChanged(QString)), SLOT(inputChanged())); + connect(ui.buttonBox, SIGNAL(accepted()), SLOT(changePassword())); + + connect(Client::instance(), SIGNAL(passwordChanged(bool)), SLOT(passwordChanged(bool))); + + ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); +} + + +void PasswordChangeDlg::inputChanged() +{ + bool ok = !ui.oldPasswordEdit->text().isEmpty() && !ui.newPasswordEdit->text().isEmpty() + && ui.newPasswordEdit->text() == ui.confirmPasswordEdit->text(); + ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok); +} + + +void PasswordChangeDlg::changePassword() +{ + ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + Client::changePassword(ui.oldPasswordEdit->text(), ui.newPasswordEdit->text()); +} + + +void PasswordChangeDlg::passwordChanged(bool success) +{ + if (!success) { + QMessageBox box(QMessageBox::Warning, tr("Password Not Changed"), + tr("Password change failed"), + QMessageBox::Ok, this); + box.setInformativeText(tr("The core reported an error when trying to change your password. Make sure you entered your old password correctly!")); + box.exec(); + } + else { + accept(); + } +} diff --git a/src/qtui/passwordchangedlg.h b/src/qtui/passwordchangedlg.h new file mode 100644 index 00000000..36bfc63b --- /dev/null +++ b/src/qtui/passwordchangedlg.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2005-2015 by the Quassel Project * + * devel@quassel-irc.org * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) version 3. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#pragma once + +#include + +#include "ui_passwordchangedlg.h" + +class PasswordChangeDlg : public QDialog +{ + Q_OBJECT + +public: + PasswordChangeDlg(QWidget *parent = nullptr); + +private slots: + void inputChanged(); + void changePassword(); + void passwordChanged(bool success); + +private: + Ui::PasswordChangeDlg ui; + QString _newPassword; +}; diff --git a/src/qtui/qtuiapplication.cpp b/src/qtui/qtuiapplication.cpp index a279442b..88b8bdb1 100644 --- a/src/qtui/qtuiapplication.cpp +++ b/src/qtui/qtuiapplication.cpp @@ -33,9 +33,10 @@ #include "qtui.h" #include "qtuisettings.h" + QtUiApplication::QtUiApplication(int &argc, char **argv) #ifdef HAVE_KDE4 - : KApplication(), + : KApplication(), // KApplication is deprecated in KF5 #else : QApplication(argc, argv), #endif @@ -45,11 +46,34 @@ QtUiApplication::QtUiApplication(int &argc, char **argv) #ifdef HAVE_KDE4 Q_UNUSED(argc); Q_UNUSED(argv); - // We need to setup KDE's data dirs + // Setup KDE's data dirs + // Because we can't use KDE stuff in (the class) Quassel directly, we need to do this here... QStringList dataDirs = KGlobal::dirs()->findDirs("data", ""); + + // Just in case, also check our install prefix + dataDirs << QCoreApplication::applicationDirPath() + "/../share/apps/"; + + // Normalize and append our application name for (int i = 0; i < dataDirs.count(); i++) - dataDirs[i].append("quassel/"); + dataDirs[i] = QDir::cleanPath(dataDirs.at(i)) + "/quassel/"; + + // Add resource path and just in case. + // Workdir should have precedence + dataDirs.prepend(QCoreApplication::applicationDirPath() + "/data/"); dataDirs.append(":/data/"); + + // Append trailing '/' and check for existence + auto iter = dataDirs.begin(); + while (iter != dataDirs.end()) { + if (!iter->endsWith(QDir::separator()) && !iter->endsWith('/')) + iter->append(QDir::separator()); + if (!QFile::exists(*iter)) + iter = dataDirs.erase(iter); + else + ++iter; + } + + dataDirs.removeDuplicates(); setDataDirPaths(dataDirs); #else /* HAVE_KDE4 */ diff --git a/src/qtui/settingspages/coreconnectionsettingspage.cpp b/src/qtui/settingspages/coreconnectionsettingspage.cpp index aeb732e5..d73c0107 100644 --- a/src/qtui/settingspages/coreconnectionsettingspage.cpp +++ b/src/qtui/settingspages/coreconnectionsettingspage.cpp @@ -24,13 +24,9 @@ CoreConnectionSettingsPage::CoreConnectionSettingsPage(QWidget *parent) : SettingsPage(tr("Remote Cores"), tr("Connection"), parent) { ui.setupUi(this); -#ifndef HAVE_KDE4 - ui.useSolid->hide(); -#endif initAutoWidgets(); - connect(ui.useSolid, SIGNAL(toggled(bool)), SLOT(widgetHasChanged())); connect(ui.useQNetworkConfigurationManager, SIGNAL(toggled(bool)), SLOT(widgetHasChanged())); connect(ui.usePingTimeout, SIGNAL(toggled(bool)), SLOT(widgetHasChanged())); connect(ui.useNoTimeout, SIGNAL(toggled(bool)), SLOT(widgetHasChanged())); @@ -50,11 +46,7 @@ void CoreConnectionSettingsPage::widgetHasChanged() void CoreConnectionSettingsPage::defaults() { -#ifdef HAVE_KDE4 - setRadioButtons(CoreConnectionSettings::UseSolid); -#else setRadioButtons(CoreConnectionSettings::UseQNetworkConfigurationManager); -#endif SettingsPage::defaults(); } @@ -81,11 +73,6 @@ void CoreConnectionSettingsPage::save() void CoreConnectionSettingsPage::setRadioButtons(CoreConnectionSettings::NetworkDetectionMode mode) { switch (mode) { -#ifdef HAVE_KDE4 - case CoreConnectionSettings::UseSolid: - ui.useSolid->setChecked(true); - break; -#endif case CoreConnectionSettings::UseQNetworkConfigurationManager: ui.useQNetworkConfigurationManager->setChecked(true); break; @@ -100,10 +87,6 @@ void CoreConnectionSettingsPage::setRadioButtons(CoreConnectionSettings::Network CoreConnectionSettings::NetworkDetectionMode CoreConnectionSettingsPage::modeFromRadioButtons() const { -#ifdef HAVE_KDE4 - if (ui.useSolid->isChecked()) - return CoreConnectionSettings::UseSolid; -#endif if (ui.useQNetworkConfigurationManager->isChecked()) return CoreConnectionSettings::UseQNetworkConfigurationManager; if (ui.usePingTimeout->isChecked()) diff --git a/src/qtui/settingspages/coreconnectionsettingspage.ui b/src/qtui/settingspages/coreconnectionsettingspage.ui index d641bfa1..15891847 100644 --- a/src/qtui/settingspages/coreconnectionsettingspage.ui +++ b/src/qtui/settingspages/coreconnectionsettingspage.ui @@ -6,7 +6,7 @@ 0 0 - 446 + 476 465 @@ -20,26 +20,13 @@ Network Status Detection - - - - Rely on KDE's hardware layer to detect if we're online. Recommended for most KDE users - - - Use KDE's network status detection (via Solid) - - - false - - - - Rely on Qt's network configuration manager to detect if we're online. + Rely on Qt's network configuration manager to detect if we're online - Use Qt's network status detection (via QNetworkConfigurationManager) + Automatic false @@ -164,7 +151,7 @@ - Actively ping the remote core and disconnect if we didn't get a reply after a certain time + Interval between consecutive connection attempts seconds @@ -219,6 +206,14 @@ + + useQNetworkConfigurationManager + usePingTimeout + pingTimeout + useNoTimeout + autoReconnect + reconnectInterval + diff --git a/src/qtui/settingspages/highlightsettingspage.cpp b/src/qtui/settingspages/highlightsettingspage.cpp index c932d9f6..2fe2a0b4 100644 --- a/src/qtui/settingspages/highlightsettingspage.cpp +++ b/src/qtui/settingspages/highlightsettingspage.cpp @@ -252,9 +252,7 @@ void HighlightSettingsPage::save() NotificationSettings notificationSettings; notificationSettings.setHighlightList(highlightList); - NotificationSettings::HighlightNickType highlightNickType; - if (ui.highlightNoNick->isChecked()) - highlightNickType = NotificationSettings::NoNick; + NotificationSettings::HighlightNickType highlightNickType = NotificationSettings::NoNick; if (ui.highlightCurrentNick->isChecked()) highlightNickType = NotificationSettings::CurrentNick; if (ui.highlightAllNicks->isChecked()) @@ -279,18 +277,18 @@ bool HighlightSettingsPage::testHasChanged() { NotificationSettings notificationSettings; - NotificationSettings::HighlightNickType highlightNickType; - if (ui.highlightNoNick->isChecked()) - highlightNickType = NotificationSettings::NoNick; + NotificationSettings::HighlightNickType highlightNickType = NotificationSettings::NoNick; if (ui.highlightCurrentNick->isChecked()) highlightNickType = NotificationSettings::CurrentNick; if (ui.highlightAllNicks->isChecked()) highlightNickType = NotificationSettings::AllNicks; - if (notificationSettings.highlightNick() != highlightNickType) return true; - if (notificationSettings.nicksCaseSensitive() != ui.nicksCaseSensitive->isChecked()) return true; - - if (notificationSettings.highlightList() != highlightList) return true; + if (notificationSettings.highlightNick() != highlightNickType) + return true; + if (notificationSettings.nicksCaseSensitive() != ui.nicksCaseSensitive->isChecked()) + return true; + if (notificationSettings.highlightList() != highlightList) + return true; return false; } diff --git a/src/qtui/settingspages/networkssettingspage.cpp b/src/qtui/settingspages/networkssettingspage.cpp index c9ba18a8..011328d5 100644 --- a/src/qtui/settingspages/networkssettingspage.cpp +++ b/src/qtui/settingspages/networkssettingspage.cpp @@ -865,6 +865,7 @@ ServerEditDlg::ServerEditDlg(const Network::Server &server, QWidget *parent) : Q ui.setupUi(this); ui.useSSL->setIcon(QIcon::fromTheme("document-encrypt")); ui.host->setText(server.host); + ui.host->setFocus(); ui.port->setValue(server.port); ui.password->setText(server.password); ui.useSSL->setChecked(server.useSsl); diff --git a/src/qtui/statusnotifieritem.cpp b/src/qtui/statusnotifieritem.cpp index a1d2916a..a75c3255 100644 --- a/src/qtui/statusnotifieritem.cpp +++ b/src/qtui/statusnotifieritem.cpp @@ -52,14 +52,7 @@ protected: virtual QString iconNameForAction(QAction *action) // TODO Qt 4.7: fixme when we have converted our iconloader { QIcon icon(action->icon()); -#if QT_VERSION >= 0x040701 - // QIcon::name() is in the 4.7 git branch, but it is not in 4.7 TP. - // If you get a build error here, you need to update your pre-release - // of Qt 4.7. return icon.isNull() ? QString() : icon.name(); -#else - return QString(); -#endif } }; diff --git a/src/qtui/ui/passwordchangedlg.ui b/src/qtui/ui/passwordchangedlg.ui new file mode 100644 index 00000000..cf68c1f9 --- /dev/null +++ b/src/qtui/ui/passwordchangedlg.ui @@ -0,0 +1,124 @@ + + + PasswordChangeDlg + + + + 0 + 0 + 455 + 173 + + + + Change Password + + + + + + + + <html><head/><body><p>This changes the password for your username <span style=" font-weight:600;">John</span> on the Quassel Core running at <span style=" font-weight:600;">example.invalid</span>.</p></body></html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + Old password: + + + + + + + QLineEdit::Password + + + + + + + New Password: + + + + + + + QLineEdit::Password + + + + + + + Confirm password: + + + + + + + QLineEdit::Password + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + rejected() + PasswordChangeDlg + reject() + + + 248 + 152 + + + 229 + -14 + + + + + diff --git a/src/uisupport/CMakeLists.txt b/src/uisupport/CMakeLists.txt index 0b78acc9..37ea3114 100644 --- a/src/uisupport/CMakeLists.txt +++ b/src/uisupport/CMakeLists.txt @@ -59,5 +59,5 @@ if (WITH_KDE4) endif() if (WITH_KF5) - target_link_libraries(mod_uisupport KF5::CoreAddons KF5::TextWidgets) + target_link_libraries(mod_uisupport KF5::CoreAddons KF5::TextWidgets KF5::XmlGui) endif() diff --git a/src/uisupport/aboutdata.cpp b/src/uisupport/aboutdata.cpp index 17356fda..4ca69840 100644 --- a/src/uisupport/aboutdata.cpp +++ b/src/uisupport/aboutdata.cpp @@ -195,7 +195,7 @@ void AboutData::setQuasselPersons(AboutData *aboutData) { "Bruno Patri", "", tr("French translation"), "", QLocale::French }, { "Celeste Paul", "seele", tr("Usability review") }, { "Chris Fuenty", "stitch", tr("SASL support") }, - { "Chris H", "Zren", tr("Various improvements") }, + { "Chris Holland", "Shade / Zren", tr("Various improvements") }, { "Chris Le Sueur", "Fish-Face", tr("Various fixes and improvements") }, { "Chris Moeller", "kode54", tr("Various fixes and improvements") }, { "", "Condex", tr("Galician translation"), "", QLocale::Galician }, @@ -242,6 +242,7 @@ void AboutData::setQuasselPersons(AboutData *aboutData) { "Jussi Schultink", "jussi01", tr("Tireless tester, {Ku|U}buntu tester and lobbyist, liters of delicious Finnish alcohol") }, { "K. Ernest Lee", "iFire", tr("Qt5 porting help, Travis CI setup") }, { "Kevin Funk", "KRF", tr("German translation"), "", QLocale::German }, + { "Kimmo Huoman", "kipe", tr("Buffer merge improvements") }, { "", "Larso", tr("Finnish translation"), "", QLocale::Finnish }, { "Lasse Liehu", "", tr("Finnish translation"), "", QLocale::Finnish }, { "Leo Franchi", "", tr("OSX improvements") }, @@ -265,6 +266,7 @@ void AboutData::setQuasselPersons(AboutData *aboutData) { "Pavel Volkovitskiy", "int", tr("Early beta tester and bughunter") }, { "Per Nielsen", "", tr("Danish translation"), "", QLocale::Danish }, { "Pete Beardmore", "elbeardmorez", tr("Linewrap for input line") }, + { "Pierre-Hugues Husson", "", tr("/print command") }, { "Ramanathan Sivagurunathan", "", tr("Bugfixes") }, { "Regis Perrin", "ZRegis", tr("French translation"), "", QLocale::French }, { "Rolf Eike Beer", "", tr("Build system fixes") }, diff --git a/src/uisupport/actioncollection.cpp b/src/uisupport/actioncollection.cpp index b862ae85..593b236e 100644 --- a/src/uisupport/actioncollection.cpp +++ b/src/uisupport/actioncollection.cpp @@ -20,7 +20,7 @@ * Parts of this implementation are based on KDE's KActionCollection. * ***************************************************************************/ -#ifndef HAVE_KDE4 +#ifndef HAVE_KDE #include #include @@ -305,4 +305,4 @@ bool ActionCollection::unlistAction(QAction *action) } -#endif /* HAVE_KDE4 */ +#endif /* HAVE_KDE */ diff --git a/src/uisupport/actioncollection.h b/src/uisupport/actioncollection.h index a76fc04a..c920adc5 100644 --- a/src/uisupport/actioncollection.h +++ b/src/uisupport/actioncollection.h @@ -20,10 +20,9 @@ * This is a subset of the API of KDE's KActionCollection. * ***************************************************************************/ -#ifndef ACTIONCOLLECTION_H_ -#define ACTIONCOLLECTION_H_ +#pragma once -#ifndef HAVE_KDE4 +#ifndef HAVE_KDE #include #include @@ -123,9 +122,12 @@ private: int ActionCollection::count() const { return actions().count(); } bool ActionCollection::isEmpty() const { return actions().count(); } -#else /* HAVE_KDE4 */ - -#include +#else /* HAVE_KDE */ +# ifdef HAVE_KDE4 +# include +# else +# include +# endif class ActionCollection : public KActionCollection { @@ -135,7 +137,4 @@ public: explicit ActionCollection(QObject *parent) : KActionCollection(parent) {}; }; - -#endif - -#endif +#endif /* HAVE_KDE */ diff --git a/src/uisupport/bufferview.cpp b/src/uisupport/bufferview.cpp index 7973785e..d0921466 100644 --- a/src/uisupport/bufferview.cpp +++ b/src/uisupport/bufferview.cpp @@ -253,7 +253,6 @@ void BufferView::dropEvent(QDropEvent *event) if (bufferList.count() != 1) return QTreeView::dropEvent(event); - NetworkId networkId = bufferList[0].first; BufferId bufferId2 = bufferList[0].second; if (index.data(NetworkModel::ItemTypeRole) != NetworkModel::BufferItemType) @@ -262,9 +261,6 @@ void BufferView::dropEvent(QDropEvent *event) if (index.data(NetworkModel::BufferTypeRole) != BufferInfo::QueryBuffer) return QTreeView::dropEvent(event); - if (index.data(NetworkModel::NetworkIdRole).value() != networkId) - return QTreeView::dropEvent(event); - BufferId bufferId1 = index.data(NetworkModel::BufferIdRole).value(); if (bufferId1 == bufferId2) return QTreeView::dropEvent(event); diff --git a/src/uisupport/contextmenuactionprovider.cpp b/src/uisupport/contextmenuactionprovider.cpp index 0d9e483a..87d104fd 100644 --- a/src/uisupport/contextmenuactionprovider.cpp +++ b/src/uisupport/contextmenuactionprovider.cpp @@ -44,6 +44,7 @@ ContextMenuActionProvider::ContextMenuActionProvider(QObject *parent) : NetworkM registerAction(BufferRemove, tr("Delete Chat(s)...")); registerAction(BufferSwitchTo, tr("Go to Chat")); + registerAction(HideJoinPartQuit, tr("Joins/Parts/Quits")); registerAction(HideJoin, tr("Joins"), true); registerAction(HidePart, tr("Parts"), true); registerAction(HideQuit, tr("Quits"), true); @@ -92,6 +93,8 @@ ContextMenuActionProvider::ContextMenuActionProvider(QObject *parent) : NetworkM registerAction(ShowIgnoreList, tr("Show Ignore List")); QMenu *hideEventsMenu = new QMenu(); + hideEventsMenu->addAction(action(HideJoinPartQuit)); + hideEventsMenu->addSeparator(); hideEventsMenu->addAction(action(HideJoin)); hideEventsMenu->addAction(action(HidePart)); hideEventsMenu->addAction(action(HideQuit)); diff --git a/src/uisupport/flatproxymodel.cpp b/src/uisupport/flatproxymodel.cpp index 80d14f2b..bd6dcd08 100644 --- a/src/uisupport/flatproxymodel.cpp +++ b/src/uisupport/flatproxymodel.cpp @@ -204,8 +204,9 @@ QItemSelection FlatProxyModel::mapSelectionToSource(const QItemSelection &proxyS row++; } - Q_ASSERT(topLeftItem && bottomRightItem); // there should be one range left. - sourceSelection << QItemSelectionRange(mapToSource(createIndex(topLeftItem->pos(), left, topLeftItem)), mapToSource(createIndex(bottomRightItem->pos(), right, bottomRightItem))); + if (topLeftItem && bottomRightItem) { // there should be one range left. + sourceSelection << QItemSelectionRange(mapToSource(createIndex(topLeftItem->pos(), left, topLeftItem)), mapToSource(createIndex(bottomRightItem->pos(), right, bottomRightItem))); + } } return sourceSelection; diff --git a/src/uisupport/graphicalui.cpp b/src/uisupport/graphicalui.cpp index 0fb34b04..d1e106d1 100644 --- a/src/uisupport/graphicalui.cpp +++ b/src/uisupport/graphicalui.cpp @@ -146,6 +146,9 @@ bool GraphicalUi::eventFilter(QObject *obj, QEvent *event) } +// NOTE: Window activation stuff seems to work just fine in Plasma 5 without requiring X11 hacks. +// TODO: Evaluate cleaning all this up once we can get rid of Qt4/KDE4 + // Code taken from KStatusNotifierItem for handling minimize/restore bool GraphicalUi::checkMainWidgetVisibility(bool perform) diff --git a/src/uisupport/multilineedit.cpp b/src/uisupport/multilineedit.cpp index 48ffdbac..ed0dbb60 100644 --- a/src/uisupport/multilineedit.cpp +++ b/src/uisupport/multilineedit.cpp @@ -551,22 +551,18 @@ QString MultiLineEdit::convertRichtextToMircCodes() cursor.clearSelection(); } - if (color) { - color = false; + + if (color) mircText.append('\x03'); - } - if (underline) { - underline = false; + + if (underline) mircText.append('\x1f'); - } - if (italic) { - italic = false; + + if (italic) mircText.append('\x1d'); - } - if (bold) { - bold = false; + + if (bold) mircText.append('\x02'); - } return mircText; } diff --git a/src/uisupport/networkmodelcontroller.cpp b/src/uisupport/networkmodelcontroller.cpp index e4472380..a8946ede 100644 --- a/src/uisupport/networkmodelcontroller.cpp +++ b/src/uisupport/networkmodelcontroller.cpp @@ -307,6 +307,19 @@ void NetworkModelController::handleHideAction(ActionType type, QAction *action) { Q_UNUSED(action) + if (type == HideJoinPartQuit) { + bool anyChecked = NetworkModelController::action(HideJoin)->isChecked(); + anyChecked |= NetworkModelController::action(HidePart)->isChecked(); + anyChecked |= NetworkModelController::action(HideQuit)->isChecked(); + + // If any are checked, uncheck them all. + // If none are checked, check them all. + bool newCheckedState = !anyChecked; + NetworkModelController::action(HideJoin)->setChecked(newCheckedState); + NetworkModelController::action(HidePart)->setChecked(newCheckedState); + NetworkModelController::action(HideQuit)->setChecked(newCheckedState); + } + int filter = 0; if (NetworkModelController::action(HideJoin)->isChecked()) filter |= Message::Join | Message::NetsplitJoin; @@ -324,6 +337,7 @@ void NetworkModelController::handleHideAction(ActionType type, QAction *action) filter |= Message::Topic; switch (type) { + case HideJoinPartQuit: case HideJoin: case HidePart: case HideQuit: diff --git a/src/uisupport/networkmodelcontroller.h b/src/uisupport/networkmodelcontroller.h index 3f1b29fc..f83e23f3 100644 --- a/src/uisupport/networkmodelcontroller.h +++ b/src/uisupport/networkmodelcontroller.h @@ -64,6 +64,7 @@ public: HideMode = 0x0500, HideDayChange = 0x0600, HideTopic = 0x0700, + HideJoinPartQuit = 0xd00, HideUseDefaults = 0xe00, HideApplyToAll = 0xf00, diff --git a/src/uisupport/uistyle.cpp b/src/uisupport/uistyle.cpp index 944b6049..ea0cb19d 100644 --- a/src/uisupport/uistyle.cpp +++ b/src/uisupport/uistyle.cpp @@ -104,8 +104,22 @@ void UiStyle::loadStyleSheet() QString styleSheet; styleSheet += loadStyleSheet("file:///" + Quassel::findDataFilePath("stylesheets/default.qss")); styleSheet += loadStyleSheet("file:///" + Quassel::configDirPath() + "settings.qss"); - if (s.value("UseCustomStyleSheet", false).toBool()) - styleSheet += loadStyleSheet("file:///" + s.value("CustomStyleSheetPath").toString(), true); + if (s.value("UseCustomStyleSheet", false).toBool()) { + QString customSheetPath(s.value("CustomStyleSheetPath").toString()); + QString customSheet = loadStyleSheet("file:///" + customSheetPath, true); + if (customSheet.isEmpty()) { + // MIGRATION: changed default install path for data from /usr/share/apps to /usr/share + if (customSheetPath.startsWith("/usr/share/apps/quassel")) { + customSheetPath.replace(QRegExp("^/usr/share/apps"), "/usr/share"); + customSheet = loadStyleSheet("file:///" + customSheetPath, true); + if (!customSheet.isEmpty()) { + s.setValue("CustomStyleSheetPath", customSheetPath); + qDebug() << "Custom stylesheet path migrated to" << customSheetPath; + } + } + } + styleSheet += customSheet; + } styleSheet += loadStyleSheet("file:///" + Quassel::optionValue("qss"), true); if (!styleSheet.isEmpty()) {