aboutsummaryrefslogtreecommitdiffstats
path: root/qt-models/diveplannermodel.cpp
AgeCommit message (Collapse)Author
2021-04-02planner: remove DivePlannerPointsModel::setRecalc()Gravatar Berthold Stoeger
The only external user of setRecalc() was turning recalculation on. In fact, this happened when constructing the planner-widget. However, for example editing of the profile only works when the recalc flag is on. This is all very confusing, let's just turn the flag on by default and remove the accessor. Internally, the planner can simply use the std::exchange function to set and reset the recalc flag. Perhaps the setting/resetting can be replaced by simple recalc = true; ... recalc = false; pairs. It is unclear whether there is need for recursion. Something to be investigated. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02planner: remove displayed_dive from DivePlannerModelGravatar Berthold Stoeger
To remove global state, make the dive that DivePlannerModel works on a member variable. Pass the dive in createSimpleDive() and loadFromDive(). Moreover, this should pave the way to more fine-grained undo in the planner. Ultimately, the planner should not be modal. Attention: for now, the dive must still be displayed_dive, because of the convoluted way in which the profile and the planner work on the same dive. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02planner: move clearing of model into loadFromDive() functionGravatar Berthold Stoeger
Both loadFromDive() callers were clearing the model before calling loadFromDive(). Move the clearing into that function since it makes no sense to load into a non-cleared model. Apparently this changes the way that no-cylinder dives are treated and the code in ProfileWidget2::repositionDiveHandlers() must now explicitly check for that condition. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02cleanup: remove pointless cylinder model updateGravatar Berthold Stoeger
In DivePlannerPointsModel::clear(), the cylinder model is updated before it is cleared. This must be an artifact. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02planner: move same-time check to DivePlannerPointsModelGravatar Berthold Stoeger
There must not be two dive planner points at the same time stamp, as this violates the laws of physics (and internal assumptions). The corresponding test was done in the profile code at two different places with floating point arithmetics. This is a bad idea, because 1) code duplication 2) danger of rounding issues Instead, do this in one central point in the planner model and use integer arithmetics. Simply add a few seconds until a unique timestamp is obtained. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02planner: implement move semantics in DivePlannerPointsModelGravatar Berthold Stoeger
When reordering the points, the DivePlannerPointsModel would not emit the appropriate move signals, but simply a data-changed signal over all elements. This obviously violates Qt's model/view API, though it is probably harmless. Let's do the right thing so that the frontend knows that the selected item changed place. Also, emit dataChanged only on the actually changed element, not all elements. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02planner: fix removal of points from DivePlannerPointsModelGravatar Berthold Stoeger
The beginRemoveRows() function was fed erroneous values. It is a mystery why this didn't crash. In any case, deletion of multiple points did not work properly. Instead of trying to be fancy, remove each point one-by-one. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02planner: insert point at correct positionGravatar Berthold Stoeger
Instead of inserting the point at the calculated position, the DivePlannerPointsModel would append it at the end and then resort the vector. That's just silly. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02cleanup: use proper model/view semantics in DivePlannerModelGravatar Berthold Stoeger
When clearing the model, use "beginResetModel/endResetModel" instead of "beginRemoveRows/endRemoveRows". Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02cleanup: add DivePlannerPointsModel::addDefaultStop() functionGravatar Berthold Stoeger
When clicking on "+" in the planner, a default stop point was added using a signal/slot connection. This used the archaic string-based connect syntax, because it was realized with default parameters passed to "addStop()". Instead, add a "addDefaultStop()" slot, which passes the default parameters. Since all other callers do not use callbacks, unslotify "addStop()". The slot was the only user of the default parameters, so they can be removed alltogether. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02cleanup: constify DivePlannerPoints model accessor functionsGravatar Berthold Stoeger
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-02-17planner: pass in_planner argument to decoMode()Gravatar Berthold Stoeger
To remove reliance on global state, pass an "in_planner" argument to decoMode(). Thus, calls to in_planner() can be removed. This is a more-or-less automated change. Ultimately it would probably be better to pass the current deco-mode to the affected functions instead of calling decoMode() with an in_planner parameter. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20cleanup: make a few DivePlannerModel functions privateGravatar Berthold Stoeger
It simplifies reasoning about control flow a lot if it is known that functions can't be invoked from a different part of the code base. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20planner: remove DivePlannerPointsModel::startTimeChanged signalGravatar Berthold Stoeger
The way the starting time of a new plan was set was bonkers: 1) PlannerWidgets::planDive() invokes DivePlannerPointsModel:: createSimpleDive(). 2) createSimpleDive() calls DivePlannerPointsModel:: setupStartTime() 3) setupStartTime() emits a signal startTimeChanged() 4) startTimeChanged is caught by PlannerWidget and sets the UI field 5) change of the UI field emits a timeChanged() signal which is connected to DivePlannerPointsModel::setStartTime() 6) setStartTime() sets the time of the plan and displayed_dive and emits dataChanged() 7) dataChanged() replots the dive() 8) Back in DivePlannerPointsModel::createSimpleDive() the diveplan start time is overwritten with displayed_dive (the value are equal owing to 6) Wow! But it gets worse: 9) The initial dive plan is set up in createSimpleDive(). Since the profile is drawn in 7) after clearing the displayed_dive and before constructing the initial plan, the profile is shown on a dive without samples. It therefore generates a dummy profile. To make this somewhat less insane, remove the startTimeChanged() signal in 3), explicitly set the start time of plan and dive to the one calculated by setupStartTime() and explicitly set the UI filed in the plannerWidget. This still indirectly draws the profile via signals in a convoluted way, but at it straightens out things somewhat. Most importantly, the profile doesn't have to generate a fake DC. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-11-24diveplannermodel: replace in_planner() by isPlanner()Gravatar Berthold Stoeger
The in_planner() function is problematic, because it depends on the application state that is only available on desktop. If we ever want to port the planner to mobile, we have to get rid of it. Luckily, the DivePlannerModel already has an appropriate flag that can be used instead. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-10-25cleanup: split out divecomputer functions from dive.cGravatar Berthold Stoeger
Since dive.c is so huge, split out divecomputer-related functions into divecomputer.[c|h], sample.[c|h] and extradata.[c|h]. This does not give huge compile time improvements, since struct dive contains a struct divecomputer and therefore dive.h has to include divecomputer.h. However, it make things distinctly more clear. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-08-24Planner: enforce minimal segement durationGravatar Robert C. Helling
You cannot be at two depths at the same time (and it confuses the planner). So give yourself at least 10 seconds. Signed-off-by: Robert C. Helling <helling@atdotde.de> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-08-24Planner: handle zero length segments when replanningGravatar Robert C. Helling
When setting up a dive for replanning, we ignored zero length segments as those tend to be generated by gas changes. But it is possible to enter those in the planner and the replanning should not ignore those. So be more clever about gas changes. Let's add 10 seconds so we are not at two depths at the same time and help since add_stop also does not like zero length segments (it thinks we are trying to replace a waypoint). Fixes #2901 Signed-off-by: Robert C. Helling <helling@atdotde.de> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-05-22cleanup: create common QDateTime -> timestamp conversion functionGravatar Berthold Stoeger
In analogy to the timestamp -> QDateTime conversion, create a common function. 1) For symmetry with the opposite conversion. 2) To remove numerous inconsistencies. 3) To remove use of the deprecated QDateTime::toTime_t() function. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-05-04planner: remove conditional command-calls for mobileGravatar Berthold Stoeger
In the planner the undo commands for adding / editing dives were only called if not on mobile. This is from days were mobile didn't have undo commands. We can remove these now. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-05-04Planner: fold MainWindow::setupForAddAndPlan into createSimpleDive()Gravatar Berthold Stoeger
There was only one caller of MainWindow::setupForAddAndPlan() left and that caller immediately called DivePlannerPointsModel::createSimpleDive(). Thus, we might just as fold the former in the latter and thus concentrate all the prepare-dive-for-plan business in one place. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-05-04planner: send plan in calculatedPlanNotesGravatar Berthold Stoeger
Thus, the MainWindow doesn't have to extract the plan from displayed_dive. This is a tiny step in an attempt to detangle the interfaces. The bigger goal will be to make displayed_dive local to the planner. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-05-04planner: update variations in planner not mainwindowGravatar Berthold Stoeger
When calculating variations, they were sent to the mainwindow, which updated displayed_dive accordingly. Do this directly in the planner-model. The idea is to detangle interdependencies and to make the code reusable (planner on mobile?). Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-05-01cleanup: move dive_table from dive.h to divelist.hGravatar Berthold Stoeger
This allows us to decouple dive.h and divelist.h, a small step in include disentangling. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-05-01core: always keep an empty cylinder at the end of the cylinder arrayGravatar Berthold Stoeger
This will be temporarilly used by the planner to mark consumption of air at the surface. Do this by creating a new function add_cylinder, which replaces add_to_cylinder_table() and takes care of always adding a dummy cylinder at the end of the table. Make the original add_to_cylinder_table() local, so that it cannot be accessed anymore. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-04-13Preserve events when editing dive in plannerGravatar Robert C. Helling
The planner does not know about events except gas changes. But if the dive comes from the log, we should preserve the dive computer events. At least those that happend before we started to delete waypoints to let the planner take over. Signed-off-by: Robert C. Helling <helling@atdotde.de>
2020-04-07CylindersModel: use flag to decide whether we are in plannerGravatar Berthold Stoeger
On desktop, we have two CylindersModel concurrently: One in the planner and one on the equipment-tab. They act differently, because the former modifies displayed_dive directly, the latter issues undo commands. To differentiate, we used the in_planner() function. However, that appears extremely brittle, especially when combined with undo-commands. Therefore when generating the model, pass in a parameter that says whether this is for the planner or the equipment tab and use that flag to decide how to act. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-04-07CylinderModel: make dive dynamicGravatar Berthold Stoeger
The CylinderModel always accessed the global "displayed_dive" and in some special cases also "current_dive". To implement cylinder undo, the model should work on an arbitrary dive. Therefore, in analogy to the weight model, make the dive dynamic. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-23cleanup: remove CleanerTableModel::warningMessage signalGravatar Berthold Stoeger
Nobody was ever listening to this signal(?) and the last sender was removed in ac52034778bc5c82bb6c689d765b337b6d75b24a. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-11Planner: don't filter cylindersGravatar Berthold Stoeger
In the planner we used to filter out "unused" cylinders as in the equipment tab. It is unclear whether that makes sense or can even easily be reproduced, since such cylinders have to come from an imported dive. To be on the save side, let's not do this. Replace the CylindersFilteredModel introduced recently by a plain CylindersModel. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-11Planner: make cylinder-model subobject of planner-modelGravatar Berthold Stoeger
The cylinder-model had an instance() function, but actually there were two cylinder models: one used by the equipment tab, one used by the planner. This is misleading. Therefore, remove the instance() function and make the cylinder-model a subobject of the planner-model. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-11Cylinders: Add CylindersModelFilteredGravatar Berthold Stoeger
When the show_unused_cylinders flag is not set, the cylinder tables in the equipment tab and the planner should not show unused cylinders. However, the code in CylindersModel is fundamentally broken if the unused cylinders are not at the end of the list: The correct number of cylinders is shown, but not the correct cylinders. Therefore, add a higher-level CylindersModelFiltered model on top of CylindersModel that does the actual filtering. Some calls are routed through to the base model (notably those that take indexes, as these have to be mapped), for some calls the caller has to get access to the source model first. We might want to adjust this. For filtering, reuse the already existing show_cylinder function and export it via CylindersModel. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-01-25diveplanner: add comments explaining different scalingGravatar jan Iversen
In some case the scaling (real value <-> UI value) is different for mobile and desktop. In order to make the difference understandable comments are added to each function. Signed-off-by: jan Iversen <jan@casacondor.com> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-01-25diveplanner: move mobile specific calc to diveplannermodelGravatar jan Iversen
setBottomSac, setDecoSac and setFactor in diveplannermodel receives display value which are then converted. subsurface-mobile have slightly different values, move the correction of these from plannershared to diveplannermodel, in order to keep the whole convert in one place. Signed-off-by: jan Iversen <jan@casacondor.com> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-01-20qt-models: add suffix Display to unit system aware asc/desc settersGravatar jan Iversen
Change ascent/descent setter function names to set_<name>Display to show the value is prepared for displaying (common for desktop and QML). Signed-off-by: jan Iversen <jan@casacondor.com> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-01-20qt-models: add getters to diveplanner modelGravatar jan Iversen
diveplannermodel already contains set_<asc/desc> function that convert from screen value to real value; this adds get functions that convert real value to screen value, so now all conversions are done in one place. Use prefix Display to identify this is values prepared for the UI (both desktop and QML). Signed-off-by: jan Iversen <jan@casacondor.com> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-01-10code cleanup: introduce empty_cylinder constantGravatar Dirk Hohndel
This deals with the issue of initializing structs in C++. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-12-27testing: prepare diveplannermodel to be used in testingGravatar jan Iversen
In order to make tests for plannerShared, some qt-models must be linked, and due to the fact that commands are currently not available for mobile (which also makes the tests) and #ifdef must be added. The test version of diveplannermodel will be specially compiled in (SUBSURFACE_TESTING set) in the tests directory. Signed-off-by: Jan Iversen <jan@casacondor.com>
2019-12-26qt-models: conditionally compile Commands:: in diveplannermodel.cppGravatar jan Iversen
commands (undo) are not available for mobile, but diveplannermodel is needed add #ifndef MOBILE around Commands:: Signed-off-by: Jan Iversen <jan@casacondor.com> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-11-14Refactoring: move undo commands to top levelGravatar Berthold Stoeger
In the future we might want to use undo-commands for mobile as well (even if not implementing undo). Therefore, move the undo-command source from desktop-widgets to their own commands top-level folder. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-09Cylinders: access cylinders with get_cylinder()Gravatar Berthold Stoeger
Instead of accessing the cylinder table directly, use the get_cylinder() function. This gives less unwieldy expressions. But more importantly, the function does bound checking. This is crucial for now as the code hasn't be properly audited since the change to arbitrarily sized cylinder tables. Accesses of invalid cylinder indexes may lead to silent data-corruption that is sometimes not even noticed by valgrind. Returning NULL instead of an invalid pointer will make debugging much easier. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-09Core: remove MAX_CYLINDERS restrictionGravatar Berthold Stoeger
Instead of using fixed size arrays, use a new cylinder_table structure. The code copies the weightsystem code, but is significantly more complex because cylinders are such an integral part of the core. Two functions to access the cylinders were added: get_cylinder() and get_or_create_cylinder() The former does a simple array access and supposes that the cylinder exists. The latter is used by the parser(s) and if a cylinder with the given id does not exist, cylinders up to that id are generated. One point will make C programmers cringe: the cylinder structure is passed by value. This is due to the way the table-macros work. A refactoring of the table macros is planned. It has to be noted that the size of a cylinder_t is 64 bytes, i.e. 8 long words on a 64-bit architecture, so passing on the stack is probably not even significantly slower than passing as reference. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-26Cleanup: avoid resource leak in dive planner modelGravatar Dirk Hohndel
Found by Coverity. Fixes CID 350121 Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-10-26Desktop: use undo command when replanning diveGravatar Berthold Stoeger
Instead of copying the displayed dive, generate an undo command. This makes the replanning an undoable action and fixes a bug where the dive details have not been updated correctly. Fixes #2280 Reported-by: Stefan Fuchs <sfuchs@gmx.de> Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-20Planner: copy deco state before passing it to worker threadGravatar Berthold Stoeger
The planner has a computeVariations() function that can be run in a worker thread. The code was not thread safe: a deco_state object allocated on the stack of the caller was passed down to the worker thread. It's well possible that the object would go out of scope before the thread run. Therefore, when running in the background, copy the object first and free it in the worker thread. Side note: Qt makes proper memory management again as difficult as possible: You can't pass a std::unique_ptr<> to QtConcurrent::run, because move-only objects are not supported. Not very friendly! Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-10Planner: remove planner disclaimer from old notesGravatar Berthold Stoeger
There used to be code to remove the old planner notes when replanning a dive. It used a global variable and seemed rather brittle. Moreover, the place that set the global variable was inadvertently removed. Therefore has been effectively dead code. Reimplement the functionality, but be more robust by considering that the deco-type may have changed: Split the translated disclaimer string in two parts, before and after the "%s" place-holder. Search for these two parts. Remove the disclaimer and everything after the disclaimer. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-08-08Core: pass dive, cylinder-id to fill_default_cylinderGravatar Berthold Stoeger
The fill_default_cylinder() function calculated the MOD based on the currently displayed dive. This does not seem to make sense: - When importing dives, why would we care about the altitude and salinity of the currently displayed dive, possibly from a different trip. - The planner is supposed to be thread-safe and should not touch global variables. Of course this means that the importing-functions have to fill out altitude and salinity before creating the default cylinder, but this is their problem. For a freshly created dive they will get the default values, which still seems less random than the values from the displayed dive. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-07-18Cleanup: remove includes from qthelper.hGravatar Berthold Stoeger
To reduce interdependencies, remove the dive.h and divelist.h includes in qthelper.h Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-07-18Cleanup: move deco function declarations to deco.hGravatar Berthold Stoeger
Another tiny step in making dive.h smaller: move function declarations to deco.h if these functions are defined in deco.c and don't directly concern dives. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-04-12Undo: remove ADD mode from main tabGravatar Berthold Stoeger
Instead of letting the user edit the fields before adding a dive, simply add an empty dive. Thus, the ADD mode of the main tab can be removed. Constructing a new dive with default-depth and making sure that the dive is displayed correctly is very subtle. This all needs to be detangled in due course. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>