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

Last change on this file since 234 was 234, checked in by Sanahuja Guillaume, 4 years ago

create file oscket only when necessary

File size: 10.5 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,"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  managerLayout->addWidget(tabBar);
49  connect(tabBar, SIGNAL(currentChanged(int)), this,
50          SLOT(tabBarCurrentChanged(int)));
51  currentTab = 0;
52
53  // layout boutons
54  button_layout = new QGridLayout();
55  managerLayout->addLayout(button_layout);
56
57  // boutons du button_Layout
58  send_button = new QPushButton("apply all");
59  reset_button = new QPushButton("reset all");
60  load_button = new QPushButton("load all locally");
61  save_button = new QPushButton("save all locally");
62  button_layout->addWidget(send_button, 0, 0);
63  button_layout->addWidget(reset_button, 0, 1);
64  button_layout->addWidget(load_button, 0, 2);
65  button_layout->addWidget(save_button, 0, 3);
66
67  connect(send_button, SIGNAL(clicked(bool)), this, SLOT(send()));
68  connect(reset_button, SIGNAL(clicked(bool)), this, SLOT(reset()));
69  connect(load_button, SIGNAL(clicked(bool)), this, SLOT(load()));
70  connect(save_button, SIGNAL(clicked(bool)), this, SLOT(save()));
71
72  status=new QStatusBar();
73  status->setSizeGripEnabled(false);
74  button_layout->addWidget(status, 1,0);
75
76  UDT::startup();
77  serv = UDT::socket(AF_INET, SOCK_DGRAM, 0);
78
79  // for non blocking accept
80  bool blocking = false;
81  UDT::setsockopt(serv, 0, UDT_RCVSYN, &blocking, sizeof(bool));
82//UDT::setsockopt(serv, 0, UDT_CC, new CCCFactory<CUDPBlast>, sizeof(CCCFactory<CUDPBlast>));
83  sockaddr_in my_addr;
84  my_addr.sin_family = AF_INET;
85  my_addr.sin_port = htons(port);
86  my_addr.sin_addr.s_addr = INADDR_ANY;
87  memset(&(my_addr.sin_zero), '\0', 8);
88
89  if (UDT::ERROR == UDT::bind(serv, (sockaddr *)&my_addr, sizeof(my_addr))) {
90    printf("bind error, %s\n", UDT::getlasterror().getErrorMessage());
91  }
92
93  if (UDT::ERROR == UDT::listen(serv, 1)) {
94    printf("listen error, %s\n", UDT::getlasterror().getErrorMessage());
95  }
96
97  QTimer *timer = new QTimer(this);
98  connect(timer, SIGNAL(timeout()), this, SLOT(acceptConnections()));
99  timer->start(500);
100}
101
102Manager::~Manager() {
103  printf("%i\n",udtSockets.count());
104  for (int i = 0; i < udtSockets.count(); i++) {
105    udtSockets.at(i)->kill();
106    udtSockets.at(i)->thread()->wait();
107  }
108
109  // delete main_layout;
110  UDT::cleanup();
111  printf("ok\n");
112}
113
114void Manager::acceptConnections(void) {
115  UDTSOCKET socket;
116
117  sockaddr_in their_addr;
118  int namelen = sizeof(their_addr);
119
120  if (UDT::INVALID_SOCK ==(socket = UDT::accept(serv, (sockaddr *)&their_addr, &namelen))) {
121    if (UDT::getlasterror().getErrorCode() != 6002)
122      printf("accept error: %s, code %i\n", UDT::getlasterror().getErrorMessage(),UDT::getlasterror().getErrorCode());
123    return;
124  } else {
125    QString name=QString("%1:%2").arg(inet_ntoa(their_addr.sin_addr)).arg(their_addr.sin_port);
126    printf("connected to %s\n",name.toLocal8Bit().constData());
127   
128    QThread *thread = new QThread(this);
129    UdtSocket *udtSocket = new UdtSocket(socket,name);
130    udtSocket->moveToThread(thread);
131    udtSockets.append(udtSocket);
132
133    connect(udtSocket, SIGNAL(newFileUI(UDTSOCKET)), this, SLOT(newFileUI(UDTSOCKET)));
134    connect(udtSocket, SIGNAL(newConnectionLayout(QString)), this, SLOT(newConnectionLayout(QString)),Qt::BlockingQueuedConnection);
135    connect(thread, SIGNAL(started()), udtSocket, SLOT(receiveData()));
136
137    thread->start(); 
138  }
139}
140
141void Manager::newConnectionLayout(QString name) {
142  UdtSocket* udtSocket=(UdtSocket *)sender();
143 
144  ConnectionLayout *newLayout = new ConnectionLayout(udtSocket, name);
145  connectionsLayout.append(newLayout);
146  connect(udtSocket, SIGNAL(UDTStats(QString)), newLayout, SIGNAL(UDTStats(QString)));//connection in 2 steps to get udtsocket as sender
147  connect(newLayout, SIGNAL(UDTStats(QString)), this, SLOT(printUDTStats(QString)));
148  connect(udtSocket, SIGNAL(dataReady(char *, int)), newLayout,SLOT(receive(char *, int)),Qt::BlockingQueuedConnection);
149  connect(newLayout, SIGNAL(destroyed(QObject *)), this, SLOT(layoutDestroyed(QObject *)));
150  connect(udtSocket, SIGNAL(destroyed()), newLayout, SLOT(deleteLater()));
151 
152   // widget
153  QWidget *newWidget = new QWidget();
154  connectionsWidget.append(newWidget);
155  newWidget->setLayout(newLayout->getQGridLayout());
156  managerLayout->insertWidget(1, newWidget);
157  newWidget->hide();
158 
159  //tab: avoid having only 1 tab (0, 2 or more)
160  if (connectionsLayout.count() == 1) { // first connection
161    connectionsWidget.at(0)->show();
162    hiddenTabName = name;
163  }
164  if (connectionsLayout.count() == 2) {
165    tabBar->addTab(hiddenTabName);
166    currentTab = 0;
167  }
168  if (connectionsLayout.count() > 1) {
169    tabBar->addTab(name);
170  }
171}
172
173void Manager::layoutDestroyed(QObject *obj) {
174  int index = connectionsLayout.indexOf((ConnectionLayout *)obj);
175
176  //tab: avoid having only 1 tab (0, 2 or more)
177  if (tabBar->count() > 1) {
178    tabBar->removeTab(index);
179  }
180
181  delete connectionsWidget.at(index);
182  connectionsWidget.removeAt(index);
183  connectionsLayout.removeOne((ConnectionLayout *)obj);
184
185  if (connectionsLayout.count() == 1) {
186    hiddenTabName = tabBar->tabText(0);
187    tabBar->removeTab(0);
188  }
189
190  if (connectionsLayout.count() == 0) {
191    status->showMessage("");
192  }
193}
194
195void Manager::newFileUI(UDTSOCKET socket) {
196  //remove udtsocket as it will be automatically destroyed
197  udtSockets.removeOne((UdtSocket *)sender());
198 
199  QThread *thread = new QThread(this);
200  file_ui* fileUi = new file_ui(socket,name);
201  fileUi->moveToThread(thread);
202  connect(thread, SIGNAL(started()), fileUi, SLOT(receive()));
203  connect(fileUi, SIGNAL(finished()), this, SLOT(deleteFileUI()));
204  thread->start();
205}
206
207void Manager::deleteFileUI(void) {
208  sender()->thread()->quit();
209  delete sender();
210}
211
212void Manager::printUDTStats(QString stats) {
213  int index = connectionsLayout.indexOf((ConnectionLayout *)sender());
214  if(index==-1) return;
215 
216  if (tabBar->count() == 0) {
217    status->showMessage(stats);
218  } else if (index==tabBar->currentIndex()) {
219    status->showMessage(QString("%1: %2").arg(tabBar->tabText(index)).arg(stats));
220  }
221}
222
223void Manager::tabBarCurrentChanged(int index) {
224  if (index >= 0) {
225    connectionsWidget.at(currentTab)->hide();
226    connectionsWidget.at(index)->show();
227    currentTab = index;
228  } else {
229    currentTab = 0;
230    connectionsWidget.at(0)->show();
231  }
232 
233  if (tabBar->count() == 0) {
234    status->showMessage(connectionsLayout.at(0)->getUDTStats());
235  } else {
236    status->showMessage(QString("%1: %2").arg(tabBar->tabText(index)).arg(connectionsLayout.at(index)->getUDTStats()));
237  }
238}
239
240void Manager::load(void) {
241  QString dir_name =
242      QFileDialog::getExistingDirectory(this, "Select a directory", 0, 0);
243
244  if (dir_name != "") {
245    for (int i = 0; i < connectionsLayout.count(); i++) {
246      QFile *file;
247      file = new QFile(dir_name + "/" +
248                       connectionsLayout.at(i)->getName() + ".xml");
249      if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
250        QMessageBox::warning(this, "Warning",
251                             "Enable to load " +
252                                 connectionsLayout.at(i)->getName() +
253                                 ".xml");
254        continue;
255      }
256
257      QDomDocument doc;
258      QString errorMsg;
259      int errorLine;
260      int errorColumn;
261      if (!doc.setContent(file, &errorMsg, &errorLine, &errorColumn)) {
262        QMessageBox::critical(
263            this, "Error",
264            "unable to read " + connectionsLayout.at(i)->getName() +
265                ".xml" + " (" + errorMsg + " at " + QString::number(errorLine) +
266                "," + QString::number(errorColumn) + ")");
267      } else {
268        connectionsLayout.at(i)->LoadXml(doc);
269      }
270      delete file;
271    }
272  }
273}
274
275void Manager::save(void) {
276  bool isUptodate = true;
277
278  for (int i = 0; i < connectionsLayout.count(); i++) {
279    if (!connectionsLayout.at(i)->IsUptodate()) {
280      isUptodate = false;
281      break;
282    }
283  }
284
285  if (!isUptodate) {
286    QMessageBox msgBox;
287    msgBox.setText("There are pending modifications");
288    msgBox.setInformativeText("Apply and save?");
289    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
290    msgBox.setDefaultButton(QMessageBox::Yes);
291    int ret = msgBox.exec();
292
293    switch (ret) {
294    case QMessageBox::Yes:
295      send();
296      break;
297    case QMessageBox::Cancel:
298      return;
299      break;
300    default:
301      // should never be reached
302      break;
303    }
304  }
305
306  // create dirctory for storage
307  QDateTime dateTime = QDateTime::currentDateTime();
308  QString dir_name =
309      "configs_" + dateTime.toString("yyyyMMdd_hhmm") + "_" + name;
310  if (QDir().exists(dir_name) == true) {
311    dir_name = "configs_" + dateTime.toString("yyyyMMdd_hhmm_ss") + "_" + name;
312  }
313  QDir().mkdir(dir_name);
314
315  for (int i = 0; i < connectionsLayout.count(); i++) {
316    QDomDocument *xml = new QDomDocument("remote_ui_xml");
317
318    connectionsLayout.at(i)->GetFullXml((QDomElement *)xml);
319
320    QFile fichier(dir_name + "/" + connectionsLayout.at(i)->getName() +
321                  ".xml");
322    QString write_doc = (xml->ownerDocument()).toString();
323
324    if (!fichier.open(QIODevice::WriteOnly)) {
325      fichier.close();
326      QMessageBox::critical(this, "Error", "Enable to write XML");
327      continue;
328    }
329    QTextStream stream(&fichier);
330    stream << write_doc;
331    fichier.close();
332
333    delete xml;
334  }
335
336  QMessageBox::information(this, "save all", "saved to ./" + dir_name);
337}
338
339void Manager::send(void) {
340  for (int i = 0; i < connectionsLayout.count(); i++) {
341    QDomDocument doc("remote_ui_xml");
342    connectionsLayout.at(i)->GetUpdateXml((QDomElement *)&doc);
343    // printf("merge\n%s\n",doc.toString().toLocal8Bit().constData());
344
345    connectionsLayout.at(i)->XmlToSend(doc);
346  }
347}
348
349void Manager::reset() {
350  for (int i = 0; i < connectionsLayout.count(); i++)
351    connectionsLayout.at(i)->ResetAllChilds();
352}
Note: See TracBrowser for help on using the repository browser.