source: ntrip/trunk/BNC/bncwindow.cpp@ 972

Last change on this file since 972 was 968, checked in by weber, 16 years ago

* empty log message *

File size: 43.9 KB
Line 
1// Part of BNC, a utility for retrieving decoding and
2// converting GNSS data streams from NTRIP broadcasters.
3//
4// Copyright (C) 2007
5// German Federal Agency for Cartography and Geodesy (BKG)
6// http://www.bkg.bund.de
7// Czech Technical University Prague, Department of Geodesy
8// http://www.fsv.cvut.cz
9//
10// Email: euref-ip@bkg.bund.de
11//
12// This program is free software; you can redistribute it and/or
13// modify it under the terms of the GNU General Public License
14// as published by the Free Software Foundation, version 2.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25/* -------------------------------------------------------------------------
26 * BKG NTRIP Client
27 * -------------------------------------------------------------------------
28 *
29 * Class: bncWindow
30 *
31 * Purpose: This class implements the main application window.
32 *
33 * Author: L. Mervart
34 *
35 * Created: 24-Dec-2005
36 *
37 * Changes:
38 *
39 * -----------------------------------------------------------------------*/
40
41#include <unistd.h>
42#include "bncwindow.h"
43#include "bncapp.h"
44#include "bncgetthread.h"
45#include "bnctabledlg.h"
46#include "bnchlpdlg.h"
47#include "bnchtml.h"
48#include "bnctableitem.h"
49
50using namespace std;
51
52// Constructor
53////////////////////////////////////////////////////////////////////////////
54bncWindow::bncWindow() {
55
56 _caster = 0;
57
58 int ww = QFontMetrics(this->font()).width('w');
59
60 static const QStringList labels = QString("account,mountpoint,decoder,lat,long,nmea,bytes").split(",");
61
62 setMinimumSize(77*ww, 65*ww);
63
64 setWindowTitle(tr("BKG Ntrip Client (BNC) Version 1.6"));
65
66 // Create Actions
67 // --------------
68 _actHelp = new QAction(tr("&Help Contents"),this);
69 connect(_actHelp, SIGNAL(triggered()), SLOT(slotHelp()));
70
71 _actAbout = new QAction(tr("&About BNC"),this);
72 connect(_actAbout, SIGNAL(triggered()), SLOT(slotAbout()));
73
74 _actFontSel = new QAction(tr("Select &Font"),this);
75 connect(_actFontSel, SIGNAL(triggered()), SLOT(slotFontSel()));
76
77 _actSaveOpt = new QAction(tr("&Save Options"),this);
78 connect(_actSaveOpt, SIGNAL(triggered()), SLOT(slotSaveOptions()));
79
80 _actQuit = new QAction(tr("&Quit"),this);
81 connect(_actQuit, SIGNAL(triggered()), SLOT(close()));
82
83 _actAddMountPoints = new QAction(tr("Add &Mountpoints"),this);
84 connect(_actAddMountPoints, SIGNAL(triggered()), SLOT(slotAddMountPoints()));
85
86 _actDeleteMountPoints = new QAction(tr("&Delete Mountpoints"),this);
87 connect(_actDeleteMountPoints, SIGNAL(triggered()), SLOT(slotDeleteMountPoints()));
88 _actDeleteMountPoints->setEnabled(false);
89
90 _actGetData = new QAction(tr("Sta&rt"),this);
91 connect(_actGetData, SIGNAL(triggered()), SLOT(slotGetData()));
92
93 _actStop = new QAction(tr("Sto&p"),this);
94 connect(_actStop, SIGNAL(triggered()), SLOT(slotStop()));
95 _actStop->setEnabled(false);
96
97 _actwhatsthis= new QAction(tr("Help=Shift+F1"),this);
98 connect(_actwhatsthis, SIGNAL(triggered()), SLOT(slotWhatsThis()));
99
100 CreateMenu();
101 AddToolbar();
102
103 QSettings settings;
104 _proxyHostLineEdit = new QLineEdit(settings.value("proxyHost").toString());
105 _proxyPortLineEdit = new QLineEdit(settings.value("proxyPort").toString());
106 _proxyPortLineEdit->setMaximumWidth(9*ww);
107 _waitTimeSpinBox = new QSpinBox();
108 _waitTimeSpinBox->setMinimum(1);
109 _waitTimeSpinBox->setMaximum(30);
110 _waitTimeSpinBox->setSingleStep(1);
111 _waitTimeSpinBox->setSuffix(" sec");
112 _waitTimeSpinBox->setMaximumWidth(9*ww);
113 _waitTimeSpinBox->setValue(settings.value("waitTime").toInt());
114 _outFileLineEdit = new QLineEdit(settings.value("outFile").toString());
115 _outPortLineEdit = new QLineEdit(settings.value("outPort").toString());
116 _outPortLineEdit->setMaximumWidth(9*ww);
117 _outEphPortLineEdit = new QLineEdit(settings.value("outEphPort").toString());
118 _outEphPortLineEdit->setMaximumWidth(9*ww);
119 _corrPortLineEdit = new QLineEdit(settings.value("corrPort").toString());
120 _corrPortLineEdit->setMaximumWidth(9*ww);
121 _rnxPathLineEdit = new QLineEdit(settings.value("rnxPath").toString());
122 _ephPathLineEdit = new QLineEdit(settings.value("ephPath").toString());
123 _corrPathLineEdit = new QLineEdit(settings.value("corrPath").toString());
124
125 _rnxV3CheckBox = new QCheckBox();
126 _rnxV3CheckBox->setCheckState(Qt::CheckState(settings.value("rnxV3").toInt()));
127 _ephV3CheckBox = new QCheckBox();
128 _ephV3CheckBox->setCheckState(Qt::CheckState(settings.value("ephV3").toInt()));
129 _rnxScrpLineEdit = new QLineEdit(settings.value("rnxScript").toString());
130 _rnxSkelLineEdit = new QLineEdit(settings.value("rnxSkel").toString());
131 _rnxSkelLineEdit->setMaximumWidth(5*ww);
132 _rnxAppendCheckBox = new QCheckBox();
133 _rnxAppendCheckBox->setCheckState(Qt::CheckState(
134 settings.value("rnxAppend").toInt()));
135 _rnxIntrComboBox = new QComboBox();
136 _rnxIntrComboBox->setMaximumWidth(9*ww);
137 _rnxIntrComboBox->setEditable(false);
138 _rnxIntrComboBox->addItems(QString("1 min,2 min,5 min,10 min,15 min,30 min,1 hour,1 day").split(","));
139 int ii = _rnxIntrComboBox->findText(settings.value("rnxIntr").toString());
140 if (ii != -1) {
141 _rnxIntrComboBox->setCurrentIndex(ii);
142 }
143 _ephIntrComboBox = new QComboBox();
144 _ephIntrComboBox->setMaximumWidth(9*ww);
145 _ephIntrComboBox->setEditable(false);
146 _ephIntrComboBox->addItems(QString("1 min,2 min,5 min,10 min,15 min,30 min,1 hour,1 day").split(","));
147 int jj = _ephIntrComboBox->findText(settings.value("ephIntr").toString());
148 if (jj != -1) {
149 _ephIntrComboBox->setCurrentIndex(jj);
150 }
151 _corrIntrComboBox = new QComboBox();
152 _corrIntrComboBox->setMaximumWidth(9*ww);
153 _corrIntrComboBox->setEditable(false);
154 _corrIntrComboBox->addItems(QString("1 min,2 min,5 min,10 min,15 min,30 min,1 hour,1 day").split(","));
155 int mm = _corrIntrComboBox->findText(settings.value("corrIntr").toString());
156 if (mm != -1) {
157 _corrIntrComboBox->setCurrentIndex(mm);
158 }
159 _corrTimeSpinBox = new QSpinBox();
160 _corrTimeSpinBox->setMinimum(0);
161 _corrTimeSpinBox->setMaximum(30);
162 _corrTimeSpinBox->setSingleStep(1);
163 _corrTimeSpinBox->setSuffix(" sec");
164 _corrTimeSpinBox->setMaximumWidth(9*ww);
165 _corrTimeSpinBox->setValue(settings.value("corrTime").toInt());
166 _rnxSamplSpinBox = new QSpinBox();
167 _rnxSamplSpinBox->setMinimum(0);
168 _rnxSamplSpinBox->setMaximum(60);
169 _rnxSamplSpinBox->setSingleStep(5);
170 _rnxSamplSpinBox->setMaximumWidth(9*ww);
171 _rnxSamplSpinBox->setValue(settings.value("rnxSampl").toInt());
172 _rnxSamplSpinBox->setSuffix(" sec");
173
174 _binSamplSpinBox = new QSpinBox();
175 _binSamplSpinBox->setMinimum(0);
176 _binSamplSpinBox->setMaximum(60);
177 _binSamplSpinBox->setSingleStep(5);
178 _binSamplSpinBox->setMaximumWidth(9*ww);
179 _binSamplSpinBox->setValue(settings.value("binSampl").toInt());
180 _binSamplSpinBox->setSuffix(" sec");
181
182 _obsRateComboBox = new QComboBox();
183 _obsRateComboBox->setMaximumWidth(9*ww);
184 _obsRateComboBox->setEditable(false);
185 _obsRateComboBox->addItems(QString(",0.1 Hz,0.2 Hz,0.5 Hz,1 Hz,5 Hz").split(","));
186 int kk = _obsRateComboBox->findText(settings.value("obsRate").toString());
187 if (kk != -1) {
188 _obsRateComboBox->setCurrentIndex(kk);
189 }
190 _makePauseCheckBox = new QCheckBox();
191 _makePauseCheckBox->setCheckState(Qt::CheckState(
192 settings.value("makePause").toInt()));
193 _adviseRecoSpinBox = new QSpinBox();
194 _adviseRecoSpinBox->setMinimum(0);
195 _adviseRecoSpinBox->setMaximum(60);
196 _adviseRecoSpinBox->setSingleStep(1);
197 _adviseRecoSpinBox->setSuffix(" min");
198 _adviseRecoSpinBox->setMaximumWidth(9*ww);
199 _adviseRecoSpinBox->setValue(settings.value("adviseReco").toInt());
200 _adviseFailSpinBox = new QSpinBox();
201 _adviseFailSpinBox->setMinimum(0);
202 _adviseFailSpinBox->setMaximum(60);
203 _adviseFailSpinBox->setSingleStep(1);
204 _adviseFailSpinBox->setSuffix(" min");
205 _adviseFailSpinBox->setMaximumWidth(9*ww);
206 _adviseFailSpinBox->setValue(settings.value("adviseFail").toInt());
207 _logFileLineEdit = new QLineEdit(settings.value("logFile").toString());
208 _adviseScriptLineEdit = new QLineEdit(settings.value("adviseScript").toString());
209
210 _perfIntrComboBox = new QComboBox();
211 _perfIntrComboBox->setMaximumWidth(9*ww);
212 _perfIntrComboBox->setEditable(false);
213 _perfIntrComboBox->addItems(QString(",1 min,5 min,15 min,1 hour,6 hours,1 day").split(","));
214 int ll = _perfIntrComboBox->findText(settings.value("perfIntr").toString());
215 if (ll != -1) {
216 _perfIntrComboBox->setCurrentIndex(ll);
217 }
218
219 _mountPointsTable = new QTableWidget(0,7);
220
221 _mountPointsTable->horizontalHeader()->resizeSection(1,34*ww);
222 _mountPointsTable->horizontalHeader()->resizeSection(2,9*ww);
223 _mountPointsTable->horizontalHeader()->resizeSection(3,7*ww);
224 _mountPointsTable->horizontalHeader()->resizeSection(4,7*ww);
225 _mountPointsTable->horizontalHeader()->resizeSection(5,5*ww);
226 _mountPointsTable->horizontalHeader()->setResizeMode(QHeaderView::Interactive);
227 _mountPointsTable->horizontalHeader()->setStretchLastSection(true);
228 _mountPointsTable->setHorizontalHeaderLabels(labels);
229 _mountPointsTable->setGridStyle(Qt::NoPen);
230 _mountPointsTable->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
231 _mountPointsTable->setSelectionMode(QAbstractItemView::ExtendedSelection);
232 _mountPointsTable->setSelectionBehavior(QAbstractItemView::SelectRows);
233 QListIterator<QString> it(settings.value("mountPoints").toStringList());
234 if (!it.hasNext()) {
235 _actGetData->setEnabled(false);
236 }
237 int iRow = 0;
238 while (it.hasNext()) {
239 QStringList hlp = it.next().split(" ");
240 if (hlp.size() < 5) continue;
241 _mountPointsTable->insertRow(iRow);
242
243 QUrl url(hlp[0]);
244
245 QString fullPath = url.host() + QString(":%1").arg(url.port()) + url.path();
246 QString format(hlp[1]); QString latitude(hlp[2]); QString longitude(hlp[3]);
247 QString nmea(hlp[4]);
248
249 QTableWidgetItem* it;
250 it = new QTableWidgetItem(url.userInfo());
251 it->setFlags(it->flags() & ~Qt::ItemIsEditable);
252 _mountPointsTable->setItem(iRow, 0, it);
253
254 it = new QTableWidgetItem(fullPath);
255 it->setFlags(it->flags() & ~Qt::ItemIsEditable);
256 _mountPointsTable->setItem(iRow, 1, it);
257
258 it = new QTableWidgetItem(format);
259 _mountPointsTable->setItem(iRow, 2, it);
260
261 if (nmea == "yes") {
262 it = new QTableWidgetItem(latitude);
263 _mountPointsTable->setItem(iRow, 3, it);
264 it = new QTableWidgetItem(longitude);
265 _mountPointsTable->setItem(iRow, 4, it);
266 } else {
267 it = new QTableWidgetItem(latitude);
268 it->setFlags(it->flags() & ~Qt::ItemIsEditable);
269 _mountPointsTable->setItem(iRow, 3, it);
270 it = new QTableWidgetItem(longitude);
271 it->setFlags(it->flags() & ~Qt::ItemIsEditable);
272 _mountPointsTable->setItem(iRow, 4, it);
273 }
274
275 it = new QTableWidgetItem(nmea);
276 it->setFlags(it->flags() & ~Qt::ItemIsEditable);
277 _mountPointsTable->setItem(iRow, 5, it);
278
279 bncTableItem* bncIt = new bncTableItem();
280 bncIt->setFlags(bncIt->flags() & ~Qt::ItemIsEditable);
281 _mountPointsTable->setItem(iRow, 6, bncIt);
282
283 iRow++;
284 }
285 _mountPointsTable->hideColumn(0);
286 _mountPointsTable->sortItems(1);
287
288 connect(_mountPointsTable, SIGNAL(itemSelectionChanged()),
289 SLOT(slotSelectionChanged()));
290
291 _log = new QTextBrowser();
292 _log->setReadOnly(true);
293
294 // WhatsThis
295 // ---------
296 _proxyHostLineEdit->setWhatsThis(tr("<p>If you are running BNC within a protected Local Area Network (LAN), you might need to use a proxy server to access the Internet. Enter your proxy server IP and port number in case one is operated in front of BNC. If you do not know the IP and port of your proxy server, check the proxy server settings in your Internet browser or ask your network administrator.</p><p>Note that IP streaming is sometimes not allowed in a LAN. In this case you need to ask your network administrator for an appropriate modification of the local security policy or for the installation of a TCP relay to the NTRIP broadcasters. If these are not possible, you might need to run BNC outside your LAN on a network that has unobstructed connection to the Internet.</p>"));
297 _proxyPortLineEdit->setWhatsThis(tr("<p>If you are running BNC within a protected Local Area Network (LAN), you might need to use a proxy server to access the Internet. Enter your proxy server IP and port number in case one is operated in front of BNC. If you do not know the IP and port of your proxy server, check the proxy server settings in your Internet browser or ask your network administrator.</p><p>Note that IP streaming is sometimes not allowed in a LAN. In this case you need to ask your network administrator for an appropriate modification of the local security policy or for the installation of a TCP relay to the NTRIP broadcasters. If these are not possible, you might need to run BNC outside your LAN on a network that has unobstructed connection to the Internet.</p>"));
298 _waitTimeSpinBox->setWhatsThis(tr("<p>When feeding a real-time GNSS engine waiting for input epoch by epoch, BNC drops whatever is received later than 'Wait for full epoch' seconds. A value of 3 to 5 seconds is recommended, depending on the latency of the incoming streams and the delay acceptable to your real-time GNSS engine or products.</p><p>Note that 'Wait for full epoch' does not effect the RINEX Observation file content. Observations received later than 'Wait for full epoch' seconds will still be included in the RINEX Observation files.</p>"));
299 _outFileLineEdit->setWhatsThis(tr("Specify the full path to a file where synchronized observations are saved in plain ASCII format. Beware that the size of this file can rapidly increase depending on the number of incoming streams."));
300 _outPortLineEdit->setWhatsThis(tr("BNC can produce synchronized observations in binary format on your local host through an IP port. Specify a port number here to activate this function."));
301 _outEphPortLineEdit->setWhatsThis(tr("BNC can produce ephemeris data in RINEX ASCII format on your local host through an IP port. Specify a port number here to activate this function."));
302 _corrPortLineEdit->setWhatsThis(tr("BNC can produce Broadcast Ephemeris Corrections on your local host through an IP port. Specify a port number here to activate this function."));
303 _corrTimeSpinBox->setWhatsThis(tr("BNC drops Broadcast Ephemeris Corrections received later than 'Wait for full epoch' seconds. Default value is '0' seconds meaning that BNC will output whatever becomes available immediately and not drop any Ephemeris Correction."));
304 _rnxPathLineEdit->setWhatsThis(tr("Here you specify the path to where the RINEX Observation files will be stored. If the specified directory does not exist, BNC will not create RINEX Observation files."));
305 _ephPathLineEdit->setWhatsThis(tr("Specify the path for saving Broadcast Ephemeris data as RINEX Navigation files. If the specified directory does not exist, BNC will not create RINEX Navigation files."));
306 _corrPathLineEdit->setWhatsThis(tr("Specify a directory for saving Broadcast Ephemeris Correction files. If the specified directory does not exist, BNC will not create the files."));
307 _rnxScrpLineEdit->setWhatsThis(tr("<p>Whenever a RINEX Observation file is saved, you might want to compress, copy or upload it immediately via FTP. BNC allows you to execute a script/batch file to carry out these operations. To do that specify the full path of the script/batch file here. BNC will pass the full RINEX Observation file path to the script as a command line parameter (%1 on Windows systems, $1 onUnix/Linux systems).</p><p>The triggering event for calling the script or batch file is the end of a RINEX Observation file 'Interval'. If that is overridden by a stream outage, the triggering event is the stream reconnection.</p>"));
308 _rnxSkelLineEdit->setWhatsThis(tr("<p>Whenever BNC starts generating RINEX Observation files (and then once every day at midnight), it first tries to retrieve information needed for RINEX headers from so-called public RINEX header skeleton files which are derived from sitelogs. However, sometimes public RINEX header skeleton files are not available, its contents is not up to date, or you need to put additional/optional records in the RINEX header.</p><p>For that BNC allows using personal skeleton files that contain the header records you would like to include. You can derive a personal RINEX header skeleton file from the information given in an up to date sitelog. A file in the RINEX 'Directory' with the RINEX 'Skeleton extension' is interpreted by BNC as a personal RINEX header skeleton file for the corresponding stream.</p>"));
309 _rnxAppendCheckBox->setWhatsThis(tr("<p>When BNC is started, new files are created by default and any existing files with the same name will be overwritten. However, users might want to append already existing files following a restart of BNC, a system crash or when BNC crashed. Tick 'Append files' to continue with existing files and keep what has been recorded so far.</p>"));
310 _rnxIntrComboBox->setWhatsThis(tr("<p>Select the length of the RINEX Observation file.</p>"));
311 _ephIntrComboBox->setWhatsThis(tr("<p>Select the length of the RINEX Navigation file.</p>"));
312 _corrIntrComboBox->setWhatsThis(tr("<p>Select the length of the Broadcast Ephemeris Correction files.</p>"));
313 _rnxSamplSpinBox->setWhatsThis(tr("<p>Select the RINEX Observation sampling interval in seconds. A value of zero '0' tells BNC to store all received epochs into RINEX.</p>"));
314 _binSamplSpinBox->setWhatsThis(tr("<p>Select the Observation sampling interval in seconds. A value of zero '0' tells BNC to send/store all received epochs.</p>"));
315 _obsRateComboBox->setWhatsThis(tr("<p>BNC can collect all returns (success or failure) coming from a decoder within a certain short time span to then decide whether a stream has an outage or its content is corrupted. The procedure needs a rough estimate of the expected 'Observation rate' of the incoming streams. When a continuous problem is detected, BNC can inform its operator about this event through an advisory note.</p><p>An empty option field (default) means that you don't want an explicit information from BNC about stream outages and incoming streams that can not be decoded and that the special procedure for handling of corrupted streams is bypassed.</p>"));
316 _adviseRecoSpinBox->setWhatsThis(tr("<p>Following a stream outage or a longer series of bad observations, an advisory note is generated when valid observations are received again throughout the 'Recovery threshold' time span. A value of about 5min (default) is recommended.</p><p>A value of zero '0' means that for any stream recovery, however short, BNC immediately generates an advisory note.</p><p>Note that for using this function you need to specify the 'Observation rate'.</p>"));
317 _adviseFailSpinBox->setWhatsThis(tr("<p>An advisory note is generated when no (or only corrupted) observations are seen throughout the 'Failure threshold' time span. A value of 15 min (default) is recommended.</p><p>A value of zero '0' means that for any stream failure, however short, BNC immediately generates an advisory note.</p><p>Note that for using this function you need to specify the 'Observation rate'.</p>"));
318 _makePauseCheckBox->setWhatsThis(tr("<p>In case of a continuously corrupted stream, the decoding process can be paused and decodings are then attempted again at decreasing rate till the stream hopefully recovers. Tick 'Pause' to activate this function.</p><p>Do not tick 'Pause' (default) in order to prevent BNC from making any decoding pause. Be aware that this may incur an unnecessary workload.</p><p>Note that this function is only effective if an 'Observation rate' is specified.</p>"));
319 _logFileLineEdit->setWhatsThis(tr("Records of BNC's activities are shown in the Log section on the bottom of this window. They can be saved into a file when a valid path is specified in the 'Logfile (full path)' field."));
320 _adviseScriptLineEdit->setWhatsThis(tr("<p>Specify the full path to a script or batch file to handle advisory notes generated in the event of corrupted streams or stream outages. The affected mountpoint and one of the comments 'Begin_Outage', 'End_Outage', 'Begin_Corrupted', or 'End_Corrupted' are passed on to the script as command line parameters.</p><p>The script can be configured to send an email to BNC's operator and/or to the affected stream provider. An empty option field (default) or invalid path means that you don't want to use this option.</p><p> Note that for using this function you need to specify the 'Observation rate'.</p>"));
321 _perfIntrComboBox->setWhatsThis(tr("<p>BNC can average all latencies per stream over a certain period of GPS time. The resulting mean latencies are recorded in the Log file/section at the end of each 'Performance log' interval together with results of a statistical evaluation (approximate number of covered epochs, data gaps).</p><p>Select a 'Performance log' interval or select the empty option field if you do not want BNC to log latencies and statistical information.</p>"));
322 _mountPointsTable->setWhatsThis(tr("<p>Streams selected for retrieval are listed in the 'Mountpoints' section. Clicking on 'Add Mountpoints' button will open a window that allows the user to select data streams from an NTRIP broadcaster according to their mountpoints. To remove a stream from the 'Mountpoints' list, highlight it by clicking on it and hit the 'Delete Mountpoints' button. You can also remove multiple mountpoints by highlighting them using +Shift and +Ctrl.</p><p>BNC automatically allocates one of its internal decoders to a stream based on the stream's 'format' and 'format-details' as given in the sourcetable. However, there might be cases where you need to override the automatic selection due to incorrect sourcetable for example. BNC allows users to manually select the required decoder by editing the decoder string. Double click on the 'decoder' field, enter your preferred decoder and then hit Enter. The accepted decoder strings are 'RTCM_2.x', 'RTCM_3.x', and 'RTIGS'.</p><p>In case you need to log the raw data as is, BNC allows users to by-pass its decoders and and directly save the input in daily log files. To do this specify the decoder string as 'ZERO'.</p><p>BNC can also retrieve streams from virtual reference stations (VRS). To initiate these streams, an approximate rover position needs to be sent in NMEA GGA message to the NTRIP broadcaster. In return, a user-specific data stream is generated, typically by a Network-RTK software. This stream is customized to the exact latitude and longitude as shown in the 'lat' and 'long' columns under 'Mountpoints'. These VRS streams are indicated by a 'yes' in the 'nmea' column under 'Mountpoints' as well as in the sourcetable. The default 'lat' and 'long' values are taken from the sourcetable. However, in most cases you would probably want to change this according to your requirement. Double click on 'lat' and 'long' fields, enter the values you wish to send and then hit Enter. The format is in positive north latitude degrees (e.g. for northern hemisphere: 52.436, for southern hemisphere: -24.567) and eastern longitude degrees (e.g.: 358.872 or -1.128). Only mountpoints with a 'yes' in its 'nmea' column can be edited. The position should preferably be a point within the coverage of the network.</p>"));
323 _log->setWhatsThis(tr("Records of BNC's activities are shown in the Log section. The message log covers the communication status between BNC and the NTRIP broadcaster as well as any problems that occur in the communication link, stream availability, stream delay, stream conversion etc."));
324 _ephV3CheckBox->setWhatsThis(tr("The default format for RINEX Navigation files containing Broadcast Ephemeris is RINEX Version 2.11. Select 'Version 3' if you want to save the ephemeris in RINEX Version 3 format."));
325 _rnxV3CheckBox->setWhatsThis(tr("The default format for RINEX Observation files is RINEX Version 2.11. Select 'Version 3' if you want to save the observations in RINEX Version 3 format."));
326
327 // Canvas with Editable Fields
328 // ---------------------------
329 _canvas = new QWidget;
330 setCentralWidget(_canvas);
331
332 QTabWidget* aogroup = new QTabWidget();
333 QWidget* pgroup = new QWidget();
334 QWidget* ggroup = new QWidget();
335 QWidget* sgroup = new QWidget();
336 QWidget* egroup = new QWidget();
337 QWidget* agroup = new QWidget();
338 QWidget* cgroup = new QWidget();
339 QWidget* ogroup = new QWidget();
340 aogroup->addTab(pgroup,tr("Proxy"));
341 aogroup->addTab(ggroup,tr("General"));
342 aogroup->addTab(ogroup,tr("RINEX Observations"));
343 aogroup->addTab(egroup,tr("RINEX Ephemeris"));
344 aogroup->addTab(sgroup,tr("Synchronized Observations"));
345 aogroup->addTab(cgroup,tr("Ephemeris Corrections"));
346 aogroup->addTab(agroup,tr("Monitor"));
347
348 QGridLayout* pLayout = new QGridLayout;
349 pLayout->setColumnMinimumWidth(0,12*ww);
350 pLayout->addWidget(new QLabel("Proxy host"),0,0, Qt::AlignLeft);
351 pLayout->addWidget(_proxyHostLineEdit,0, 1);
352 pLayout->addWidget(new QLabel("Proxy port"),1,0, Qt::AlignLeft);
353 pLayout->addWidget(_proxyPortLineEdit,1,1);
354 pLayout->addWidget(new QLabel("Settings for the proxy in protected networks, leave the boxes blank if none."),2, 0, 1, 2, Qt::AlignLeft);
355 pLayout->addWidget(new QLabel(" "),3,0);
356 pLayout->addWidget(new QLabel(" "),4,0);
357 pLayout->addWidget(new QLabel(" "),5,0);
358 pgroup->setLayout(pLayout);
359
360 QGridLayout* gLayout = new QGridLayout;
361 gLayout->setColumnMinimumWidth(0,12*ww);
362 gLayout->addWidget(new QLabel("Logfile (full path)"), 0,0);
363 gLayout->addWidget(_logFileLineEdit, 0,1);
364 gLayout->addWidget(new QLabel("Append files") ,1,0 );
365 gLayout->addWidget(_rnxAppendCheckBox, 1,1 );
366 gLayout->addWidget(new QLabel("General settings for logfile and file handling."),2, 0, 1, 2, Qt::AlignLeft);
367 gLayout->addWidget(new QLabel(" "),3,0);
368 gLayout->addWidget(new QLabel(" "),4,0);
369 gLayout->addWidget(new QLabel(" "),5,0);
370 ggroup->setLayout(gLayout);
371
372 QGridLayout* sLayout = new QGridLayout;
373 sLayout->setColumnMinimumWidth(0,12*ww);
374 sLayout->addWidget(new QLabel("Port"), 0, 0);
375 sLayout->addWidget(_outPortLineEdit, 0, 1);
376 sLayout->addWidget(new QLabel("Wait for full epoch"), 1, 0);
377 sLayout->addWidget(_waitTimeSpinBox, 1, 1);
378 sLayout->addWidget(new QLabel("File (full path)"), 2, 0);
379 sLayout->addWidget(_outFileLineEdit, 2, 1);
380 sLayout->addWidget(new QLabel("Sampling"), 3, 0, Qt::AlignLeft);
381 sLayout->addWidget(_binSamplSpinBox, 3, 1, Qt::AlignLeft);
382 sLayout->addWidget(new QLabel("Output synchronized observations epoch by epoch."),4,0,1,2,Qt::AlignLeft);
383 sLayout->addWidget(new QLabel(" "),5,0);
384 sLayout->addWidget(new QLabel(" "),6,0);
385 sgroup->setLayout(sLayout);
386
387 QGridLayout* eLayout = new QGridLayout;
388 eLayout->setColumnMinimumWidth(0,12*ww);
389 eLayout->addWidget(new QLabel("Directory"), 0, 0);
390 eLayout->addWidget(_ephPathLineEdit, 0, 1);
391 eLayout->addWidget(new QLabel("Interval"), 1, 0);
392 eLayout->addWidget(_ephIntrComboBox, 1, 1);
393 eLayout->addWidget(new QLabel("Port"), 2, 0);
394 eLayout->addWidget(_outEphPortLineEdit, 2, 1);
395 eLayout->addWidget(new QLabel("Version 3"), 3, 0);
396 eLayout->addWidget(_ephV3CheckBox, 3, 1);
397 eLayout->addWidget(new QLabel("Saving RINEX ephemeris files and ephemeris output through IP port."),4,0,1,2,Qt::AlignLeft);
398 eLayout->addWidget(new QLabel(" "),5,0);
399 egroup->setLayout(eLayout);
400
401 QGridLayout* aLayout = new QGridLayout;
402 aLayout->setColumnMinimumWidth(0,12*ww);
403 aLayout->setColumnMinimumWidth(1,8*ww);
404 aLayout->setColumnMinimumWidth(2,12*ww);
405 aLayout->setColumnMinimumWidth(3,40*ww);
406 aLayout->addWidget(new QLabel("Observation rate"), 0, 0);
407 aLayout->addWidget(_obsRateComboBox, 0, 1);
408 aLayout->addWidget(new QLabel("Failure threshold"), 1, 0);
409 aLayout->addWidget(_adviseFailSpinBox, 1, 1);
410 aLayout->addWidget(new QLabel("Recovery threshold"), 2, 0);
411 aLayout->addWidget(_adviseRecoSpinBox, 2, 1);
412 aLayout->addWidget(new QLabel("Pause"), 2, 2, Qt::AlignRight);
413 aLayout->addWidget(_makePauseCheckBox, 2, 3, Qt::AlignLeft);
414 aLayout->addWidget(new QLabel("Script (full path)"), 3, 0);
415 aLayout->addWidget(_adviseScriptLineEdit, 3, 1,1,3);
416 aLayout->addWidget(new QLabel("Performance log"), 4, 0);
417 aLayout->addWidget(_perfIntrComboBox, 4, 1);
418 aLayout->addWidget(new QLabel("Network monitoring, outages, handling of corrupted streams, latencies, statistics."),5,0,1,4,Qt::AlignLeft);
419 agroup->setLayout(aLayout);
420
421 QGridLayout* oLayout = new QGridLayout;
422 oLayout->setColumnMinimumWidth(0,12*ww);
423 oLayout->setColumnMinimumWidth(1,8*ww);
424 oLayout->setColumnMinimumWidth(2,12*ww);
425 oLayout->setColumnMinimumWidth(3,40*ww);
426 oLayout->addWidget(new QLabel("Directory"), 0, 0);
427 oLayout->addWidget(_rnxPathLineEdit, 0, 1,1,3);
428 oLayout->addWidget(new QLabel("Interval"), 1, 0);
429 oLayout->addWidget(_rnxIntrComboBox, 1, 1);
430 oLayout->addWidget(new QLabel("Sampling"), 1, 2, Qt::AlignRight);
431 oLayout->addWidget(_rnxSamplSpinBox, 1, 3, Qt::AlignLeft);
432 oLayout->addWidget(new QLabel("Skeleton extension"), 2, 0);
433 oLayout->addWidget(_rnxSkelLineEdit, 2, 1);
434 oLayout->addWidget(new QLabel("Script (full path)"), 3, 0);
435 oLayout->addWidget(_rnxScrpLineEdit, 3, 1, 1, 3);
436 oLayout->addWidget(new QLabel("Version 3"), 4, 0);
437 oLayout->addWidget(_rnxV3CheckBox, 4, 1);
438 oLayout->addWidget(new QLabel("Saving RINEX observation files."),5,0,1,4, Qt::AlignLeft);
439 ogroup->setLayout(oLayout);
440
441 QGridLayout* cLayout = new QGridLayout;
442 cLayout->setColumnMinimumWidth(0,12*ww);
443 cLayout->addWidget(new QLabel("Directory"), 0, 0);
444 cLayout->addWidget(_corrPathLineEdit, 0, 1);
445 cLayout->addWidget(new QLabel("Interval"), 1, 0);
446 cLayout->addWidget(_corrIntrComboBox, 1, 1);
447 cLayout->addWidget(new QLabel("Port"), 2, 0);
448 cLayout->addWidget(_corrPortLineEdit, 2, 1);
449 cLayout->addWidget(new QLabel("Wait for full epoch"), 3, 0);
450 cLayout->addWidget(_corrTimeSpinBox, 3, 1);
451 cLayout->addWidget(new QLabel("Saving Broadcast Ephemeris correction files and correction output through IP port."),4,0,1,2,Qt::AlignLeft);
452 cLayout->addWidget(new QLabel(" "),5,0);
453 cgroup->setLayout(cLayout);
454
455 QVBoxLayout* mLayout = new QVBoxLayout;
456 mLayout->addWidget(aogroup);
457 mLayout->addWidget(_mountPointsTable);
458 mLayout->addWidget(_log);
459
460 _canvas->setLayout(mLayout);
461}
462
463// Destructor
464////////////////////////////////////////////////////////////////////////////
465bncWindow::~bncWindow() {
466 delete _caster;
467}
468
469// Retrieve Table
470////////////////////////////////////////////////////////////////////////////
471void bncWindow::slotAddMountPoints() {
472
473 QSettings settings;
474 QString proxyHost = settings.value("proxyHost").toString();
475 int proxyPort = settings.value("proxyPort").toInt();
476 if (proxyHost != _proxyHostLineEdit->text() ||
477 proxyPort != _proxyPortLineEdit->text().toInt()) {
478 int iRet = QMessageBox::question(this, "Question", "Proxy options "
479 "changed. Use the new ones?",
480 QMessageBox::Yes, QMessageBox::No,
481 QMessageBox::NoButton);
482 if (iRet == QMessageBox::Yes) {
483 settings.setValue("proxyHost", _proxyHostLineEdit->text());
484 settings.setValue("proxyPort", _proxyPortLineEdit->text());
485 }
486 }
487
488 bncTableDlg* dlg = new bncTableDlg(this);
489 dlg->move(this->pos().x()+50, this->pos().y()+50);
490 connect(dlg, SIGNAL(newMountPoints(QStringList*)),
491 this, SLOT(slotNewMountPoints(QStringList*)));
492 dlg->exec();
493 delete dlg;
494
495}
496
497// Delete Selected Mount Points
498////////////////////////////////////////////////////////////////////////////
499void bncWindow::slotDeleteMountPoints() {
500
501 int nRows = _mountPointsTable->rowCount();
502 bool flg[nRows];
503 for (int iRow = 0; iRow < nRows; iRow++) {
504 if (_mountPointsTable->isItemSelected(_mountPointsTable->item(iRow,1))) {
505 flg[iRow] = true;
506 }
507 else {
508 flg[iRow] = false;
509 }
510 }
511 for (int iRow = nRows-1; iRow >= 0; iRow--) {
512 if (flg[iRow]) {
513 _mountPointsTable->removeRow(iRow);
514 }
515 }
516 _actDeleteMountPoints->setEnabled(false);
517
518 if (_mountPointsTable->rowCount() == 0) {
519 _actGetData->setEnabled(false);
520 }
521}
522
523// New Mount Points Selected
524////////////////////////////////////////////////////////////////////////////
525void bncWindow::slotNewMountPoints(QStringList* mountPoints) {
526 int iRow = 0;
527 QListIterator<QString> it(*mountPoints);
528 while (it.hasNext()) {
529 QStringList hlp = it.next().split(" ");
530 QUrl url(hlp[0]);
531 QString fullPath = url.host() + QString(":%1").arg(url.port()) + url.path();
532 QString format(hlp[1]); QString latitude(hlp[2]); QString longitude(hlp[3]);
533 QString nmea(hlp[4]);
534
535 _mountPointsTable->insertRow(iRow);
536
537 QTableWidgetItem* it;
538 it = new QTableWidgetItem(url.userInfo());
539 it->setFlags(it->flags() & ~Qt::ItemIsEditable);
540 _mountPointsTable->setItem(iRow, 0, it);
541
542 it = new QTableWidgetItem(fullPath);
543 it->setFlags(it->flags() & ~Qt::ItemIsEditable);
544 _mountPointsTable->setItem(iRow, 1, it);
545
546 it = new QTableWidgetItem(format);
547 _mountPointsTable->setItem(iRow, 2, it);
548
549 if (nmea == "yes") {
550 it = new QTableWidgetItem(latitude);
551 _mountPointsTable->setItem(iRow, 3, it);
552 it = new QTableWidgetItem(longitude);
553 _mountPointsTable->setItem(iRow, 4, it);
554 } else {
555 it = new QTableWidgetItem(latitude);
556 it->setFlags(it->flags() & ~Qt::ItemIsEditable);
557 _mountPointsTable->setItem(iRow, 3, it);
558 it = new QTableWidgetItem(longitude);
559 it->setFlags(it->flags() & ~Qt::ItemIsEditable);
560 _mountPointsTable->setItem(iRow, 4, it);
561 }
562
563 it = new QTableWidgetItem(nmea);
564 it->setFlags(it->flags() & ~Qt::ItemIsEditable);
565 _mountPointsTable->setItem(iRow, 5, it);
566
567 bncTableItem* bncIt = new bncTableItem();
568 _mountPointsTable->setItem(iRow, 6, bncIt);
569
570 iRow++;
571 }
572 _mountPointsTable->hideColumn(0);
573 _mountPointsTable->sortItems(1);
574 if (mountPoints->count() > 0) {
575 _actGetData->setEnabled(true);
576 }
577 delete mountPoints;
578}
579
580// Save Options
581////////////////////////////////////////////////////////////////////////////
582void bncWindow::slotSaveOptions() {
583 QSettings settings;
584 settings.setValue("proxyHost", _proxyHostLineEdit->text());
585 settings.setValue("proxyPort", _proxyPortLineEdit->text());
586 settings.setValue("waitTime", _waitTimeSpinBox->value());
587 settings.setValue("obsRate", _obsRateComboBox->currentText());
588 settings.setValue("adviseFail", _adviseFailSpinBox->value());
589 settings.setValue("adviseReco", _adviseRecoSpinBox->value());
590 settings.setValue("makePause", _makePauseCheckBox->checkState());
591 settings.setValue("outFile", _outFileLineEdit->text());
592 settings.setValue("perfIntr", _perfIntrComboBox->currentText());
593 settings.setValue("outPort", _outPortLineEdit->text());
594 settings.setValue("outEphPort", _outEphPortLineEdit->text());
595 settings.setValue("corrPort", _corrPortLineEdit->text());
596 settings.setValue("corrTime", _corrTimeSpinBox->value());
597 settings.setValue("rnxPath", _rnxPathLineEdit->text());
598 settings.setValue("ephPath", _ephPathLineEdit->text());
599 settings.setValue("corrPath", _corrPathLineEdit->text());
600 settings.setValue("rnxScript", _rnxScrpLineEdit->text());
601 settings.setValue("rnxIntr", _rnxIntrComboBox->currentText());
602 settings.setValue("ephIntr", _ephIntrComboBox->currentText());
603 settings.setValue("corrIntr", _corrIntrComboBox->currentText());
604 settings.setValue("rnxSampl", _rnxSamplSpinBox->value());
605 settings.setValue("binSampl", _binSamplSpinBox->value());
606 settings.setValue("rnxSkel", _rnxSkelLineEdit->text());
607 settings.setValue("rnxAppend", _rnxAppendCheckBox->checkState());
608 settings.setValue("rnxV3", _rnxV3CheckBox->checkState());
609 settings.setValue("ephV3", _ephV3CheckBox->checkState());
610 settings.setValue("logFile", _logFileLineEdit->text());
611 settings.setValue("adviseScript",_adviseScriptLineEdit->text());
612
613QStringList mountPoints;
614
615 for (int iRow = 0; iRow < _mountPointsTable->rowCount(); iRow++) {
616 QUrl url( "//" + _mountPointsTable->item(iRow, 0)->text() +
617 "@" + _mountPointsTable->item(iRow, 1)->text() );
618
619 mountPoints.append(url.toString() + " " +
620 _mountPointsTable->item(iRow, 2)->text()
621 + " " + _mountPointsTable->item(iRow, 3)->text()
622 + " " + _mountPointsTable->item(iRow, 4)->text()
623 + " " + _mountPointsTable->item(iRow, 5)->text());
624 }
625 settings.setValue("mountPoints", mountPoints);
626}
627
628// All get slots terminated
629////////////////////////////////////////////////////////////////////////////
630void bncWindow::slotGetThreadErrors() {
631 slotMessage("All Get Threads Terminated");
632 ((bncApp*)qApp)->slotMessage("All Get Threads Terminated");
633 _actAddMountPoints->setEnabled(true);
634 _actGetData->setEnabled(true);
635}
636
637// Retrieve Data
638////////////////////////////////////////////////////////////////////////////
639void bncWindow::slotGetData() {
640 slotSaveOptions();
641
642 _actAddMountPoints->setEnabled(false);
643 _actDeleteMountPoints->setEnabled(false);
644 _actGetData->setEnabled(false);
645 _actStop->setEnabled(true);
646
647 _caster = new bncCaster(_outFileLineEdit->text(),
648 _outPortLineEdit->text().toInt());
649
650 ((bncApp*)qApp)->setPort(_outEphPortLineEdit->text().toInt());
651 ((bncApp*)qApp)->setPortCorr(_corrPortLineEdit->text().toInt());
652
653 connect(_caster, SIGNAL(getThreadErrors()),
654 this, SLOT(slotGetThreadErrors()));
655
656 connect(_caster, SIGNAL(newMessage(QByteArray)),
657 this, SLOT(slotMessage(QByteArray)));
658 connect(_caster, SIGNAL(newMessage(QByteArray)),
659 (bncApp*)qApp, SLOT(slotMessage(QByteArray)));
660
661 slotMessage("============ Start BNC ============");
662 ((bncApp*)qApp)->slotMessage("============ Start BNC ============");
663
664 for (int iRow = 0; iRow < _mountPointsTable->rowCount(); iRow++) {
665 QUrl url( "//" + _mountPointsTable->item(iRow, 0)->text() +
666 "@" + _mountPointsTable->item(iRow, 1)->text() );
667
668 QByteArray format = _mountPointsTable->item(iRow, 2)->text().toAscii();
669
670 QByteArray latitude = _mountPointsTable->item(iRow, 3)->text().toAscii();
671 QByteArray longitude = _mountPointsTable->item(iRow, 4)->text().toAscii();
672 QByteArray nmea = _mountPointsTable->item(iRow, 5)->text().toAscii();
673
674 bncGetThread* getThread = new bncGetThread(url, format, latitude, longitude, nmea, iRow);
675
676 connect(getThread, SIGNAL(newMessage(QByteArray)),
677 this, SLOT(slotMessage(QByteArray)));
678 connect(getThread, SIGNAL(newMessage(QByteArray)),
679 (bncApp*)qApp, SLOT(slotMessage(QByteArray)));
680
681 connect(getThread, SIGNAL(newBytes(QByteArray, double)),
682 (bncTableItem*) _mountPointsTable->item(iRow, 6),
683 SLOT(slotNewBytes(QByteArray, double)));
684
685 _caster->addGetThread(getThread);
686
687 getThread->start();
688 }
689}
690
691// Retrieve Data
692////////////////////////////////////////////////////////////////////////////
693void bncWindow::slotStop() {
694 int iRet = QMessageBox::question(this, "Stop", "Stop retrieving data?",
695 QMessageBox::Yes, QMessageBox::No,
696 QMessageBox::NoButton);
697 if (iRet == QMessageBox::Yes) {
698 delete _caster; _caster = 0;
699 _actGetData->setEnabled(true);
700 _actStop->setEnabled(false);
701 _actAddMountPoints->setEnabled(true);
702 }
703}
704
705// Close Application gracefully
706////////////////////////////////////////////////////////////////////////////
707void bncWindow::closeEvent(QCloseEvent* event) {
708
709 int iRet = QMessageBox::question(this, "Close", "Save Options?",
710 QMessageBox::Yes, QMessageBox::No,
711 QMessageBox::Cancel);
712
713 if (iRet == QMessageBox::Cancel) {
714 event->ignore();
715 return;
716 }
717 else if (iRet == QMessageBox::Yes) {
718 slotSaveOptions();
719 }
720
721 QMainWindow::closeEvent(event);
722}
723
724// User changed the selection of mountPoints
725////////////////////////////////////////////////////////////////////////////
726void bncWindow::slotSelectionChanged() {
727 if (_mountPointsTable->selectedItems().isEmpty()) {
728 _actDeleteMountPoints->setEnabled(false);
729 }
730 else {
731 _actDeleteMountPoints->setEnabled(true);
732 }
733}
734
735// Display Program Messages
736////////////////////////////////////////////////////////////////////////////
737void bncWindow::slotMessage(const QByteArray msg) {
738
739 const int maxBufferSize = 10000;
740
741 QString txt = _log->toPlainText() + "\n" +
742 QDateTime::currentDateTime().toUTC().toString("yy-MM-dd hh:mm:ss ") + msg;
743 _log->clear();
744 _log->append(txt.right(maxBufferSize));
745}
746
747// About Message
748////////////////////////////////////////////////////////////////////////////
749void bncWindow::slotAbout() {
750 new bncAboutDlg(0);
751}
752
753// Help Window
754////////////////////////////////////////////////////////////////////////////
755void bncWindow::slotHelp() {
756 QUrl url;
757 url.setPath(":bnchelp.html");
758 new bncHlpDlg(0, url);
759}
760
761// Select Fonts
762////////////////////////////////////////////////////////////////////////////
763void bncWindow::slotFontSel() {
764 bool ok;
765 QFont newFont = QFontDialog::getFont(&ok, this->font(), this);
766 if (ok) {
767 QSettings settings;
768 settings.setValue("font", newFont.toString());
769 QApplication::setFont(newFont);
770 int ww = QFontMetrics(newFont).width('w');
771 setMinimumSize(60*ww, 80*ww);
772 resize(60*ww, 80*ww);
773 }
774}
775
776// Whats This Help
777void bncWindow::slotWhatsThis() {
778QWhatsThis::enterWhatsThisMode();
779}
780
781void bncWindow::CreateMenu() {
782 // Create Menus
783 // ------------
784 _menuFile = menuBar()->addMenu(tr("&File"));
785 _menuFile->addAction(_actFontSel);
786 _menuFile->addSeparator();
787 _menuFile->addAction(_actSaveOpt);
788 _menuFile->addSeparator();
789 _menuFile->addAction(_actQuit);
790
791 _menuHlp = menuBar()->addMenu(tr("&Help"));
792 _menuHlp->addAction(_actHelp);
793 _menuHlp->addAction(_actAbout);
794
795}
796
797void bncWindow::AddToolbar() {
798 // Tool (Command) Bar
799 // ------------------
800 QToolBar* toolBar = new QToolBar;
801 addToolBar(Qt::BottomToolBarArea, toolBar);
802 toolBar->setMovable(false);
803 toolBar->addAction(_actAddMountPoints);
804 toolBar->addAction(_actDeleteMountPoints);
805 toolBar->addAction(_actGetData);
806 toolBar->addAction(_actStop);
807 toolBar->addWidget(new QLabel(" "));
808 toolBar->addAction(_actwhatsthis);
809}
810
811bncAboutDlg::bncAboutDlg(QWidget* parent) :
812 QDialog(parent) {
813
814 QTextBrowser* tb = new QTextBrowser;
815 QUrl url; url.setPath(":bncabout.html");
816 tb->setSource(url);
817 tb->setReadOnly(true);
818
819 int ww = QFontMetrics(font()).width('w');
820 QPushButton* _closeButton = new QPushButton("Close");
821 _closeButton->setMaximumWidth(10*ww);
822 connect(_closeButton, SIGNAL(clicked()), this, SLOT(close()));
823
824 QGridLayout* dlgLayout = new QGridLayout();
825 QLabel* img = new QLabel();
826 img->setPixmap(QPixmap(":ntrip-logo.png"));
827 dlgLayout->addWidget(img, 0,0);
828 dlgLayout->addWidget(new QLabel("BKG NTRIP Client (BNC) Version 1.6"), 0,1);
829 dlgLayout->addWidget(tb,1,0,1,2);
830 dlgLayout->addWidget(_closeButton,2,1,Qt::AlignRight);
831
832 setLayout(dlgLayout);
833 resize(60*ww, 60*ww);
834 show();
835}
836
837bncAboutDlg::~bncAboutDlg() {
838};
839
Note: See TracBrowser for help on using the repository browser.