source: flair-src/trunk/tools/FlairGCS/src/Manager.cpp@ 399

Last change on this file since 399 was 399, checked in by Sanahuja Guillaume, 23 months ago

change color of status bar in gcs if high bandwidth usage is detected

File size: 12.1 KB
Line 
1// %flair:license{
2// This file is part of the Flair framework distributed under the
3// CECILL-C License, Version 1.0.
4// %flair:license}
5#include "Manager.h"
6#include "UdtSocket.h"
7#include "ConnectionLayout.h"
8#include "communication.h"
9#include "file_ui.h"
10#include <QDate>
11#include <QFileDialog>
12#include <QMessageBox>
13#include <QPushButton>
14#include <QTabBar>
15#include <QTimer>
16#include <QThread>
17#include <QTextStream>
18#include <QVBoxLayout>
19#include <QModelIndex>
20#include <QStatusBar>
21#include <qendian.h>
22#include <iostream>
23#include <string>
24#include <fstream>
25#include <stdio.h>
26
27#ifndef WIN32
28#include <arpa/inet.h>
29#else
30#include <winsock2.h>
31#include <ws2tcpip.h>
32#endif
33
34using namespace std;
35
36Manager::Manager(QString name, int port) : QWidget() {
37 qRegisterMetaType<QModelIndex>("QModelIndex"); // pour le file ui??
38 this->name = name;
39//fprintf(stderr,stderr,"Manager %x\n",thread());
40 setWindowTitle(name);
41
42 // manager layout
43 managerLayout = new QVBoxLayout;
44 setLayout(managerLayout);
45
46 // tab bar for multiple connections
47 tabBar = new QTabBar();
48 //tabBar->setTabsClosable(true);
49 managerLayout->addWidget(tabBar);
50 connect(tabBar, SIGNAL(currentChanged(int)), this,
51 SLOT(tabBarCurrentChanged(int)));
52 currentTab = 0;
53
54 // layout boutons
55 button_layout = new QGridLayout();
56 managerLayout->addLayout(button_layout);
57
58 // boutons du button_Layout
59 send_button = new QPushButton("apply all");
60 reset_button = new QPushButton("reset all");
61 load_button = new QPushButton("load all locally");
62 save_button = new QPushButton("save all locally");
63 button_layout->addWidget(send_button, 0, 0);
64 button_layout->addWidget(reset_button, 0, 1);
65 button_layout->addWidget(load_button, 0, 2);
66 button_layout->addWidget(save_button, 0, 3);
67
68 connect(send_button, SIGNAL(clicked(bool)), this, SLOT(send()));
69 connect(reset_button, SIGNAL(clicked(bool)), this, SLOT(reset()));
70 connect(load_button, SIGNAL(clicked(bool)), this, SLOT(load()));
71 connect(save_button, SIGNAL(clicked(bool)), this, SLOT(save()));
72
73 status=new QStatusBar();
74 status->setSizeGripEnabled(false);
75 managerLayout->addWidget(status);
76
77 UDT::startup();
78 serv = UDT::socket(AF_INET, SOCK_DGRAM, 0);
79
80 // for non blocking accept
81 bool blocking = false;
82 UDT::setsockopt(serv, 0, UDT_RCVSYN, &blocking, sizeof(bool));
83//UDT::setsockopt(serv, 0, UDT_CC, new CCCFactory<CUDPBlast>, sizeof(CCCFactory<CUDPBlast>));
84 sockaddr_in my_addr;
85 my_addr.sin_family = AF_INET;
86 my_addr.sin_port = htons(port);
87 my_addr.sin_addr.s_addr = INADDR_ANY;
88 memset(&(my_addr.sin_zero), '\0', 8);
89
90 if (UDT::ERROR == UDT::bind(serv, (sockaddr *)&my_addr, sizeof(my_addr))) {
91 fprintf(stderr,"bind error, %s\n", UDT::getlasterror().getErrorMessage());
92 }
93
94 if (UDT::ERROR == UDT::listen(serv, 1)) {
95 fprintf(stderr,"listen error, %s\n", UDT::getlasterror().getErrorMessage());
96 }
97
98
99 icon_green = QIcon(":green.png");
100 icon_red = QIcon(":red.png");
101 icon_orange = QIcon(":orange.png");
102
103 QTimer *timer = new QTimer(this);
104 connect(timer, SIGNAL(timeout()), this, SLOT(acceptConnections()));
105 timer->start(500);
106}
107
108Manager::~Manager() {
109 for (int i = 0; i < connections.count(); i++) {
110 if(connections.at(i).socket!=NULL) {
111 connections.at(i).socket->kill();
112 connections.at(i).socket->thread()->wait();
113 }
114 }
115
116 // delete main_layout;
117 UDT::cleanup();
118}
119
120void Manager::acceptConnections(void) {
121 UDTSOCKET socket;
122
123 sockaddr_in their_addr;
124 int namelen = sizeof(their_addr);
125
126 if (UDT::INVALID_SOCK ==(socket = UDT::accept(serv, (sockaddr *)&their_addr, &namelen))) {
127 if (UDT::getlasterror().getErrorCode() != 6002)
128 fprintf(stderr,"accept error: %s, code %i\n", UDT::getlasterror().getErrorMessage(),UDT::getlasterror().getErrorCode());
129 return;
130 } else {
131 QString name=QString("%1:%2").arg(inet_ntoa(their_addr.sin_addr)).arg(their_addr.sin_port);
132 fprintf(stderr,"connected to %s\n",name.toLocal8Bit().constData());
133
134 QThread *thread = new QThread(this);
135 UdtSocket *udtSocket = new UdtSocket(socket,name);
136 udtSocket->moveToThread(thread);
137
138 connect(udtSocket, SIGNAL(newFileUI(UDTSOCKET)), this, SLOT(newFileUI(UDTSOCKET)));
139 connect(udtSocket, SIGNAL(newConnectionLayout(QString)), this, SLOT(newConnectionLayout(QString)),Qt::BlockingQueuedConnection);
140 connect(thread, SIGNAL(started()), udtSocket, SLOT(receiveData()));
141
142 thread->start();
143 }
144}
145
146void Manager::newConnectionLayout(QString name) {
147 UdtSocket* udtSocket=(UdtSocket *)sender();
148
149 ConnectionLayout *newLayout = new ConnectionLayout(udtSocket, name);
150 connect(udtSocket, SIGNAL(UDTStats(QString,QString,bool)), newLayout, SIGNAL(UDTStats(QString,QString,bool)));//connection in 2 steps to get udtsocket as sender
151 connect(newLayout, SIGNAL(UDTStats(QString,QString,bool)), this, SLOT(printUDTStats(QString,QString,bool)));
152 connect(udtSocket, SIGNAL(dataReady(char *, int)), newLayout,SLOT(receive(char *, int)),Qt::BlockingQueuedConnection);
153 connect(newLayout, SIGNAL(destroyed(QObject *)), this, SLOT(layoutDestroyed(QObject *)));
154 connect(udtSocket, SIGNAL(destroyed(QObject *)), this, SLOT(udtSocketDestroyed(QObject *)));
155 connect(udtSocket, SIGNAL(destroyed(QObject *)), newLayout, SLOT(udtSocketDestroyed(QObject *)));
156
157 // widget
158 QWidget *newWidget = new QWidget();
159 newWidget->setLayout(newLayout->getQGridLayout());
160 managerLayout->insertWidget(1, newWidget);
161 newWidget->hide();
162
163 connections_t connection;
164 connection.layout=newLayout;
165 connection.widget=newWidget;
166 connection.socket=udtSocket;
167 connections.append(connection);
168
169 //tab: avoid having only 1 tab (0, 2 or more)
170 if (connections.count() == 1) { // first connection
171 newWidget->show();
172 hiddenTabName = name;
173 }
174 if (connections.count() == 2) {
175 if(connections[0].socket!=NULL) {
176 tabBar->addTab(icon_green,hiddenTabName);
177 } else {
178 tabBar->addTab(icon_red,hiddenTabName);
179 }
180 currentTab = 0;
181 }
182 if (connections.count() > 1) {
183 tabBar->addTab(icon_green,name);
184 }
185}
186
187void Manager::udtSocketDestroyed(QObject *obj) {
188 //mark socket as not valid, it can be a connection lost
189 //in this case we keep the layout for reading, and mark it as problematic (socket=NULL)
190 for(int i=0;i<connections.count();i++) {
191 if(connections.at(i).socket==(UdtSocket *)obj) {
192 connections[i].socket=NULL;
193 tabBar->setTabIcon(i,icon_red);
194 break;
195 }
196 }
197}
198
199void Manager::layoutDestroyed(QObject *obj) {
200 //remove the connection, it comes from a proper close
201 int index=-1;
202 for(int i=0;i<connections.count();i++) {
203 if(connections.at(i).layout==(ConnectionLayout *)obj) {
204 delete connections.at(i).widget;
205 //connections[i].widget=NULL;
206 //connections[i].layout=NULL;
207 connections.removeAt(i);
208 index=i;
209 break;
210 }
211 }
212
213 if(index==-1) {
214 fprintf(stderr,"layoutDestroyed: error, layout not found!\n");
215 return;
216 }
217
218 //tab: avoid having only 1 tab (only 0, 2 or more)
219 if (tabBar->count() > 1) {
220 tabBar->removeTab(index);
221 }
222
223 if (connections.count() == 1) {
224 hiddenTabName = tabBar->tabText(0);
225 tabBar->removeTab(0);
226 }
227
228 if (connections.count() == 0) {
229 status->showMessage("");
230 }
231}
232
233void Manager::newFileUI(UDTSOCKET socket) {
234 QThread *thread = new QThread(this);
235 file_ui* fileUi = new file_ui(socket,name);
236 fileUi->moveToThread(thread);
237 connect(thread, SIGNAL(started()), fileUi, SLOT(receive()));
238 connect(fileUi, SIGNAL(finished()), this, SLOT(deleteFileUI()));
239 thread->start();
240}
241
242void Manager::deleteFileUI(void) {
243 sender()->thread()->quit();
244 delete sender();
245}
246
247void Manager::printUDTStats(QString stats,QString stylesheet,bool loosingPackets) {
248 int index = -1;
249 for(int i=0;i<connections.count();i++) {
250 if(connections.at(i).layout==(ConnectionLayout *)sender()) {
251 index=i;
252 break;
253 }
254 }
255
256 if(index==-1) return;
257
258 if(!loosingPackets) {
259 tabBar->setTabIcon(index,icon_green);
260 } else {
261 tabBar->setTabIcon(index,icon_orange);
262 }
263
264 if (tabBar->count() == 0) {
265 status->setStyleSheet(stylesheet);
266 status->showMessage(stats);
267 } else if (index==tabBar->currentIndex()) {
268 status->setStyleSheet(stylesheet);
269 status->showMessage(QString("%1: %2").arg(tabBar->tabText(index)).arg(stats));
270 }
271}
272
273void Manager::tabBarCurrentChanged(int index) {
274
275 if (index >= 0) {
276 //if we are coming from layout destroyed
277 if(currentTab<connections.count()) connections.at(currentTab).widget->hide();
278 connections.at(index).widget->show();
279 currentTab = index;
280 } else {
281 currentTab = 0;
282 connections.at(0).widget->show();
283 }
284 QString msg="not connected";
285 if (tabBar->count() == 0) {
286 if(connections.at(0).socket!=NULL) msg=connections.at(0).socket->getUDTStats();
287
288 } else {
289 if(connections.at(index).socket!=NULL) msg=QString("%1: %2").arg(tabBar->tabText(index)).arg(connections.at(index).socket->getUDTStats());
290 }
291 status->showMessage(msg);
292}
293
294void Manager::load(void) {
295 QString dir_name =
296 QFileDialog::getExistingDirectory(this, "Select a directory", 0, 0);
297
298 if (dir_name != "") {
299 for (int i = 0; i < connections.count(); i++) {
300 QFile *file;
301 file = new QFile(dir_name + "/" +
302 connections.at(i).layout->getName() + ".xml");
303 if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
304 QMessageBox::warning(this, "Warning",
305 "Enable to load " +
306 connections.at(i).layout->getName() +
307 ".xml");
308 continue;
309 }
310
311 QDomDocument doc;
312 QString errorMsg;
313 int errorLine;
314 int errorColumn;
315 if (!doc.setContent(file, &errorMsg, &errorLine, &errorColumn)) {
316 QMessageBox::critical(
317 this, "Error",
318 "unable to read " + connections.at(i).layout->getName() +
319 ".xml" + " (" + errorMsg + " at " + QString::number(errorLine) +
320 "," + QString::number(errorColumn) + ")");
321 } else {
322 connections.at(i).layout->LoadXml(&doc);
323 }
324 delete file;
325 }
326 }
327}
328
329void Manager::save(void) {
330 bool isUptodate = true;
331
332 for (int i = 0; i < connections.count(); i++) {
333 if (!connections.at(i).layout->IsUptodate()) {
334 isUptodate = false;
335 break;
336 }
337 }
338
339 if (!isUptodate) {
340 QMessageBox msgBox;
341 msgBox.setText("There are pending modifications");
342 msgBox.setInformativeText("Apply and save?");
343 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
344 msgBox.setDefaultButton(QMessageBox::Yes);
345 int ret = msgBox.exec();
346
347 switch (ret) {
348 case QMessageBox::Yes:
349 send();
350 break;
351 case QMessageBox::Cancel:
352 return;
353 break;
354 default:
355 // should never be reached
356 break;
357 }
358 }
359
360 // create dirctory for storage
361 QDateTime dateTime = QDateTime::currentDateTime();
362 QString dir_name =
363 "configs_" + dateTime.toString("yyyyMMdd_hhmm") + "_" + name;
364 if (QDir().exists(dir_name) == true) {
365 dir_name = "configs_" + dateTime.toString("yyyyMMdd_hhmm_ss") + "_" + name;
366 }
367 QDir().mkdir(dir_name);
368
369 for (int i = 0; i < connections.count(); i++) {
370 QDomDocument *xml = new QDomDocument("remote_ui_xml");
371
372 connections.at(i).layout->GetFullXml((QDomElement *)xml);
373
374 QFile fichier(dir_name + "/" + connections.at(i).layout->getName() +
375 ".xml");
376 QString write_doc = (xml->ownerDocument()).toString();
377
378 if (!fichier.open(QIODevice::WriteOnly)) {
379 fichier.close();
380 QMessageBox::critical(this, "Error", "Enable to write XML");
381 continue;
382 }
383 QTextStream stream(&fichier);
384 stream << write_doc;
385 fichier.close();
386
387 delete xml;
388 }
389
390 QMessageBox::information(this, "save all", "saved to ./" + dir_name);
391}
392
393void Manager::send(void) {
394 for (int i = 0; i < connections.count(); i++) {
395 if(connections.at(i).socket!=NULL) {
396 QDomDocument doc("remote_ui_xml");
397 connections.at(i).layout->GetUpdateXml((QDomElement *)&doc);
398 // fprintf(stderr,"merge\n%s\n",doc.toString().toLocal8Bit().constData());
399
400 connections.at(i).layout->XmlToSend(doc);
401 }
402 }
403}
404
405void Manager::reset() {
406 for (int i = 0; i < connections.count(); i++)
407 connections.at(i).layout->ResetAllChilds();
408}
Note: See TracBrowser for help on using the repository browser.