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 <[email protected]>
---
 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

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

Reply via email to