aboutsummaryrefslogtreecommitdiffstats
path: root/qt-models/divetripmodel.cpp
AgeCommit message (Collapse)Author
2019-09-06Dive site: don't emit divesChanged signals when editing dive siteGravatar Berthold Stoeger
When editing the dive site, for certain fields a divesChanged signal was emitted so that the dive-list can be updated. Arguably it is wrong to decide which fields are relevant to the dive list in the undo-command code. Therefore, let the list catch the dive-site-edited signal and decide itself. But the actual reason for this commit is that if the dive-site field of a dive changes, we might have to reload the dive-location-model because suddenly a new dive site appears. Now if this is done in QML context on some Qt version (notably 5.9) we get crashes later on. But that can happen if the user moves a flag. So in that case only send a diveSiteChanged signal. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-07-19Undo: make editing of dive number undoableGravatar Berthold Stoeger
When pressing F2 in the dive list, the number can be edited. Make this action undoable by implementing a EditNumber command. This command is differs from the other undo commands, as not the currently selected dives are changed. This means that the EditCommand needs an alternative constructor taking a single dive. This constructor was implemented in the base class so that all edit commands can now be called with a single dive. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-06-23Cleanup: unify selection signalsGravatar Berthold Stoeger
For historic reasons, there where three distinct signals concerning dive-selection from the undo-machinery: 1) divesSelected: sent newly selected dives 2) currentDiveChanged: sent if the current dive changed 3) selectionChanged: sent at the end of a command if either the selection or the current dive changed Since now the undo-commands do a full reset of the selection, merge these three signals into a single signal. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-06-23Undo: unify selection behavior in dive-list commandsGravatar Berthold Stoeger
Some commands tried to retain the current selection on undo/redo, others set the selection to the modified dives. The latter was introduced because it was easier in some cases, but it is probably more user-friendly because the user gets feedback on the change. Therefore, unify to always select the affected dives on undo()/redo(). Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-06-23Undo: don't send signals batched by tripGravatar Berthold Stoeger
Since the default view is batched by trips, signals were sent trip-wise. This seemed like a good idea at first, but when more and more parts used these signals, it became a burden. Therefore push the batching to the part of the code where it is needed: the trip view. The divesAdded and divesDeleted are not yet converted, because these are combined with trip addition/deletion. This should also be detangled, but not now. Since the dive-lists were sorted in the processByTrip function, the dive-list model now does its own sorting. This will have to be audited. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-06-23Dive list: cache shown flag in model (quick-fix for undo-crash)Gravatar Berthold Stoeger
We have a very fundamental problem with data-duplication in core and qt-models. In a particular case, this led to an easily reproducible crash: 1) An undo command moved the last dive of a trip to another. 2) When an undo-command removed the last dive of a trip to a different trip, the dive was removed from the trip in the core. Then, the model was updated. 3) That lead at first to a rearrangement of the trips, because the trip with the added dive is moved before the trip with the removed dive. 4) In such a case, the filter-model checks the visibility of the trip. 5) Since the trip with the removed dive has no dives in the core, visibility was determined as false. 6) From this point on the mappings of the QSortFilterProxyModel were messed up. Accesses led to crashes. It is unclear whether this is a Qt bug or only a QOI issue. As a quick-fix, cache the visibility flag of trips directly in the Qt-models. Don't set the visibility directly in the core, but go via the Qt-models. Thus, a more clear layering is achieved. In the long run, we can hopefully get rid of the data-duplication in the models. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-06-19Cleanup: move trip-related functions into own translation unitGravatar Berthold Stoeger
These functions were spread out over dive.c and divelist.c. Move them into their own file to make all this a bit less monolithic. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-06-19Cleanup: move tag functions into own translation unitGravatar Berthold Stoeger
Make dive.h a bit slimmer. It's only a drop in the bucket - but at least when modifying tag functions not the *whole* application is rebuilt anymore. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-05-20Cleanup: fix a few comments and debug messagesGravatar Berthold Stoeger
This is just minor fixes that are not user-visible: Fix a few erroneous comments and a debug message. These are copy & paste mistakes and mistakes introduced during code- refactoring. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-05-15Cleanup: small coding style fixesGravatar Dirk Hohndel
And addressing a cut and paste error in a comment. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-05-12Cleanup: remove UTF8 macrosGravatar Berthold Stoeger
At some places we use UTF8 string literals. Therefore, we effectively only support UTF8 build systems. We might just as well remove all the other UTF_* macros and use direct string literals. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-04-12Undo: update filter flag when dives changeGravatar Berthold Stoeger
The filter code is strange: it actually only checks the dive->hidden_by_filter flag. Thus, before propagating the dive changed signal, this flag has to be updated. Do this in the DiveTripModel. Ultimately, this should be refactored. Moreover, if the filter-flag changed notify the frontend of a changed trip so that the trip is hidden / unhidden. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-04-12Undo: update dive list if trip changedGravatar Berthold Stoeger
In tree-mode, the trip locations are displayed. Update the corresponding entries if the trip changed, by hooking into the tripChanged() signal. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-07Dive list: split DiveTripModel into distinct models (tree and list)Gravatar Berthold Stoeger
The DiveTripModel was used to represent both, trip and list views. Thus many functions had conditionals checking for the current mode and both modes had to be represented by the same data structure. Instead, split the model in two and derive them from a base class, which implements common functions and defines an interface. The model can be switched by a call to resetModel(), which invalidates any pointer obtained by instance(). This is quite surprising behavior. To handle it, straighten out the control flow: DiveListView --> MultiFilterSortModel --> DiveTripModelBase Before, DiveListView accessed DiveTripModelBase directly. A goal of this commit is to enable usage of the same model by mobile and desktop. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-12-06Dive list: fix off-by-two bug in DiveTripModelGravatar Berthold Stoeger
Commit 911edfca712a046944de6d033cc4b8dd50cedfc3 changed the dive list on desktop to update positions of trips when adding/removing dives. A very unlikely case, but necessary for consistency. For a trip to be moveable down, its index has to be one-less than the maximum index, which is "items - 1". The code was doubly wrong: it forget the "1" and checked for less-or-equal instead less-than. Thus this was effectively an off-by-two error. Fix it. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-23Core: move is-single-day-trip and count-shown functions into coreGravatar Berthold Stoeger
These functionality was used by the desktop filter. To unify desktop and mobile, move it into two new functions in divelist.c Since one of them is the only caller of is_same_day() move that likewise into divelist.c and make it of static linkage. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-23Cleanup: make "struct dive *" and "struct dive_trip *" Qt metatypesGravatar Berthold Stoeger
Just as we did for pointer to struct dive_site, make pointers to struct dive and struct dive_trip "Qt metatypes". This means that they can be passed through QVariants without taking a detour via void *. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-18Dive list: update position of trip if data changedGravatar Berthold Stoeger
If the date of a dive changed, it might be necessary to reorder the trips, as the date of the trip changed. Although this seems like an odd usecase, move the trip if necessary, for consistency's sake. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-18Core: remove "when" field of struct dive_tripGravatar Berthold Stoeger
The when field gives the time of the first dive. Instead of keeping this field in sync, replace it by a function that determines the time of the first dive. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-18Coding style: fix indentation in addDivesToTrip()Gravatar Berthold Stoeger
addDivesToTrip() had one level of indentation too much owing to a copy-and-paste error. Remove. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-18Dive list: move sort-functionality into coreGravatar Berthold Stoeger
To make sorting more controlled, move all sorting functions into the core. For this, introduce a "dive_or_trip" structure, which represents a top-level item. Adapt the DiveTripModel accordingly. There are now three sorting functions: 1) dive_less_than 2) trip_less_than 3) dive_or_trip_less_than These should be used by all sorting code. By moving them to a single place, the mess can hopefully be cleaned up. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-18Dive list: replace dive-list of trips by a tableGravatar Berthold Stoeger
The dives of each trip were kept in a list. Replace this by a struct dive_table. This will make it significantly easier to keep the dives of a trip in sorted state. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-16Dive list: invert sort-direction to reflect coreGravatar Berthold Stoeger
Traditionally, the DiveTripModel has its data sorted in opposite direction to the core-data (chronologically descending vs. ascending). This bring a number of subtle problems. For example, when filling the model, trips are filled according to the *last* dive, whereas later insertion points are according to the ->when value from the core, which depends on the *first* dive. As a start of fixing these subtleties, change the sort direction to reflect the core-data. Ideally, this should lead to a removal of the redundant data-representation. Since the model is now sorted in ascending order, sorting has to be enabled in the DiveListView constructor to reflect the default-descending order. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-05Dive list: let sort arrows reflect sort order for NR and DATEGravatar Berthold Stoeger
The old code always sorted by "ascending" by default. But because users typically want their new dives top, "ascending" was defined for NR and DATE, such that it is actually descending. Turn these around and intitialize these two fields as default-descending. This is possible using the Qt::InitialSortOrderRole role in DiveTripModel::headerData(). Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-04Dive list: use proper comparison when comparing dive to tripGravatar Berthold Stoeger
The DiveTripModels are sorted in *reverse* chronological order. Therefore, when comparing a dive against a trip, the dive has to be inserted if the dive has a *later* date. Change the comparison accordingly. Reported-by: Jan Mulder <jlmulder@xs4all.nl> Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-04Undo: fix addition of multiple divesGravatar Berthold Stoeger
The generic addInBatches() function is used to add batches of contiguous sets of dives to the dive-list models. The loop searching for the end of the batch used the wrong index and would therefore not properly cut the batches. Fix this. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-01Dive list: implement custom lessThan functionGravatar Berthold Stoeger
The dive list was sorted using the default-sorter of QSortFilterProxy model. This is mighty inflexible as it considers only one column. This has the funky effect that for rows with identical elements, the sort order depends on the previous sorting. Implement a lessThan() function in the MultiFilterSortModel, which simply hands the sorting down to the actual model. This might be considered a layering violation, but it makes things so much easier. Sadly, it seems like the column-to-be-sorted is transported in the provided indices. Therefore, the comparison is chosen using a switch for *every* comparison. It would seem much more logical to set a function pointer once and use that. Further investigations are necessary. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-01Dive list: make filter model aware of its sourceGravatar Berthold Stoeger
The data-flow from C-core to list-view is as follows: C-core --> DiveTripModel --> MultiSortFilterModel --> DiveListView The control-flow, on the other hand, differs as DiveListView accesses both MultiSortFilterModel and DiveTripModel, whereas MultiSortFilterModel is mostly unaware of its source model. This is in principle legitimate, as the MultiSortFilterModel might be used for different sources. In our particular case, this is not so. MultiSortFilterModel is written for a particular use case. Therefore, model control-flow follow after data-flow: Let MultiSortFilterModel set its own source model and DiveListView access the MultiSortFilterModel, which then manages its source model. This is not bike-shedding, but will enable a more flexible and higher-performance sorting. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-28Cleanup: remove DiveTripModel::layout() functionGravatar Berthold Stoeger
This accessor was never used. This is a small step in splitting the DiveTripModel in two (list & tree), which means that the layout is moved up to the view. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-21Dive list: update trip headers on filter-finishGravatar Berthold Stoeger
On change of the filter, the headers of non-extended trips were not updated. Therefore, on filter-finish-event loop over all trips in DiveTripModel and signal data-changed. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-14Cleanup: remove DiveItem and TripItem classesGravatar Berthold Stoeger
The DiveItem and TripItem classes were wrappers around dive * and dive_trip * used to extract tabular data. With the rework of DiveTripModel they lost all their state besides the pointer itself. The usage was: DiveItem item(d); item.data(...); This can now be simplified to the much more idiomatic diveData(d, ...); and analoguously for TripItem. While adapting the data() function to be part of DiveTripModel, change the QVariant ret switch(...) { ... case ...: ret = ...; break; ... } return ret; style to switch(...) { ... case ...: return ...; } Not only is this shorter and easier to reason about, it generally also improves the generated code. The compiler can directly construct the return value in the buffer provided by the caller. Though modern compilers start to be very good at avoiding unnecessary copies. In total this cleanup results in a net-reduction of 190 lines of code. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11Dive list: unify sorting in core and Qt-modelGravatar Berthold Stoeger
Ultimately, we want to use a single dive-list and not replicate it in the Qt-model code. To this goal, let's start with using the same sort function. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11Dive list: retain selection on moval of divesGravatar Berthold Stoeger
The current code cheats when it comes to move dives inside a trip or move dives between trips: Instead of using the *MoveRows() functionality, the dives are removed from and re-added to the respective trips. This loses the selection. Therefore, remember which of the moved dives are selected and select them manually after they are re-added. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11Dive list: propagate current-item to frontendGravatar Berthold Stoeger
The command-objects select a current item, but this selection was not propagated to the front-end. The current item is the base for keyboard-navigation through the dive-list and therefore should be set correctly. It took some experimentation to get the flags right: QItemSelectionModel::Current Hopefully, these are the correct flags across all supported Qt versions! Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11Undo: select dives after add, remove, merge, split dive commandsGravatar Berthold Stoeger
Select the proper dives after the add, remove, split and merge dives commands on undo *and* redo. Generally, select the added dives. For undo of add, remember the pre-addition selection. For redo of remove, select the closest dive to the first removed dive. The biggest part of the commit is the signal-interface between the dive commands and the dive-list model and dive-list view. This is done in two steps: 1) To the DiveTripModel in batches of trips. The dive trip model transforms the dives into indices. 2) To the DiveListView. The DiveListView has to translate the DiveTripModel indexes to actual indexes via its QSortFilterProxy- model. For code-reuse, derive all divelist-changing commands from a new base-class, which has a flag that describes whether the divelist changed. The helper functions which add and remove dives are made members of the base class and set the flag is a selected dive is added or removed. To properly detect when the current dive was deleted it became necessary to turn the current dive from an index to a pointer, because indices are not stable. Unfortunately, in some cases an index was expected and these places now have to transform the dive into an index. These should be converted in due course. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11Dive list: remember selected divesGravatar Berthold Stoeger
Don't delesect dives, when unregistering them from the backend. If a previously selected dive is added, select it in the dive-list. For this purpose introduce a SELECTED_ROLE to query the DiveTripModel for selected dives. Unfortunately, when adding multiple selected dives, current_dive_changed is called for each of them, making this very slow. This will have to be fixed in subsequent commits. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11Dive list: implement proper Qt-model semantics for DiveTripModelGravatar Berthold Stoeger
Previously, each dive-list modifying function would lead to a full model reset. Instead, implement proper Qt-model semantics using beginInsertRows()/endInsertRows(), beginRemoveRows()/ endRemoveRows(), dataChange(). To do so, a DiveListNotifer singleton is generatated, which broadcasts all changes to the dive-list. Signals are sent by the commands and received by the DiveTripModel. Signals are batched by dive-trip. This seems to be an adequate compromise for the two kinds of list-views (tree and list). In the common usecase mostly dives of a single trip are affected. Thus, batching of dives is performed in two positions: - At command-level to batch by trip - In DiveTripModel to feed batches of contiguous elements to Qt's begin*/end*-functions. This is conceptually simple, but rather complex code. To avoid repetition of complex loops, the batching is implemented in templated-functions, which are passed lambda-functions, which are called for each batch. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11Undo: make diverse trip-related operations undo-ableGravatar Berthold Stoeger
AddDivesToTrip, CreateTrip, AutogroupDives, RemoveAutogenTrips and MergeTrips basically all did the same thing as RemoveDivesFromTrip, which was already implemented. Thus, factor our the common functionality and hook it up to make all these functions undo-able. Don't do the autogroup-call everytime the dive-list is rebuilt (that would create innumberable undo-actions), but only on dive-load / import or if expressly asked by the user [by switching the autogroup flag]. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11Dive list: hand-code the DiveTripModelGravatar Berthold Stoeger
The dive list is fed data by means of a sorted "DiveTripModel". There are two modes: list and tree. This was implemented rather elegantly with a general "TreeModel", which can represent trees of arbitrary depths. Nevertheless, we have at most two levels and on the second level only dives can reside. Implementing proper model-semantics (insert, delete, move) will be quite a challenge and implementing it under the umbrella of a very general model will not make it easier. Therefore, for now, hardcode the model: At the top-level there are items which may either be a trip (can contain multiple dives) or a dive (contains exactly one dive). Thus, we can completely de-virutalize the DiveItem and TripItem classes, which are now trivial wrappers around dive * and dive_trip *. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11Dive list: replace dive-id by dive pointerGravatar Berthold Stoeger
The undo-system now guarantees that pointers to dives are stable throughout their lifetime. Therefore, replace the unique index by pointers. This is a small performance improvement, but much more importantly, it will make it more natural to transport a pointer to the dive inside QModelIndex's private pointer. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-06Core: remove preexisting field from struct dive_tableGravatar Berthold Stoeger
Dives are now in all cases imported via distinct dive_tables. Therefore the "preexisting" marker is useless. Remove. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-09-04Desktop: buddies in the dive listGravatar Jan Mulder
As proposed in RFC #1587, now also alllow buddies to be shown in the divelist. Fixes: #1587 Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
2018-09-01Cleanup: make DiveTripModel a global objectGravatar Berthold Stoeger
DiveTripModel (the model describing the dive-list) was destroyed and recreated on every reset of the list. This seems excessive. Instead - in analogy to most other models - make it a single global object. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-07-30Cleanup: remove DiveListView::fixMessyQtModelBehaviour()Gravatar Berthold Stoeger
The function DiveListView::fixMessyQtModelBehaviour() was used to expand the first columns of dive-trips in the dive-list view. This function was called everytime that the dive-list was modified. It is kind of ludicrous that external callers would have to tell the DiveListView, when it has to update its column headers. Instead, place this functionality in the overriden reset() and rowsInserted() functions, as these are the only ways that rows can be added. Change the DiveTripModel to use the proper beginResetModel()/endResetModel() pair instead of the previous full deletion and full repopulation using the beginRemoveRows()/ endRemoveRows() and beginInsertRows()/endInsertRows(). Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-07-27Dive list view: move column width logic back from DiveTripModelGravatar Berthold Stoeger
Conceptually, the width of the columns should probably reside in the view not the model. But much more severly, the old code didn't work: Columns were set in a DiveTripModel, which was deleted right away. Therefore, move the logic back to the DiveListView. Introduce a QVector<int> of the initial column widths, so that they can be erased from the setting if unchanged. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-07-23Cleanup: remove DiveItem::icon_names member arrayGravatar Berthold Stoeger
Each DiveItem (which is a wrapper around diveId with some virtual functions), had a member icon_names, which is an array of four QStrings. These were not used anywhere and must be an obscure oversight and was probably planned as a static cons array?. In any case, remove it. There *was* a function-local analogous icon_names array in DiveItem::data() though. This array would initialize four QStrings from C-string literals on every invocation. Make this array static, local to the translation unit and use the QStringLiteral macro to construct the QString object at compile-time. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-07-15UI change of "images"/"photo" to "media" or "media files"Gravatar Stefan Fuchs
This changes the above mentioned terms everywhere in the UI to reflect the fact that Subsurface now also supports video files on top of image files. Signed-off-by: Stefan Fuchs <sfuchs@gmx.de>
2018-06-04Cleanup: fold core/helpers.h into core/qthelper.hGravatar Berthold Stoeger
helpers.h included qthelper.h and all functions declared in helpers.h were defined in qthelper.h. Therefore fold the former into the latter, since the split seems completely arbitrary. While doing so, change the return-type of get_dc_nichname from "const QString" to "QString". Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-05-14Core: remove dive.h from files that don't need itGravatar Dirk Hohndel
Of course, quite a few of them indirectly get it through other header files. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-05-14Core: introduce new subsurface-string headerGravatar Dirk Hohndel
First small step to shrinking dive.h. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>