Merge pull request #107 from siduction-upstream/master
authorManuel Nickschas <sputnick@quassel-irc.org>
Wed, 18 Feb 2015 20:03:51 +0000 (21:03 +0100)
committerManuel Nickschas <sputnick@quassel-irc.org>
Wed, 18 Feb 2015 20:03:51 +0000 (21:03 +0100)
Set GIT_HEAD and GIT_DESCRIBE from environment

64 files changed:
.travis.yml
CMakeLists.txt
cmake/FindQCA2-QT5.cmake [new file with mode: 0644]
data/CMakeLists.txt
data/quassel.desktop
data/quasselclient.desktop
icons/import/import_oxygen.pl
icons/oxygen.qrc
src/CMakeLists.txt
src/client/CMakeLists.txt
src/client/client.cpp
src/client/client.h
src/client/clientauthhandler.cpp
src/client/clientsettings.cpp
src/client/clientsettings.h
src/client/coreconnection.cpp
src/client/coreconnection.h
src/common/CMakeLists.txt
src/common/abstractcliparser.h
src/common/cliparser.cpp
src/common/main.cpp
src/common/qt5cliparser.cpp [new file with mode: 0644]
src/common/qt5cliparser.h [new file with mode: 0644]
src/common/quassel.cpp
src/common/quassel.h
src/common/remotepeer.cpp
src/core/CMakeLists.txt
src/core/core.cpp
src/core/core.h
src/core/corenetwork.cpp
src/core/coresession.cpp
src/core/coresession.h
src/core/coreuserinputhandler.cpp
src/core/coreuserinputhandler.h
src/core/eventstringifier.cpp
src/core/sessionthread.cpp
src/core/sessionthread.h
src/qtui/CMakeLists.txt
src/qtui/aboutdlg.cpp
src/qtui/aboutdlg.h
src/qtui/chatviewsearchcontroller.h
src/qtui/knotificationbackend.cpp
src/qtui/knotificationbackend.h
src/qtui/mainwin.cpp
src/qtui/mainwin.h
src/qtui/qtuiapplication.cpp
src/qtui/settingspages/coreconnectionsettingspage.cpp
src/qtui/settingspages/coreconnectionsettingspage.ui
src/qtui/settingspages/highlightsettingspage.cpp
src/qtui/settingspages/networkssettingspage.cpp
src/qtui/statusnotifieritem.cpp
src/uisupport/CMakeLists.txt
src/uisupport/aboutdata.cpp [new file with mode: 0644]
src/uisupport/aboutdata.h [new file with mode: 0644]
src/uisupport/actioncollection.cpp
src/uisupport/actioncollection.h
src/uisupport/contextmenuactionprovider.cpp
src/uisupport/flatproxymodel.cpp
src/uisupport/graphicalui.cpp
src/uisupport/kcmdlinewrapper.cpp
src/uisupport/multilineedit.cpp
src/uisupport/networkmodelcontroller.cpp
src/uisupport/networkmodelcontroller.h
src/uisupport/uistyle.cpp

index defbb62..476319e 100644 (file)
@@ -26,4 +26,9 @@ script:
   - cd build
   - if [ "$QT_VERSION" = "qt4" ]; then cmake ..; fi
   - if [ "$QT_VERSION" = "qt5" ]; then source /opt/qt52/bin/qt52-env.sh && cmake  -DUSE_QT5=ON ..; fi
-  - make
\ No newline at end of file
+  - make
+
+matrix:
+  exclude:
+    - compiler: clang
+      env: QT_VERSION=qt4
index d9a397f..c65f6be 100644 (file)
@@ -6,7 +6,6 @@
 # General setup
 #####################################################################
 
-cmake_minimum_required(VERSION 2.8.9)  # You'll need at least 2.8.12 for KDE Frameworks integration
 project(QuasselIRC)
 
 # Versions
@@ -34,11 +33,6 @@ include(FeatureSummary)
 include(QuasselCompileSettings)
 include(QuasselMacros)
 
-# Setting COMPILE_DEFINITIONS_<CONFIG> 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_<CONFIG> 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
 #####################################################################
 
@@ -139,11 +149,7 @@ if (USE_QT5)
     add_definitions(-DHAVE_QT5)
 else()
     message(STATUS "Building for Qt4...")
-    if (BUILD_GUI)
-        set(QT_MIN_VERSION "4.6.0")
-    else()
-        set(QT_MIN_VERSION "4.4.0")
-    endif()
+    set(QT_MIN_VERSION "4.8.0")
 
     # Select a Qt installation here, if you don't want to use system Qt
     if(QT_PATH)
@@ -256,16 +262,17 @@ if (USE_QT5)
         endif()
 
         if (WITH_KDE)
-            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 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
@@ -276,14 +283,12 @@ if (USE_QT5)
             DESCRIPTION "the database support module for Qt5"
         )
 
-        # While QCA2 seems to support Qt5, it is not actually co-installable or distinguishable from the Qt4 version...
-        # In order to avoid linking against the Qt4 version (which is probably the one installed), disable this for now
-        #find_package(QCA2 QUIET)
-        #set_package_properties(QCA2 PROPERTIES TYPE RECOMMENDED
-        #    URL "https://projects.kde.org/projects/kdesupport/qca"
-        #    DESCRIPTION "Qt Cryptographic Architecture"
-        #    PURPOSE "Required for encryption support"
-        #)
+        find_package(QCA2-QT5)
+        set_package_properties(QCA2-QT5 PROPERTIES TYPE RECOMMENDED
+            URL "https://projects.kde.org/projects/kdesupport/qca"
+            DESCRIPTION "Qt Cryptographic Architecture"
+            PURPOSE "Required for encryption support"
+        )
 
     endif(BUILD_CORE)
 
@@ -292,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)
@@ -424,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
 #####################################################################
diff --git a/cmake/FindQCA2-QT5.cmake b/cmake/FindQCA2-QT5.cmake
new file mode 100644 (file)
index 0000000..0d28590
--- /dev/null
@@ -0,0 +1,48 @@
+# - Try to find QCA2 (Qt Cryptography Architecture 2) for QT5
+# Once done this will define
+#
+#  QCA2-QT5_FOUND - system has QCA2-QT5
+#  QCA2-QT5_INCLUDE_DIR - the QCA2-QT5 include directory
+#  QCA2-QT5_LIBRARIES - the libraries needed to use QCA2-QT5
+#  QCA2-QT5_DEFINITIONS - Compiler switches required for using QCA2-QT5
+#
+# use pkg-config to get the directories and then use these values
+# in the FIND_PATH() and FIND_LIBRARY() calls
+
+# Copyright (c) 2006, Michael Larouche, <michael.larouche@kdemail.net>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+include(FindLibraryWithDebug)
+
+if (QCA2-QT5_INCLUDE_DIR AND QCA2-QT5_LIBRARIES)
+
+  # in cache already
+  set(QCA2-QT5_FOUND TRUE)
+
+else (QCA2-QT5_INCLUDE_DIR AND QCA2-QT5_LIBRARIES)
+
+
+  if (NOT WIN32)
+    find_package(PkgConfig)
+    pkg_check_modules(PC_QCA2-QT5 QUIET qca2-qt5)
+    set(QCA2-QT5_DEFINITIONS ${PC_QCA2-QT5_CFLAGS_OTHER})
+  endif (NOT WIN32)
+
+  find_library_with_debug(QCA2-QT5_LIBRARIES
+                  WIN32_DEBUG_POSTFIX d
+                  NAMES qca-qt5
+                  HINTS ${PC_QCA2-QT5_LIBDIR} ${PC_QCA2-QT5_LIBRARY_DIRS}
+                  )
+
+  find_path(QCA2-QT5_INCLUDE_DIR QtCrypto
+            HINTS ${PC_QCA2-QT5_INCLUDEDIR} ${PC_QCA2-QT5_INCLUDE_DIRS}
+            PATH_SUFFIXES QtCrypto)
+
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(QCA2-QT5 DEFAULT_MSG QCA2-QT5_LIBRARIES QCA2-QT5_INCLUDE_DIR)
+
+  mark_as_advanced(QCA2-QT5_INCLUDE_DIR QCA2-QT5_LIBRARIES)
+
+endif (QCA2-QT5_INCLUDE_DIR AND QCA2-QT5_LIBRARIES)
index 04b322b..5c6762d 100644 (file)
@@ -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)
index 158b9b9..a067eb6 100644 (file)
@@ -73,3 +73,4 @@ Icon=quassel
 TryExec=quassel
 Exec=quassel
 Categories=Qt;Network;Chat;IRCClient;
+X-DBUS-ServiceName=org.quassel-irc.quassel
index c11cffe..5be24ce 100644 (file)
@@ -72,3 +72,4 @@ Icon=quassel
 TryExec=quasselclient
 Exec=quasselclient
 Categories=Qt;Network;Chat;IRCClient;
+X-DBUS-ServiceName=org.quassel-irc.quasselclient
index c6132d0..c6fb817 100755 (executable)
@@ -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>$File::Find::name</file>";
 }
index 3b01942..b451269 100644 (file)
@@ -1,5 +1,6 @@
 <RCC>
   <qresource prefix="/icons">
+    <file>oxygen/index.theme</file>
     <file>oxygen/22x22/actions/irc-voice.png</file>
     <file>oxygen/22x22/actions/go-next.png</file>
     <file>oxygen/22x22/actions/im-user.png</file>
index 2e24ea4..6221930 100644 (file)
@@ -30,6 +30,11 @@ if (WITH_OXYGEN)
     add_definitions(-DWITH_OXYGEN)
 endif()
 
+# For KAboutData
+if (WITH_KF5)
+    set(CLIENT_LIBRARIES ${CLIENT_LIBRARIES} KF5::CoreAddons)
+endif()
+
 # Needed for showing the cli option if appropriate
 if (HAVE_SYSLOG)
     add_definitions(-DHAVE_SYSLOG)
index 4f0106c..4eef7d5 100644 (file)
@@ -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()
index 7bbbefe..d8dbcbf 100644 (file)
@@ -48,6 +48,7 @@
 #include "quassel.h"
 #include "signalproxy.h"
 #include "util.h"
+#include "clientauthhandler.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -383,32 +384,39 @@ 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();
+
+    if ((Client::coreFeatures() & Quassel::PasswordChange)) {
+        p->attachSignal(this, SIGNAL(clientChangePassword(QString)));
+    }
+
+    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()));
@@ -645,6 +653,14 @@ void Client::markBufferAsRead(BufferId id)
         bufferSyncer()->requestMarkBufferAsRead(id);
 }
 
+void Client::changePassword(QString newPassword) {
+    CoreAccount account = currentCoreAccount();
+    account.setPassword(newPassword);
+    coreAccountModel()->createOrUpdateAccount(account);
+    coreAccountModel()->save();
+    emit clientChangePassword(newPassword);
+}
+
 
 #if QT_VERSION < 0x050000
 void Client::logMessage(QtMsgType type, const char *msg)
index 8c707f3..445648b 100644 (file)
@@ -191,6 +191,8 @@ signals:
      */
     void bufferMarkedAsRead(BufferId id);
 
+    void clientChangePassword(QString password);
+
 public slots:
     void disconnectFromCore();
 
@@ -200,6 +202,8 @@ public slots:
 
     void markBufferAsRead(BufferId id);
 
+    void changePassword(QString newPassword);
+
 private slots:
     void setSyncedToCore();
     void setDisconnectedFromCore();
index b8a62ef..7ed231c 100644 (file)
@@ -169,6 +169,7 @@ void ClientAuthHandler::onSocketConnected()
         _probing = true;
 
         QDataStream stream(socket()); // stream handles the endianness for us
+        stream.setVersion(QDataStream::Qt_4_2);
 
         quint32 magic = Protocol::magic;
 #ifdef HAVE_SSL
index c27e03a..dc8e5c1 100644 (file)
@@ -249,12 +249,10 @@ void CoreConnectionSettings::setNetworkDetectionMode(NetworkDetectionMode mode)
 
 CoreConnectionSettings::NetworkDetectionMode CoreConnectionSettings::networkDetectionMode()
 {
-#ifdef HAVE_KDE4
-    NetworkDetectionMode def = UseSolid;
-#else
-    NetworkDetectionMode def = UsePingTimeout;
-#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<NetworkDetectionMode>(mode);
 }
 
 
index 755667d..dd413e0 100644 (file)
@@ -124,7 +124,7 @@ class CoreConnectionSettings : public ClientSettings
 {
 public:
     enum NetworkDetectionMode {
-        UseSolid,
+        UseQNetworkConfigurationManager = 1, // UseSolid is gone
         UsePingTimeout,
         NoActiveDetection
     };
index a4e24e0..0e4b4f9 100644 (file)
@@ -57,10 +57,8 @@ 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)));
 
     CoreConnectionSettings s;
     s.initAndNotify("PingTimeoutInterval", this, SLOT(pingTimeoutIntervalChanged(QVariant)), 60);
@@ -127,16 +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) {
+            // If using QNetworkConfigurationManager, we don't want to reconnect if we're offline
+            if (s.networkDetectionMode() == CoreConnectionSettings::UseQNetworkConfigurationManager) {
+               if (!_qNetworkConfigurationManager->isOnline()) {
                     return;
-                }
+               }
             }
-#endif /* HAVE_KDE4 */
-
             reconnectToCore();
         }
     }
@@ -169,35 +163,26 @@ void CoreConnection::reconnectIntervalChanged(const QVariant &interval)
 }
 
 
-#ifdef HAVE_KDE4
-
-void CoreConnection::solidNetworkStatusChanged(Solid::Networking::Status status)
+void CoreConnection::onlineStateChanged(bool isOnline)
 {
     CoreConnectionSettings s;
-    if (s.networkDetectionMode() != CoreConnectionSettings::UseSolid)
+    if (s.networkDetectionMode() != CoreConnectionSettings::UseQNetworkConfigurationManager)
         return;
 
-    switch (status) {
-    case Solid::Networking::Unknown:
-    case Solid::Networking::Connected:
-        //qDebug() << "Solid: Network status changed to connected or unknown";
+    if(isOnline) {
+        // qDebug() << "QNetworkConfigurationManager reports Online";
         if (state() == Disconnected) {
             if (_wantReconnect && s.autoReconnect()) {
                 reconnectToCore();
             }
         }
-        break;
-    case Solid::Networking::Disconnecting:
-    case Solid::Networking::Unconnected:
+    } else {
+        // qDebug() << "QNetworkConfigurationManager reports Offline";
         if (state() != Disconnected && !isLocalConnection())
             disconnectFromCore(tr("Network is down"), true);
-        break;
-    default:
-        break;
     }
 }
 
-#endif
 
 bool CoreConnection::isEncrypted() const
 {
index c6b2e26..0019a53 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
-#ifndef CORECONNECTION_H_
-#define CORECONNECTION_H_
+#pragma once
 
-#include "QPointer"
-#include "QTimer"
+#include <QNetworkConfigurationManager>
+#include <QPointer>
+#include <QTimer>
 
 #ifdef HAVE_SSL
 #  include <QSslSocket>
 #  include <QTcpSocket>
 #endif
 
-#ifdef HAVE_KDE4
-#  include <Solid/Networking>
-#endif
-
 #include "coreaccount.h"
 #include "remotepeer.h"
 #include "types.h"
@@ -148,9 +144,7 @@ private slots:
     void reconnectIntervalChanged(const QVariant &interval);
     void reconnectTimeout();
 
-#ifdef HAVE_KDE4
-    void solidNetworkStatusChanged(Solid::Networking::Status status);
-#endif
+    void onlineStateChanged(bool isOnline);
 
 private:
     QPointer<ClientAuthHandler> _authHandler;
@@ -171,6 +165,8 @@ private:
     CoreAccount _account;
     CoreAccountModel *accountModel() const;
 
+    QPointer<QNetworkConfigurationManager> _qNetworkConfigurationManager;
+
     friend class CoreConfigWizard;
 };
 
@@ -186,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
index fa48020..90ccb5f 100644 (file)
@@ -9,7 +9,6 @@ set(SOURCES
     buffersyncer.cpp
     bufferviewconfig.cpp
     bufferviewmanager.cpp
-    cliparser.cpp
     compressor.cpp
     ctcpevent.cpp
     event.cpp
@@ -46,8 +45,13 @@ set(SOURCES
     coreinfo.h
 )
 
+if (USE_QT5)
+    list(APPEND SOURCES qt5cliparser.cpp)
+else()
+    list(APPEND SOURCES cliparser.cpp)
+endif()
 
-if (QCA2_FOUND)
+if (QCA2_FOUND OR QCA2-QT5_FOUND)
     set(SOURCES ${SOURCES} keyevent.cpp)
 endif()
 
index 2441a6e..293ccd9 100644 (file)
@@ -36,9 +36,9 @@ public:
     }
 
 
-    inline void addOption(const QString &longName, const char shortName = 0, const QString &help = QString(), const QString &def = QString())
+    inline void addOption(const QString &longName, const char shortName = 0, const QString &help = QString(), const QString &valueName = QString(), const QString &def = QString())
     {
-        addArgument(longName, CliParserArg(CliParserArg::CliArgOption, shortName, help, def));
+        addArgument(longName, CliParserArg(CliParserArg::CliArgOption, shortName, help, valueName, def));
     }
 
 
@@ -54,20 +54,21 @@ protected:
             CliArgOption
         };
 
-        CliParserArg(const CliArgType _type = CliArgInvalid, const char _shortName = 0, const QString _help = QString(), const QString _def = QString())
-            : type(_type),
-            shortName(_shortName),
-            help(_help),
-            def(_def),
-            value(QString()),
-            boolValue(false) {};
+        CliParserArg(const CliArgType type = CliArgInvalid, const char shortName = 0, const QString &help = QString(), const QString &valueName = QString(), const QString def = QString())
+            : type(type)
+            , shortName(shortName)
+            , help(help)
+            , valueName(valueName)
+            , def(def)
+            {};
 
         CliArgType type;
         char shortName;
         QString help;
+        QString valueName;
         QString def;
         QString value;
-        bool boolValue;
+        bool boolValue = false;
     };
 
     virtual void addArgument(const QString &longName, const CliParserArg &arg) = 0;
index ac70b4a..2e94e55 100644 (file)
@@ -32,10 +32,8 @@ CliParser::CliParser() : AbstractCliParser()
 }
 
 
-void CliParser::addArgument(const QString &longName_, const CliParserArg &arg)
+void CliParser::addArgument(const QString &longName, const CliParserArg &arg)
 {
-    QString longName = longName_;
-    longName.remove(QRegExp("\\s*<.*>\\s*")); // KCmdLineArgs takes args of the form "arg <defval>"
     if (argsMap.contains(longName)) qWarning() << "Warning: Multiple definition of argument" << longName;
     if (arg.shortName != 0 && !lnameOfShortArg(arg.shortName).isNull())
         qWarning().nospace() << "Warning: Redefining shortName '" << arg.shortName << "' for " << longName << " previously defined for " << lnameOfShortArg(arg.shortName);
@@ -189,8 +187,8 @@ void CliParser::usage()
         }
         else output.append("    ");
         lnameField.append(" --").append(arg.key());
-        if (arg.value().type == CliParserArg::CliArgOption) {
-            lnameField.append("=[").append(arg.key().toUpper()).append("]");
+        if (arg.value().type == CliParserArg::CliArgOption && !arg.value().valueName.isEmpty()) {
+            lnameField.append("=<").append(arg.value().valueName).append(">");
         }
         output.append(lnameField.leftJustified(lnameFieldSize));
         if (!arg.value().help.isEmpty()) {
index 6552598..6847371 100644 (file)
 
 #include <cstdlib>
 
+#include <QTextCodec>
+
 #ifdef BUILD_CORE
 #  include "coreapplication.h"
 #elif defined BUILD_QTUI
+#  include "aboutdata.h"
 #  include "qtuiapplication.h"
 #elif defined BUILD_MONO
+#  include "aboutdata.h"
 #  include "monoapplication.h"
 
 #else
 #if defined HAVE_KDE4 && defined BUILD_CORE
 #  undef HAVE_KDE4
 #endif
+// We don't want quasselcore to depend on KDE
+#if defined HAVE_KF5 && defined BUILD_CORE
+#  undef HAVE_KF5
+#endif
 
 #ifdef HAVE_KDE4
 #  include <KAboutData>
 #  include "kcmdlinewrapper.h"
+#elif defined HAVE_KF5
+#  include <KCoreAddons/KAboutData>
+#  include <KCoreAddons/Kdelibs4ConfigMigrator>
+#  include "qt5cliparser.h"
+#elif defined HAVE_QT5
+#  include "qt5cliparser.h"
+#else
+#  include "cliparser.h"
 #endif
 
 #if !defined(BUILD_CORE) && defined(STATIC)
@@ -47,13 +63,19 @@ Q_IMPORT_PLUGIN(qjpeg)
 Q_IMPORT_PLUGIN(qgif)
 #endif
 
-#include "cliparser.h"
 #include "quassel.h"
 
 int main(int argc, char **argv)
 {
+#if QT_VERSION < 0x050000
+    // All our source files are in UTF-8, and Qt5 even requires that
+    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
+    QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
+#endif
+
     Quassel::setupBuildInfo();
     QCoreApplication::setApplicationName(Quassel::buildInfo().applicationName);
+    QCoreApplication::setApplicationVersion(Quassel::buildInfo().plainVersionString);
     QCoreApplication::setOrganizationName(Quassel::buildInfo().organizationName);
     QCoreApplication::setOrganizationDomain(Quassel::buildInfo().organizationDomain);
 
@@ -81,11 +103,17 @@ 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
     // We need to init KCmdLineArgs first
-    // TODO: build an AboutData compat class to replace our aboutDlg strings
     KAboutData aboutData("quassel", "kdelibs4", ki18n("Quassel IRC"), Quassel::buildInfo().plainVersionString.toUtf8(),
         ki18n("A modern, distributed IRC client"));
     aboutData.addLicense(KAboutData::License_GPL_V2);
@@ -95,6 +123,8 @@ int main(int argc, char **argv)
     KCmdLineArgs::init(argc, argv, &aboutData);
 
     cliParser = new KCmdLineWrapper();
+#elif defined HAVE_QT5
+    cliParser = new Qt5CliParser();
 #else
     cliParser = new CliParser();
 #endif
@@ -102,41 +132,42 @@ int main(int argc, char **argv)
 
     // Initialize CLI arguments
     // NOTE: We can't use tr() at this point, since app is not yet created
+    // TODO: Change this once we get rid of KDE4 and can initialize the parser after creating the app
 
     // put shared client&core arguments here
     cliParser->addSwitch("debug", 'd', "Enable debug output");
     cliParser->addSwitch("help", 'h', "Display this help and exit");
     cliParser->addSwitch("version", 'v', "Display version information");
 #ifdef BUILD_QTUI
-    cliParser->addOption("configdir <path>", 'c', "Specify the directory holding the client configuration");
+    cliParser->addOption("configdir", 'c', "Specify the directory holding the client configuration", "path");
 #else
-    cliParser->addOption("configdir <path>", 'c', "Specify the directory holding configuration files, the SQlite database and the SSL certificate");
+    cliParser->addOption("configdir", 'c', "Specify the directory holding configuration files, the SQlite database and the SSL certificate", "path");
 #endif
-    cliParser->addOption("datadir <path>", 0, "DEPRECATED - Use --configdir instead");
+    cliParser->addOption("datadir", 0, "DEPRECATED - Use --configdir instead", "path");
 
 #ifndef BUILD_CORE
     // put client-only arguments here
-    cliParser->addOption("icontheme <theme>", 0, "Override the system icon theme ('oxygen' is recommended)");
-    cliParser->addOption("qss <file.qss>", 0, "Load a custom application stylesheet");
+    cliParser->addOption("icontheme", 0, "Override the system icon theme ('oxygen' is recommended)", "theme");
+    cliParser->addOption("qss", 0, "Load a custom application stylesheet", "file.qss");
     cliParser->addSwitch("debugbufferswitches", 0, "Enables debugging for bufferswitches");
     cliParser->addSwitch("debugmodel", 0, "Enables debugging for models");
     cliParser->addSwitch("hidewindow", 0, "Start the client minimized to the system tray");
 #endif
 #ifndef BUILD_QTUI
     // put core-only arguments here
-    cliParser->addOption("listen <address>[,<address[,...]]>", 0, "The address(es) quasselcore will listen on", "::,0.0.0.0");
-    cliParser->addOption("port <port>", 'p', "The port quasselcore will listen at", QString("4242"));
+    cliParser->addOption("listen", 0, "The address(es) quasselcore will listen on", "<address>[,<address>[,...]]", "::,0.0.0.0");
+    cliParser->addOption("port", 'p', "The port quasselcore will listen at", "port", "4242");
     cliParser->addSwitch("norestore", 'n', "Don't restore last core's state");
-    cliParser->addOption("loglevel <level>", 'L', "Loglevel Debug|Info|Warning|Error", "Info");
+    cliParser->addOption("loglevel", 'L', "Loglevel Debug|Info|Warning|Error", "level", "Info");
 #ifdef HAVE_SYSLOG
     cliParser->addSwitch("syslog", 0, "Log to syslog");
 #endif
-    cliParser->addOption("logfile <path>", 'l', "Log to a file");
-    cliParser->addOption("select-backend <backendidentifier>", 0, "Switch storage backend (migrating data if possible)");
+    cliParser->addOption("logfile", 'l', "Log to a file", "path");
+    cliParser->addOption("select-backend", 0, "Switch storage backend (migrating data if possible)", "backendidentifier");
     cliParser->addSwitch("add-user", 0, "Starts an interactive session to add a new core user");
-    cliParser->addOption("change-userpass <username>", 0, "Starts an interactive session to change the password of the user identified by username");
+    cliParser->addOption("change-userpass", 0, "Starts an interactive session to change the password of the user identified by <username>", "username");
     cliParser->addSwitch("oidentd", 0, "Enable oidentd integration");
-    cliParser->addOption("oidentd-conffile <file>", 0, "Set path to oidentd configuration file");
+    cliParser->addOption("oidentd-conffile", 0, "Set path to oidentd configuration file", "file");
 #ifdef HAVE_SSL
     cliParser->addSwitch("require-ssl", 0, "Require SSL for client connections");
 #endif
@@ -167,6 +198,15 @@ 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;
+    AboutData::setQuasselPersons(&aboutData);
+    KAboutData::setApplicationData(aboutData.kAboutData());
+#endif
+
+    if (!app.init())
+        return EXIT_FAILURE;
+
     return app.exec();
 }
diff --git a/src/common/qt5cliparser.cpp b/src/common/qt5cliparser.cpp
new file mode 100644 (file)
index 0000000..e224911
--- /dev/null
@@ -0,0 +1,72 @@
+/***************************************************************************
+ *   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 "qt5cliparser.h"
+
+#include <QCoreApplication>
+#include <QDebug>
+
+bool Qt5CliParser::init(const QStringList &arguments)
+{
+    _qCliParser.addHelpOption();
+    _qCliParser.addVersionOption();
+    _qCliParser.setApplicationDescription(QCoreApplication::translate("CliParser", "Quassel IRC is a modern, distributed IRC client."));
+
+    _qCliParser.process(arguments);
+    return true; // process() does error handling by itself
+}
+
+
+bool Qt5CliParser::isSet(const QString &longName)
+{
+
+    return _qCliParser.isSet(longName);
+}
+
+
+QString Qt5CliParser::value(const QString &longName)
+{
+    return _qCliParser.value(longName);
+}
+
+
+void Qt5CliParser::usage()
+{
+    _qCliParser.showHelp();
+}
+
+
+void Qt5CliParser::addArgument(const QString &longName, const AbstractCliParser::CliParserArg &arg)
+{
+    QStringList names(longName);
+    if (arg.shortName != 0)
+        names << QString(arg.shortName);
+
+    switch(arg.type) {
+    case CliParserArg::CliArgSwitch:
+        _qCliParser.addOption(QCommandLineOption(names, arg.help));
+        break;
+    case CliParserArg::CliArgOption:
+        _qCliParser.addOption(QCommandLineOption(names, arg.help, arg.valueName, arg.def));
+        break;
+    default:
+        qWarning() << "Warning: Unrecognized argument:" << longName;
+    }
+}
diff --git a/src/common/qt5cliparser.h b/src/common/qt5cliparser.h
new file mode 100644 (file)
index 0000000..1a7e788
--- /dev/null
@@ -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 <QCommandLineParser>
+
+#include "abstractcliparser.h"
+
+
+class Qt5CliParser : public AbstractCliParser
+{
+public:
+    bool init(const QStringList &arguments = QStringList());
+
+    QString value(const QString &longName);
+    bool isSet(const QString &longName);
+    void usage();
+
+private:
+    void addArgument(const QString &longName, const CliParserArg &arg);
+
+    QCommandLineParser _qCliParser;
+
+};
index c9da049..f43423c 100644 (file)
@@ -427,43 +427,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 +480,8 @@ QStringList Quassel::findDataDirPaths() const
             ++iter;
     }
 
+    dataDirNames.removeDuplicates();
+
     return dataDirNames;
 }
 
index bcfad07..30d3d35 100644 (file)
@@ -71,8 +71,9 @@ public:
         SaslAuthentication = 0x0002,
         SaslExternal = 0x0004,
         HideInactiveNetworks = 0x0008,
+        PasswordChange = 0x0010,
 
-        NumFeatures = 0x0008
+        NumFeatures = 0x0010
     };
     Q_DECLARE_FLAGS(Features, Feature);
 
index a3fb287..e8fa578 100644 (file)
@@ -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
 }
 
 
index a9ea5ee..43e6840 100644 (file)
@@ -54,6 +54,13 @@ if (QCA2_FOUND)
     list(APPEND LIBS ${QCA2_LIBRARIES})
 endif()
 
+if (QCA2-QT5_FOUND)
+    add_definitions(-DHAVE_QCA2)
+    include_directories(${QCA2-QT5_INCLUDE_DIR})
+    list(APPEND SOURCES cipher.cpp)
+    list(APPEND LIBS ${QCA2-QT5_LIBRARIES})
+endif()
+
 include_directories(${CMAKE_SOURCE_DIR}/src/common)
 
 set(CORE_RCS ${CORE_RCS} ${CMAKE_CURRENT_SOURCE_DIR}/sql.qrc)
index a86424f..dfd2c95 100644 (file)
@@ -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<UserId>(user);
+    foreach(UserId user, instance()->_sessions.keys())
+        activeSessions << QVariant::fromValue<UserId>(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<UserId>();
-            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,21 @@ 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();
+    connect(session, SIGNAL(passwordChangeRequested(UserId, QString)), _storage, SLOT(updateUser(UserId, QString)));
+    return session;
 }
 
 
index d544744..deef911 100644 (file)
@@ -524,13 +524,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 +543,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<CoreAuthHandler *> _connectingClients;
-    QHash<UserId, SessionThread *> sessions;
+    QHash<UserId, SessionThread *> _sessions;
     Storage *_storage;
     QTimer _storageSyncTimer;
 
index 1ba393f..7e9ce26 100644 (file)
@@ -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());
 
index 112aa85..1f6345d 100644 (file)
@@ -100,6 +100,8 @@ 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(clientChangePassword(QString)), this, SLOT(changePassword(QString)));
+
     loadSettings();
     initScriptEngine();
 
@@ -638,3 +640,8 @@ void CoreSession::globalAway(const QString &msg)
         net->userInputHandler()->issueAway(msg, false /* no force away */);
     }
 }
+
+void CoreSession::changePassword(QString password)
+{
+    emit passwordChangeRequested(_user, password);
+}
index 3eecc4b..0861b18 100644 (file)
@@ -132,6 +132,8 @@ public slots:
     //! Marks us away (or unaway) on all networks
     void globalAway(const QString &msg = QString());
 
+    void changePassword(QString password);
+
 signals:
     void initialized();
     void sessionState(const Protocol::SessionState &sessionState);
@@ -158,6 +160,8 @@ signals:
     void networkRemoved(NetworkId);
     void networkDisconnected(NetworkId);
 
+    void passwordChangeRequested(UserId user, QString password);
+
 protected:
     virtual void customEvent(QEvent *event);
 
index 6a53cad..33d1f67 100644 (file)
@@ -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)
 {
index dd9696c..69a429e 100644 (file)
@@ -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);
index afb70c2..943727c 100644 (file)
@@ -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
     }
 }
index c2f9b5a..1439bfc 100644 (file)
@@ -121,6 +121,7 @@ void SessionThread::addInternalClientToSession(InternalPeer *internalPeer)
 void SessionThread::run()
 {
     _session = new CoreSession(user(), _restoreState);
+    connect(_session, SIGNAL(passwordChangeRequested(UserId, QString)), SIGNAL(passwordChangeRequested(UserId, QString)));
     connect(this, SIGNAL(addRemoteClient(RemotePeer*)), _session, SLOT(addClient(RemotePeer*)));
     connect(this, SIGNAL(addInternalClient(InternalPeer*)), _session, SLOT(addClient(InternalPeer*)));
     connect(_session, SIGNAL(sessionState(Protocol::SessionState)), Core::instance(), SIGNAL(sessionState(Protocol::SessionState)));
index fee6e64..9a4a1b6 100644 (file)
@@ -57,6 +57,8 @@ signals:
     void addRemoteClient(RemotePeer *peer);
     void addInternalClient(InternalPeer *peer);
 
+    void passwordChangeRequested(UserId user, QString newPassword);
+
 private:
     CoreSession *_session;
     UserId _user;
index c9274a2..f17cd45 100644 (file)
@@ -81,13 +81,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})
index 68fd655..b5b7c76 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
+#include "aboutdlg.h"
+
 #include <QDateTime>
 #include <QIcon>
 
-#include "aboutdlg.h"
+#include "aboutdata.h"
 #include "quassel.h"
 
-AboutDlg::AboutDlg(QWidget *parent) : QDialog(parent)
+AboutDlg::AboutDlg(QWidget *parent)
+    : QDialog(parent)
+    , _aboutData(new AboutData(this))
 {
+    AboutData::setQuasselPersons(_aboutData);
+
     ui.setupUi(this);
     ui.quasselLogo->setPixmap(QIcon(":/icons/quassel-64.png").pixmap(64)); // don't let the icon theme affect our logo here
 
@@ -63,16 +69,14 @@ QString AboutDlg::about() const
 QString AboutDlg::authors() const
 {
     QString res;
-    res = tr("Quassel IRC is mainly developed by:") +
-          "<dl>"
-          "<dt><b>Manuel \"Sputnick\" Nickschas</b></dt><dd><a href=\"mailto:sput@quassel-irc.org\">sput@quassel-irc.org</a><br>"
-          "Project Founder, Lead Developer</dd>"
-          "<dt><b>Marcus \"EgS\" Eggenberger</b></dt><dd><a href=\"mailto:egs@quassel-irc.org\">egs@quassel-irc.org</a><br>"
-          "Project Motivator, Lead Developer, Mac Maintainer</dd>"
-          "<dt><b>Alexander \"phon\" von Renteln</b></dt><dd><a href=\"mailto:phon@quassel-irc.org\">phon@quassel-irc.org</a><br>"
-          "Developer, Windows Maintainer</dd>"
-          "</dl>";
-
+    res = tr("Quassel IRC is mainly developed by:") + "<dl>";
+    for (const auto &person : _aboutData->authors()) {
+        res.append("<dt><b>" + person.prettyName() + "</b></dt><dd>");
+        if (!person.emailAddress().isEmpty())
+            res.append("<a href=\"mailto:" + person.emailAddress() + "\">" + person.emailAddress() + "</a><br>");
+        res.append("<i>" + person.task() + "</i><br></dd>");
+    }
+    res.append("</dl>");
     return res;
 }
 
@@ -80,126 +84,11 @@ QString AboutDlg::authors() const
 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:")
-          + QString::fromUtf8("<br>"
-                              "<dl>"
-                              "<dt><b>Daniel \"al\" Albers</b></dt><dd>Master Of Translation, many fixes and enhancements</dd>"
-                              "<dt><b>Liudas Alisauskas</b></dt><dd>Lithuanian translation</dd>"
-                              "<dt><b>Terje \"tan\" Andersen</b></dt><dd>Norwegian translation, documentation</dd>"
-                              "<dt><b>Jens \"amiconn\" Arnold</b></dt><dd>Postgres migration fixes</dd>"
-                              "<dt><b>Adolfo Jayme Barrientos</b></dt><dd>Spanish translation</dd>"
-                              "<dt><b>Mattia Basaglia</b></dt><dd>Fixes</dd>"
-                              "<dt><b>Pete \"elbeardmorez\" Beardmore</b></dt><dd>Linewrap for input line</dd>"
-                              "<dt><b>Rafael \"EagleScreen\" Belmonte</b></dt><dd>Spanish translation</dd>"
-                              "<dt><b>Sergiu Bivol</b></dt><dd>Romanian translation</dd>"
-                              "<dt><b>Bruno Brigras</b></dt><dd>Crash fixes</dd>"
-                              "<dt><b>Florent Castelli</b></dt><dd>Sanitize topic handling</dd>"
-                              "<dt><b>Theo \"tampakrap\" Chatzimichos</b></dt><dd>Greek translation</dd>"
-                              "<dt><b>Yuri Chornoivan</b></dt><dd>Ukrainian translation</dd>"
-                              "<dt><b>Tomáš \"scarabeus\" Chvátal</b></dt><dd>Czech translation</dd>"
-                              "<dt><b>\"Condex\"</b></dt><dd>Galician translation</dd>"
-                              "<dt><b>Joshua \"tvakah\" Corbin</b></dt><dd>Various fixes</dd>"
-                              "<dt><b>\"cordata\"</b></dt><dd>Esperanto translation</dd>"
-                              "<dt><b>Matthias \"pennywise\" Coy</b></dt><dd>German translation</dd>"
-                              "<dt><b>\"derpella\"</b></dt><dd>Polish translation</dd>"
-                              "<dt><b>\"Dorian\"</b></dt><dd>French translation</dd>"
-                              "<dt><b>Luke Faraone</b></dt><dd>Doc fixes</dd>"
-                              "<dt><b>Chris \"stitch\" Fuenty</b></dt><dd>SASL support</dd>"
-                              "<dt><b>Kevin \"KRF\" Funk</b></dt><dd>German translation</dd>"
-                              "<dt><b>Fabiano \"elbryan\" Francesconi</b></dt><dd>Italian translation</dd>"
-                              "<dt><b>Leo Franchi</b></dt><dd>OSX improvements</dd>"
-                              "<dt><b>Sebastien Fricker</b></dt><dd>Audio backend improvements</dd>"
-                              "<dt><b>Alf Gaida</b></dt><dd>Language improvements</dd>"
-                              "<dt><b>Aurélien \"agateau\" Gâteau</b></dt><dd>Message Indicator support</dd>"
-                              "<dt><b>Marco \"kaffeedoktor\" Genise</b></dt><dd>Ideas, hacking, motivation</dd>"
-                              "<dt><b>Felix \"debfx\" Geyer</b></dt><dd>Certificate handling improvements</dd>"
-                              "<dt><b>Volkan Gezer</b></dt><dd>Turkish translation</dd>"
-                              "<dt><b>Sjors \"dazjorz\" Gielen</b></dt><dd>Fixes</dd>"
-                              "<dt><b>Sebastian \"seezer\" Goth</b></dt><dd>Many improvements and features</dd>"
-                              "<dt><b>Michael \"brot\" Groh</b></dt><dd>German translation, fixes</dd>"
-                              "<dt><b>\"Gryllida\"</b></dt><dd>IRC parser improvements</dd>"
-                              "<dt><b>H. İbrahim \"igungor\" Güngör</b></dt><dd>Turkish translation</dd>"
-                              "<dt><b>Jiri Grönroos</b></dt><dd>Finnish translation</dd>"
-                              "<dt><b>Chris \"Zren\" H</b></dt><dd>Various improvements</dd>"
-                              "<dt><b>Edward Hades</b></dt><dd>Russian translation</dd>"
-                              "<dt><b>John \"nox\" Hand</b></dt><dd>Former All-Seeing Eye logo</dd>"
-                              "<dt><b>Adam \"2kah\" Harwood</b></dt><dd>ChatView improvements</dd>"
-                              "<dt><b>Jonas \"Dante\" Heese</b></dt><dd>Project founder, various improvements</dd>"
-                              "<dt><b>Thomas \"Datafreak\" Hogh</b></dt><dd>Windows builder</dd>"
-                              "<dt><b>Johannes \"j0hu\" Huber</b></dt><dd>Many fixes and features, bug triaging</dd>"
-                              "<dt><b>Theofilos Intzoglou</b></dt><dd>Greek translation</dd>"
-                              "<dt><b>Jovan Jojkić</b></dt><dd>Serbian translation</dd>"
-                              "<dt><b>Allan Jude</b></dt><dd>Documentation improvements</dd>"
-                              "<dt><b>Michael \"ycros\" Kedzierski</b></dt><dd>Mac fixes</dd>"
-                              "<dt><b>Scott \"ScottK\" Kitterman<b></dt><dd>Kubuntu nightly packager, (packaging/build system) bughunter</dd>"
-                              "<dt><b>Paul \"Haudrauf\" Klumpp</b></dt><dd>Initial design and mainwindow layout</dd>"
-                              "<dt><b>Maia Kozheva</b></dt><dd>Russian translation</dd>"
-                              "<dt><b>Tae-Hoon Kwon</b></dt><dd>Korean translation</dd>"
-                              "<dt><b>\"Larso\"</b></dt><dd>Finnish translation</dd>"
-                              "<dt><b>Patrick \"bonsaikitten\" Lauer</b></dt><dd>Gentoo packaging</dd>"
-                              "<dt><b>Chris \"Fish-Face\" Le Sueur</b></dt><dd>Various fixes and improvements</dd>"
-                              "<dt><b>Jerome \"Adys\" Leclanche</b></dt><dd>Context menu fixes</dd>"
-                              "<dt><b>Hendrik \"nevcairiel\" Leppkes</b></dt><dd>Various features</dd>"
-                              "<dt><b>Jason Lynch</b></dt><dd>Bugfixes</dd>"
-                              "<dt><b>Awad \"firesock\" Mackie</b></dt><dd>ChatView improvements</dd>"
-                              "<dt><b>Michael \"mamarley\" Marley</b></dt><dd>Various fixes and improvements</dd>"
-                              "<dt><b>Martin \"m4yer\" Mayer</b></dt><dd>German translation</dd>"
-                              "<dt><b>Daniel \"hydrogen\" Meltzer</b></dt><dd>Various fixes and improvements</dd>"
-                              "<dt><b>Sebastian Meyer</b></dt><dd>Fixes</dd>"
-                              "<dt><b>Daniel E. Moctezuma</b></dt><dd>Japanese translation</dd>"
-                              "<dt><b>Chris \"kode54\" Moeller</b></dt><dd>Various fixes and improvements</dd>"
-                              "<dt><b>Thomas Müller</b></dt><dd>Fixes, Debian packaging</dd>"
-                              "<dt><b>Gábor \"ELITE_x\" Németh</b></dt><dd>Hungarian translation</dd>"
-                              "<dt><b>Per Nielsen</b></dt><dd>Danish translation</dd>"
-                              "<dt><b>J-P Nurmi</b></dt><dd>Fixes</dd>"
-                              "<dt><b>Marco \"Quizzlo\" Paolone</b></dt><dd>Italian translation</dd>"
-                              "<dt><b>Bas \"Tucos\" Pape</b></dt><dd>Many fixes and improvements, bug and patch triaging, tireless community support</dd>"
-                              "<dt><b>Bruno Patri</b></dt><dd>French translation</dd>"
-                              "<dt><b>Drew \"LinuxDolt\" Patridge</b></dt><dd>BluesTheme stylesheet</dd>"
-                              "<dt><b>Celeste \"seele\" Paul</b></dt><dd>Usability Queen</dd>"
-                              "<dt><b>Vit Pelcak</b></dt><dd>Czech translation</dd>"
-                              "<dt><b>Regis \"ZRegis\" Perrin</b></dt><dd>French translation</dd>"
-                              "<dt><b>Diego \"Flameeyes\" Petten&ograve;</b></dt><dd>Gentoo maintainer, build system improvements</dd>"
-                              "<dt><b>Simon Philips</b></dt><dd>Dutch translation</dd>"
-                              "<dt><b>Daniel \"billie\" Pielmeier</b></dt><dd>Gentoo maintainer</dd>"
-                              "<dt><b>Nuno \"pinheiro\" Pinheiro</b></dt><dd>Tons of Oxygen icons including our application icon</dd>"
-                              "<dt><b>David Planella</b></dt><dd>Translation system fixes</dd>"
-                              "<dt><b>Jure \"JLP\" Repinc</b></dt><dd>Slovenian translation</dd>"
-                              "<dt><b>Patrick \"TheOneRing\" von Reth</b></dt><dd>MinGW support, SNORE backend, Windows packager</dd>"
-                              "<dt><b>Dirk \"MarcLandis\" Rettschlag</b></dt><dd>Various fixes and new features</dd>"
-                              "<dt><b>Miguel Revilla</b></dt><dd>Spanish translation</dd>"
-                              "<dt><b>Jaak Ristioja</b></dt><dd>Fixes</dd>"
-                              "<dt><b>David \"Bombe\" Roden</b></dt><dd>Fixes</dd>"
-                              "<dt><b>Henning \"honk\" Rohlfs</b></dt><dd>Various fixes</dd>"
-                              "<dt><b>Stella \"differentreality\" Rouzi</b></dt><dd>Greek translation</dd>"
-                              "<dt><b>\"salnx\"</b></dt><dd>Highlight configuration improvements</dd>"
-                              "<dt><b>Martin \"sandsmark\" Sandsmark</b></dt><dd>Core fixes, Quasseldroid</dd>"
-                              "<dt><b>David Sansome</b></dt><dd>OSX Notification Center support</dd>"
-                              "<dt><b>Dennis \"DevUrandom\" Schridde</b></dt><dd>D-Bus notifications</dd>"
-                              "<dt><b>Jussi \"jussi01\" Schultink</b></dt><dd>Tireless tester, {ku|U}buntu tester and lobbyist, liters of delicious Finnish alcohol</dd>"
-                              "<dt><b>Tim \"xAFFE\" Schumacher</b></dt><dd>Fixes and feedback</dd>"
-                              "<dt><b>\"sfionov\"</b></dt><dd>Russian translation</dd>"
-                              "<dt><b>Harald \"apachelogger\" Sitter</b></dt><dd>{ku|U}buntu packager, motivator, promoter</dd>"
-                              "<dt><b>Ramanathan Sivagurunathan</b></dt><dd>Fixes</dd>"
-                              "<dt><b>Stefanos Sofroniou</b></dt><dd>Greek translation</dd>"
-                              "<dt><b>Rüdiger \"ruediger\" Sonderfeld</b></dt><dd>Emacs keybindings</dd>"
-                              "<dt><b>Alexander Stein</b></dt><dd>Tray icon fix</dd>"
-                              "<dt><b>Daniel \"son\" Steinmetz</b></dt><dd>Early beta tester and bughunter (on Vista&trade;!)</dd>"
-                              "<dt><b>Jesper Thomschütz</b></dt><dd>Various fixes</dd>"
-                              "<dt><b>Arthur \"roentgen\" Titeica</b></dt><dd>Romanian translation</dd>"
-                              "<dt><b>\"ToBeFree\"</b></dt><dd>German translation</dd>"
-                              "<dt><b>Edward \"Aides\" Toroshchin</b></dt><dd>Russian translation</dd>"
-                              "<dt><b>Adam \"adamt\" Tulinius</b></dt><dd>Early beta tester and bughunter, Danish translation</dd>"
-                              "<dt><b>Deniz Türkoglu</b></dt><dd>Mac fixes</dd>"
-                              "<dt><b>Frederik M.J. \"freqmod\" Vestre</b></dt><dd>Norwegian translation</dd>"
-                              "<dt><b>Atte Virtanen</b></dt><dd>Finnish translation</dd>"
-                              "<dt><b>Pavel \"int\" Volkovitskiy</b></dt><dd>Early beta tester and bughunter</dd>"
-                              "<dt><b>Roscoe van Wyk</b></dt><dd>Fixes</dd>"
-                              "<dt><b>Zé</b></dt><dd>Portuguese translation</dd>"
-                              "<dt><b>Benjamin \"zbenjamin\" Zeller</b></dt><dd>Windows build system fixes</dd>"
-                              "<dt><b>\"zeugma\"</b></dt><dd>Turkish translation</dd>"
-                              "</dl><br>"
-                              "...and anybody else finding and reporting bugs, giving feedback, helping others and being part of the community!");
+    res = tr("We would like to thank the following contributors (in alphabetical order) and everybody we forgot to mention here:") + "<br><dl>";
+    for (const auto &person : _aboutData->credits()) {
+        res.append("<dt><b>" + person.prettyName() + "</b></dt><dd><i>" + person.task() + "</i><br></dd>");
+    }
+    res.append("</dl>" + tr("...and anybody else finding and reporting bugs, giving feedback, helping others and being part of the community!"));
 
     return res;
 }
@@ -211,13 +100,13 @@ QString AboutDlg::thanksTo() const
     res = tr("Special thanks goes to:<br>"
              "<dl>"
              "<dt><img src=\":/pics/quassel-eye.png\">&nbsp;<b>John \"nox\" Hand</b></dt>"
-             "<dd>for the original Quassel icon - The All-Seeing Eye</dt>"
+             "<dd><i>for the original Quassel icon - The All-Seeing Eye</i><br></dt>"
              "<dt><img src=\":/pics/oxygen.png\">&nbsp;<b><a href=\"http://www.oxygen-icons.org\">The Oxygen Team</a></b></dt>"
-             "<dd>for creating all the artwork you see throughout Quassel</dd>"
+             "<dd><i>for creating all the artwork you see throughout Quassel</i><br></dd>"
              "<dt><img src=\":/pics/qt-logo-32.png\">&nbsp;<b><a href=\"http://www.trolltech.com\">Qt Software formerly known as Trolltech</a></b></dt>"
-             "<dd>for creating Qt and Qtopia, and for sponsoring development of QuasselTopia with Greenphones and more</dd>"
+             "<dd><i>for creating Qt and Qtopia, and for sponsoring development of QuasselTopia with Greenphones and more</i><br></dd>"
              "<dt><a href=\"http://www.nokia.com\"><img src=\":/pics/nokia.png\"></a></b></dt>"
-             "<dd>for keeping Qt alive, and for sponsoring development of Quassel Mobile with N810s</dd>"
+             "<dd><i>for sponsoring development of Quassel Mobile with N810s</i></dd>"
         );
 
     return res;
index d9fe3c2..d54df8c 100644 (file)
@@ -25,6 +25,8 @@
 
 #include "ui_aboutdlg.h"
 
+class AboutData;
+
 class AboutDlg : public QDialog
 {
     Q_OBJECT
@@ -39,6 +41,8 @@ private:
     QString authors() const;
     QString contributors() const;
     QString thanksTo() const;
+
+    AboutData *_aboutData;
 };
 
 
index 294693d..2ad0eda 100644 (file)
@@ -21,7 +21,7 @@
 #ifndef CHATVIEWSEARCHCONTROLLER_H
 #define CHATVIEWSEARCHCONTROLLER_H
 
-#include <QObject>
+#include <QGraphicsItem>
 #include <QHash>
 #include <QPointer>
 #include <QString>
@@ -87,11 +87,11 @@ private:
 
 
 // Highlight Items
-#include <QGraphicsItem>
-
 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
index 41d5638..1b09927 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
-#include <KNotification>
-#include <KNotifyConfigWidget>
+#include "knotificationbackend.h"
+
 #include <QIcon>
 #include <QTextDocument>
 #include <QVBoxLayout>
 
-#include "knotificationbackend.h"
+#ifdef HAVE_KDE4
+#  include <KNotification>
+#  include <KNotifyConfigWidget>
+#else
+#  include <KNotifications/KNotification>
+#  include <KNotifyConfig/KNotifyConfigWidget>
+#endif
 
 #include "client.h"
 #include "mainwin.h"
index 2f21c9e..25abcf9 100644 (file)
@@ -18,8 +18,7 @@
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
-#ifndef KNOTIFICATIONBACKEND_H_
-#define KNOTIFICATIONBACKEND_H_
+#pragma once
 
 #include <QPointer>
 
@@ -52,7 +51,7 @@ private:
     void removeNotificationById(uint id);
     void updateToolTip();
 
-    QList<QPair<uint, QPointer<KNotification> > > _notifications;
+    QList<QPair<uint, QPointer<KNotification>>> _notifications;
 };
 
 
@@ -72,6 +71,3 @@ private slots:
 private:
     KNotifyConfigWidget *_widget;
 };
-
-
-#endif
index cd4a5fe..84c3159 100644 (file)
 #include <QMessageBox>
 #include <QStatusBar>
 #include <QToolBar>
+#include <QInputDialog>
 
 #ifdef HAVE_KDE4
-#  include <KAction>
-#  include <KActionCollection>
 #  include <KHelpMenu>
 #  include <KMenuBar>
 #  include <KShortcutsDialog>
 #  include <KStatusBar>
 #  include <KToggleFullScreenAction>
 #  include <KToolBar>
-#  include <KWindowSystem>
+#endif
+
+#ifdef HAVE_KF5
+#  include <KConfigWidgets/KStandardAction>
+#  include <KXmlGui/KHelpMenu>
+#  include <KXmlGui/KShortcutsDialog>
+#  include <KXmlGui/KToolBar>
+#  include <KWidgetsAddons/KToggleFullScreenAction>
 #endif
 
 #ifdef Q_WS_X11
@@ -93,7 +99,7 @@
 #include "topicwidget.h"
 #include "verticaldock.h"
 
-#ifndef HAVE_KDE4
+#ifndef HAVE_KDE
 #  ifdef HAVE_PHONON
 #    include "phononnotificationbackend.h"
 #  endif
 #  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"
 #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
@@ -192,6 +197,8 @@ void MainWin::init()
     connect(Client::coreConnection(), SIGNAL(handleSslErrors(const QSslSocket *, bool *, bool *)), SLOT(handleSslErrors(const QSslSocket *, bool *, bool *)));
 #endif
 
+    connect(this, SIGNAL(changePassword(QString)), Client::instance(), SLOT(changePassword(QString)));
+
     // Setup Dock Areas
     setDockNestingEnabled(true);
     setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
@@ -214,7 +221,7 @@ void MainWin::init()
     setupTitleSetter();
     setupHotList();
 
-#ifndef HAVE_KDE4
+#ifndef HAVE_KDE
 #  ifdef HAVE_PHONON
     QtUi::registerNotificationBackend(new PhononNotificationBackend(this));
 #  endif
@@ -226,9 +233,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 +256,7 @@ void MainWin::init()
 
     setDisconnectedState(); // Disable menus and stuff
 
-#ifdef HAVE_KDE4
+#ifdef HAVE_KDE
     setAutoSaveSettings();
 #endif
 
@@ -295,7 +302,7 @@ void MainWin::saveStateToSettings(UiSettings &s)
     if (lastBufId.isValid())
         s.setValue("LastUsedBufferId", lastBufId.toInt());
 
-#ifdef HAVE_KDE4
+#ifdef HAVE_KDE
     saveAutoSaveSettings();
 #endif
 }
@@ -307,7 +314,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 +362,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(showChangePasswordDialog())));
     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 +390,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 +405,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 +517,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 +551,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 +559,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 +738,25 @@ void MainWin::changeActiveBufferView(int bufferViewId)
 }
 
 
+void MainWin::showChangePasswordDialog()
+{
+    if((Client::coreFeatures() & Quassel::PasswordChange)) {
+        bool ok;
+        QString newPassword = QInputDialog::getText(this, tr("Set Core Password"), tr("New password for your Quassel Core:"), QLineEdit::Password, QString(), &ok);
+        if (ok && !newPassword.isEmpty()) {
+            emit changePassword(newPassword);
+        }
+    }
+    else {
+        QMessageBox box(QMessageBox::Warning, tr("Feature Not Supported"),
+                        tr("<b>Your Quassel Core does not support this feature</b>"),
+                        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 +947,7 @@ void MainWin::setupTopicWidget()
 void MainWin::setupViewMenuTail()
 {
     _viewMenu->addSeparator();
-    _viewMenu->addAction(QtUi::actionCollection("General")->action("ToggleFullScreen"));
+    _viewMenu->addAction(_fullScreenAction);
 }
 
 
@@ -998,7 +1028,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 +1079,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 +1196,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 +1395,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 +1419,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<KToggleFullScreenAction *>(action);
-    kAct->setFullScreen(this, kAct->isChecked());
+#ifdef HAVE_KDE
+    static_cast<KToggleFullScreenAction*>(_fullScreenAction)->setFullScreen(this, _fullScreenAction->isChecked());
 #else
-    if (action->isChecked())
+    if (_fullScreenAction->isChecked())
         setWindowState(windowState() | Qt::WindowFullScreen);
     else
         setWindowState(windowState() & ~Qt::WindowFullScreen);
index 30e5726..4444426 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
-#ifndef MAINWIN_H_
-#define MAINWIN_H_
+#pragma once
 
 #ifdef HAVE_KDE4
 #  include <KMainWindow>
+#elif defined HAVE_KF5
+#  include <KXmlGui/KMainWindow>
 #else
 #  include <QMainWindow>
 #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
 
@@ -164,12 +164,15 @@ private slots:
     void changeActiveBufferView(bool backwards);
     void changeActiveBufferView(int bufferViewId);
 
+    void showChangePasswordDialog();
+
 signals:
     void connectToCore(const QVariantMap &connInfo);
     void disconnectFromCore();
+    void changePassword(QString newPassword);
 
 private:
-#ifdef HAVE_KDE4
+#ifdef HAVE_KDE
     KHelpMenu *_kHelpMenu;
 #endif
 
@@ -203,6 +206,7 @@ private:
     ChatMonitorView *_chatMonitorView;
     TopicWidget *_topicWidget;
 
+    QAction *_fullScreenAction;
     QMenu *_fileMenu, *_networksMenu, *_viewMenu, *_bufferViewsMenu, *_settingsMenu, *_helpMenu, *_helpDebugMenu;
     QMenu *_toolbarMenu;
     QToolBar *_mainToolBar, *_chatViewToolBar, *_nickToolBar;
@@ -220,6 +224,3 @@ private:
 
     friend class QtUi;
 };
-
-
-#endif
index a279442..88b8bdb 100644 (file)
 #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 */
index a9d0bca..d73c010 100644 (file)
@@ -24,13 +24,10 @@ 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()));
 }
@@ -49,11 +46,7 @@ void CoreConnectionSettingsPage::widgetHasChanged()
 
 void CoreConnectionSettingsPage::defaults()
 {
-#ifdef HAVE_KDE4
-    setRadioButtons(CoreConnectionSettings::UseSolid);
-#else
-    setRadioButtons(CoreConnectionSettings::UsePingTimeout);
-#endif
+    setRadioButtons(CoreConnectionSettings::UseQNetworkConfigurationManager);
 
     SettingsPage::defaults();
 }
@@ -80,11 +73,9 @@ void CoreConnectionSettingsPage::save()
 void CoreConnectionSettingsPage::setRadioButtons(CoreConnectionSettings::NetworkDetectionMode mode)
 {
     switch (mode) {
-#ifdef HAVE_KDE4
-    case CoreConnectionSettings::UseSolid:
-        ui.useSolid->setChecked(true);
+    case CoreConnectionSettings::UseQNetworkConfigurationManager:
+        ui.useQNetworkConfigurationManager->setChecked(true);
         break;
-#endif
     case CoreConnectionSettings::UsePingTimeout:
         ui.usePingTimeout->setChecked(true);
         break;
@@ -96,10 +87,8 @@ 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())
         return CoreConnectionSettings::UsePingTimeout;
 
index 0e0308d..1589184 100644 (file)
@@ -6,7 +6,7 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>446</width>
+    <width>476</width>
     <height>465</height>
    </rect>
   </property>
      </property>
      <layout class="QVBoxLayout" name="verticalLayout">
       <item>
-       <widget class="QRadioButton" name="useSolid">
+       <widget class="QRadioButton" name="useQNetworkConfigurationManager">
         <property name="toolTip">
-         <string>Rely on KDE's hardware layer to detect if we're online. Recommended for most KDE users</string>
+         <string>Rely on Qt's network configuration manager to detect if we're online</string>
         </property>
         <property name="text">
-         <string>Use KDE's network status detection (via Solid)</string>
+         <string>Automatic</string>
         </property>
         <property name="checked">
          <bool>false</bool>
      <item>
       <widget class="QSpinBox" name="reconnectInterval">
        <property name="toolTip">
-        <string>Actively ping the remote core and disconnect if we didn't get a reply after a certain time</string>
+        <string>Interval between consecutive connection attempts</string>
        </property>
        <property name="suffix">
         <string> seconds</string>
    </item>
   </layout>
  </widget>
+ <tabstops>
+  <tabstop>useQNetworkConfigurationManager</tabstop>
+  <tabstop>usePingTimeout</tabstop>
+  <tabstop>pingTimeout</tabstop>
+  <tabstop>useNoTimeout</tabstop>
+  <tabstop>autoReconnect</tabstop>
+  <tabstop>reconnectInterval</tabstop>
+ </tabstops>
  <resources/>
  <connections>
   <connection>
index c932d9f..2fe2a0b 100644 (file)
@@ -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;
 }
index c9ba18a..011328d 100644 (file)
@@ -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);
index a1d2916..a75c325 100644 (file)
@@ -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
     }
 };
 
index c0d6e4b..37ea311 100644 (file)
@@ -1,6 +1,7 @@
 # Builds the uisupport module
 
 set(SOURCES
+    aboutdata.cpp
     abstractbuffercontainer.cpp
     abstractitemview.cpp
     action.cpp
@@ -58,5 +59,5 @@ if (WITH_KDE4)
 endif()
 
 if (WITH_KF5)
-    target_link_libraries(mod_uisupport 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
new file mode 100644 (file)
index 0000000..17356fd
--- /dev/null
@@ -0,0 +1,300 @@
+/***************************************************************************
+ *   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 "aboutdata.h"
+
+#include <QImage>
+
+#include "quassel.h"
+
+
+AboutPerson::AboutPerson(const QString &name, const QString &nick, const QString &task, const QString &emailAddress, QLocale::Language translatedLanguage)
+    : _name(name)
+    , _nick(nick)
+    , _task(task)
+    , _emailAddress(emailAddress)
+    , _language(translatedLanguage)
+{
+
+}
+
+
+QString AboutPerson::name() const
+{
+    return _name;
+}
+
+
+QString AboutPerson::nick() const
+{
+    return _nick;
+}
+
+
+QString AboutPerson::task() const
+{
+    return _task;
+}
+
+
+QString AboutPerson::emailAddress() const
+{
+    return _emailAddress;
+}
+
+
+QLocale::Language AboutPerson::translatedLanguage() const
+{
+    return _language;
+}
+
+
+QString AboutPerson::prettyName() const
+{
+    if (!name().isEmpty() && !nick().isEmpty())
+        return name() + " (" + nick() + ')';
+
+    if (name().isEmpty() && !nick().isEmpty())
+        return nick();
+
+    return name();
+}
+
+
+/**************************************************************************************************/
+
+
+AboutData::AboutData(QObject *parent)
+    : QObject(parent)
+{
+
+}
+
+
+QList<AboutPerson> AboutData::authors() const
+{
+    return _authors;
+}
+
+
+QList< AboutPerson > AboutData::credits() const
+{
+    return _credits;
+}
+
+
+AboutData &AboutData::addAuthor(const AboutPerson &author)
+{
+    _authors.append(author);
+    return *this;
+}
+
+
+AboutData &AboutData::addAuthors(std::initializer_list<AboutPerson> authors)
+{
+    _authors.append(authors);
+    return *this;
+}
+
+
+AboutData &AboutData::addCredit(const AboutPerson &credit)
+{
+    _credits.append(credit);
+    return *this;
+}
+
+
+AboutData &AboutData::addCredits(std::initializer_list<AboutPerson> credits)
+{
+    _credits.append(credits);
+    return *this;
+}
+
+#ifdef HAVE_KF5
+
+KAboutData AboutData::kAboutData() const
+{
+    KAboutData aboutData(
+        Quassel::buildInfo().applicationName,
+        tr("Quassel IRC"),
+        Quassel::buildInfo().plainVersionString
+    );
+    aboutData.addLicense(KAboutLicense::GPL_V2);
+    aboutData.addLicense(KAboutLicense::GPL_V3);
+    aboutData.setShortDescription(tr("A modern, distributed IRC client"));
+    aboutData.setProgramLogo(QVariant::fromValue(QImage(":/pics/quassel-logo.png")));
+    aboutData.setBugAddress("http://bugs.quassel-irc.org/projects/quassel-irc/issues/new");
+    aboutData.setOrganizationDomain(Quassel::buildInfo().organizationDomain.toUtf8());
+
+    for (const auto &person : authors()) {
+        aboutData.addAuthor(person.prettyName(), person.task(), person.emailAddress());
+    }
+
+    for (const auto &person : credits()) {
+        aboutData.addCredit(person.prettyName(), person.task(), person.emailAddress());
+    }
+
+    return aboutData;
+}
+
+#endif
+
+
+/**************************************************************************************************/
+
+/*
+ * NOTE: The list of contributors was retrieved from the Git history, but sometimes things fall
+ *       through the cracks... especially for translations, we don't have an easy way to track
+ *       contributors' names.
+ *       If you find wrong data for yourself, want your nickname and/or mail addresses added or
+ *       removed, or feel left out or unfairly credited, please don't hesitate to let us know! We
+ *       do want to credit everyone who has contributed to Quassel development.
+ */
+
+void AboutData::setQuasselPersons(AboutData *aboutData)
+{
+    aboutData->addAuthors({
+        { "Manuel Nickschas", "Sputnick", tr("Project Founder, Lead Developer"), "sputnick@quassel-irc.org" },
+        { "Marcus Eggenberger", "EgS", tr("Project Motivator, Lead Developer"), "egs@quassel-irc.org" },
+        { "Alexander von Renteln", "phon", tr("Former Lead Developer"), "phon@quassel-irc.org" },
+        { "Daniel Albers", "al", tr("Master of Translation, many fixes and enhancements") },
+        { "Sebastian Goth", "seezer", tr("Many features, fixes and improvements") },
+        { "Bas Pape", "Tucos", tr("Many fixes and improvements, bug and patch triaging, community support") },
+    });
+
+    aboutData->addCredits({
+        { "Adam Harwood", "2kah", tr("Chatview improvements") },
+        { "Adam Tulinius", "adamt", tr("Early beta tester and bughunter, Danish translation"), "", QLocale::Danish },
+        { "Adolfo Jayme Barrientos", "", tr("Spanish translation"), "", QLocale::Spanish },
+        { "Alexander Stein", "", tr("Tray icon fix") },
+        { "Alf Gaida", "agaida", tr("Language improvements") },
+        { "Allan Jude", "", tr("Documentation improvements") },
+        { "Arthur Titeica", "roentgen", tr("Romanian translation"), "", QLocale::Romanian },
+        { "Atte Virtanen", "", tr("Finnish translation"), "", QLocale::Finnish },
+        { "Aurélien Gâteau", "agateau", tr("Message indicator support") },
+        { "Awad Mackie", "firesock", tr("Chatview improvements") },
+        { "Benjamin Zeller", "zbenjamin", tr("Windows build system fixes") },
+        { "Bruno Brigras", "", tr("Crash fixes") },
+        { "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 Le Sueur", "Fish-Face", tr("Various fixes and improvements") },
+        { "Chris Moeller", "kode54", tr("Various fixes and improvements") },
+        { "", "Condex", tr("Galician translation"), "", QLocale::Galician },
+        { "", "cordata", tr("Esperanto translation"), "", QLocale::Esperanto },
+        { "Daniel E. Moctezuma", "", tr("Japanese translation"), "", QLocale::Japanese },
+        { "Daniel Meltzer", "hydrogen", tr("Various fixes and improvements") },
+        { "Daniel Pielmeier", "billie", tr("Gentoo maintainer") },
+        { "Daniel Steinmetz", "son", tr("Early beta tester and bughunter (on Vista™!)") },
+        { "David Planella", "", tr("Translation system fixes") },
+        { "David Sansome", "", tr("OSX Notification Center support") },
+        { "David Roden", "Bombe", tr("Fixes") },
+        { "Deniz Türkoglu", "", tr("Mac fixes") },
+        { "Dennis Schridde", "devurandom", tr("D-Bus notifications") },
+        { "", "derpella", tr("Polish translation"), "", QLocale::Polish },
+        { "Diego Pettenò", "Flameeyes", tr("Build system improvements") },
+        { "Dirk Rettschlag", "MarcLandis", tr("Formatting support and other input line improvements, many other fixes") },
+        { "", "Dorian", tr("French translation"), "", QLocale::French },
+        { "Drew Patridge", "LinuxDolt", tr("BluesTheme stylesheet") },
+        { "Edward Hades", "", tr("Russian translation"), "", QLocale::Russian },
+        { "Fabiano Francesconi", "elbryan", tr("Italian translation"), "", QLocale::Italian },
+        { "Felix Geyer", "debfx", tr("Certificate handling improvements") },
+        { "Florent Castelli", "", tr("Sanitize topic handling") },
+        { "Frederik M.J. Vestre", "freqmod", tr("Norwegian translation"), "", QLocale::Norwegian },
+        { "Gábor Németh", "ELITE_x", tr("Hungarian translation"), "", QLocale::Hungarian },
+        { "Gryllida A", "gry", tr("IRC parser improvements") },
+        { "H. İbrahim Güngör", "igungor", tr("Turkish translation"), "", QLocale::Turkish },
+        { "Harald Fernengel", "harryF", tr("Initial Qt5 support") },
+        { "Harald Sitter", "apachelogger", tr("{Ku|U}buntu packager, motivator, promoter") },
+        { "Hendrik Leppkes", "nevcairiel", tr("Various features") },
+        { "Henning Rohlfs", "honk", tr("Various fixes") },
+        { "J-P Nurmi", "", tr("Various fixes") },
+        { "Jaak Ristioja", "", tr("Bugfixes") },
+        { "Jason Lynch", "", tr("Bugfixes") },
+        { "Jens Arnold", "amiconn", tr("Postgres migration fixes") },
+        { "Jerome Leclanche", "Adys", tr("Context menu fixes") },
+        { "Jesper Thomschütz", "", tr("Various fixes") },
+        { "Jiri Grönroos", "", tr("Finnish translation"), "", QLocale::Finnish },
+        { "Johannes Huber", "johu", tr("Many fixes and improvements, bug triaging") },
+        { "John Hand", "nox", tr("Original \"All-Seeing Eye\" logo") },
+        { "Jonas Heese", "Dante", tr("Project founder, various improvements") },
+        { "Joshua T Corbin", "tvakah", tr("Various fixes") },
+        { "Jovan Jojkić", "", tr("Serbian translation"), "", QLocale::Serbian },
+        { "Jure Repinc", "JLP", tr("Slovenian translation"), "", QLocale::Slovenian },
+        { "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 },
+        { "", "Larso", tr("Finnish translation"), "", QLocale::Finnish },
+        { "Lasse Liehu", "", tr("Finnish translation"), "", QLocale::Finnish },
+        { "Leo Franchi", "", tr("OSX improvements") },
+        { "Liudas Alisauskas", "", tr("Lithuanian translation"), "", QLocale::Lithuanian },
+        { "Luke Faraone", "", tr("Documentation fixes") },
+        { "Maia Kozheva", "", tr("Russian translation"), "", QLocale::Russian },
+        { "Marco Genise", "kaffeedoktor", tr("Ideas, hacking, initial motivation") },
+        { "Marco Paolone", "Quizzlo", tr("Italian translation"), "", QLocale::Italian },
+        { "Martin Mayer", "m4yer", tr("German translation"), "", QLocale::German },
+        { "Martin Sandsmark", "sandsmark", tr("Core and other fixes, QuasselDroid") },
+        { "Matthias Coy", "pennywise", tr("German translation"), "", QLocale::German },
+        { "Mattia Basaglia", "", tr("Fixes") },
+        { "Michael Groh", "brot", tr("German translation, fixes"), "", QLocale::German },
+        { "Michael Kedzierski", "ycros", tr("Mac fixes") },
+        { "Michael Marley", "mamarley", tr("Many fixes and improvements; Ubuntu live packages") },
+        { "Miguel Revilla", "", tr("Spanish translation"), "", QLocale::Spanish },
+        { "Nuno Pinheiro", "", tr("Tons of Oxygen icons including the Quassel logo") },
+        { "Patrick Lauer", "bonsaikitten", tr("Gentoo maintainer") },
+        { "Patrick von Reth", "TheOneRing", tr("MinGW support, SNORE backend, Windows packaging") },
+        { "Paul Klumpp", "Haudrauf", tr("Initial design and main window layout") },
+        { "Pavel Volkovitskiy", "int", tr("Early beta tester and bughunter") },
+        { "Per Nielsen", "", tr("Danish translation"), "", QLocale::Danish },
+        { "Pete Beardmore", "elbeardmorez", tr("Linewrap for input line") },
+        { "Ramanathan Sivagurunathan", "", tr("Bugfixes") },
+        { "Regis Perrin", "ZRegis", tr("French translation"), "", QLocale::French },
+        { "Rolf Eike Beer", "", tr("Build system fixes") },
+        { "Roscoe van Wyk", "", tr("Bugfixes") },
+        { "Rüdiger Sonderfeld", "ruediger", tr("Emacs keybindings") },
+        { "", "salnx", tr("Highlight configuration improvements") },
+        { "Scott Kitterman", "ScottK", tr("Kubuntu packager, (packaging/build system) bughunter") },
+        { "Sebastian Meyer", "", tr("Bugfixes") },
+        { "Sebastien Fricker", "", tr("Audio backend improvements") },
+        { "", "sfionov", tr("Russian translation"), "", QLocale::Russian },
+        { "Simon Philips", "", tr("Dutch translation"), "", QLocale::Dutch },
+        { "Sjors Gielen", "dazjorz", tr("Bugfixes") },
+        { "Stefanos Sofroniou", "", tr("Greek translation"), "", QLocale::Greek },
+        { "Stella Rouzi", "differentreality", tr("Greek translation"), "", QLocale::Greek },
+        { "Rafael Belmonte", "EagleScreen", tr("Spanish translation"), "", QLocale::Spanish },
+        { "Sergiu Bivol", "", tr("Romanian translation"), "", QLocale::Romanian },
+        { "Tae-Hoon Kwon", "", tr("Korean translation"), "", QLocale::Korean },
+        { "Terje Andersen", "tan", tr("Norwegian translation, documentation") },
+        { "Theo Chatzimichos", "tampakrap", tr("Greek translation"), "", QLocale::Greek },
+        { "Theofilos Intzoglou", "", tr("Greek translation"), "", QLocale::Greek },
+        { "Thomas Hogh", "Datafreak", tr("Former Windows builder") },
+        { "Thomas Müller", "", tr("Fixes, Debian packaging") },
+        { "Tim Schumacher", "xAFFE", tr("Fixes and feedback") },
+        { "", "ToBeFree", tr("German translation"), "", QLocale::German },
+        { "Tomáš Chvátal", "scarabeus", tr("Czech translation"), "", QLocale::Czech },
+        { "Vit Pelcak", "", tr("Czech translation"), "", QLocale::Czech },
+        { "Volkan Gezer", "", tr("Turkish translation"), "", QLocale::Turkish },
+        { "Yaohan Chen", "hagabaka", tr("Network detection improvements") },
+        { "Yuri Chornoivan", "", tr("Ukrainian translation"), "", QLocale::Ukrainian },
+        { "Zé", "", tr("Portuguese translation"), "", QLocale::Portuguese },
+        { "", "zeugma", tr("Turkish translation"), "", QLocale::Turkish }
+    });
+}
diff --git a/src/uisupport/aboutdata.h b/src/uisupport/aboutdata.h
new file mode 100644 (file)
index 0000000..6c306be
--- /dev/null
@@ -0,0 +1,194 @@
+/***************************************************************************
+ *   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 <QLocale>
+
+#ifdef HAVE_KF5
+#  include <KCoreAddons/KAboutData>
+#endif
+
+
+/**
+ * Represents a contributor or author for Quassel.
+ *
+ * This is used to show a list of contributors in the About Quassel dialog.
+ */
+class AboutPerson
+{
+public:
+    /**
+     * Constructor.
+     *
+     * @param[in] name The person's name (in the form "Firstname Surname")
+     * @param[in] nick The person's nickname, if applicable
+     * @param[in] task Things the person does or has done for the project
+     * @param[in] emailAddress The person's email address, if applicable
+     * @param[in] translatedLanguage The language the person helped translate (only applicable for translators)
+     */
+    AboutPerson(const QString &name, const QString &nick, const QString &task, const QString &emailAddress = QString(), QLocale::Language translatedLanguage = QLocale::C);
+
+    /**
+     * Gets the person's name.
+     *
+     * @returns The person's name
+     */
+    QString name() const;
+
+    /**
+     * Gets the person's nick.
+     *
+     * @returns The person's nick
+     */
+    QString nick() const;
+
+    /**
+     * Gets the person's task.
+     *
+     * @returns The person's task
+     */
+    QString task() const;
+
+    /**
+     * Gets the person's e-mail address.
+     *
+     * @returns The person's e-mail address
+     */
+    QString emailAddress() const;
+
+    /**
+     * Gets the language this person helped translate.
+     *
+     * @returns The language this person helped translate
+     */
+    QLocale::Language translatedLanguage() const;
+
+    /**
+     * Gets the person's formatted name and nick.
+     *
+     * @returns The person's name and nick formatted for combined output
+     */
+    QString prettyName() const;
+
+private:
+    QString _name;               ///< The person's name
+    QString _nick;               ///< The person's nick
+    QString _task;               ///< The person's task
+    QString _emailAddress;       ///< The person's email address
+    QLocale::Language _language; ///< The language the person helps translate
+};
+
+
+/**
+ * Holds a list of authors, contributors and translators.
+ *
+ * This class is meant to hold the list of people who contributed to Quassel, used for displaying
+ * the About Quassel dialog. Additionally, this class can provide a KAboutData object to be shown
+ * if KDE integration is enabled.
+ */
+class AboutData : public QObject
+{
+    Q_OBJECT
+public:
+    /**
+     * Default constructor.
+     *
+     * @param[in] parent The parent object, if applicable
+     */
+    AboutData(QObject *parent = nullptr);
+
+    /**
+     * Adds an author to the list of contributors.
+     *
+     * Authors are people who contributed a significant amount of code to Quassel.
+     *
+     * @param[in] author The author to add
+     * @returns A reference to this AboutData instance
+     */
+    AboutData &addAuthor(const AboutPerson &author);
+
+    /**
+     * Adds a list of authors to the list of contributors.
+     *
+     * This method allows the use of a brace initializer in order to easily add a long list of
+     * people.
+     *
+     * @param[in] authors A list of authors to add
+     * @returns A reference to this AboutData instance
+     */
+    AboutData &addAuthors(std::initializer_list<AboutPerson> authors);
+
+    /**
+     * Adds a contributor.
+     *
+     * @param[in] author The contributor to add
+     * @returns A reference to this AboutData instance
+     */
+    AboutData &addCredit(const AboutPerson &credit);
+
+    /**
+     * Adds a list of contributors.
+     *
+     * This method allows the use of brace initializers in order to easily add a long list of
+     * people.
+     *
+     * @param[in] authors A list of contributors to add
+     * @returns A reference to this AboutData instance
+     */
+    AboutData &addCredits(std::initializer_list<AboutPerson> credits);
+
+    /**
+     * Gets the list of authors stored in this AboutData instance.
+     *
+     * @returns A list of authors
+     */
+    QList<AboutPerson> authors() const;
+
+    /**
+     * Gets the list of non-author contributors stored in this AboutData instance.
+     *
+     * @returns A list of contributors
+     */
+    QList<AboutPerson> credits() const;
+
+#ifdef HAVE_KF5
+    /**
+     * Creates a KAboutData instance based on the contents of this AboutData instance.
+     *
+     * @returns A KAboutData instance holding the list of contributors as well as any additional
+     *          data required for KAboutDialog and friends
+     */
+    KAboutData kAboutData() const;
+#endif
+
+    /**
+     * Fills the given AboutData instance with data relevant for Quassel itself.
+     *
+     * This method adds a (hardcoded) list of contributors to the given AboutData instance.
+     *
+     * @param[in,out] aboutData An existing AboutData instance to add Quassel's contributors to
+     */
+    static void setQuasselPersons(AboutData *aboutData);
+
+private:
+    QList<AboutPerson> _authors;  ///< The list of authors
+    QList<AboutPerson> _credits;  ///< The list of other contributors
+};
index b862ae8..593b236 100644 (file)
@@ -20,7 +20,7 @@
  * Parts of this implementation are based on KDE's KActionCollection.      *
  ***************************************************************************/
 
-#ifndef HAVE_KDE4
+#ifndef HAVE_KDE
 
 #include <QAction>
 #include <QDebug>
@@ -305,4 +305,4 @@ bool ActionCollection::unlistAction(QAction *action)
 }
 
 
-#endif /* HAVE_KDE4 */
+#endif /* HAVE_KDE */
index a76fc04..c920adc 100644 (file)
  * 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 <QDebug>
 #include <QList>
@@ -123,9 +122,12 @@ private:
 int ActionCollection::count() const { return actions().count(); }
 bool ActionCollection::isEmpty() const { return actions().count(); }
 
-#else /* HAVE_KDE4 */
-
-#include <KActionCollection>
+#else /* HAVE_KDE */
+#  ifdef HAVE_KDE4
+#    include <KActionCollection>
+#  else
+#    include <KXmlGui/KActionCollection>
+#  endif
 
 class ActionCollection : public KActionCollection
 {
@@ -135,7 +137,4 @@ public:
     explicit ActionCollection(QObject *parent) : KActionCollection(parent) {};
 };
 
-
-#endif
-
-#endif
+#endif /* HAVE_KDE */
index 0d9e483..87d104f 100644 (file)
@@ -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));
index 80d14f2..bd6dcd0 100644 (file)
@@ -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;
index 0fb34b0..d1e106d 100644 (file)
@@ -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)
index fc102cc..a263e3c 100644 (file)
@@ -27,11 +27,16 @@ KCmdLineWrapper::KCmdLineWrapper()
 }
 
 
-void KCmdLineWrapper::addArgument(const QString &longName, const CliParserArg &arg)
+void KCmdLineWrapper::addArgument(const QString &longName_, const CliParserArg &arg)
 {
+    QString longName = longName_;
+    if (arg.type == CliParserArg::CliArgOption && !arg.valueName.isEmpty())
+        longName += " <" + arg.valueName + ">";
+
     if (arg.shortName != 0) {
-        _cmdLineOptions.add(QByteArray().append(arg.shortName));
+        _cmdLineOptions.add(QByteArray(1, arg.shortName));
     }
+
     _cmdLineOptions.add(longName.toUtf8(), ki18n(arg.help.toUtf8()), arg.def.toUtf8());
 }
 
index 48ffdba..ed0dbb6 100644 (file)
@@ -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;
 }
index e447238..a8946ed 100644 (file)
@@ -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:
index 3f1b29f..f83e23f 100644 (file)
@@ -64,6 +64,7 @@ public:
         HideMode = 0x0500,
         HideDayChange = 0x0600,
         HideTopic = 0x0700,
+        HideJoinPartQuit = 0xd00,
         HideUseDefaults = 0xe00,
         HideApplyToAll = 0xf00,
 
index 944b604..ea0cb19 100644 (file)
@@ -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()) {