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)); +} |