Fork me on GitHub
2.15.20
FGx
A cross-platform launcher for FlightGear
pilotswidget.cpp
Go to the documentation of this file.
1 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-
2 // FGx FlightGear Launcher // pilotswidget.cpp
3 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-
4 // (c) 2010-2012
5 // Yves Sablonier, Pete Morgan
6 // Geoff McLane
7 // GNU GPLv2, see main.cpp and shipped licence.txt for further information
8 
9 #include <QtCore/QTimer>
10 
11 #include <QListIterator>
12 
13 #include <QDomNodeList>
14 #include <QDomNamedNodeMap>
15 
16 
17 #include <QNetworkRequest>
18 #include <QNetworkReply>
19 
20 
21 #include <QVBoxLayout>
22 #include <QToolBar>
23 #include <QVBoxLayout>
24 #include <QTreeWidgetItem>
25 #include <QHeaderView>
26 
27 #include "utilities/utilities.h"
29 #include "pilotswidget.h"
30 
31 
32 
33 
35  QWidget(parent)
36 {
37 
38  mainObject = mob;
39 
40  setMinimumWidth(300);
41 
42 
43  QVBoxLayout *mainLayout = new QVBoxLayout();
44  mainLayout->setContentsMargins(0,0,0,0);
45  mainLayout->setSpacing(0);
46  setLayout(mainLayout);
47 
48 
49 
50  //========================================
51  //= Toolbar
52  QToolBar *toolbar = new QToolBar();
53  mainLayout->addWidget(toolbar);
54  toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
55 
56 
57  checkBoxFollowSelected = new QCheckBox();
58  checkBoxFollowSelected->setText("Follow Selected");
59  toolbar->addWidget(checkBoxFollowSelected);
60 
61 
62  //= CheckBox AutoRefresh
63  checkBoxAutoRefresh = new QCheckBox("Auto");
64  toolbar->addWidget(checkBoxAutoRefresh);
65  checkBoxAutoRefresh->setChecked(mainObject->settings->value("mpxmap_autorefresh_enabled").toBool());
66  connect(checkBoxAutoRefresh, SIGNAL(stateChanged(int)), this, SLOT(on_check_autorefresh(int)));
67 
68  //= ComboBox HZ
69  comboBoxHz = new QComboBox();
70  toolbar->addWidget(comboBoxHz);
71  for(int sex=1; sex < 10; sex++){
72  comboBoxHz->addItem(QString("%1 sec").arg(QString::number(sex)), QString::number(sex));
73  }
74  int cidx = comboBoxHz->findData(mainObject->settings->value("mpxmap_autorefresh_hz").toString());
75  comboBoxHz->setCurrentIndex(cidx == -1 ? 0 : cidx);
76  connect(comboBoxHz, SIGNAL(currentIndexChanged(int)), this, SLOT(on_combo_changed(int)));
77 
78  //= Refresh
79  QAction *actionRefresh = new QAction(this);
80  //actionRefresh->setText("Refresh");
81  actionRefresh->setIcon(QIcon(":/icon/refresh"));
82  toolbar->addAction(actionRefresh);
83  connect(actionRefresh, SIGNAL(triggered()), this, SLOT(fetch_pilots()));
84 
85 
86 
87  //===================================================
88  // Show cols actiona re created here but added below to status bar
89  //=============================================
90  // Cols Selector
91  QToolButton *buttShowColumns = new QToolButton(this);
92  buttShowColumns->setText("Show");
93  buttShowColumns->setIcon(QIcon(":/icon/select_cols"));
94  buttShowColumns->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
95  buttShowColumns->setPopupMode(QToolButton::InstantPopup);
96 
97 
98  QMenu *menuCols = new QMenu();
99  buttShowColumns->setMenu(menuCols);
100 
101  //= Cols Widget
102  QWidget *widgetColsSelecta = new QWidget();
103  QVBoxLayout *layCols = new QVBoxLayout();
104  widgetColsSelecta->setLayout(layCols);
105 
106  buttonGroupCols = new QButtonGroup(this);
107  buttonGroupCols->setExclusive(false);
108  connect(buttonGroupCols, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(on_show_cols(QAbstractButton*)));
109 
110  mainObject->settings->beginGroup("pilots_widget_cols");
111 
112  QCheckBox *chkShowModel = new QCheckBox();
113  chkShowModel->setText("Aircraft Type");
114  layCols->addWidget(chkShowModel);
115  buttonGroupCols->addButton(chkShowModel, C_AIRCRAFT);
116  chkShowModel->setChecked(mainObject->settings->value(QString::number(C_AIRCRAFT), "1").toBool());
117 
118  QCheckBox *chkShowLatLon = new QCheckBox();
119  chkShowLatLon->setText("Lat/Lon");
120  layCols->addWidget(chkShowLatLon);
121  buttonGroupCols->addButton(chkShowLatLon, C_LAT);
122  chkShowLatLon->setChecked(mainObject->settings->value(QString::number(C_LAT), "1").toBool());
123 
124  QCheckBox *chkShowAlt = new QCheckBox();
125  chkShowAlt->setText("Altitude");
126  layCols->addWidget(chkShowAlt);
127  buttonGroupCols->addButton(chkShowAlt, C_ALTITUDE);
128  chkShowAlt->setChecked(mainObject->settings->value(QString::number(C_ALTITUDE), "1").toBool());
129 
130  QCheckBox *chkShowHdg = new QCheckBox();
131  chkShowHdg->setText("Heading");
132  layCols->addWidget(chkShowHdg);
133  buttonGroupCols->addButton(chkShowHdg, C_HEADING);
134  chkShowHdg->setChecked(mainObject->settings->value(QString::number(C_HEADING), "1").toBool());
135 
136  mainObject->settings->endGroup();
137 
138  QWidgetAction *colsWidgetAction = new QWidgetAction(this);
139  colsWidgetAction->setDefaultWidget(widgetColsSelecta);
140  menuCols->addAction(colsWidgetAction);
141 
142 
143 
144  //=========================================================
145  //== Tree
146  tree = new QTreeWidget();
147  mainLayout->addWidget(tree);
148 
149  tree->setRootIsDecorated(false);
150  tree->setUniformRowHeights(true);
151  tree->setAlternatingRowColors(true);
152 
153  tree->header()->setStretchLastSection(true);
154  tree->header()->setResizeMode(QHeaderView::Stretch);
155  tree->headerItem()->setText(C_CALLSIGN, "Callsign");
156  tree->headerItem()->setText(C_AIRCRAFT, "Aircraft");
157  tree->headerItem()->setText(C_ALTITUDE, "Alt");
158  tree->headerItem()->setText(C_HEADING, "Hdg");
159  tree->headerItem()->setText(C_PITCH, "Pitch");
160  tree->headerItem()->setText(C_LAT, "Lat");
161  tree->headerItem()->setText(C_LON, "Lon");
162  tree->headerItem()->setText(C_FLAG, "Flag");
163  tree->headerItem()->setText(C_COUNT, "Count");
164 
165  tree->headerItem()->setTextAlignment(C_ALTITUDE, Qt::AlignRight);
166  tree->headerItem()->setTextAlignment(C_HEADING, Qt::AlignRight);
167  tree->headerItem()->setTextAlignment(C_LAT, Qt::AlignRight);
168  tree->headerItem()->setTextAlignment(C_LON, Qt::AlignRight);
169 
170  tree->setColumnHidden(C_PITCH, true);
171  tree->setColumnHidden(C_FLAG, true);
172  tree->setColumnHidden(C_COUNT, true);
173 
174  tree->setColumnHidden(C_AIRCRAFT, !chkShowModel->isChecked());
175  tree->setColumnHidden(C_HEADING, !chkShowHdg->isChecked());
176  tree->setColumnHidden(C_ALTITUDE, !chkShowAlt->isChecked());
177  tree->setColumnHidden(C_LAT, !chkShowLatLon->isChecked());
178  tree->setColumnHidden(C_LON, !chkShowLatLon->isChecked());
179 
180  tree->setColumnWidth(C_CALLSIGN, 100);
181  tree->setColumnWidth(C_AIRCRAFT, 100);
182  tree->setColumnWidth(C_ALTITUDE, 50);
183  tree->setColumnWidth(C_HEADING, 50);
184 
185  tree->setSortingEnabled(true);
186  tree->sortByColumn(C_CALLSIGN, Qt::AscendingOrder);
187 
188  connect(tree,SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),
189  this, SLOT(on_item_doubled_clicked(QTreeWidgetItem*,int)));
190 
191  //===========================================================================
192  //= Status Bar
193  statusBar = new QStatusBar();
194  mainLayout->addWidget(statusBar);
195  statusBar->showMessage("Click refresh to load");
196 
197  statusBar->addPermanentWidget(buttShowColumns);
198 
199 
200 
201 
202 
203 
204  //==========================================================
205  //= Initialize Objects
206  netMan = new QNetworkAccessManager(this);
207 
208 
209 }
210 
212 {
213 
214  server_string = "";
215  QUrl url("http://mpmap01.flightgear.org/fg_server_xml.cgi?mpserver01.flightgear.org:5001");
216  QNetworkRequest request;
217  request.setUrl(url );
218 
219  reply = netMan->get(request);
220  connect(reply, SIGNAL( error(QNetworkReply::NetworkError)),
221  this, SLOT(on_server_error(QNetworkReply::NetworkError))
222  );
223  connect(reply, SIGNAL( readyRead()),
224  this, SLOT(on_server_ready_read())
225  );
226  connect(reply, SIGNAL( finished()),
227  this, SLOT(on_server_read_finished())
228  );
229  statusBar->showMessage("Request");
230 
231 }
232 
233 
234 //==========================================================
235 //= Server Events
236 //==========================================================
237 void PilotsWidget::on_server_error(QNetworkReply::NetworkError error){
238  //qDebug() << "error" << error;
239  Q_UNUSED(error);
240  //outLog("FGx: PilotsWidget::on_server_error()");
241 }
242 
244  QString s(reply->readAll());
245  server_string.append(s);
246 }
247 
248 //=============================================
249 // Server call finished.. so parse to tree
250 //=============================================
251 /* we do not want to clear the tree and reload as user would loose focus..
252  Also the last "communicate tiem means a pilot does not clear of the list"
253  A net conection might drop and reappear later = crash or terrain terrain etc..
254  SO current plan is to make a time stamp when a new pilot is gr
255 */
256 
258  //qDebug() << "done"; // << server_string;
259 
260  statusBar->showMessage("Processing data");
261 
262  tree->setUpdatesEnabled(false);
263  //emit freeze_map(true);
265 
266  QStringList tower_names;
267  tower_names << "atc" << "atc-tower" << "atc-tower2";
268 
269  QTreeWidgetItem *rootItem = tree->invisibleRootItem();
270 
271  //== Loop all ndes and set flag to 1 - item remaining will b enuked
272  for(int idx=0; idx < rootItem->childCount(); idx++){
273  rootItem->child(idx)->setText(C_FLAG, "1");
274  }
275 
276 
277  //= Create Dom Document
278  dom.setContent(server_string);
279 
280  //= get the <fg_server> node
281  QDomNodeList nodes = dom.elementsByTagName("marker");
282 
283  QTreeWidgetItem *item;
284 
285  if (nodes.count() > 0){
286  for(int idxd =0; idxd < nodes.count(); idxd++){
287 
288  QDomNode node = nodes.at(idxd);
289  QDomNamedNodeMap attribs = node.attributes();
290 
291  // = check if pilot in list or update
292  QList<QTreeWidgetItem *> fitems = tree->findItems(attribs.namedItem("callsign").nodeValue(), Qt::MatchExactly, C_CALLSIGN);
293  if(fitems.size() == 0){
294  item = new QTreeWidgetItem(rootItem);
295  item->setText(C_CALLSIGN, attribs.namedItem("callsign").nodeValue().toUpper());
296  item->setText(C_AIRCRAFT, attribs.namedItem("model").nodeValue());
297  item->setText(C_COUNT, "0");
298 
299  tree->addTopLevelItem(item);
300  }else{
301  item = fitems.at(0);
302  }
303 
304  //== Check for atc
305  QString model = QString(attribs.namedItem("model").nodeValue());
306 
307  //= Need to catch atc models here?
308 
309  bool is_tower = tower_names.contains( model.toLower() );
310 
311 
312 
313  item->setText(C_ALTITUDE, QString::number(attribs.namedItem("alt").nodeValue().toFloat(), 'f', 0));
314  item->setTextAlignment(C_ALTITUDE, Qt::AlignRight);
315 
316  item->setText(C_HEADING, QString::number(attribs.namedItem("heading").nodeValue().toFloat(), 'f', 0));
317  item->setTextAlignment(C_HEADING, Qt::AlignRight);
318 
319  item->setText(C_LAT, attribs.namedItem("lat").nodeValue());
320  item->setTextAlignment(C_LAT, Qt::AlignRight);
321  item->setText(C_LON, attribs.namedItem("lng").nodeValue());
322  item->setTextAlignment(C_LON, Qt::AlignRight);
323 
324  item->setText(C_PITCH, attribs.namedItem("pitch").nodeValue());
325  item->setText(C_FLAG, "0");
326 
327  mapWidget->show_radar( item->text(C_CALLSIGN),
328  item->text(C_LAT),
329  item->text(C_LON),
330  item->text(C_HEADING),
331  item->text(C_ALTITUDE),
332  is_tower);
333  /*
334  emit radar(item->text(C_CALLSIGN),
335  item->text(C_LAT),
336  item->text(C_LON),
337  item->text(C_HEADING),
338  item->text(C_ALTITUDE),
339  is_tower
340  );
341  */
342  }
343  }
344 
345  //= Inc the flagged count items
346  QList<QTreeWidgetItem *> items = tree->findItems("1", Qt::MatchExactly, C_FLAG);
347  for(int idxr=0; idxr < items.count(); idxr++){
348  int count = items.at(idxr)->text(C_COUNT).toInt();
349  items.at(idxr)->setText( C_COUNT, QString::number(count + 1) );
350  }
351 
352  //== Remove dead
353  items = tree->findItems("1", Qt::MatchExactly, C_COUNT);
354  QListIterator<QTreeWidgetItem *> it(items);
355  while (it.hasNext()){
356  QTreeWidgetItem *rItem = it.next();
357  tree->invisibleRootItem()->removeChild( rItem );
358  }
359 
360  tree->setUpdatesEnabled(true);
361 
362  //= Follow selected
363  if(checkBoxFollowSelected->isChecked() && tree->selectionModel()->hasSelection()){
364  mapWidget->zoom_to_latlon(tree->currentItem()->text(C_LAT), tree->currentItem()->text(C_LON),12);
365  }
366 
367 
368  if(checkBoxAutoRefresh->isChecked()){
369  QTimer::singleShot( comboBoxHz->itemData(comboBoxHz->currentIndex()).toInt() * 1000, this, SLOT(fetch_pilots()) );
370  statusBar->showMessage(QString("Waiting %1").arg(comboBoxHz->itemData(comboBoxHz->currentIndex()).toInt()));
371 
372  }else{
373  statusBar->showMessage("Idle");
374  }
375 }
376 
377 
379  mainObject->settings->setValue("mpxmap_autorefresh_enabled", checked);
380  if(checked){
381  fetch_pilots();
382  //timer->start();
383  }else{
384  //timer->stop();
385  }
386 }
387 
389  Q_UNUSED(idx);
390  mainObject->settings->setValue("mpxmap_autorefresh_hz", comboBoxHz->itemData(comboBoxHz->currentIndex()).toString());
391  //timer->setInterval(comboBoxHz->itemData(comboBoxHz->currentIndex()).toInt());
392 }
393 
395  Q_UNUSED(colidx);
396  //emit aircraft_selected(item->text(C_CALLSIGN));
397  XAero aero(item->text(C_CALLSIGN));
398  aero.lat = item->text(C_LAT);
399  aero.lon = item->text(C_LON);
400  emit aircraft_selected(aero);
401 }
402 
403 
404 
405 void PilotsWidget::on_show_cols(QAbstractButton *button)
406 {
407  int col_idx = buttonGroupCols->id(button);
408  tree->setColumnHidden(col_idx, !button->isChecked() );
409  if(col_idx == C_LAT){
410  tree->setColumnHidden(C_LON, !button->isChecked() );
411  }
412  mainObject->settings->beginGroup("pilots_widget_cols");
413  mainObject->settings->setValue(QString::number(col_idx), button->isChecked());
414  mainObject->settings->endGroup();
415  mainObject->settings->sync();
416 }
417 
418 
420 {
421  this->mapWidget = mWidget;
422 }
QComboBox * comboBoxHz
Definition: pilotswidget.h:62
QNetworkReply * reply
Definition: pilotswidget.h:56
void zoom_to_latlon(QString lat, QString lon, int zoom)
void on_item_doubled_clicked(QTreeWidgetItem *, int)
The MainObject is an extended QObject, and the main "controller" for FGx.
Definition: mainobject.h:66
QString server_string
Definition: pilotswidget.h:57
void on_server_error(QNetworkReply::NetworkError)
void aircraft_selected(XAero aero)
QCheckBox * checkBoxAutoRefresh
Definition: pilotswidget.h:61
void on_server_read_finished()
void set_map_widget(OpenLayerWidget *mapWidget)
void show_radar(QString callsign, QString lat, QString lon, QString heading, QString altitude, bool is_tower)
QButtonGroup * buttonGroupCols
Definition: pilotswidget.h:68
QCheckBox * checkBoxFollowSelected
Definition: pilotswidget.h:59
QNetworkAccessManager * netMan
Definition: pilotswidget.h:55
QString lat
Definition: xaero.h:20
void on_show_cols(QAbstractButton *)
QDomDocument dom
Definition: pilotswidget.h:53
OpenLayerWidget * mapWidget
Definition: pilotswidget.h:52
void on_check_autorefresh(int)
void on_combo_changed(int)
QTreeWidget * tree
Definition: pilotswidget.h:64
void on_server_ready_read()
Definition: xaero.h:14
void fetch_pilots()
PilotsWidget(MainObject *mob, QWidget *parent=0)
XSettings * settings
Definition: mainobject.h:85
MainObject * mainObject
Definition: pilotswidget.h:50
QStatusBar * statusBar
Definition: pilotswidget.h:66