summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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));
+}