Following excellent review of a recent PR, I was asked to update the conventional string-based Qt connections to the new-style Qt connections. (https://wiki.qt.io/New_Signal_Slot_Syntax) The old style is:

connect(
    sender, SIGNAL( valueChanged( QString, QString ) ),
    receiver, SLOT( updateValue( QString ) )
);

My old-style connection is:

connect(ui.timeDiffEdit, SIGNAL(timeChanged(const QTime)), this, SLOT(timeDiffEditChanged()));

For the new style the specification in the Qt documentation is:

connect(
    sender, &Sender::valueChanged,
    receiver, &Receiver::updateValue
);

My formulation, reflecting my strong deficiencies in Qt coding but following the above, for the new connection is:

connect(this, ui.timeDiffEdit->timeChanged(ui.timeDiffEdit->time()),this, this->timeDiffEditChanged());

The second parameter needs to be a pointer, for which I used ui.timeDiffEdit. The timeChanged() signal needs a QTime value, so I provided that with ui.timeDeffEdit->time(), the actual amount of time by which the timeDiffEdit has been changed.

The last parameter also needs an address, provided by this->timeDiffEditChanged() is the response to the signal fromtimeDiffEdit->timeChanged(). It is a void function and the source of build problems. The compiler generates an error:

/home/willem/src/subsurface/desktop-widgets/importgps.cpp:30:104: error: invalid use of void expression connect(this, ui.timeDiffEdit->timeChanged(ui.timeDiffEdit->time()), this, this->timeDiffEditChanged());
^

Obviously, accessing the pointer this->timeDiffEditChanged() should not return a void value. I have no idea of how to respond to this error. Any suggestions are very welcome. For completeness I attach the code for the full object to this email.

Kind regards,

willem




--
This message and attachments are subject to a disclaimer.

Please refer to 
http://upnet.up.ac.za/services/it/documentation/docs/004167.pdf <http://upnet.up.ac.za/services/it/documentation/docs/004167.pdf> for full details.
// SPDX-License-Identifier: GPL-2.0
#include "ui_importgps.h"
#include "desktop-widgets/importgps.h"
#include "desktop-widgets/locationinformation.h"
#include "core/dive.h"

#include <time.h>
#include <QFileDialog>
#include <QProcess>
#include <QDateTime>
#include <QDate>
#include <stdlib.h>
#include <stdio.h>
#include <QDebug>

#define BUFFER_SIZE 5000

/* Import dive coordinates from a GPS device and synchronise them with the dive profile information
   of a dive computer. This file contains the infrastructure to:
   1) Read a .GPX file from a GPS system.
   2) Find the first gpx trackpoint that follows after the start of the dive.
   3) Allow modification of the coordinates dependent on international time zone and
              on differences in local time settings between the GPS and the dive computer.
   4) Saving the coordinates into the Coordinates text box in the Dive Site Edit panel
              and which which causes the map to show the location of the dive site. 
   The structure coords is used to store critical information.  */
ImportGPS::ImportGPS(QWidget *parent, QString fileName, class Ui::LocationInformation *LocationUI) : QDialog(parent),
	fileName(fileName), LocationUI(LocationUI)
{
	connect(this, ui.timeDiffEdit->timeChanged(ui.timeDiffEdit->time()), this, this->timeDiffEditChanged());

//	connect(ui.timeDiffEdit, SIGNAL(timeChanged(const QTime)), this, SLOT(timeDiffEditChanged()));
	connect(ui.timeZoneEdit, SIGNAL(timeChanged(const QTime)), this, SLOT(timeZoneEditChanged()));
	connect(ui.timezone_backwards, SIGNAL(toggled(bool)), this, SLOT(changeZoneBackwards()));
	connect(ui.timezone_forward, SIGNAL(toggled(bool)), this, SLOT(changeZoneForward()));
	connect(ui.diff_backwards, SIGNAL(toggled(bool)), this, SLOT(changeDiffBackwards()));
	connect(ui.diff_forward, SIGNAL(toggled(bool)), this, SLOT(changeDiffForward()));
	connect(ui.GPSbuttonBox, SIGNAL(clicked(QAbstractButton *)), this, SLOT(buttonClicked(QAbstractButton *)));
	coords.settingsDiff_offset = 0;
	coords.timeZone_offset = 0;
	coords.lat = 0;
	coords.lon = 0;
	pixmapSize = (int) (ui.diveDateLabel->height() / 2);
}

void  ImportGPS::buttonClicked(QAbstractButton *button)
{
	if (ui.GPSbuttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) {
		// Write the coordinates in decimal degree format to the Coordinates QLineEdit of the LocationaInformationWidget UI:
		LocationUI->diveSiteCoordinates->setText(QString::number(coords.lat) + ", " + QString::number(coords.lon));
		LocationUI->diveSiteCoordinates->editingFinished();
	} else {
		close();
	}
}

// Extract text from the present position in the file until
//  the first 'delim' character is encountered.
int ImportGPS::get_substring(FILE *f, char *buf, char delim)
{
	int j;
	char c;
	for (j = 0; (c = fgetc(f)); j++) {
		if (c == delim) break;
		if (c == EOF) return 1;
		buf[j] = c;
		if (j >= BUFFER_SIZE)
			return 2;
	}
	buf[j] = 0x0; // terminate the string
	return 0;
}

// Find the next occurence of a specified GPX element in the file,
// characerised by a "<xxx " or "<xxx>" character sequence.
// s specifies the name of the element searched for.
// termc is the ending character of the element name search = '>' or ' '.
int ImportGPS::find_xml_element(FILE *f, const char *s, char *buf, char termc)
{
	bool match = false;
	int j;
	char c;
	char skipdelim = (termc == ' ') ? '>' : ' ';
	do {
		for (j = 0; (c = fgetc(f)); j++) {  // Find the first '<' character
			if (c == '<')
				break;
			if (c == EOF)
				return 1;
			if (j >= BUFFER_SIZE)
				return 2;
		}
		for (j = 0; (c = fgetc(f)); j++) {  // Extract the xml element name after the '<'
			if (c == EOF)
				return 1;
			buf[j] = c;
			if ((c == '>') || (c == ' '))
				break;
		}
		buf[j] = 0x0;	// terminate the xml element name
		if (!(strcmp(buf, "/trk"))) // End of GPS track found: return EOF
			return 1;
		if (c == skipdelim) continue; // if wrong delimiter for this element was found
		if (strcmp(s, buf))       // Compare xml element name from gpx file with the
			match = false;    // the element searched for.
		else
			match = true;
	} while (match == false);
	return 0;
}

// Extract characters in src from first to last position 
// e.g. substr("ascdef",dest,3,5) yields dest = "cde".
char* ImportGPS::substr(const char *src, char *dest, int first, int last)
{
	char *substring = dest;
	for (int i = first; i <= last && (*src != '\0'); i++) {
		*substring = *(src + i);  // copy substr from src to  dest
		substring++;
	}
	*substring = '\0';    // terminate and return..
	return dest;          // ..the destination string
}

// Find the coordinates at the time specified in coords.start_dive
// by searching the gpx file "fileName"
int ImportGPS::getCoordsFromFile() 
{
	struct tm tm1;
	time_t when = 0;
	double lon, lat;
	char buf[BUFFER_SIZE];
	char strbuf[50];
	int line=0;
	int64_t time_offset = coords.settingsDiff_offset + coords.timeZone_offset;
	time_t divetime;
	bool first_line = true;
	bool found = false;
	QByteArray local8bitBAString1 = fileName.toLocal8Bit(); // Do these stupid gymnastics to
	char * fname = local8bitBAString1.data();               // convert QString to a C string filename
	divetime = coords.start_dive;
	FILE *f1;
	if (!(f1 = fopen(fname, "r"))) {
		fprintf(stderr, "File open error %s\n", fname);
		return 1;
		}
#ifdef GPSDEBUG
	struct tm time; // decode the time of start of dive:
	utc_mkdate(divetime, &time);
	int dyr,dmon,dday,dhr,dmin;
	dyr = time.tm_year;
	dmon = time.tm_mon;
	dday = time.tm_mday;
	dhr = time.tm_hour;
	dmin = time.tm_min;
#endif

	do {
		line++;  // this is the sequence number of the trkpt xml element processed
		// Find next trkpt xml element
		if (find_xml_element(f1, "trkpt", buf, ' ')) // find start of next trackpoint
			break;           // (This function also detects </trk> and signals EOF)
		// == Get coordinates: ==
		if (get_substring(f1, buf, '"'))  // read up to the "lat" attribute
			break; // on EOF
		if (strcmp(buf, "lat=")) {
			fprintf(stderr, "GPX parse error: cannot find latitude (trkpt #%d)\n", line);
			return 1;
		}
		if (get_substring(f1, buf, '"'))  // get string with latitude
			break; // on EOF
		lat = atof(buf);                  // Convert lat to decimal
		if (get_substring(f1, buf, ' '))  // Read past space char
			break; // on EOF
		if (get_substring(f1, buf, '"'))  // Read up to "lon" attribute
			break; // on EOF
		if (strcmp(buf, "lon=")) {
			fprintf(stderr, "GPX parse error: cannot find longitude (trkpt #%d)\n", line);
			return 1;
		}
		if (get_substring(f1, buf, '"'))  // get string with longitude
			break; // on EOF
		lon = atof(buf);                  // Convert longitude to decimal
		// == get time: ==
		if (find_xml_element(f1, "time", buf, '>')) // Find the <time> element
			break; // on EOF
		if (get_substring(f1, buf, '<'))  // Read the string containing date/time
			break; // on EOF
		tm1.tm_year = atoi(substr(buf, strbuf, 0,3));  // Extract the different substrings:
		tm1.tm_mon = atoi(substr(buf, strbuf, 5,6))-1;
		tm1.tm_mday = atoi(substr(buf, strbuf, 8,9));
		tm1.tm_hour = atoi(substr(buf, strbuf, 11,12));
		tm1.tm_min = atoi(substr(buf, strbuf, 14,15));
		tm1.tm_sec = atoi(substr(buf, strbuf, 17,18));
		when = utc_mktime(&tm1) + time_offset;
		if (first_line) {
			first_line = false;
			coords.start_track = when;
		}
		if ((when > divetime) && (found == false)) {   // This GPS time corresponds to the start of the dive
			coords.lon = lon; // save the coordinates
			coords.lat = lat;
			found = true;
		}
#ifdef GPSDEBUG
		utc_mkdate(when, &time); // print time and coordinates of each of the trkpt elements of the GPX file
		fprintf(stderr, " %02d: lat=%f lon=%f timestamp=%ld (%ld) %02d/%02d/%02d %02d:%02d  dt=%ld  %02d/%02d/%02d %02d:%02d\n", line, lat,
		lon, when, time_offset, time.tm_year, time.tm_mon+1, time.tm_mday, time.tm_hour, time.tm_min, divetime, dyr, dmon+1, dday,dhr, dmin );
#endif
	} while (true); // This loop executes until EOF causes a break out of the loop
	coords.end_track = when;
	fclose(f1);
	return 0;
}

// Fill the visual elements of the synchronisation panel with information
void  ImportGPS::updateUI()
{
	struct tm time;
	int dive_day, gps_day;
	char datestr[50];
	QString problemString;

	utc_mkdate(coords.start_track, &time); // Display GPS date and start and end times:
	gps_day = time.tm_mday;
	datestr[0] = 0x0;
	strftime(datestr, sizeof(datestr), "%A %d %B ", &time); // GPS date
	ui.trackDateLabel->setText("GPS date  = " + QString(datestr) + QString::number(time.tm_year));
	ui.startTimeLabel->setText(QString::number(time.tm_hour) + ":" + QString::number(time.tm_min)); // track start time
	utc_mkdate(coords.end_track, &time);
	ui.endTimeLabel->setText(QString::number(time.tm_hour) + ":" + QString::number(time.tm_min));  // track end time

	utc_mkdate(coords.start_dive, &time); // Display dive date and start and end times:
	dive_day = time.tm_mday;
	datestr[0] = 0x0;
	strftime(datestr, sizeof(datestr), "%A %d %B ", localtime(&(coords.start_dive))); // dive date
	ui.diveDateLabel->setText("Dive date = " + QString(datestr) + QString::number(time.tm_year));
	ui.startTimeSyncLabel->setText( QString::number(time.tm_hour) + ":" + QString::number(time.tm_min)); // dive start time
	utc_mkdate(coords.end_dive, &time);
	ui.endTimeSyncLabel->setText(QString::number(time.tm_hour) + ":" + QString::number(time.tm_min));  // dive end time

	// This section implements extensive warnings in case there is not synchronisation between dive and GPS data:
	if (gps_day != dive_day)
		problemString = "(different dates)";
	else 
		problemString = "";
	// Create 3 icons to indicate the quality of the synchrinisation between dive and GPS
	QPixmap goodResultIcon (":gps_good_result-icon");
	ui.goodIconLabel->setPixmap(goodResultIcon.scaled(pixmapSize,pixmapSize,Qt::KeepAspectRatio));
	ui.goodIconLabel->setVisible(false);

	QPixmap warningResultIcon (":gps_warning_result-icon");
	ui.warningIconLabel->setPixmap(warningResultIcon.scaled(pixmapSize,pixmapSize,Qt::KeepAspectRatio));
	ui.warningIconLabel->setVisible(false);

	QPixmap badResultIcon (":gps_bad_result-icon");
	ui.badIconLabel->setPixmap(badResultIcon.scaled(pixmapSize,pixmapSize,Qt::KeepAspectRatio));
	ui.badIconLabel->setVisible(false);
	// Show information or warning message as well as synch quality icon
	if (coords.start_dive < coords.start_track) {
		ui.resultLabel->setStyleSheet("QLabel { color: red;} ");
		ui.resultLabel->setText("PROBLEM: Dive started before the GPS track "+ problemString);
		ui.badIconLabel->setVisible(true);
	} else {
		if (coords.start_dive > coords.end_track) {
		ui.resultLabel->setStyleSheet("QLabel { color: red;} ");
			ui.resultLabel->setText("PROBLEM: Dive started after the GPS track " + problemString);
			ui.badIconLabel->setVisible(true);
		} else {
			if (coords.end_dive > coords.end_track) {
				ui.resultLabel->setStyleSheet("QLabel { color: red;} ");
				ui.resultLabel->setText("WARNING: Dive ended after the GPS track " + problemString);
				ui.warningIconLabel->setVisible(true);
			} else {
				ui.resultLabel->setStyleSheet("QLabel { color: darkgreen;} ");
				ui.resultLabel->setText("Dive coordinates: "+ QString::number(coords.lat) + "S, " + QString::number(coords.lon) + "E");
				ui.goodIconLabel->setVisible(true);
			}
		}
	}
}

void ImportGPS::changeZoneForward()
{
	coords.timeZone_offset = abs(coords.timeZone_offset);
	getCoordsFromFile(); // If any of the time controls are changed
	updateUI();          // .. then recalculate the synchronisation
}

void ImportGPS::changeZoneBackwards()
{
	if (coords.timeZone_offset > 0)
		coords.timeZone_offset = 0 - coords.timeZone_offset;
	getCoordsFromFile();
	updateUI();
}

void ImportGPS::changeDiffForward()
{
	coords.settingsDiff_offset = abs(coords.settingsDiff_offset);
	getCoordsFromFile();
	updateUI();
}

void ImportGPS::changeDiffBackwards()
{
	if (coords.settingsDiff_offset > 0)
		coords.settingsDiff_offset = 0 - coords.settingsDiff_offset;
	getCoordsFromFile();
	updateUI();
}

void  ImportGPS::timeDiffEditChanged()
{
	coords.settingsDiff_offset = ui.timeDiffEdit->time().hour() * 3600 + ui.timeDiffEdit->time().minute() * 60;
	if (ui.diff_backwards->isChecked())
		coords.settingsDiff_offset = 0 - coords.settingsDiff_offset;
	getCoordsFromFile();
	updateUI();
}

void  ImportGPS::timeZoneEditChanged()
{
	coords.timeZone_offset = ui.timeZoneEdit->time().hour() * 3600;
	if (ui.timezone_backwards->isChecked())
		coords.timeZone_offset = 0 - coords.timeZone_offset;
	getCoordsFromFile();
	updateUI();
}

_______________________________________________
subsurface mailing list
[email protected]
http://lists.subsurface-divelog.org/cgi-bin/mailman/listinfo/subsurface

Reply via email to