mirror of
				https://github.com/subsurface/subsurface.git
				synced 2025-02-19 22:16:15 +00:00 
			
		
		
		
	current_dive is the selected dive, and displayed_dive is the one we are currently drawing. They are quite often the same one, but not in the case of adding a dive for example. This fixes potential null pointer dereferences in the case of a blank divelist, and makes sure we use the correct data in the case of adding and planning dives. Signed-off-by: Anton Lundin <glance@acc.umu.se> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
		
			
				
	
	
		
			164 lines
		
	
	
	
		
			4.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			164 lines
		
	
	
	
		
			4.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "diveeventitem.h"
 | |
| #include "diveplotdatamodel.h"
 | |
| #include "divecartesianaxis.h"
 | |
| #include "animationfunctions.h"
 | |
| #include "libdivecomputer.h"
 | |
| #include "dive.h"
 | |
| #include "planner.h"
 | |
| #include "profile.h"
 | |
| #include <QDebug>
 | |
| #include "gettextfromc.h"
 | |
| 
 | |
| extern struct ev_select *ev_namelist;
 | |
| extern int evn_used;
 | |
| 
 | |
| DiveEventItem::DiveEventItem(QObject *parent) : DivePixmapItem(parent),
 | |
| 	vAxis(NULL),
 | |
| 	hAxis(NULL),
 | |
| 	dataModel(NULL),
 | |
| 	internalEvent(NULL)
 | |
| {
 | |
| 	setFlag(ItemIgnoresTransformations);
 | |
| }
 | |
| 
 | |
| 
 | |
| void DiveEventItem::setHorizontalAxis(DiveCartesianAxis *axis)
 | |
| {
 | |
| 	hAxis = axis;
 | |
| 	recalculatePos(true);
 | |
| }
 | |
| 
 | |
| void DiveEventItem::setModel(DivePlotDataModel *model)
 | |
| {
 | |
| 	dataModel = model;
 | |
| 	recalculatePos(true);
 | |
| }
 | |
| 
 | |
| void DiveEventItem::setVerticalAxis(DiveCartesianAxis *axis)
 | |
| {
 | |
| 	vAxis = axis;
 | |
| 	recalculatePos(true);
 | |
| 	connect(vAxis, SIGNAL(sizeChanged()), this, SLOT(recalculatePos()));
 | |
| }
 | |
| 
 | |
| struct event *DiveEventItem::getEvent()
 | |
| {
 | |
| 	return internalEvent;
 | |
| }
 | |
| 
 | |
| void DiveEventItem::setEvent(struct event *ev)
 | |
| {
 | |
| 	if (!ev)
 | |
| 		return;
 | |
| 	internalEvent = ev;
 | |
| 	setupPixmap();
 | |
| 	setupToolTipString();
 | |
| 	recalculatePos(true);
 | |
| }
 | |
| 
 | |
| void DiveEventItem::setupPixmap()
 | |
| {
 | |
| #define EVENT_PIXMAP(PIX) QPixmap(QString(PIX)).scaled(20, 20, Qt::KeepAspectRatio, Qt::SmoothTransformation)
 | |
| #define EVENT_PIXMAP_BIGGER(PIX) QPixmap(QString(PIX)).scaled(40, 38, Qt::KeepAspectRatio, Qt::SmoothTransformation)
 | |
| 	if (!internalEvent->name) {
 | |
| 		setPixmap(EVENT_PIXMAP(":warning"));
 | |
| 	} else if (internalEvent->type == SAMPLE_EVENT_BOOKMARK) {
 | |
| 		setPixmap(EVENT_PIXMAP(":flag"));
 | |
| 	} else if (strcmp(internalEvent->name, "heading") == 0) {
 | |
| 		setPixmap(EVENT_PIXMAP(":flag"));
 | |
| 	} else if (internalEvent->type == SAMPLE_EVENT_GASCHANGE || internalEvent->type == SAMPLE_EVENT_GASCHANGE2) {
 | |
| 		if (internalEvent->value >> 16)
 | |
| 			setPixmap(EVENT_PIXMAP_BIGGER(":gaschangeTrimix"));
 | |
| 		else if (internalEvent->value == 0)
 | |
| 			setPixmap(EVENT_PIXMAP_BIGGER(":gaschangeAir"));
 | |
| 		else
 | |
| 			setPixmap(EVENT_PIXMAP_BIGGER(":gaschangeNitrox"));
 | |
| 	} else {
 | |
| 		setPixmap(EVENT_PIXMAP(":warning"));
 | |
| 	}
 | |
| #undef EVENT_PIXMAP
 | |
| }
 | |
| 
 | |
| void DiveEventItem::setupToolTipString()
 | |
| {
 | |
| 	// we display the event on screen - so translate
 | |
| 	QString name = gettextFromC::instance()->tr(internalEvent->name);
 | |
| 	int value = internalEvent->value;
 | |
| 	int type = internalEvent->type;
 | |
| 	if (value) {
 | |
| 		if (type == SAMPLE_EVENT_GASCHANGE || type == SAMPLE_EVENT_GASCHANGE2) {
 | |
| 			QModelIndexList result = dataModel->match(dataModel->index(0, DivePlotDataModel::TIME), Qt::DisplayRole, internalEvent->time.seconds);
 | |
| 			if (result.isEmpty()) {
 | |
| 				Q_ASSERT("can't find a spot in the dataModel");
 | |
| 				return;
 | |
| 			}
 | |
| 			// We need to look at row + 1, where the new gas is active to find what we are switching to.
 | |
| 			int cylinder_idx = dataModel->data(dataModel->index(result.first().row() + 1, DivePlotDataModel::CYLINDERINDEX)).toInt();
 | |
| 			name += ": ";
 | |
| 			name += gasname(&displayed_dive.cylinder[cylinder_idx].gasmix);
 | |
| 		} else if (type == SAMPLE_EVENT_PO2 && name == "SP change") {
 | |
| 			name += QString(":%1").arg((double)value / 1000);
 | |
| 		} else {
 | |
| 			name += QString(":%1").arg(value);
 | |
| 		}
 | |
| 	} else if (type == SAMPLE_EVENT_PO2 && name == "SP change") {
 | |
| 		// this is a bad idea - we are abusing an existing event type that is supposed to
 | |
| 		// warn of high or low pO₂ and are turning it into a set point change event
 | |
| 		name += "\n" + tr("Bailing out to OC");
 | |
| 	} else {
 | |
| 		name += internalEvent->flags == SAMPLE_FLAGS_BEGIN ? tr(" begin", "Starts with space!") :
 | |
| 								     internalEvent->flags == SAMPLE_FLAGS_END ? tr(" end", "Starts with space!") : "";
 | |
| 	}
 | |
| 	// qDebug() << name;
 | |
| 	setToolTip(name);
 | |
| }
 | |
| 
 | |
| void DiveEventItem::eventVisibilityChanged(const QString &eventName, bool visible)
 | |
| {
 | |
| }
 | |
| 
 | |
| bool DiveEventItem::shouldBeHidden()
 | |
| {
 | |
| 	struct event *event = internalEvent;
 | |
| 
 | |
| 	/*
 | |
| 	 * Gas change events - particularly at the beginning of a dive - are
 | |
| 	 * special. It's just the dive computer specifying the initial gas.
 | |
| 	 *
 | |
| 	 * Don't bother showing them if they match the first gas already
 | |
| 	 */
 | |
| 	if (!strcmp(event->name, "gaschange") && event->time.seconds <= 30) {
 | |
| 		struct dive *dive = &displayed_dive;
 | |
| 		if (dive && get_cylinder_index(dive, event) == 0)
 | |
| 			return true;
 | |
| 	}
 | |
| 	for (int i = 0; i < evn_used; i++) {
 | |
| 		if (!strcmp(event->name, ev_namelist[i].ev_name) && ev_namelist[i].plot_ev == false)
 | |
| 			return true;
 | |
| 	}
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| void DiveEventItem::recalculatePos(bool instant)
 | |
| {
 | |
| 	if (!vAxis || !hAxis || !internalEvent || !dataModel)
 | |
| 		return;
 | |
| 
 | |
| 	QModelIndexList result = dataModel->match(dataModel->index(0, DivePlotDataModel::TIME), Qt::DisplayRole, internalEvent->time.seconds);
 | |
| 	if (result.isEmpty()) {
 | |
| 		Q_ASSERT("can't find a spot in the dataModel");
 | |
| 		hide();
 | |
| 		return;
 | |
| 	}
 | |
| 	if (!isVisible() && !shouldBeHidden())
 | |
| 		show();
 | |
| 	int depth = dataModel->data(dataModel->index(result.first().row(), DivePlotDataModel::DEPTH)).toInt();
 | |
| 	qreal x = hAxis->posAtValue(internalEvent->time.seconds);
 | |
| 	qreal y = vAxis->posAtValue(depth);
 | |
| 	if (!instant)
 | |
| 		Animations::moveTo(this, x, y);
 | |
| 	else
 | |
| 		setPos(x, y);
 | |
| 	if (isVisible() && shouldBeHidden())
 | |
| 		hide();
 | |
| }
 |