diff options
| -rw-r--r-- | QA/UnitTest/SConscript | 1 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatController.cpp | 5 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatController.h | 13 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatControllerBase.cpp | 32 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatControllerBase.h | 10 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/ChatsManager.cpp | 2 | ||||
| -rw-r--r-- | Swift/Controllers/Chat/MUCController.cpp | 2 | ||||
| -rw-r--r-- | Swift/Controllers/UIInterfaces/ChatWindow.h | 2 | ||||
| -rw-r--r-- | Swift/QtUI/QtChatWindow.cpp | 20 | ||||
| -rw-r--r-- | Swift/QtUI/QtChatWindow.h | 5 | ||||
| -rw-r--r-- | Swift/QtUI/QtUtilities.cpp | 15 | ||||
| -rw-r--r-- | Swift/QtUI/QtUtilities.h | 11 | ||||
| -rw-r--r-- | Swift/QtUI/SConscript | 15 | ||||
| -rw-r--r-- | Swift/QtUI/UnitTest/QtUtilitiesTest.cpp | 30 | 
14 files changed, 109 insertions, 54 deletions
| diff --git a/QA/UnitTest/SConscript b/QA/UnitTest/SConscript index 5dbd81c..5c19432 100644 --- a/QA/UnitTest/SConscript +++ b/QA/UnitTest/SConscript @@ -18,6 +18,7 @@ if env["TEST"] :          myenv.UseFlags(env.get("CPPUNIT_FLAGS",""))          myenv.UseFlags(env.get("GOOGLETEST_FLAGS", ""))          myenv.UseFlags(env.get("SWIFTEN_DEP_FLAGS", "")) +        myenv.UseFlags(env.get("SWIFT_QTUI_TEST_FLAGS", ""))          if env.get("HAVE_LIBXML") :              myenv.Append(CPPDEFINES = ["HAVE_LIBXML"])          if env.get("HAVE_EXPAT") : diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp index 8cbf059..d0ee891 100644 --- a/Swift/Controllers/Chat/ChatController.cpp +++ b/Swift/Controllers/Chat/ChatController.cpp @@ -26,6 +26,7 @@  #include <Swiften/Elements/DeliveryReceiptRequest.h>  #include <Swiften/Elements/Idle.h>  #include <Swiften/FileTransfer/FileTransferManager.h> +#include <Swiften/Network/TimerFactory.h>  #include <Swift/Controllers/Chat/ChatMessageParser.h>  #include <Swift/Controllers/FileTransfer/FileTransferController.h> @@ -51,8 +52,8 @@ namespace Swift {  /**   * The controller does not gain ownership of the stanzaChannel, nor the factory.   */ -ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider) -    : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, nickResolver, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), userWantsReceipts_(userWantsReceipts), settings_(settings), clientBlockListManager_(clientBlockListManager) { +ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider) +    : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, nickResolver, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), userWantsReceipts_(userWantsReceipts), settings_(settings), clientBlockListManager_(clientBlockListManager) {      isInMUC_ = isInMUC;      lastWasPresence_ = false;      chatStateNotifier_ = new ChatStateNotifier(stanzaChannel, contact, entityCapsProvider, timerFactory, 20000); diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h index 3c5656a..bae00c8 100644 --- a/Swift/Controllers/Chat/ChatController.h +++ b/Swift/Controllers/Chat/ChatController.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2017 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -19,18 +19,19 @@ namespace Swift {      class AvatarManager;      class ChatStateNotifier;      class ChatStateTracker; -    class NickResolver; +    class ClientBlockListManager;      class EntityCapsProvider;      class FileTransferController; -    class SettingsProvider; -    class HistoryController;      class HighlightManager; -    class ClientBlockListManager; +    class HistoryController; +    class NickResolver; +    class SettingsProvider; +    class TimerFactory;      class UIEvent;      class ChatController : public ChatControllerBase {          public: -            ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider); +            ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider);              virtual ~ChatController();              virtual void setToJID(const JID& jid) SWIFTEN_OVERRIDE;              virtual void setAvailableServerFeatures(std::shared_ptr<DiscoInfo> info) SWIFTEN_OVERRIDE; diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp index 5839d6c..f5865ea 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.cpp +++ b/Swift/Controllers/Chat/ChatControllerBase.cpp @@ -38,28 +38,22 @@  namespace Swift { -ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), timerFactory_(timerFactory), entityCapsProvider_(entityCapsProvider), historyController_(historyController), mucRegistry_(mucRegistry), chatMessageParser_(chatMessageParser), autoAcceptMUCInviteDecider_(autoAcceptMUCInviteDecider), eventStream_(eventStream) { +ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), entityCapsProvider_(entityCapsProvider), historyController_(historyController), mucRegistry_(mucRegistry), chatMessageParser_(chatMessageParser), autoAcceptMUCInviteDecider_(autoAcceptMUCInviteDecider), eventStream_(eventStream) {      chatWindow_ = chatWindowFactory_->createChatWindow(toJID, eventStream);      chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this));      chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1, _2)); -    chatWindow_->onLogCleared.connect(boost::bind(&ChatControllerBase::handleLogCleared, this)); +    chatWindow_->onContinuationsBroken.connect(boost::bind(&ChatControllerBase::handleContinuationsBroken, this));      entityCapsProvider_->onCapsChanged.connect(boost::bind(&ChatControllerBase::handleCapsChanged, this, _1));      highlighter_ = highlightManager->createHighlighter(nickResolver);      ChatControllerBase::setOnline(stanzaChannel->isAvailable() && iqRouter->isAvailable()); -    createDayChangeTimer();  }  ChatControllerBase::~ChatControllerBase() { -    if (dateChangeTimer_) { -        dateChangeTimer_->onTick.disconnect(boost::bind(&ChatControllerBase::handleDayChangeTick, this)); -        dateChangeTimer_->stop(); -    } -      delete highlighter_;      delete chatWindow_;  } -void ChatControllerBase::handleLogCleared() { +void ChatControllerBase::handleContinuationsBroken() {      cancelReplaces();  } @@ -81,26 +75,6 @@ void ChatControllerBase::setCanStartImpromptuChats(bool supportsImpromptu) {      }  } -void ChatControllerBase::createDayChangeTimer() { -    if (timerFactory_) { -        boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); -        boost::posix_time::ptime midnight(now.date() + boost::gregorian::days(1)); -        int millisecondsUntilMidnight = boost::numeric_cast<int>((midnight - now).total_milliseconds()); -        dateChangeTimer_ = timerFactory_->createTimer(millisecondsUntilMidnight); -        dateChangeTimer_->onTick.connect(boost::bind(&ChatControllerBase::handleDayChangeTick, this)); -        dateChangeTimer_->start(); -    } -} - -void ChatControllerBase::handleDayChangeTick() { -    dateChangeTimer_->stop(); -    boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); -    chatWindow_->addSystemMessage(chatMessageParser_->parseMessageBody(str(format(QT_TRANSLATE_NOOP("", "The day is now %1%")) % std::string(boost::posix_time::to_iso_extended_string(now)).substr(0,10))), ChatWindow::DefaultDirection); -    lastWasPresence_ = false; -    dayTicked(); -    createDayChangeTimer(); -} -  void ChatControllerBase::setEnabled(bool enabled) {      chatWindow_->setOnline(enabled);      chatWindow_->setCanInitiateImpromptuChats(false); diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h index 7f118bd..5ddda52 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.h +++ b/Swift/Controllers/Chat/ChatControllerBase.h @@ -23,8 +23,6 @@  #include <Swiften/Elements/Stanza.h>  #include <Swiften/JID/JID.h>  #include <Swiften/MUC/MUCRegistry.h> -#include <Swiften/Network/Timer.h> -#include <Swiften/Network/TimerFactory.h>  #include <Swiften/Presence/PresenceOracle.h>  #include <Swiften/Queries/IQRouter.h> @@ -74,7 +72,7 @@ namespace Swift {              boost::signals2::signal<void(ChatWindow* /*window to reuse*/, const std::vector<JID>& /*invite people*/, const std::string& /*reason*/)> onConvertToMUC;          protected: -            ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider); +            ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, EntityCapsProvider* entityCapsProvider, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, std::shared_ptr<ChatMessageParser> chatMessageParser, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider);              /**               * Pass the Message appended, and the stanza used to send it. @@ -103,16 +101,14 @@ namespace Swift {          private:              IDGenerator idGenerator_;              std::string lastSentMessageStanzaID_; -            void createDayChangeTimer();              void handleSendMessageRequest(const std::string &body, bool isCorrectionMessage);              void handleAllMessagesRead();              void handleSecurityLabelsCatalogResponse(std::shared_ptr<SecurityLabelsCatalog>, ErrorPayload::ref error); -            void handleDayChangeTick();              void handleMUCInvitation(Message::ref message);              void handleMediatedMUCInvitation(Message::ref message);              void handleGeneralMUCInvitation(MUCInviteEvent::ref event); -            void handleLogCleared(); +            void handleContinuationsBroken();          protected:              JID selfJID_; @@ -129,8 +125,6 @@ namespace Swift {              AvatarManager* avatarManager_;              bool useDelayForLatency_;              EventController* eventController_; -            std::shared_ptr<Timer> dateChangeTimer_; -            TimerFactory* timerFactory_;              EntityCapsProvider* entityCapsProvider_;              SecurityLabelsCatalog::Item lastLabel_;              HistoryController* historyController_; diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index fc96701..db3b3b7 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -747,7 +747,7 @@ ChatController* ChatsManager::getChatControllerOrFindAnother(const JID &contact)  ChatController* ChatsManager::createNewChatController(const JID& contact) {      assert(chatControllers_.find(contact) == chatControllers_.end());      std::shared_ptr<ChatMessageParser> chatMessageParser = std::make_shared<ChatMessageParser>(emoticons_, highlightManager_->getConfiguration(), ChatMessageParser::Mode::Chat); /* a message parser that knows this is a chat (not a room/MUC) */ -    ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, eventController_, timerFactory_, entityCapsProvider_, userWantsReceipts_, settings_, historyController_, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser, autoAcceptMUCInviteDecider_); +    ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, timerFactory_, eventController_, entityCapsProvider_, userWantsReceipts_, settings_, historyController_, mucRegistry_, highlightManager_, clientBlockListManager_, chatMessageParser, autoAcceptMUCInviteDecider_);      chatControllers_[contact] = controller;      controller->setAvailableServerFeatures(serverDiscoInfo_);      controller->onActivity.connect(boost::bind(&ChatsManager::handleChatActivity, this, contact, _1, false)); diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp index e65bfa6..a142ee0 100644 --- a/Swift/Controllers/Chat/MUCController.cpp +++ b/Swift/Controllers/Chat/MUCController.cpp @@ -99,7 +99,7 @@ MUCController::MUCController (          AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider,          VCardManager* vcardManager,          MUCBookmarkManager* mucBookmarkManager) : -    ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), nickResolver, presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), muc_(muc), nick_(nick), desiredNick_(nick), password_(password), renameCounter_(0), isImpromptu_(isImpromptu), isImpromptuAlreadyConfigured_(false), clientBlockListManager_(clientBlockListManager), mucBookmarkManager_(mucBookmarkManager) { +    ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), nickResolver, presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), muc_(muc), nick_(nick), desiredNick_(nick), password_(password), renameCounter_(0), isImpromptu_(isImpromptu), isImpromptuAlreadyConfigured_(false), clientBlockListManager_(clientBlockListManager), mucBookmarkManager_(mucBookmarkManager) {      assert(avatarManager_);      parting_ = true; diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h index f9c4164..8273802 100644 --- a/Swift/Controllers/UIInterfaces/ChatWindow.h +++ b/Swift/Controllers/UIInterfaces/ChatWindow.h @@ -264,7 +264,7 @@ namespace Swift {              boost::signals2::signal<void ()> onGetAffiliationsRequest;              boost::signals2::signal<void (MUCOccupant::Affiliation, const JID&)> onSetAffiliationRequest;              boost::signals2::signal<void (const std::vector<std::pair<MUCOccupant::Affiliation, JID> >& changes)> onChangeAffiliationsRequest; -            boost::signals2::signal<void ()> onLogCleared; +            boost::signals2::signal<void ()> onContinuationsBroken;              // File transfer related              boost::signals2::signal<void (std::string /* id */)> onFileTransferCancel; diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp index c509ab3..48d331e 100644 --- a/Swift/QtUI/QtChatWindow.cpp +++ b/Swift/QtUI/QtChatWindow.cpp @@ -36,6 +36,7 @@  #include <QTextDocument>  #include <QTextEdit>  #include <QTime> +#include <QTimer>  #include <QToolButton>  #include <QUrl> @@ -189,9 +190,20 @@ QtChatWindow::QtChatWindow(const QString& contact, QtChatTheme* theme, UIEventSt      settings_->onSettingChanged.connect(boost::bind(&QtChatWindow::handleSettingChanged, this, _1));      messageLog_->showEmoticons(settings_->getSetting(QtUISettingConstants::SHOW_EMOTICONS));      setMinimumSize(100, 100); + +    dayChangeTimer = new QTimer(this); +    dayChangeTimer->setSingleShot(true); +    connect(dayChangeTimer, &QTimer::timeout, [this](){ +        addSystemMessage(ChatMessage(Q2PSTRING(tr("The day is now %1").arg(QDateTime::currentDateTime().date().toString(Qt::SystemLocaleLongDate)))), ChatWindow::DefaultDirection); +        onContinuationsBroken(); +        resetDayChangeTimer(); +    }); + +    resetDayChangeTimer();  }  QtChatWindow::~QtChatWindow() { +    dayChangeTimer->stop();      settings_->onSettingChanged.disconnect(boost::bind(&QtChatWindow::handleSettingChanged, this, _1));      if (mucConfigurationWindow_) {          delete mucConfigurationWindow_.data(); @@ -206,7 +218,7 @@ void QtChatWindow::handleSettingChanged(const std::string& setting) {  }  void QtChatWindow::handleLogCleared() { -    onLogCleared(); +    onContinuationsBroken();  }  void QtChatWindow::handleOccupantSelectionChanged(RosterItem* item) { @@ -656,6 +668,12 @@ std::vector<JID> QtChatWindow::jidListFromQByteArray(const QByteArray& dataBytes      return invites;  } +void QtChatWindow::resetDayChangeTimer() { +    assert(dayChangeTimer); +    // Add a second so the handled is definitly called on the next day, and not multiple times exactly at midnight. +    dayChangeTimer->start(QtUtilities::secondsToNextMidnight(QDateTime::currentDateTime()) * 1000 + 1000); +} +  void QtChatWindow::setAvailableOccupantActions(const std::vector<OccupantAction>& actions) {      treeWidget_->setAvailableOccupantActions(actions);  } diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h index 46186ba..361d7c6 100644 --- a/Swift/QtUI/QtChatWindow.h +++ b/Swift/QtUI/QtChatWindow.h @@ -192,6 +192,8 @@ namespace Swift {              static std::vector<JID> jidListFromQByteArray(const QByteArray& dataBytes); +            void resetDayChangeTimer(); +          private:              int unreadCount_;              bool contactIsTyping_; @@ -219,7 +221,7 @@ namespace Swift {              bool tabCompletion_;              UIEventStream* eventStream_;              bool isOnline_; -            QSplitter *logRosterSplitter_; +            QSplitter* logRosterSplitter_;              Tristate correctionEnabled_;              Tristate fileTransferEnabled_;              QString alertStyleSheet_; @@ -238,5 +240,6 @@ namespace Swift {              std::unique_ptr<QMenu> emojisMenu_;              QPointer<QtEmojisSelector> emojisGrid_;              std::map<std::string, std::string> emoticonsMap_; +            QTimer* dayChangeTimer = nullptr;      };  } diff --git a/Swift/QtUI/QtUtilities.cpp b/Swift/QtUI/QtUtilities.cpp index 401af17..6eb0b04 100644 --- a/Swift/QtUI/QtUtilities.cpp +++ b/Swift/QtUI/QtUtilities.cpp @@ -1,10 +1,10 @@  /* - * Copyright (c) 2010-2015 Isode Limited. + * Copyright (c) 2010-2017 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ -#include "QtUtilities.h" +#include <Swift/QtUI/QtUtilities.h>  #include <QtGui>  #if defined (Q_OS_UNIX) && !defined(Q_OS_MAC) @@ -14,8 +14,9 @@  #endif  #include <QTextDocument>  #include <QWidget> +#include <QDateTime> -#include "Swift/Controllers/ApplicationInfo.h" +#include <Swift/Controllers/ApplicationInfo.h>  namespace QtUtilities { @@ -42,4 +43,12 @@ QString htmlEscape(const QString& s) {  #endif  } +long long secondsToNextMidnight(const QDateTime& currentTime) { +    auto secondsToMidnight = 0ll; +    auto nextMidnight = currentTime.addDays(1); +    nextMidnight.setTime(QTime(0,0)); +    secondsToMidnight = currentTime.secsTo(nextMidnight); +    return secondsToMidnight; +} +  } diff --git a/Swift/QtUI/QtUtilities.h b/Swift/QtUI/QtUtilities.h index ad58499..c6f4311 100644 --- a/Swift/QtUI/QtUtilities.h +++ b/Swift/QtUI/QtUtilities.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2013 Isode Limited. + * Copyright (c) 2010-2017 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -8,6 +8,7 @@  class QWidget;  class QString; +class QDateTime;  #include <QKeyEvent> @@ -19,4 +20,12 @@ namespace QtUtilities {      #else      const Qt::KeyboardModifier ctrlHardwareKeyModifier = Qt::ControlModifier;      #endif + +    /** +     * @brief secondsToNextMidnight calculates the seconds until next midnight. +     * @param currentTime This is the current time, which SHOULD have a Qt::TimeSpec +     * of Qt::LocalTime to correctly handle DST changes in the current locale. +     * @return +     */ +    long long secondsToNextMidnight(const QDateTime& currentTime);  } diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript index 2f95b3e..3ce2057 100644 --- a/Swift/QtUI/SConscript +++ b/Swift/QtUI/SConscript @@ -71,6 +71,21 @@ if env["PLATFORM"] != "win32" and env["PLATFORM"] != "darwin" :  myenv.EnableQt4Modules(qt4modules, debug = False, version = qt_version) + +## Qt related unit tests +testQtEnv = env.Clone(); +testQtEnv.Tool("qt4", toolpath = ["#/BuildTools/SCons/Tools"]) +testQtEnv.EnableQt4Modules(qt4modules, debug = False, version = qt_version) +env["SWIFT_QTUI_TEST_FLAGS"] = { +    "CPPFLAGS": testQtEnv["CPPFLAGS"], +    "LIBS": testQtEnv["LIBS"], +    "LINKFLAGS": testQtEnv["LINKFLAGS"], +} + +env.Append(UNITTEST_SOURCES = [ +    File("UnitTest/QtUtilitiesTest.cpp") +]) +  myenv.Append(CPPPATH = ["."])  # Qt requires applications to be build with the -fPIC flag on some 32-bit Linux distributions. diff --git a/Swift/QtUI/UnitTest/QtUtilitiesTest.cpp b/Swift/QtUI/UnitTest/QtUtilitiesTest.cpp new file mode 100644 index 0000000..45d2239 --- /dev/null +++ b/Swift/QtUI/UnitTest/QtUtilitiesTest.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <gtest/gtest.h> + +#include <QDateTime> +#include <QLocale> + +#include <Swift/QtUI/QtUtilities.h> +#include <Swift/QtUI/QtUtilities.cpp> + +TEST(QtUtilitiesTest, testDSTawareness) { +    QLocale::setDefault(QLocale(QLocale::English, QLocale::Germany)); + +    auto beforeDSTpoint = QDateTime(QDate(2017, 3, 26), QTime(0, 0)); + +    ASSERT_EQ(23 * 60 * 60, QtUtilities::secondsToNextMidnight(beforeDSTpoint)); +} + + +TEST(QtUtilitiesTest, testNoDSTChange) { +    QLocale::setDefault(QLocale(QLocale::English, QLocale::Germany)); + +    auto beforeDSTpoint = QDateTime(QDate(2017, 3, 23), QTime(0, 0)); + +    ASSERT_EQ(24 * 60 * 60, QtUtilities::secondsToNextMidnight(beforeDSTpoint)); +} | 
 Swift
 Swift