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

Last change on this file was 436, checked in by Sanahuja Guillaume, 4 weeks ago

gcs:sync graphs

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  startTime=QTime::currentTime();
108}
109
110Manager::~Manager() {
111  for (int i = 0; i < connections.count(); i++) {
112    if(connections.at(i).socket!=NULL) {
113      connections.at(i).socket->kill();
114      connections.at(i).socket->thread()->wait();
115    }
116  }
117
118  // delete main_layout;
119  UDT::cleanup();
120}
121
122void Manager::acceptConnections(void) {
123  UDTSOCKET socket;
124
125  sockaddr_in their_addr;
126  int namelen = sizeof(their_addr);
127
128  if (UDT::INVALID_SOCK ==(socket = UDT::accept(serv, (sockaddr *)&their_addr, &namelen))) {
129    if (UDT::getlasterror().getErrorCode() != 6002)
130      fprintf(stderr,"accept error: %s, code %i\n", UDT::getlasterror().getErrorMessage(),UDT::getlasterror().getErrorCode());
131    return;
132  } else {
133    QString name=QString("%1:%2").arg(inet_ntoa(their_addr.sin_addr)).arg(their_addr.sin_port);
134    fprintf(stderr,"connected to %s\n",name.toLocal8Bit().constData());
135   
136    QThread *thread = new QThread(this);
137    UdtSocket *udtSocket = new UdtSocket(socket,name);
138    udtSocket->moveToThread(thread);
139   
140    connect(udtSocket, SIGNAL(newFileUI(UDTSOCKET)), this, SLOT(newFileUI(UDTSOCKET)));
141    connect(udtSocket, SIGNAL(newConnectionLayout(QString)), this, SLOT(newConnectionLayout(QString)),Qt::BlockingQueuedConnection);
142    connect(thread, SIGNAL(started()), udtSocket, SLOT(receiveData()));
143
144    thread->start(); 
145  }
146}
147
148void Manager::newConnectionLayout(QString name) {
149  UdtSocket* udtSocket=(UdtSocket *)sender();
150 
151  ConnectionLayout *newLayout = new ConnectionLayout(udtSocket, name, startTime);
152  connect(udtSocket, SIGNAL(UDTStats(QString,QString,bool)), newLayout, SIGNAL(UDTStats(QString,QString,bool)));//connection in 2 steps to get udtsocket as sender
153  connect(newLayout, SIGNAL(UDTStats(QString,QString,bool)), this, SLOT(printUDTStats(QString,QString,bool)));
154  connect(udtSocket, SIGNAL(dataReady(char *, int)), newLayout,SLOT(receive(char *, int)),Qt::BlockingQueuedConnection);
155  connect(newLayout, SIGNAL(destroyed(QObject *)), this, SLOT(layoutDestroyed(QObject *)));
156  connect(udtSocket, SIGNAL(destroyed(QObject *)), this, SLOT(udtSocketDestroyed(QObject *)));
157  connect(udtSocket, SIGNAL(destroyed(QObject *)), newLayout, SLOT(udtSocketDestroyed(QObject *)));
158 
159  // widget
160  QWidget *newWidget = new QWidget();
161  newWidget->setLayout(newLayout->getQGridLayout());
162  managerLayout->insertWidget(1, newWidget);
163  newWidget->hide();
164 
165  connections_t connection;
166  connection.layout=newLayout;
167  connection.widget=newWidget;
168  connection.socket=udtSocket;
169  connections.append(connection);
170 
171  //tab: avoid having only 1 tab (0, 2 or more)
172  if (connections.count() == 1) { // first connection
173    newWidget->show();
174    hiddenTabName = name;
175  }
176  if (connections.count() == 2) {
177    if(connections[0].socket!=NULL) {
178      tabBar->addTab(icon_green,hiddenTabName);
179    } else {
180      tabBar->addTab(icon_red,hiddenTabName);
181    }
182    currentTab = 0;
183  }
184  if (connections.count() > 1) {
185    tabBar->addTab(icon_green,name);
186  }
187}
188
189void Manager::udtSocketDestroyed(QObject *obj) {
190  //mark socket as not valid, it can be a connection lost
191  //in this case we keep the layout for reading, and mark it as problematic (socket=NULL)
192  for(int i=0;i<connections.count();i++) {
193    if(connections.at(i).socket==(UdtSocket *)obj) {
194      connections[i].socket=NULL;
195      tabBar->setTabIcon(i,icon_red);
196      break;
197    }
198  }
199}
200
201void Manager::layoutDestroyed(QObject *obj) {
202  //remove the connection, it comes from a proper close
203  int index=-1;
204  for(int i=0;i<connections.count();i++) {
205    if(connections.at(i).layout==(ConnectionLayout *)obj) {
206      delete connections.at(i).widget;
207      //connections[i].widget=NULL;
208      //connections[i].layout=NULL;
209      connections.removeAt(i);
210      index=i;
211      break;
212    }
213  }
214 
215  if(index==-1) {
216    fprintf(stderr,"layoutDestroyed: error, layout not found!\n");
217    return;
218  }
219 
220  //tab: avoid having only 1 tab (only 0, 2 or more)
221  if (tabBar->count() > 1) {
222    tabBar->removeTab(index);
223  }
224
225  if (connections.count() == 1) {
226    hiddenTabName = tabBar->tabText(0);
227    tabBar->removeTab(0);
228  }
229
230  if (connections.count() == 0) {
231    status->showMessage("");
232  }
233}
234
235void Manager::newFileUI(UDTSOCKET socket) {
236  QThread *thread = new QThread(this);
237  file_ui* fileUi = new file_ui(socket,name);
238  fileUi->moveToThread(thread);
239  connect(thread, SIGNAL(started()), fileUi, SLOT(receive()));
240  connect(fileUi, SIGNAL(finished()), this, SLOT(deleteFileUI()));
241  thread->start();
242}
243
244void Manager::deleteFileUI(void) {
245  sender()->thread()->quit();
246  delete sender();
247}
248
249void Manager::printUDTStats(QString stats,QString stylesheet,bool loosingPackets) {
250  int index = -1;
251  for(int i=0;i<connections.count();i++) {
252    if(connections.at(i).layout==(ConnectionLayout *)sender()) {
253      index=i;
254      break;
255    }
256  }
257 
258  if(index==-1) return;
259 
260  if(!loosingPackets) {
261    tabBar->setTabIcon(index,icon_green);
262  } else {
263    tabBar->setTabIcon(index,icon_orange);
264  }
265 
266  if (tabBar->count() == 0) {
267    status->setStyleSheet(stylesheet);
268    status->showMessage(stats);
269  } else if (index==tabBar->currentIndex()) {
270    status->setStyleSheet(stylesheet);
271    status->showMessage(QString("%1: %2").arg(tabBar->tabText(index)).arg(stats));
272  }
273}
274
275void Manager::tabBarCurrentChanged(int index) {
276 
277  if (index >= 0) {
278    //if we are coming from layout destroyed
279    if(currentTab<connections.count()) connections.at(currentTab).widget->hide();
280    connections.at(index).widget->show();
281    currentTab = index;
282  } else {
283    currentTab = 0;
284    connections.at(0).widget->show();
285  }
286  QString msg="not connected";
287  if (tabBar->count() == 0) {
288    if(connections.at(0).socket!=NULL) msg=connections.at(0).socket->getUDTStats();
289   
290  } else {
291    if(connections.at(index).socket!=NULL) msg=QString("%1: %2").arg(tabBar->tabText(index)).arg(connections.at(index).socket->getUDTStats());
292  }
293  status->showMessage(msg);
294}
295
296void Manager::load(void) {
297  QString dir_name =
298      QFileDialog::getExistingDirectory(this, "Select a directory", 0, 0);
299
300  if (dir_name != "") {
301    for (int i = 0; i < connections.count(); i++) {
302      QFile *file;
303      file = new QFile(dir_name + "/" +
304                       connections.at(i).layout->getName() + ".xml");
305      if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
306        QMessageBox::warning(this, "Warning",
307                             "Enable to load " +
308                                 connections.at(i).layout->getName() +
309                                 ".xml");
310        continue;
311      }
312
313      QDomDocument doc;
314      QString errorMsg;
315      int errorLine;
316      int errorColumn;
317      if (!doc.setContent(file, &errorMsg, &errorLine, &errorColumn)) {
318        QMessageBox::critical(
319            this, "Error",
320            "unable to read " + connections.at(i).layout->getName() +
321                ".xml" + " (" + errorMsg + " at " + QString::number(errorLine) +
322                "," + QString::number(errorColumn) + ")");
323      } else {
324        connections.at(i).layout->LoadXml(&doc);
325      }
326      delete file;
327    }
328  }
329}
330
331void Manager::save(void) {
332  bool isUptodate = true;
333
334  for (int i = 0; i < connections.count(); i++) {
335    if (!connections.at(i).layout->IsUptodate()) {
336      isUptodate = false;
337      break;
338    }
339  }
340
341  if (!isUptodate) {
342    QMessageBox msgBox;
343    msgBox.setText("There are pending modifications");
344    msgBox.setInformativeText("Apply and save?");
345    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
346    msgBox.setDefaultButton(QMessageBox::Yes);
347    int ret = msgBox.exec();
348
349    switch (ret) {
350    case QMessageBox::Yes:
351      send();
352      break;
353    case QMessageBox::Cancel:
354      return;
355      break;
356    default:
357      // should never be reached
358      break;
359    }
360  }
361
362  // create dirctory for storage
363  QDateTime dateTime = QDateTime::currentDateTime();
364  QString dir_name =
365      "configs_" + dateTime.toString("yyyyMMdd_hhmm") + "_" + name;
366  if (QDir().exists(dir_name) == true) {
367    dir_name = "configs_" + dateTime.toString("yyyyMMdd_hhmm_ss") + "_" + name;
368  }
369  QDir().mkdir(dir_name);
370
371  for (int i = 0; i < connections.count(); i++) {
372    QDomDocument *xml = new QDomDocument("remote_ui_xml");
373
374    connections.at(i).layout->GetFullXml((QDomElement *)xml);
375
376    QFile fichier(dir_name + "/" + connections.at(i).layout->getName() +
377                  ".xml");
378    QString write_doc = (xml->ownerDocument()).toString();
379
380    if (!fichier.open(QIODevice::WriteOnly)) {
381      fichier.close();
382      QMessageBox::critical(this, "Error", "Enable to write XML");
383      continue;
384    }
385    QTextStream stream(&fichier);
386    stream << write_doc;
387    fichier.close();
388
389    delete xml;
390  }
391
392  QMessageBox::information(this, "save all", "saved to ./" + dir_name);
393}
394
395void Manager::send(void) {
396  for (int i = 0; i < connections.count(); i++) {
397    if(connections.at(i).socket!=NULL) {
398      QDomDocument doc("remote_ui_xml");
399      connections.at(i).layout->GetUpdateXml((QDomElement *)&doc);
400      // fprintf(stderr,"merge\n%s\n",doc.toString().toLocal8Bit().constData());
401
402      connections.at(i).layout->XmlToSend(doc);
403    }
404  }
405}
406
407void Manager::reset() {
408  for (int i = 0; i < connections.count(); i++)
409    connections.at(i).layout->ResetAllChilds();
410}
Note: See TracBrowser for help on using the repository browser.