source: projectionDesigner/trunk/projdesigner/src/RSync.cpp @ 373

Last change on this file since 373 was 4, checked in by Torben Dannhauer, 15 years ago
File size: 10.1 KB
Line 
1#include <QtNetwork/QtNetwork>
2#include <QApplication>
3#include <QMessageBox>
4
5#include "ProjectionModel.h"
6#include "Screen.h"
7#include "Scene.h"
8#include "Channel.h"
9#include "Exporter.h"
10#include "GUIControler.h"
11
12#include "RSync.h"
13
14using namespace projection;
15
16/**
17 * Constructor.
18 *
19 * @param pModel Projection model.
20 */
21RSync::RSync(ProjectionModel* pModel) : QObject()
22{
23    m_pModel = pModel;
24
25    m_hostName = QHostInfo::localHostName();
26    m_pTcpServer = NULL;
27    m_pTcpClient = NULL;
28    m_portNo = DEFAULT_PORT_NO;
29    m_serverAddress = QHostInfo::localHostName();
30
31    m_bBlockSync = false;
32}
33
34/**
35 * Destructor.
36 */
37RSync::~RSync()
38{
39    if (!m_bServer)
40        sendChanges(RSYNC_COMMAND_DISCONNECT, "Disconnect");
41
42    if (m_pTcpServer)
43        delete m_pTcpServer;
44    if (m_pTcpClient)
45        delete m_pTcpClient;
46}
47
48/**
49 * Initialize as a server.
50 *
51 * @param portNo Port number.
52 */
53void RSync::initServer(int portNo)
54{
55    m_bServer = true;
56
57    if (portNo != 0)
58        m_portNo = portNo;
59
60    m_bServer = true;
61
62//return;
63
64    m_pTcpServer = new QTcpServer(m_pModel);
65    if (!m_pTcpServer->listen(QHostAddress::Any, m_portNo)) {
66        QMessageBox::critical(NULL, APPLICATION_NAME,
67                              QString("Unable to start the server: %1.").arg(m_pTcpServer->errorString()));
68        return;
69    }
70    connect(m_pTcpServer, SIGNAL(newConnection()), this, SLOT(acceptNewClient()));
71}
72
73/**
74 * Initialize as a client.
75 *
76 * @param address Client address.
77 * @param portNo Port number.
78 */
79void RSync::initClient(const QString& address, int portNo)
80{
81    m_bServer = false;
82
83    if (!address.isEmpty()) m_serverAddress = address;
84    if (portNo != 0) m_portNo = portNo;
85
86    m_pTcpClient = new QTcpSocket(this);
87    m_pTcpClient->setReadBufferSize(0);
88    connect(m_pTcpClient, SIGNAL(readyRead()), this, SLOT(recvSettings()));
89    connect(m_pTcpClient, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayNetworkError(QAbstractSocket::SocketError)));
90
91    connectToServer();
92}
93
94/**
95 * Send a sync command to clients.
96 *
97 * @param command Synchronize command.
98 * @param command Synchronize data.
99 */
100void RSync::sendChanges(RSYNC_COMMAND command, const QString& data)
101{
102    if (m_bBlockSync)
103        return;
104
105    QByteArray block;
106    QDataStream out(&block, QIODevice::WriteOnly);
107    out.setVersion(QDataStream::Qt_4_5);
108    out << (quint32)0;
109    out << (int)command;
110    out << data;
111    out.device()->seek(0);
112    out << (quint32)(block.size() - sizeof(quint32));
113
114    for (int i=0; i<m_pClientConnections.size(); ++i)
115    {
116        if (m_pClientConnections[i]->isValid()) {
117            m_pClientConnections[i]->write(block);
118            m_pClientConnections[i]->flush();
119        }
120    }
121}
122
123/**
124 * Send a reload command to clients.
125 */
126void RSync::sendReloadSettings()
127{
128    if (m_bBlockSync)
129        return;
130
131    if (m_bServer)
132    {
133        QDomDocument doc;
134        m_pModel->storeSettings(doc);
135        sendChanges(RSYNC_COMMAND_RELOAD, doc.toString(0));
136    }
137}
138
139/**
140 * Connect to a server.
141 */
142void RSync::connectToServer()
143{
144    m_pTcpClient->abort();
145    m_pTcpClient->connectToHost(m_serverAddress, m_portNo);
146}
147
148/**
149 * Called when a new client connects to the server. Send all states to synchronize.
150 */
151void RSync::acceptNewClient()
152{
153    QDomDocument doc;
154    m_pModel->storeSettings(doc);
155
156    QByteArray block;
157    QDataStream out(&block, QIODevice::WriteOnly);
158    out.setVersion(QDataStream::Qt_4_5);
159    out << (quint32)0;
160    out << (int)RSYNC_COMMAND_INIT;
161    out << doc.toString(0);
162    out.device()->seek(0);
163    out << (quint32)(block.size() - sizeof(quint32));
164
165    QTcpSocket* pClientConnection = m_pTcpServer->nextPendingConnection();
166//  connect(pClientConnection, SIGNAL(disconnected()),
167//            pClientConnection, SLOT(deleteLater()));
168    m_pClientConnections.push_back(pClientConnection);
169
170    m_pModel->getGUI()->showStatusBarMessage(QString("%1 connected").arg(pClientConnection->peerAddress().toString()), 2000);
171
172    pClientConnection->write(block);
173    pClientConnection->flush();
174//  pClientConnection->disconnectFromHost();
175
176        // Inform Clients about acutal loaded Scene/Model/Screen
177        m_pModel->getScreen()->notifyRedraw();
178}
179
180/**
181 * Called when a new synchronize message is received.
182 */
183void RSync::recvSettings()
184{
185    QDataStream in(m_pTcpClient);
186    in.setVersion(QDataStream::Qt_4_5);
187
188
189    while (m_pTcpClient->bytesAvailable() > 0)
190    {
191        static quint32 blockSize = 0;
192        if (blockSize == 0) {
193            if (m_pTcpClient->bytesAvailable() < (int)sizeof(quint32))
194                return;
195            in >> blockSize;
196        }
197
198        if (m_pTcpClient->bytesAvailable() < blockSize)
199            return;
200
201        int command;
202        in >> command;
203
204        QString data;
205        in >> data;
206
207        blockSize = 0;
208
209        switch (command)
210        {
211            case RSYNC_COMMAND_INIT:
212            {
213                m_lastErrorString = "";
214                m_pModel->getGUI()->appendClientLog(tr("Connected to server : %1:%2.").arg(m_serverAddress).arg(m_portNo));
215
216                QDomDocument doc;
217                doc.setContent(data);
218                m_pModel->restoreSettings(doc);
219                break;
220            }
221            case RSYNC_COMMAND_VIEWPOINT:
222            {
223                m_pModel->getScene()->setCameraViewpoint(data);
224                break;
225            }
226            case RSYNC_COMMAND_EXPORT:
227            {
228                QDomDocument doc;
229                doc.setContent(data);
230                m_pModel->getExporter()->initFromDOMElement(doc.firstChildElement("Exporter"));
231                break;
232            }
233            case RSYNC_COMMAND_MODEL:
234            {
235                QDomDocument doc;
236                doc.setContent(data);
237                m_pModel->initFromDOMElement(doc.firstChildElement("Model"));
238                break;
239            }
240            case RSYNC_COMMAND_SCENE:
241            {
242                QDomDocument doc;
243                doc.setContent(data);
244                m_pModel->getScene()->initFromDOMElement(doc.firstChildElement("Scene"));
245                break;
246            }
247            case RSYNC_COMMAND_SCREEN:
248            {
249                QDomDocument doc;
250                doc.setContent(data);
251                m_pModel->getScreen()->initFromDOMElement(doc.firstChildElement("Screen"));
252                break;
253            }
254            case RSYNC_COMMAND_CHANNEL:
255            {
256                QDomDocument doc;
257                doc.setContent(data);
258                QDomElement channel = doc.firstChildElement("Channel");
259                QString channelName = channel.attribute("name");
260                for (unsigned int i=0; i<m_pModel->getNumChannels(); ++i) {
261                    if (channelName == m_pModel->getChannel(i)->getName())
262                        m_pModel->getChannel(i)->initFromDOMElement(channel, APPLICATION_VERSION);
263                }
264                break;
265            }
266            case RSYNC_COMMAND_GUI:
267            {
268                QDomDocument doc;
269                doc.setContent(data);
270                m_pModel->getGUI()->initFromDOMElement(doc.firstChildElement("GUI"));
271                break;
272            }
273            case RSYNC_COMMAND_RELOAD:
274            {
275                QDomDocument doc;
276                doc.setContent(data);
277                m_pModel->restoreSettings(doc);
278                break;
279            }
280            case RSYNC_COMMAND_EXPORTFILE:
281            {
282                m_pModel->getExporter()->exportDataset(data);
283                break;
284            }
285            case RSYNC_COMMAND_DISCONNECT:
286            {
287                m_pModel->removeAllChannels();
288                m_lastErrorString = "";
289                m_pModel->getGUI()->appendClientLog(tr("Connection shutdowned."));
290
291                connectToServer();
292                break;
293            }
294            case RSYNC_COMMAND_END:
295            {
296                qApp->closeAllWindows();
297            }
298        }
299    }
300}
301
302/**
303 * Called when a network error is occured.
304 */
305void RSync::displayNetworkError(QAbstractSocket::SocketError socketError)
306{
307/*
308    switch (socketError) {
309    case QAbstractSocket::RemoteHostClosedError:
310        break;
311    case QAbstractSocket::HostNotFoundError:
312        QMessageBox::information(NULL, APPLICATION_NAME,
313                                 tr("The host was not found. Please check the "
314                                    "host name and port settings."));
315        break;
316    case QAbstractSocket::ConnectionRefusedError:
317        QMessageBox::information(NULL, APPLICATION_NAME,
318                                 tr("The connection was refused by the peer. "
319                                    "Make sure the Multichannnel Projection Designer server is running, "
320                                    "and check that the host name and port settings are correct."));
321        break;
322    default:
323        QMessageBox::information(NULL, APPLICATION_NAME,
324                                 tr("The following error occurred: %1.")
325                                 .arg(m_pTcpClient->errorString()));
326    }
327*/
328
329    if (socketError != QAbstractSocket::UnknownSocketError &&
330        m_lastErrorString != m_pTcpClient->errorString())
331    {
332        m_pModel->removeAllChannels();
333        m_lastErrorString = m_pTcpClient->errorString();
334        m_pModel->getGUI()->appendClientLog(m_lastErrorString);
335        m_pModel->getGUI()->appendClientLog(tr("Try connecting again..."));
336    }
337
338    QTimer* pTimer = new QTimer(this);
339    connect(pTimer, SIGNAL(timeout()), this, SLOT(connectToServer()));
340    pTimer->setSingleShot(true);
341    pTimer->start(1000);
342}
343
344/**
345 * Set sync message blocking.
346 *
347 * @param bBlock True to block sending sync data to clients.
348 */
349void RSync::setBlockSync(bool bBlock)
350{
351    m_bBlockSync = bBlock;
352}
353
354/**
355 * Check whether sync message is blocked or not.
356 *
357 * @param bBlock True to block sending sync data to clients.
358 */
359bool RSync::getBlockSync() const
360{
361    return m_bBlockSync;
362}
Note: See TracBrowser for help on using the repository browser.