[PATCH 01/11] Have divedatapoint store cylinder id instead of gasmix

Rick Walsh rickmwalsh at gmail.com
Wed Jul 6 05:40:28 PDT 2016


Determining the correct cylinder index from a known gas mix can be
complicated, but it is trivial to look up the gasmix from the cylinder_t
structure.

It makes sense to remember which cylinder is being used. This simplifies
handling changing a cylinder's gas mix, either directly by the user, or
indirectly in the planner. It also permits tracking of multiple cylinders of
the same mix, e.g. independent twins / sidemount.

Signed-off-by: Rick Walsh <rickmwalsh at gmail.com>
---
 core/dive.h                        |   6 +-
 core/planner.c                     |  94 +++++++++++++++---------------
 core/planner.h                     |   1 +
 core/qthelper.cpp                  |   5 +-
 core/qthelper.h                    |   2 +-
 desktop-widgets/diveplanner.cpp    |   5 +-
 desktop-widgets/modeldelegates.cpp |   2 +-
 profile-widget/profilewidget2.cpp  |   2 +-
 qt-models/cylindermodel.cpp        |   6 +-
 qt-models/diveplannermodel.cpp     | 113 ++++++++++---------------------------
 qt-models/diveplannermodel.h       |   6 +-
 11 files changed, 99 insertions(+), 143 deletions(-)

diff --git a/core/dive.h b/core/dive.h
index 5988990..9c61204 100644
--- a/core/dive.h
+++ b/core/dive.h
@@ -821,7 +821,7 @@ extern double tissue_tolerance_calc(const struct dive *dive, double pressure);
 struct divedatapoint {
 	int time;
 	int depth;
-	struct gasmix gasmix;
+	int cylinderid;
 	int setpoint;
 	bool entered;
 	struct divedatapoint *next;
@@ -838,8 +838,8 @@ struct diveplan {
 	struct divedatapoint *dp;
 };
 
-struct divedatapoint *plan_add_segment(struct diveplan *diveplan, int duration, int depth, struct gasmix gasmix, int po2, bool entered);
-struct divedatapoint *create_dp(int time_incr, int depth, struct gasmix gasmix, int po2);
+struct divedatapoint *plan_add_segment(struct diveplan *diveplan, int duration, int depth, int cylinderid, int po2, bool entered);
+struct divedatapoint *create_dp(int time_incr, int depth, int cylinderid, int po2);
 #if DEBUG_PLAN
 void dump_plan(struct diveplan *diveplan);
 #endif
diff --git a/core/planner.c b/core/planner.c
index e67033d..4946024 100644
--- a/core/planner.c
+++ b/core/planner.c
@@ -92,6 +92,20 @@ void get_gas_at_time(struct dive *dive, struct divecomputer *dc, duration_t time
 	}
 }
 
+/* get the cylinder index at a certain time during the dive */
+int get_cylinderid_at_time(struct dive *dive, struct divecomputer *dc, duration_t time)
+{
+	// we start with the first cylinder unless an event tells us otherwise
+	int cylinder_idx = 0;
+	struct event *event = dc->events;
+	while (event && event->time.seconds <= time.seconds) {
+		if (!strcmp(event->name, "gaschange"))
+			cylinder_idx = get_cylinder_index(dive, event);
+		event = event->next;
+	}
+	return cylinder_idx;
+}
+
 int get_gasidx(struct dive *dive, struct gasmix *mix)
 {
 	return find_best_gasmix_match(mix, dive->cylinder, 0);
@@ -255,12 +269,12 @@ static void create_dive_from_plan(struct diveplan *diveplan, bool track_gas)
 	struct divedatapoint *dp;
 	struct divecomputer *dc;
 	struct sample *sample;
-	struct gasmix oldgasmix;
 	struct event *ev;
 	cylinder_t *cyl;
 	int oldpo2 = 0;
 	int lasttime = 0;
 	int lastdepth = 0;
+	int lastcylid = 0;
 	enum dive_comp_type type = displayed_dive.dc.divemode;
 
 	if (!diveplan || !diveplan->dp)
@@ -284,8 +298,7 @@ static void create_dive_from_plan(struct diveplan *diveplan, bool track_gas)
 		free(ev);
 	}
 	dp = diveplan->dp;
-	cyl = &displayed_dive.cylinder[0];
-	oldgasmix = cyl->gasmix;
+	cyl = &displayed_dive.cylinder[lastcylid];
 	sample = prepare_sample(dc);
 	sample->setpoint.mbar = dp->setpoint;
 	sample->sac.mliter = prefs.bottomsac;
@@ -295,7 +308,6 @@ static void create_dive_from_plan(struct diveplan *diveplan, bool track_gas)
 	sample->manually_entered = true;
 	finish_sample(dc);
 	while (dp) {
-		struct gasmix gasmix = dp->gasmix;
 		int po2 = dp->setpoint;
 		if (dp->setpoint)
 			type = CCR;
@@ -305,8 +317,6 @@ static void create_dive_from_plan(struct diveplan *diveplan, bool track_gas)
 		if (time == 0) {
 			/* special entries that just inform the algorithm about
 			 * additional gases that are available */
-			if (verify_gas_exists(gasmix) < 0)
-				goto gas_error_exit;
 			dp = dp->next;
 			continue;
 		}
@@ -321,13 +331,10 @@ static void create_dive_from_plan(struct diveplan *diveplan, bool track_gas)
 		}
 
 		/* Make sure we have the new gas, and create a gas change event */
-		if (gasmix_distance(&gasmix, &oldgasmix) > 0) {
-			int idx;
-			if ((idx = verify_gas_exists(gasmix)) < 0)
-				goto gas_error_exit;
+		if (dp->cylinderid != lastcylid) {
 			/* need to insert a first sample for the new gas */
-			add_gas_switch_event(&displayed_dive, dc, lasttime + 1, idx);
-			cyl = &displayed_dive.cylinder[idx];
+			add_gas_switch_event(&displayed_dive, dc, lasttime + 1, dp->cylinderid);
+			cyl = &displayed_dive.cylinder[dp->cylinderid];
 			sample = prepare_sample(dc);
 			sample[-1].setpoint.mbar = po2;
 			sample->time.seconds = lasttime + 1;
@@ -337,7 +344,7 @@ static void create_dive_from_plan(struct diveplan *diveplan, bool track_gas)
 			if (track_gas && cyl->type.workingpressure.mbar)
 				sample->cylinderpressure.mbar = cyl->sample_end.mbar;
 			finish_sample(dc);
-			oldgasmix = gasmix;
+			lastcylid = dp->cylinderid;
 		}
 		/* Create sample */
 		sample = prepare_sample(dc);
@@ -382,14 +389,14 @@ void free_dps(struct diveplan *diveplan)
 	diveplan->dp = NULL;
 }
 
-struct divedatapoint *create_dp(int time_incr, int depth, struct gasmix gasmix, int po2)
+struct divedatapoint *create_dp(int time_incr, int depth, int cylinderid, int po2)
 {
 	struct divedatapoint *dp;
 
 	dp = malloc(sizeof(struct divedatapoint));
 	dp->time = time_incr;
 	dp->depth = depth;
-	dp->gasmix = gasmix;
+	dp->cylinderid = cylinderid;
 	dp->setpoint = po2;
 	dp->entered = false;
 	dp->next = NULL;
@@ -412,9 +419,9 @@ void add_to_end_of_diveplan(struct diveplan *diveplan, struct divedatapoint *dp)
 		dp->time += lasttime;
 }
 
-struct divedatapoint *plan_add_segment(struct diveplan *diveplan, int duration, int depth, struct gasmix gasmix, int po2, bool entered)
+struct divedatapoint *plan_add_segment(struct diveplan *diveplan, int duration, int depth, int cylinderid, int po2, bool entered)
 {
-	struct divedatapoint *dp = create_dp(duration, depth, gasmix, po2);
+	struct divedatapoint *dp = create_dp(duration, depth, cylinderid, po2);
 	dp->entered = entered;
 	add_to_end_of_diveplan(diveplan, dp);
 	return (dp);
@@ -428,14 +435,12 @@ struct gaschanges {
 
 static struct gaschanges *analyze_gaslist(struct diveplan *diveplan, int *gaschangenr, int depth, int *asc_cylinder)
 {
-	struct gasmix gas;
 	int nr = 0;
 	struct gaschanges *gaschanges = NULL;
 	struct divedatapoint *dp = diveplan->dp;
 	int best_depth = displayed_dive.cylinder[*asc_cylinder].depth.mm;
 	while (dp) {
 		if (dp->time == 0) {
-			gas = dp->gasmix;
 			if (dp->depth <= depth) {
 				int i = 0;
 				nr++;
@@ -448,13 +453,13 @@ static struct gaschanges *analyze_gaslist(struct diveplan *diveplan, int *gascha
 					i++;
 				}
 				gaschanges[i].depth = dp->depth;
-				gaschanges[i].gasidx = get_gasidx(&displayed_dive, &gas);
+				gaschanges[i].gasidx = dp->cylinderid;
 				assert(gaschanges[i].gasidx != -1);
 			} else {
 				/* is there a better mix to start deco? */
 				if (dp->depth < best_depth) {
 					best_depth = dp->depth;
-					*asc_cylinder = get_gasidx(&displayed_dive, &gas);
+					*asc_cylinder = dp->cylinderid;
 				}
 			}
 		}
@@ -614,13 +619,13 @@ static void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool
 		nextdp = dp->next;
 		if (dp->time == 0)
 			continue;
-		gasmix = dp->gasmix;
+		gasmix = dive->cylinder[dp->cylinderid].gasmix;
 		depthvalue = get_depth_units(dp->depth, &decimals, &depth_unit);
 		/* analyze the dive points ahead */
 		while (nextdp && nextdp->time == 0)
 			nextdp = nextdp->next;
 		if (nextdp)
-			newgasmix = nextdp->gasmix;
+			newgasmix = dive->cylinder[nextdp->cylinderid].gasmix;
 		gaschange_after = (nextdp && (gasmix_distance(&gasmix, &newgasmix) || dp->setpoint != nextdp->setpoint));
 		gaschange_before =  (gasmix_distance(&lastprintgasmix, &gasmix) || lastprintsetpoint != dp->setpoint);
 		/* do we want to skip this leg as it is devoid of anything useful? */
@@ -837,7 +842,8 @@ static void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool
 		while (dp) {
 			if (dp->time != 0) {
 				struct gas_pressures pressures;
-				fill_pressures(&pressures, depth_to_atm(dp->depth, dive), &dp->gasmix, 0.0, dive->dc.divemode);
+				struct gasmix *gasmix = &dive->cylinder[dp->cylinderid].gasmix;
+				fill_pressures(&pressures, depth_to_atm(dp->depth, dive), gasmix, 0.0, dive->dc.divemode);
 
 				if (pressures.o2 > (dp->entered ? prefs.bottompo2 : prefs.decopo2) / 1000.0) {
 					const char *depth_unit;
@@ -846,7 +852,7 @@ static void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool
 					len = strlen(buffer);
 					snprintf(temp, sz_temp,
 						 translate("gettextFromC", "high pO₂ value %.2f at %d:%02u with gas %s at depth %.*f %s"),
-						 pressures.o2, FRACTION(dp->time, 60), gasname(&dp->gasmix), decimals, depth_value, depth_unit);
+						 pressures.o2, FRACTION(dp->time, 60), gasname(gasmix), decimals, depth_value, depth_unit);
 					len += snprintf(buffer + len, sz_buffer - len, "<span style='color: red;'>%s </span> %s<br>",
 							translate("gettextFromC", "Warning:"), temp);
 				} else if (pressures.o2 < 0.16) {
@@ -856,7 +862,7 @@ static void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool
 					len = strlen(buffer);
 					snprintf(temp, sz_temp,
 						 translate("gettextFromC", "low pO₂ value %.2f at %d:%02u with gas %s at depth %.*f %s"),
-						 pressures.o2, FRACTION(dp->time, 60), gasname(&dp->gasmix), decimals, depth_value, depth_unit);
+						 pressures.o2, FRACTION(dp->time, 60), gasname(gasmix), decimals, depth_value, depth_unit);
 					len += snprintf(buffer + len, sz_buffer - len, "<span style='color: red;'>%s </span> %s<br>",
 							translate("gettextFromC", "Warning:"), temp);
 
@@ -929,7 +935,7 @@ bool trial_ascent(int trial_depth, int stoplevel, int avg_depth, int bottom_time
 		int deltad = ascent_velocity(trial_depth, avg_depth, bottom_time) * TIMESTEP;
 		if (deltad > trial_depth) /* don't test against depth above surface */
 			deltad = trial_depth;
-		add_segment(depth_to_bar(trial_depth, &displayed_dive),
+		add_segment(depth_to_bar(trial_depth, &displayed_dive), 
 			    gasmix,
 			    TIMESTEP, po2, &displayed_dive, prefs.decosac);
 		if (deco_allowed_depth(tissue_tolerance_calc(&displayed_dive, depth_to_bar(trial_depth, &displayed_dive)),
@@ -1025,13 +1031,10 @@ bool plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool
 	/* Let's start at the last 'sample', i.e. the last manually entered waypoint. */
 	sample = &displayed_dive.dc.sample[displayed_dive.dc.samples - 1];
 
-	get_gas_at_time(&displayed_dive, &displayed_dive.dc, sample->time, &gas);
+	current_cylinder = get_cylinderid_at_time(&displayed_dive, &displayed_dive.dc, sample->time);
+	gas = displayed_dive.cylinder[current_cylinder].gasmix;
 
 	po2 = sample->setpoint.mbar;
-	if ((current_cylinder = get_gasidx(&displayed_dive, &gas)) == -1) {
-		report_error(translate("gettextFromC", "Can't find gas %s"), gasname(&gas));
-		current_cylinder = 0;
-	}
 	depth = displayed_dive.dc.sample[displayed_dive.dc.samples - 1].depth.mm;
 	average_max_depth(diveplan, &avg_depth, &max_depth);
 	last_ascend_rate = ascent_velocity(depth, avg_depth, bottom_time);
@@ -1039,7 +1042,7 @@ bool plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool
 	/* if all we wanted was the dive just get us back to the surface */
 	if (!is_planner) {
 		transitiontime = depth / 75; /* this still needs to be made configurable */
-		plan_add_segment(diveplan, transitiontime, 0, gas, po2, false);
+		plan_add_segment(diveplan, transitiontime, 0, current_cylinder, po2, false);
 		create_dive_from_plan(diveplan, is_planner);
 		return(false);
 	}
@@ -1047,6 +1050,7 @@ bool plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool
 #if DEBUG_PLAN & 4
 	printf("gas %s\n", gasname(&gas));
 	printf("depth %5.2lfm \n", depth / 1000.0);
+	printf("current_cylinder %i\n", current_cylinder);
 #endif
 
 	best_first_ascend_cylinder = current_cylinder;
@@ -1097,13 +1101,13 @@ bool plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool
 		// so we don't really have to compute the deco state.
 		update_cylinder_pressure(&displayed_dive, depth, depth, -DECOTIMESTEP, prefs.bottomsac, &displayed_dive.cylinder[current_cylinder], false);
 		clock -= DECOTIMESTEP;
-		plan_add_segment(diveplan, clock - previous_point_time, depth, gas, po2, true);
+		plan_add_segment(diveplan, clock - previous_point_time, depth, current_cylinder, po2, true);
 		previous_point_time = clock;
 		do {
 			/* Ascend to surface */
 			int deltad = ascent_velocity(depth, avg_depth, bottom_time) * TIMESTEP;
 			if (ascent_velocity(depth, avg_depth, bottom_time) != last_ascend_rate) {
-				plan_add_segment(diveplan, clock - previous_point_time, depth, gas, po2, false);
+				plan_add_segment(diveplan, clock - previous_point_time, depth, current_cylinder, po2, false);
 				previous_point_time = clock;
 				last_ascend_rate = ascent_velocity(depth, avg_depth, bottom_time);
 			}
@@ -1113,15 +1117,15 @@ bool plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool
 			clock += TIMESTEP;
 			depth -= deltad;
 			if (depth <= 5000 && depth >= (5000 - deltad) && safety_stop) {
-				plan_add_segment(diveplan, clock - previous_point_time, 5000, gas, po2, false);
+				plan_add_segment(diveplan, clock - previous_point_time, 5000, current_cylinder, po2, false);
 				previous_point_time = clock;
 				clock += 180;
-				plan_add_segment(diveplan, clock - previous_point_time, 5000, gas, po2, false);
+				plan_add_segment(diveplan, clock - previous_point_time, 5000, current_cylinder, po2, false);
 				previous_point_time = clock;
 				safety_stop = false;
 			}
 		} while (depth > 0);
-		plan_add_segment(diveplan, clock - previous_point_time, 0, gas, po2, false);
+		plan_add_segment(diveplan, clock - previous_point_time, 0, current_cylinder, po2, false);
 		create_dive_from_plan(diveplan, is_planner);
 		add_plan_to_notes(diveplan, &displayed_dive, show_disclaimer, error);
 		fixup_dc_duration(&displayed_dive.dc);
@@ -1192,7 +1196,7 @@ bool plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool
 				int deltad = ascent_velocity(depth, avg_depth, bottom_time) * TIMESTEP;
 				if (ascent_velocity(depth, avg_depth, bottom_time) != last_ascend_rate) {
 					if (is_final_plan)
-						plan_add_segment(diveplan, clock - previous_point_time, depth, gas, po2, false);
+						plan_add_segment(diveplan, clock - previous_point_time, depth, current_cylinder, po2, false);
 					previous_point_time = clock;
 					stopping = false;
 					last_ascend_rate = ascent_velocity(depth, avg_depth, bottom_time);
@@ -1214,7 +1218,7 @@ bool plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool
 				/* We have reached a gas change.
 				 * Record this in the dive plan */
 				if (is_final_plan)
-					plan_add_segment(diveplan, clock - previous_point_time, depth, gas, po2, false);
+					plan_add_segment(diveplan, clock - previous_point_time, depth, current_cylinder, po2, false);
 				previous_point_time = clock;
 				stopping = true;
 
@@ -1264,7 +1268,7 @@ bool plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool
 					/* The last segment was an ascend segment.
 					 * Add a waypoint for start of this deco stop */
 					if (is_final_plan)
-						plan_add_segment(diveplan, clock - previous_point_time, depth, gas, po2, false);
+						plan_add_segment(diveplan, clock - previous_point_time, depth, current_cylinder, po2, false);
 					previous_point_time = clock;
 					stopping = true;
 				}
@@ -1312,7 +1316,7 @@ bool plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool
 							breaktime = 0;
 							breakcylinder = current_cylinder;
 							if (is_final_plan)
-								plan_add_segment(diveplan, clock - previous_point_time, depth, gas, po2, false);
+								plan_add_segment(diveplan, clock - previous_point_time, depth, current_cylinder, po2, false);
 							previous_point_time = clock;
 							current_cylinder = 0;
 							gas = displayed_dive.cylinder[current_cylinder].gasmix;
@@ -1323,7 +1327,7 @@ bool plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool
 							if (breaktime >= 6 * 60) {
 								o2time = 0;
 								if (is_final_plan)
-									plan_add_segment(diveplan, clock - previous_point_time, depth, gas, po2, false);
+									plan_add_segment(diveplan, clock - previous_point_time, depth, current_cylinder, po2, false);
 								previous_point_time = clock;
 								current_cylinder = breakcylinder;
 								gas = displayed_dive.cylinder[current_cylinder].gasmix;
@@ -1336,7 +1340,7 @@ bool plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool
 			if (stopping) {
 				/* Next we will ascend again. Add a waypoint if we have spend deco time */
 				if (is_final_plan)
-					plan_add_segment(diveplan, clock - previous_point_time, depth, gas, po2, false);
+					plan_add_segment(diveplan, clock - previous_point_time, depth, current_cylinder, po2, false);
 				previous_point_time = clock;
 				stopping = false;
 			}
@@ -1345,7 +1349,7 @@ bool plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool
 		deco_time = clock - bottom_time;
 	} while (!is_final_plan);
 
-	plan_add_segment(diveplan, clock - previous_point_time, 0, gas, po2, false);
+	plan_add_segment(diveplan, clock - previous_point_time, 0, current_cylinder, po2, false);
 	create_dive_from_plan(diveplan, is_planner);
 	add_plan_to_notes(diveplan, &displayed_dive, show_disclaimer, error);
 	fixup_dc_duration(&displayed_dive.dc);
diff --git a/core/planner.h b/core/planner.h
index a675989..3298d7d 100644
--- a/core/planner.h
+++ b/core/planner.h
@@ -17,6 +17,7 @@ extern void set_display_runtime(bool display);
 extern void set_display_duration(bool display);
 extern void set_display_transitions(bool display);
 extern void get_gas_at_time(struct dive *dive, struct divecomputer *dc, duration_t time, struct gasmix *gas);
+extern int get_cylinderid_at_time(struct dive *dive, struct divecomputer *dc, duration_t time);
 extern int get_gasidx(struct dive *dive, struct gasmix *mix);
 extern bool diveplan_empty(struct diveplan *diveplan);
 
diff --git a/core/qthelper.cpp b/core/qthelper.cpp
index d6a6c25..0135137 100644
--- a/core/qthelper.cpp
+++ b/core/qthelper.cpp
@@ -1215,9 +1215,10 @@ QString get_gas_string(struct gasmix gas)
 	return result;
 }
 
-QString get_divepoint_gas_string(const divedatapoint &p)
+QString get_divepoint_gas_string(struct dive *d, const divedatapoint &p)
 {
-	return get_gas_string(p.gasmix);
+	int idx = p.cylinderid;
+	return get_gas_string(d->cylinder[idx].gasmix);
 }
 
 weight_t string_to_weight(const char *str)
diff --git a/core/qthelper.h b/core/qthelper.h
index 3a5ef60..95bdf4d 100644
--- a/core/qthelper.h
+++ b/core/qthelper.h
@@ -18,7 +18,7 @@ bool gpsHasChanged(struct dive *dive, struct dive *master, const QString &gps_te
 extern "C" const char *printGPSCoords(int lat, int lon);
 QList<int> getDivesInTrip(dive_trip_t *trip);
 QString get_gas_string(struct gasmix gas);
-QString get_divepoint_gas_string(const divedatapoint& dp);
+QString get_divepoint_gas_string(struct dive *d, const divedatapoint& dp);
 void read_hashes();
 void write_hashes();
 void updateHash(struct picture *picture);
diff --git a/desktop-widgets/diveplanner.cpp b/desktop-widgets/diveplanner.cpp
index 0455573..4e462cc 100644
--- a/desktop-widgets/diveplanner.cpp
+++ b/desktop-widgets/diveplanner.cpp
@@ -49,6 +49,7 @@ void DiveHandler::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
 		for (int i = 0; i < rowCount; i++) {
 			QAction *action = new QAction(&m);
 			action->setText(model->data(model->index(i, 0), Qt::DisplayRole).toString());
+			action->setData(i);
 			connect(action, SIGNAL(triggered(bool)), this, SLOT(changeGas()));
 			m.addAction(action);
 		}
@@ -72,7 +73,7 @@ void DiveHandler::changeGas()
 {
 	QAction *action = qobject_cast<QAction *>(sender());
 	QModelIndex index = plannerModel->index(parentIndex(), DivePlannerPointsModel::GAS);
-	plannerModel->gaschange(index.sibling(index.row() + 1, index.column()), action->text());
+	plannerModel->gaschange(index.sibling(index.row() + 1, index.column()), action->data().toInt());
 }
 
 void DiveHandler::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
@@ -126,6 +127,8 @@ DivePlannerWidget::DivePlannerWidget(QWidget *parent, Qt::WindowFlags f) : QWidg
 	connect(CylindersModel::instance(), SIGNAL(rowsRemoved(QModelIndex, int, int)),
 		GasSelectionModel::instance(), SLOT(repopulate()));
 	connect(CylindersModel::instance(), SIGNAL(dataChanged(QModelIndex, QModelIndex)),
+		plannerModel, SLOT(emitDataChanged()));
+	connect(CylindersModel::instance(), SIGNAL(dataChanged(QModelIndex, QModelIndex)),
 		plannerModel, SIGNAL(cylinderModelEdited()));
 	connect(CylindersModel::instance(), SIGNAL(rowsInserted(QModelIndex, int, int)),
 		plannerModel, SIGNAL(cylinderModelEdited()));
diff --git a/desktop-widgets/modeldelegates.cpp b/desktop-widgets/modeldelegates.cpp
index a80137e..01e8f4d 100644
--- a/desktop-widgets/modeldelegates.cpp
+++ b/desktop-widgets/modeldelegates.cpp
@@ -403,7 +403,7 @@ void AirTypesDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
 	if (!index.isValid())
 		return;
 	QComboBox *combo = qobject_cast<QComboBox *>(editor);
-	model->setData(index, QVariant(combo->currentText()));
+	model->setData(index, QVariant(combo->currentIndex()));
 }
 
 AirTypesDelegate::AirTypesDelegate(QObject *parent) : ComboBoxDelegate(GasSelectionModel::instance(), parent)
diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp
index 5aa0c53..aae8fdd 100644
--- a/profile-widget/profilewidget2.cpp
+++ b/profile-widget/profilewidget2.cpp
@@ -1739,7 +1739,7 @@ void ProfileWidget2::repositionDiveHandlers()
 		QLineF line(p1, p2);
 		QPointF pos = line.pointAt(0.5);
 		gases[i]->setPos(pos);
-		gases[i]->setText(get_divepoint_gas_string(datapoint));
+		gases[i]->setText(get_gas_string(displayed_dive.cylinder[datapoint.cylinderid].gasmix));
 		gases[i]->setVisible(datapoint.entered &&
 				(i == 0 || gases[i]->text() != gases[i-1]->text()));
 	}
diff --git a/qt-models/cylindermodel.cpp b/qt-models/cylindermodel.cpp
index 20b7207..6ea27f1 100644
--- a/qt-models/cylindermodel.cpp
+++ b/qt-models/cylindermodel.cpp
@@ -296,8 +296,6 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
 		}
 		break;
 	}
-	if (addDiveMode)
-		DivePlannerPointsModel::instance()->tanksUpdated();
 	dataChanged(index, index);
 	return true;
 }
@@ -391,8 +389,8 @@ void CylindersModel::remove(const QModelIndex &index)
 	}
 	if (same_gas == -1 &&
 			((DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING &&
-				DivePlannerPointsModel::instance()->tankInUse(cyl->gasmix)) ||
-			 (DivePlannerPointsModel::instance()->currentMode() == DivePlannerPointsModel::NOTHING &&
+				DivePlannerPointsModel::instance()->tankInUse(index.row())) ||
+			(DivePlannerPointsModel::instance()->currentMode() == DivePlannerPointsModel::NOTHING &&
 				is_cylinder_used(&displayed_dive, index.row())))) {
 				emit warningMessage(TITLE_OR_TEXT(
 															tr("Cylinder cannot be removed"),
diff --git a/qt-models/diveplannermodel.cpp b/qt-models/diveplannermodel.cpp
index 16a2e40..f44d94c 100644
--- a/qt-models/diveplannermodel.cpp
+++ b/qt-models/diveplannermodel.cpp
@@ -25,24 +25,21 @@ void DivePlannerPointsModel::removeSelectedPoints(const QVector<int> &rows)
 
 void DivePlannerPointsModel::createSimpleDive()
 {
-	struct gasmix gas = {};
-
 	// initialize the start time in the plan
 	diveplan.when = displayed_dive.when;
 
-	if (isPlanner())
-		// let's use the gas from the first cylinder
-		gas = displayed_dive.cylinder[0].gasmix;
+	// Use gas from the first cylinder
+	int cylinderid = 0;
 
 	// If we're in drop_stone_mode, don't add a first point.
 	// It will be added implicit.
 	if (!prefs.drop_stone_mode)
-		addStop(M_OR_FT(15, 45), 1 * 60, &gas, 0, true);
+		addStop(M_OR_FT(15, 45), 1 * 60, cylinderid, 0, true);
 
-	addStop(M_OR_FT(15, 45), 20 * 60, &gas, 0, true);
+	addStop(M_OR_FT(15, 45), 20 * 60, 0, 0, true);
 	if (!isPlanner()) {
-		addStop(M_OR_FT(5, 15), 42 * 60, &gas, 0, true);
-		addStop(M_OR_FT(5, 15), 45 * 60, &gas, 0, true);
+		addStop(M_OR_FT(5, 15), 42 * 60, 0, cylinderid, true);
+		addStop(M_OR_FT(5, 15), 45 * 60, 0, cylinderid, true);
 	}
 }
 
@@ -99,8 +96,8 @@ void DivePlannerPointsModel::loadFromDive(dive *d)
 			j++;
 		}
 		if (samplecount) {
-			get_gas_at_time(d, &d->dc, lasttime, &gas);
-			addStop(depthsum / samplecount, newtime.seconds, &gas, 0, true);
+			int cylinderid = get_cylinderid_at_time(d, &d->dc, lasttime);
+			addStop(depthsum / samplecount, newtime.seconds, cylinderid, 0, true);
 			lasttime = newtime;
 			depthsum = 0;
 			samplecount = 0;
@@ -222,7 +219,7 @@ QVariant DivePlannerPointsModel::data(const QModelIndex &index, int role) const
 			else
 				return p.time / 60;
 		case GAS:
-			return get_divepoint_gas_string(p);
+			return get_gas_string(displayed_dive.cylinder[p.cylinderid].gasmix);
 		}
 	} else if (role == Qt::DecorationRole) {
 		switch (index.column()) {
@@ -282,9 +279,8 @@ bool DivePlannerPointsModel::setData(const QModelIndex &index, const QVariant &v
 				p.setpoint = po2;
 		} break;
 		case GAS:
-			QByteArray gasv = value.toByteArray();
-			if (validate_gas(gasv.data(), &gas))
-				p.gasmix = gas;
+			if (value.toInt() >= 0 && value.toInt() < MAX_CYLINDERS)
+				p.cylinderid = value.toInt();
 			break;
 		}
 		editStop(index.row(), p);
@@ -292,15 +288,11 @@ bool DivePlannerPointsModel::setData(const QModelIndex &index, const QVariant &v
 	return QAbstractItemModel::setData(index, value, role);
 }
 
-void DivePlannerPointsModel::gaschange(const QModelIndex &index, QString newgas)
+void DivePlannerPointsModel::gaschange(const QModelIndex &index, int newcylinderid)
 {
-	int i = index.row();
-	gasmix oldgas = divepoints[i].gasmix;
-	gasmix gas = {};
-	if (!validate_gas(newgas.toUtf8().data(), &gas))
-		return;
-	while (i < rowCount() && gasmix_distance(&oldgas, &divepoints[i].gasmix) == 0)
-		divepoints[i++].gasmix = gas;
+	int i = index.row(), oldcylinderid = divepoints[i].cylinderid;
+	while (i < rowCount() && oldcylinderid == divepoints[i].cylinderid)
+		divepoints[i++].cylinderid = newcylinderid;
 	emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1));
 }
 
@@ -589,13 +581,12 @@ int DivePlannerPointsModel::lastEnteredPoint()
 	return -1;
 }
 
-int DivePlannerPointsModel::addStop(int milimeters, int seconds, gasmix *gas_in, int ccpoint, bool entered)
+int DivePlannerPointsModel::addStop(int milimeters, int seconds, int cylinderid_in, int ccpoint, bool entered)
 {
-	struct gasmix air = {};
-	struct gasmix gas = {};
+	int cylinderid;
 	bool usePrevious = false;
-	if (gas_in)
-		gas = *gas_in;
+	if (cylinderid_in)
+		cylinderid = cylinderid_in;
 	else
 		usePrevious = true;
 	if (recalcQ())
@@ -607,19 +598,14 @@ int DivePlannerPointsModel::addStop(int milimeters, int seconds, gasmix *gas_in,
 		const divedatapoint t = divepoints.at(lastEnteredPoint());
 		milimeters = t.depth;
 		seconds = t.time + 600; // 10 minutes.
-		gas = t.gasmix;
+		cylinderid = t.cylinderid;
 		ccpoint = t.setpoint;
 	} else if (seconds == 0 && milimeters == 0 && row == 0) {
 		milimeters = M_OR_FT(5, 15); // 5m / 15ft
 		seconds = 600;		     // 10 min
-		//Default to the first defined gas, if we got one.
-		cylinder_t *cyl = &displayed_dive.cylinder[0];
-		if (cyl)
-			gas = cyl->gasmix;
+		// Default to the first cylinder
+		cylinderid = 0;
 	}
-	if (!usePrevious)
-		if (!addGas(gas))
-			qDebug("addGas failed"); // FIXME add error propagation
 
 	// check if there's already a new stop before this one:
 	for (int i = 0; i < row; i++) {
@@ -640,13 +626,9 @@ int DivePlannerPointsModel::addStop(int milimeters, int seconds, gasmix *gas_in,
 	// the segment is determined by the waypoint at the end.
 	if (usePrevious) {
 		if (row  < divepoints.count()) {
-			gas = divepoints.at(row).gasmix;
+			cylinderid = divepoints.at(row).cylinderid;
 		} else if (row > 0) {
-			gas = divepoints.at(row - 1).gasmix;
-		} else {
-			if (!addGas(air))
-				qDebug("addGas failed"); // FIXME add error propagation
-
+			cylinderid = divepoints.at(row - 1).cylinderid;
 		}
 	}
 
@@ -655,7 +637,7 @@ int DivePlannerPointsModel::addStop(int milimeters, int seconds, gasmix *gas_in,
 	divedatapoint point;
 	point.depth = milimeters;
 	point.time = seconds;
-	point.gasmix = gas;
+	point.cylinderid = cylinderid;
 	point.setpoint = ccpoint;
 	point.entered = entered;
 	point.next = NULL;
@@ -772,7 +754,7 @@ void DivePlannerPointsModel::rememberTanks()
 	oldGases = collectGases(&displayed_dive);
 }
 
-bool DivePlannerPointsModel::tankInUse(struct gasmix gasmix)
+bool DivePlannerPointsModel::tankInUse(int cylinderid)
 {
 	for (int j = 0; j < rowCount(); j++) {
 		divedatapoint &p = divepoints[j];
@@ -780,45 +762,12 @@ bool DivePlannerPointsModel::tankInUse(struct gasmix gasmix)
 			continue;
 		if (!p.entered) // removing deco gases is ok
 			continue;
-		if (gasmix_distance(&p.gasmix, &gasmix) < 100)
+		if (p.cylinderid == cylinderid) // tank is in use
 			return true;
 	}
 	return false;
 }
 
-void DivePlannerPointsModel::tanksUpdated()
-{
-	// we don't know exactly what changed - what we care about is
-	// "did a gas change on us". So we look through the diveplan to
-	// see if there is a gas that is now missing and if there is, we
-	// replace it with the matching new gas.
-	QVector<QPair<int, int> > gases = collectGases(&displayed_dive);
-	if (gases.count() == oldGases.count()) {
-		// either nothing relevant changed, or exactly ONE gasmix changed
-		for (int i = 0; i < gases.count(); i++) {
-			if (gases.at(i) != oldGases.at(i)) {
-				if (oldGases.count(oldGases.at(i)) > 1) {
-					// we had this gas more than once, so don't
-					// change segments that used this gas as it still exists
-					break;
-				}
-				for (int j = 0; j < rowCount(); j++) {
-					divedatapoint &p = divepoints[j];
-					struct gasmix gas;
-					gas.o2.permille = oldGases.at(i).first;
-					gas.he.permille = oldGases.at(i).second;
-					if (gasmix_distance(&gas, &p.gasmix) < 100) {
-						p.gasmix.o2.permille = gases.at(i).first;
-						p.gasmix.he.permille = gases.at(i).second;
-					}
-				}
-				break;
-			}
-		}
-	}
-	emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1));
-}
-
 void DivePlannerPointsModel::clear()
 {
 	bool oldRecalc = setRecalc(false);
@@ -843,12 +792,12 @@ void DivePlannerPointsModel::createTemporaryPlan()
 		int deltaT = lastIndex != -1 ? p.time - at(lastIndex).time : p.time;
 		lastIndex = i;
 		if (i == 0 && prefs.drop_stone_mode) {
-			/* Okay, we add a fist segment where we go down to depth */
-			plan_add_segment(&diveplan, p.depth / prefs.descrate, p.depth, p.gasmix, p.setpoint, true);
+			/* Okay, we add a first segment where we go down to depth */
+			plan_add_segment(&diveplan, p.depth / prefs.descrate, p.depth, p.cylinderid, p.setpoint, true);
 			deltaT -= p.depth / prefs.descrate;
 		}
 		if (p.entered)
-			plan_add_segment(&diveplan, deltaT, p.depth, p.gasmix, p.setpoint, true);
+			plan_add_segment(&diveplan, deltaT, p.depth, p.cylinderid, p.setpoint, true);
 	}
 
 	// what does the cache do???
@@ -857,7 +806,7 @@ void DivePlannerPointsModel::createTemporaryPlan()
 	for (int i = 0; i < MAX_CYLINDERS; i++) {
 		cylinder_t *cyl = &displayed_dive.cylinder[i];
 		if (cyl->depth.mm) {
-			dp = create_dp(0, cyl->depth.mm, cyl->gasmix, 0);
+			dp = create_dp(0, cyl->depth.mm, i, 0);
 			if (diveplan.dp) {
 				dp->next = diveplan.dp;
 				diveplan.dp = dp;
diff --git a/qt-models/diveplannermodel.h b/qt-models/diveplannermodel.h
index 0770aa0..da84119 100644
--- a/qt-models/diveplannermodel.h
+++ b/qt-models/diveplannermodel.h
@@ -30,7 +30,7 @@ public:
 	virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
 	virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
 	virtual Qt::ItemFlags flags(const QModelIndex &index) const;
-	void gaschange(const QModelIndex &index, QString newgas);
+	void gaschange(const QModelIndex &index, int newcylinderid);
 	void removeSelectedPoints(const QVector<int> &rows);
 	void setPlanMode(Mode mode);
 	bool isPlanner();
@@ -42,7 +42,7 @@ public:
 	bool recalcQ();
 	void tanksUpdated();
 	void rememberTanks();
-	bool tankInUse(struct gasmix gasmix);
+	bool tankInUse(int cylinderid);
 	void setupCylinders();
 	/**
 	 * @return the row number.
@@ -59,7 +59,7 @@ public:
 
 public
 slots:
-	int addStop(int millimeters = 0, int seconds = 0, struct gasmix *gas = 0, int ccpoint = 0, bool entered = true);
+	int addStop(int millimeters = 0, int seconds = 0, int cylinderid_in = 0, int ccpoint = 0, bool entered = true);
 	void addCylinder_clicked();
 	void setGFHigh(const int gfhigh);
 	void triggerGFHigh();
-- 
2.7.4



More information about the subsurface mailing list