Moved the connection and configuration of XMPP to the log-in process.

This commit is contained in:
Dimitar Dobrev 2014-03-10 16:01:53 +02:00
parent 9eb217794c
commit 86643803cf
13 changed files with 208 additions and 82 deletions

View file

@ -34,12 +34,6 @@ if (APPLE)
endif (DARWIN_VERSION GREATER 12) endif (DARWIN_VERSION GREATER 12)
endif (APPLE) endif (APPLE)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/")
find_package(qxmpp REQUIRED)
add_definitions(-DQXMPP_STATIC)
include_directories(SYSTEM ${QXMPP_INCLUDE_DIR})
# targets not supported on windows # targets not supported on windows
if (NOT WIN32) if (NOT WIN32)
add_subdirectory(animation-server) add_subdirectory(animation-server)

View file

@ -29,10 +29,10 @@ else ()
if (QXMPP_FOUND) if (QXMPP_FOUND)
if (NOT QXMPP_FIND_QUIETLY) if (NOT QXMPP_FIND_QUIETLY)
message(STATUS "Found qxmpp: ${QXMPP_LIBRARY}") message(STATUS "Found qxmpp: ${QXMPP_LIBRARY}")
endif (NOT QXMPP_FIND_QUIETLY) endif ()
else () else ()
if (QXMPP_FIND_REQUIRED) if (QXMPP_FIND_REQUIRED)
message(FATAL_ERROR "Could not find qxmpp") message(FATAL_ERROR "Could not find qxmpp")
endif (SIXENSE_FIND_REQUIRED) endif ()
endif () endif ()
endif () endif ()

View file

@ -182,6 +182,7 @@ target_link_libraries(
${TARGET_NAME} ${TARGET_NAME}
"${FACESHIFT_LIBRARIES}" "${FACESHIFT_LIBRARIES}"
"${ZLIB_LIBRARIES}" "${ZLIB_LIBRARIES}"
"${QXMPP_LIBRARY}"
Qt5::Core Qt5::Gui Qt5::Multimedia Qt5::Network Qt5::OpenGL Qt5::Core Qt5::Gui Qt5::Multimedia Qt5::Network Qt5::OpenGL
Qt5::Script Qt5::Svg Qt5::WebKit Qt5::WebKitWidgets Qt5::Xml Qt5::UiTools Qt5::Script Qt5::Svg Qt5::WebKit Qt5::WebKitWidgets Qt5::Xml Qt5::UiTools
) )

View file

@ -45,7 +45,7 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="src/ui/ChatWindow.cpp" line="93"/> <location filename="src/ui/ChatWindow.cpp" line="100"/>
<source>day</source> <source>day</source>
<translation> <translation>
<numerusform>%n day</numerusform> <numerusform>%n day</numerusform>
@ -53,7 +53,7 @@
</translation> </translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="src/ui/ChatWindow.cpp" line="93"/> <location filename="src/ui/ChatWindow.cpp" line="100"/>
<source>hour</source> <source>hour</source>
<translation> <translation>
<numerusform>%n hour</numerusform> <numerusform>%n hour</numerusform>
@ -61,7 +61,7 @@
</translation> </translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="src/ui/ChatWindow.cpp" line="93"/> <location filename="src/ui/ChatWindow.cpp" line="100"/>
<source>minute</source> <source>minute</source>
<translation> <translation>
<numerusform>%n minute</numerusform> <numerusform>%n minute</numerusform>
@ -76,7 +76,7 @@
</translation> </translation>
</message> </message>
<message> <message>
<location filename="src/ui/ChatWindow.cpp" line="140"/> <location filename="src/ui/ChatWindow.cpp" line="150"/>
<source>%1 online now:</source> <source>%1 online now:</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -113,18 +113,18 @@
<context> <context>
<name>Menu</name> <name>Menu</name>
<message> <message>
<location filename="src/Menu.cpp" line="408"/> <location filename="src/Menu.cpp" line="414"/>
<source>Open .ini config file</source> <source>Open .ini config file</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/Menu.cpp" line="410"/> <location filename="src/Menu.cpp" line="416"/>
<location filename="src/Menu.cpp" line="422"/> <location filename="src/Menu.cpp" line="428"/>
<source>Text files (*.ini)</source> <source>Text files (*.ini)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/Menu.cpp" line="420"/> <location filename="src/Menu.cpp" line="426"/>
<source>Save .ini config file</source> <source>Save .ini config file</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>

View file

@ -26,6 +26,7 @@
#include <QWindow> #include <QWindow>
#include <AccountManager.h> #include <AccountManager.h>
#include <XmppClient.h>
#include <UUID.h> #include <UUID.h>
#include "Application.h" #include "Application.h"
@ -161,7 +162,12 @@ Menu::Menu() :
QMenu* toolsMenu = addMenu("Tools"); QMenu* toolsMenu = addMenu("Tools");
addActionToQMenuAndActionHash(toolsMenu, MenuOption::MetavoxelEditor, 0, this, SLOT(showMetavoxelEditor())); addActionToQMenuAndActionHash(toolsMenu, MenuOption::MetavoxelEditor, 0, this, SLOT(showMetavoxelEditor()));
addActionToQMenuAndActionHash(toolsMenu, MenuOption::FstUploader, 0, Application::getInstance(), SLOT(uploadFST())); addActionToQMenuAndActionHash(toolsMenu, MenuOption::FstUploader, 0, Application::getInstance(), SLOT(uploadFST()));
addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, 0, this, SLOT(showChat()));
_chatAction = addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, 0, this, SLOT(showChat()));
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
toggleChat();
connect(&xmppClient, SIGNAL(connected()), this, SLOT(toggleChat()));
connect(&xmppClient, SIGNAL(disconnected()), this, SLOT(toggleChat()));
QMenu* viewMenu = addMenu("View"); QMenu* viewMenu = addMenu("View");
@ -1039,6 +1045,13 @@ void Menu::showChat() {
_chatWindow->raise(); _chatWindow->raise();
} }
void Menu::toggleChat() {
_chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected());
if (!_chatAction->isEnabled() && _chatWindow) {
_chatWindow->close();
}
}
void Menu::audioMuteToggled() { void Menu::audioMuteToggled() {
QAction *muteAction = _actionHash.value(MenuOption::MuteAudio); QAction *muteAction = _actionHash.value(MenuOption::MuteAudio);
muteAction->setChecked(Application::getInstance()->getAudio()->getMuted()); muteAction->setChecked(Application::getInstance()->getAudio()->getMuted());

View file

@ -144,6 +144,7 @@ private slots:
void runTests(); void runTests();
void showMetavoxelEditor(); void showMetavoxelEditor();
void showChat(); void showChat();
void toggleChat();
void audioMuteToggled(); void audioMuteToggled();
private: private:
@ -204,6 +205,7 @@ private:
quint64 _lastAdjust; quint64 _lastAdjust;
SimpleMovingAverage _fpsAverage; SimpleMovingAverage _fpsAverage;
QAction* _loginAction; QAction* _loginAction;
QAction* _chatAction;
}; };
namespace MenuOption { namespace MenuOption {

View file

@ -0,0 +1,65 @@
//
// XmppClient.cpp
// interface
//
// Created by Dimitar Dobrev on 10/3/14
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include <AccountManager.h>
#include "XmppClient.h"
const QString DEFAULT_XMPP_SERVER = "chat.highfidelity.io";
const QString DEFAULT_CHAT_ROOM = "public@public-chat.highfidelity.io";
XmppClient::XmppClient() :
_xmppClient(),
_xmppMUCManager() {
AccountManager& accountManager = AccountManager::getInstance();
connect(&accountManager, SIGNAL(accessTokenChanged()), this, SLOT(connectToServer()));
connect(&accountManager, SIGNAL(logoutComplete()), this, SLOT(disconnectFromServer()));
}
XmppClient& XmppClient::getInstance() {
static XmppClient sharedInstance;
return sharedInstance;
}
void XmppClient::xmppConnected() {
_publicChatRoom = _xmppMUCManager.addRoom(DEFAULT_CHAT_ROOM);
_publicChatRoom->setNickName(AccountManager::getInstance().getUsername());
_publicChatRoom->join();
}
void XmppClient::xmppError(QXmppClient::Error error) {
qDebug() << "Error connnecting to XMPP for user " << AccountManager::getInstance().getUsername() << ": " << error;
}
void XmppClient::connectToServer() {
disconnectFromServer();
if (_xmppClient.addExtension(&_xmppMUCManager)) {
connect(&_xmppClient, SIGNAL(connected()), this, SLOT(xmppConnected()));
connect(&_xmppClient, SIGNAL(error(QXmppClient::Error)), this, SLOT(xmppError(QXmppClient::Error)));
}
AccountManager& accountManager = AccountManager::getInstance();
QString user = accountManager.getUsername();
const QString& password = accountManager.getXMPPPassword();
_xmppClient.connectToServer(user + "@" + DEFAULT_XMPP_SERVER, password);
}
void XmppClient::disconnectFromServer()
{
if (_xmppClient.isConnected()) {
_xmppClient.disconnectFromServer();
}
}
XmppClient::XmppClient(const XmppClient& other) {
Q_UNUSED(other);
}
void XmppClient::operator =(XmppClient const& other) {
Q_UNUSED(other);
}

View file

@ -0,0 +1,43 @@
//
// XmppClient.h
// interface
//
// Created by Dimitar Dobrev on 10/3/14
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef __interface__XmppClient__
#define __interface__XmppClient__
#include <QObject>
#include <QXmppClient.h>
#include <QXmppMucManager.h>
/// Generalized threaded processor for handling received inbound packets.
class XmppClient : public QObject {
Q_OBJECT
public:
static XmppClient& getInstance();
QXmppClient& getXMPPClient() { return _xmppClient; }
const QXmppMucRoom* getPublicChatRoom() const { return _publicChatRoom; }
private slots:
void xmppConnected();
void xmppError(QXmppClient::Error error);
void connectToServer();
void disconnectFromServer();
private:
XmppClient();
XmppClient(XmppClient const& other); // not implemented
void operator=(XmppClient const& other); // not implemented
QXmppClient _xmppClient;
QXmppMucManager _xmppMUCManager;
QXmppMucRoom* _publicChatRoom;
};
#endif // __interface__XmppClient__

View file

@ -16,17 +16,13 @@
#include <QTimer> #include <QTimer>
#include "ChatWindow.h" #include "ChatWindow.h"
#include "ui_chatwindow.h" #include "ui_chatWindow.h"
#include "FlowLayout.h" #include "FlowLayout.h"
#include "qtimespan.h" #include "qtimespan.h"
#include <QXmppClient.h>
#include <QXmppMessage.h>
#include <Application.h> #include <Application.h>
#include <AccountManager.h> #include <XmppClient.h>
const QString DEFAULT_SERVER = "chat.highfidelity.io";
const QString DEFAULT_CHAT_ROOM = "public@public-chat.highfidelity.io";
const int NUM_MESSAGES_TO_TIME_STAMP = 20; const int NUM_MESSAGES_TO_TIME_STAMP = 20;
const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)"); const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)");
@ -42,25 +38,34 @@ ChatWindow::ChatWindow() :
ui->messagePlainTextEdit->installEventFilter(this); ui->messagePlainTextEdit->installEventFilter(this);
ui->numOnlineLabel->hide();
ui->usersWidget->hide();
ui->messagesScrollArea->hide();
ui->messagePlainTextEdit->hide();
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
_xmppClient.addExtension(&_xmppMUCManager); const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
connect(&_xmppClient, SIGNAL(connected()), this, SLOT(connected())); if (xmppClient.isConnected()) {
connect(&_xmppClient, SIGNAL(error(QXmppClient::Error)), this, SLOT(error(QXmppClient::Error))); participantsChanged();
connect(&_xmppClient, SIGNAL(messageReceived(QXmppMessage)), this, SLOT(messageReceived(QXmppMessage))); const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
connect(publicChatRoom, SIGNAL(participantsChanged()), this, SLOT(participantsChanged()));
AccountManager& accountManager = AccountManager::getInstance(); ui->connectingToXMPPLabel->hide();
QString user = accountManager.getUsername(); startTimerForTimeStamps();
const QString& password = accountManager.getXMPPPassword(); }
_xmppClient.connectToServer(user + "@" + DEFAULT_SERVER, password); else {
ui->numOnlineLabel->hide();
ui->usersWidget->hide();
ui->messagesScrollArea->hide();
ui->messagePlainTextEdit->hide();
connect(&xmppClient, SIGNAL(connected()), this, SLOT(connected()));
}
connect(&xmppClient, SIGNAL(messageReceived(QXmppMessage)), this, SLOT(messageReceived(QXmppMessage)));
} }
ChatWindow::~ChatWindow() { ChatWindow::~ChatWindow() {
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
disconnect(&xmppClient, SIGNAL(connected()), this, SLOT(connected()));
disconnect(&xmppClient, SIGNAL(messageReceived(QXmppMessage)), this, SLOT(messageReceived(QXmppMessage)));
const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
disconnect(publicChatRoom, SIGNAL(participantsChanged()), this, SLOT(participantsChanged()));
delete ui; delete ui;
} }
@ -75,7 +80,8 @@ bool ChatWindow::eventFilter(QObject* sender, QEvent* event) {
(keyEvent->modifiers() & Qt::ShiftModifier) == 0) { (keyEvent->modifiers() & Qt::ShiftModifier) == 0) {
QString message = ui->messagePlainTextEdit->document()->toPlainText(); QString message = ui->messagePlainTextEdit->document()->toPlainText();
if (!message.trimmed().isEmpty()) { if (!message.trimmed().isEmpty()) {
_xmppClient.sendMessage(_chatRoom->jid(), message); const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
XmppClient::getInstance().getXMPPClient().sendMessage(publicChatRoom->jid(), message);
ui->messagePlainTextEdit->document()->clear(); ui->messagePlainTextEdit->document()->clear();
} }
return true; return true;
@ -84,7 +90,8 @@ bool ChatWindow::eventFilter(QObject* sender, QEvent* event) {
} }
QString ChatWindow::getParticipantName(const QString& participant) { QString ChatWindow::getParticipantName(const QString& participant) {
return participant.right(participant.count() - 1 - _chatRoom->jid().count()); const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
return participant.right(participant.count() - 1 - publicChatRoom->jid().count());
} }
void ChatWindow::addTimeStamp() { void ChatWindow::addTimeStamp() {
@ -107,22 +114,25 @@ void ChatWindow::addTimeStamp() {
numMessagesAfterLastTimeStamp = 0; numMessagesAfterLastTimeStamp = 0;
} }
void ChatWindow::connected() { void ChatWindow::startTimerForTimeStamps()
_chatRoom = _xmppMUCManager.addRoom(DEFAULT_CHAT_ROOM); {
connect(_chatRoom, SIGNAL(participantsChanged()), this, SLOT(participantsChanged())); QTimer* timer = new QTimer(this);
_chatRoom->setNickName(AccountManager::getInstance().getUsername()); timer->setInterval(10 * 60 * 1000);
_chatRoom->join(); connect(timer, SIGNAL(timeout()), this, SLOT(timeout()));
timer->start();
}
void ChatWindow::connected() {
ui->connectingToXMPPLabel->hide(); ui->connectingToXMPPLabel->hide();
ui->numOnlineLabel->show(); ui->numOnlineLabel->show();
ui->usersWidget->show(); ui->usersWidget->show();
ui->messagesScrollArea->show(); ui->messagesScrollArea->show();
ui->messagePlainTextEdit->show(); ui->messagePlainTextEdit->show();
QTimer* timer = new QTimer(this); const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom();
timer->setInterval(10 * 60 * 1000); connect(publicChatRoom, SIGNAL(participantsChanged()), this, SLOT(participantsChanged()));
connect(timer, SIGNAL(timeout()), this, SLOT(timeout()));
timer->start(); startTimerForTimeStamps();
} }
void ChatWindow::timeout() { void ChatWindow::timeout() {
@ -136,7 +146,7 @@ void ChatWindow::error(QXmppClient::Error error) {
} }
void ChatWindow::participantsChanged() { void ChatWindow::participantsChanged() {
QStringList participants = _chatRoom->participants(); QStringList participants = XmppClient::getInstance().getPublicChatRoom()->participants();
ui->numOnlineLabel->setText(tr("%1 online now:").arg(participants.count())); ui->numOnlineLabel->setText(tr("%1 online now:").arg(participants.count()));
while (QLayoutItem* item = ui->usersWidget->layout()->takeAt(0)) { while (QLayoutItem* item = ui->usersWidget->layout()->takeAt(0)) {

View file

@ -16,7 +16,7 @@
#include <Application.h> #include <Application.h>
#include <QXmppClient.h> #include <QXmppClient.h>
#include <QXmppMucManager.h> #include <QXmppMessage.h>
namespace Ui { namespace Ui {
class ChatWindow; class ChatWindow;
@ -34,12 +34,10 @@ protected:
private: private:
QString getParticipantName(const QString& participant); QString getParticipantName(const QString& participant);
void startTimerForTimeStamps();
void addTimeStamp(); void addTimeStamp();
Ui::ChatWindow* ui; Ui::ChatWindow* ui;
QXmppClient _xmppClient;
QXmppMucManager _xmppMUCManager;
QXmppMucRoom* _chatRoom;
int numMessagesAfterLastTimeStamp; int numMessagesAfterLastTimeStamp;
QDateTime lastMessageStamp; QDateTime lastMessageStamp;

View file

@ -40,7 +40,7 @@
#include <QtWidgets> #include <QtWidgets>
#include "flowlayout.h" #include "FlowLayout.h"
//! [1] //! [1]
FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing) FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
: QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing) : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)

View file

@ -32,4 +32,4 @@ if (UNIX AND NOT APPLE)
target_link_libraries(${TARGET_NAME} "${CMAKE_THREAD_LIBS_INIT}") target_link_libraries(${TARGET_NAME} "${CMAKE_THREAD_LIBS_INIT}")
endif (UNIX AND NOT APPLE) endif (UNIX AND NOT APPLE)
target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Xml "${QXMPP_LIBRARY}") target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Xml)

View file

@ -79,7 +79,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::TimeSpanFormat)
class QTimeSpanPrivate; class QTimeSpanPrivate;
class Q_CORE_EXPORT QTimeSpan class QTimeSpan
{ {
public: public:
QTimeSpan(); QTimeSpan();
@ -247,8 +247,8 @@ public:
private: private:
#ifndef QT_NO_DATASTREAM #ifndef QT_NO_DATASTREAM
friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QTimeSpan &); friend QDataStream &operator<<(QDataStream &, const QTimeSpan &);
friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QTimeSpan &); friend QDataStream &operator>>(QDataStream &, QTimeSpan &);
#endif #endif
QSharedDataPointer<QTimeSpanPrivate> d; QSharedDataPointer<QTimeSpanPrivate> d;
@ -258,40 +258,40 @@ Q_DECLARE_METATYPE(QTimeSpan);
Q_DECLARE_METATYPE(Qt::TimeSpanUnit); Q_DECLARE_METATYPE(Qt::TimeSpanUnit);
//non-member operators //non-member operators
Q_CORE_EXPORT QTimeSpan operator+(const QTimeSpan &left, const QTimeSpan &right); QTimeSpan operator+(const QTimeSpan &left, const QTimeSpan &right);
Q_CORE_EXPORT QTimeSpan operator-(const QTimeSpan &left, const QTimeSpan &right); QTimeSpan operator-(const QTimeSpan &left, const QTimeSpan &right);
Q_CORE_EXPORT QTimeSpan operator*(const QTimeSpan &left, qreal right);//no problem QTimeSpan operator*(const QTimeSpan &left, qreal right);//no problem
Q_CORE_EXPORT QTimeSpan operator*(const QTimeSpan &left, int right);//no problem QTimeSpan operator*(const QTimeSpan &left, int right);//no problem
inline QTimeSpan operator*(qreal left, const QTimeSpan &right) {return right * left;} // works inline QTimeSpan operator*(qreal left, const QTimeSpan &right) {return right * left;} // works
inline QTimeSpan operator*(int left, const QTimeSpan &right) {return right * left;} // works inline QTimeSpan operator*(int left, const QTimeSpan &right) {return right * left;} // works
//Q_CORE_EXPORT QTimeSpan operator*(qreal left, const QTimeSpan &right) {return right * left;} //does not work //QTimeSpan operator*(qreal left, const QTimeSpan &right) {return right * left;} //does not work
//Q_CORE_EXPORT QTimeSpan operator*(int left, const QTimeSpan &right) {return right * left;} //does not work //QTimeSpan operator*(int left, const QTimeSpan &right) {return right * left;} //does not work
Q_CORE_EXPORT QTimeSpan operator/(const QTimeSpan &left, qreal right); QTimeSpan operator/(const QTimeSpan &left, qreal right);
Q_CORE_EXPORT QTimeSpan operator/(const QTimeSpan &left, int right); QTimeSpan operator/(const QTimeSpan &left, int right);
Q_CORE_EXPORT qreal operator/(const QTimeSpan &left, const QTimeSpan &right); qreal operator/(const QTimeSpan &left, const QTimeSpan &right);
Q_CORE_EXPORT QTimeSpan operator-(const QTimeSpan &right); // Unary negation QTimeSpan operator-(const QTimeSpan &right); // Unary negation
Q_CORE_EXPORT QTimeSpan operator|(const QTimeSpan &left, const QTimeSpan &right); // Union QTimeSpan operator|(const QTimeSpan &left, const QTimeSpan &right); // Union
Q_CORE_EXPORT QTimeSpan operator&(const QTimeSpan &left, const QTimeSpan &right); // Intersection QTimeSpan operator&(const QTimeSpan &left, const QTimeSpan &right); // Intersection
// Operators that use QTimeSpan and other date/time classes // Operators that use QTimeSpan and other date/time classes
Q_CORE_EXPORT QTimeSpan operator-(const QDateTime &left, const QDateTime &right); QTimeSpan operator-(const QDateTime &left, const QDateTime &right);
Q_CORE_EXPORT QTimeSpan operator-(const QDate &left, const QDate &right); QTimeSpan operator-(const QDate &left, const QDate &right);
Q_CORE_EXPORT QTimeSpan operator-(const QTime &left, const QTime &right); QTimeSpan operator-(const QTime &left, const QTime &right);
Q_CORE_EXPORT QDate operator+(const QDate &left, const QTimeSpan &right); QDate operator+(const QDate &left, const QTimeSpan &right);
Q_CORE_EXPORT QDate operator-(const QDate &left, const QTimeSpan &right); QDate operator-(const QDate &left, const QTimeSpan &right);
Q_CORE_EXPORT QTime operator+(const QTime &left, const QTimeSpan &right); QTime operator+(const QTime &left, const QTimeSpan &right);
Q_CORE_EXPORT QTime operator-(const QTime &left, const QTimeSpan &right); QTime operator-(const QTime &left, const QTimeSpan &right);
Q_CORE_EXPORT QDateTime operator+(const QDateTime &left, const QTimeSpan &right); QDateTime operator+(const QDateTime &left, const QTimeSpan &right);
Q_CORE_EXPORT QDateTime operator-(const QDateTime &left, const QTimeSpan &right); QDateTime operator-(const QDateTime &left, const QTimeSpan &right);
#ifndef QT_NO_DATASTREAM #ifndef QT_NO_DATASTREAM
Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QTimeSpan &); QDataStream &operator<<(QDataStream &, const QTimeSpan &);
Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QTimeSpan &); QDataStream &operator>>(QDataStream &, QTimeSpan &);
#endif // QT_NO_DATASTREAM #endif // QT_NO_DATASTREAM
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_NO_DATESTRING) #if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_NO_DATESTRING)
Q_CORE_EXPORT QDebug operator<<(QDebug, const QTimeSpan &); QDebug operator<<(QDebug, const QTimeSpan &);
#endif #endif
QT_END_NAMESPACE QT_END_NAMESPACE