summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2017-04-07 09:17:07 (GMT)
committerTobias Markmann <tm@ayena.de>2017-04-07 10:42:24 (GMT)
commited2226782ac15345aeb8e615b41d30e5aab67b51 (patch)
treea519ef4b314570fb134b969bb5fcff0e1f2be6e9
parent7d2e5e200d8449a4492c6fafa4811197e6fbe40b (diff)
downloadswift-ed2226782ac15345aeb8e615b41d30e5aab67b51.zip
swift-ed2226782ac15345aeb8e615b41d30e5aab67b51.tar.bz2
Make day change chat system message DST aware
Moved the code for day change message handling from Swift/Controllers to Swift/QtUI. Use QDateTime in local time time spec, which allows DST aware calculation of the duration to the next midnight. Added Swift Qt UI unit tests, which are build when Qt has been successfully detected. Test-Information: Added unit tests for duration to next midnight calculation. Set clock shortly before midnight and verified that a single day change message is added to the chat log at midnight. Tested on macOS 10.12.4 with Qt 5.4.2. Change-Id: I34d69eaa3272981fd220a7963a0417f73ff78e68
-rw-r--r--QA/UnitTest/SConscript1
-rw-r--r--Swift/Controllers/Chat/ChatController.cpp5
-rw-r--r--Swift/Controllers/Chat/ChatController.h13
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.cpp32
-rw-r--r--Swift/Controllers/Chat/ChatControllerBase.h10
-rw-r--r--Swift/Controllers/Chat/ChatsManager.cpp2
-rw-r--r--Swift/Controllers/Chat/MUCController.cpp2
-rw-r--r--Swift/Controllers/UIInterfaces/ChatWindow.h2
-rw-r--r--Swift/QtUI/QtChatWindow.cpp20
-rw-r--r--Swift/QtUI/QtChatWindow.h5
-rw-r--r--Swift/QtUI/QtUtilities.cpp15
-rw-r--r--Swift/QtUI/QtUtilities.h11
-rw-r--r--Swift/QtUI/SConscript15
-rw-r--r--Swift/QtUI/UnitTest/QtUtilitiesTest.cpp30
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));
+}