aboutsummaryrefslogtreecommitdiffstats
AgeCommit message (Collapse)Author
2021-05-06export: show progress dialog for TeX exportsGravatar Berthold Stoeger
The TeX exports may hang the UI for a long time. Show a progress-dialog that is updated after every exported dive and allows the user to cancel the export. This is pretty lame, because it is synchronous (export still runs in UI thread) and therefore the UI still is sluggish. But it is an improvement. Since the TeX-exporting code is in a shared directory (desktop and mobile), this uses a slim interface class. Mobile does not yet use TeX export, but you never know. Better than #ifdefs sprinkled all around, I reckon. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-05-06export: remove redundant QString::isNull() checksGravatar Berthold Stoeger
If QString::isEmpty() is false, QString::isNull() is likewise false, so these tests are redundant. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-26profile: move checking for DiveTextItem into its own functionGravatar Berthold Stoeger
When creating the context menu, a special menu is created for the dive computer name. This was checked in a loop, that set a flag and exited early. This can all be simplified by moving the loop into its own function. No more flag, less indentation. Overall better. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-26profile: simplify checking for DiveTextItemGravatar Berthold Stoeger
When creating the context menu on the profile, the code has to check whether the context menu is activated on the dive computer name to show a special menu (delete / split dive computer). This was done by setting a special property on the item and then checking for that property on the item that the menu is invoked on or its parents. The reason the code didn't simply check the pointer was probably that DiveTextItem uses multiple inheritance: It derives from QObject and QGraphicsItem. It has to derive from QObject first, because (the ridiculously broken) MOC needs it that way. The object added to the scene is a QGraphicsItem. Thus, we get a pointer _into_ the DiveTextItem object. However, that's all completely unnecessary. We can simply compare the pointers, as the compiler will understand that QGraphicsItem is only the second base class of DiveTextItem. Magic! Let's remove the cruft and simply compare the pointers. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-26cleanup: remove unnecessary includes from profilewidget2.cppGravatar Berthold Stoeger
These became unnecessary along the way. "qthelper.hpp" was included twice and <QtWidget> was to broad and was replaced by <QMimeData>. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-25cleanup: make a few ToolTipItem member functions privateGravatar Berthold Stoeger
They were not used outside the class. Moreover, mark ToolTipItem::persistPos() as const. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-25profile: ignore animation-speed setting when printingGravatar Berthold Stoeger
When printing, the animation speed was set to 0 by the caller and later reset to the original value. Instead of modifying global state, set it internally (in the profile-code) to zero when in print mode. This is another small step in making the printing independent from the shown profile. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-23Update to latest libdivecomputerGravatar Dirk Hohndel
Merge git://github.com/libdivecomputer/libdivecomputer into Subsurface-DS9 Merge upstream updates from Jef: - add suppoort for various new variants of existing dive computers: + Suunto Eon Steel Black, and new variant of Zoop Novo + Sherwood Beacon + new Shearwater Perdix AI model number - add new Sporasub SP2 support - various minor fixes and updates * 'master' of git://github.com/libdivecomputer/libdivecomputer: (22 commits) Add support for a new Suunto Zoop Novo variant Add support for the EON Steel Black Add support for the Sporasub SP2 Fix an overflow in the progress events Use a common sleep implementation Fix the clang compiler flag detection Add Github Actions CI builds and releases Show a summary after configuration Extend the OS detection to non Windows platforms Implement the ndl/deco sample Fix the maximum depth Mark the McLean Extreme as supporting BLE Fix -Wcast-qual compiler warning Mark the new iX3M 2021 models as supporting BLE Add support for the Sherwood Beacon Remove the infinite timeout Simplify the loop for reading the packet header Add a new Perdix AI hardware type Fix the McLean Extreme fingerprint feature Perform the check for the NULL key earlier ... Merge-done-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-04-21cleanup: remove MainWindow::turnOffNdlTts()Gravatar Berthold Stoeger
This flag is handled directly by the profile code since 2015 (000c9cc21c8991682169987ae8f348243ec5008b). The function therefore can be removed. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-21xml parsing: add XML_PARSE_HUGE flag to xmlReadMemory()Gravatar Linus Torvalds
It looks like libxml2 has some internal limitations by default that causes parse failures in some situations. Avoid them with XML_PARSE_HUGE. Without this, you get errors like test.xml:349250: parser error : internal error: Huge input lookup όμουν τουλάχιστον αλλά +2kg και ενδεχομένως +4 ^ when something in the xml file grows too large. I don't know libxml2 internals, so I have no idea what exactly goes wrong, but the docs say: XML_PARSE_HUGE = 524288 : relax any hardcoded limit from the parser and that makes us successfully parse the Greek file from Kostas. Reported-by: Kostas Katsioulis <kostaskatsioulis@gmail.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2021-04-19cleanup: don't hardcode array lengthGravatar Dirk Hohndel
Move the ARRAY_SIZE macro into a header file and use it to determine the number of cloud servers that we need to check. Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-04-19cloudstorage: update remote if cloud server changesGravatar Dirk Hohndel
If we can't reach the cloud server in the URL (which might come from the settings or be passed in by the user), we try the alternative server(s). If we end up changing servers, we need to update the remote that we have already parsed from the URL. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-04-19cloudstorage: try alternative server if first connection failsGravatar Dirk Hohndel
If we can't reach our preferred server, try using a different one. The diff makes more sense when ignoring white space. With this we check the connection to the cloud server much earlier and in case of failure to connect try a different cloud_base_url. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-04-19cloudstorage: adapt testsGravatar Dirk Hohndel
The code assumes that prefs.cloud_base_url is non NULL. Allowing that to be NULL makes no sense during normal operation of the app. Yet, most of the tests don't initialize the prefs at all. Making things worse, if we do correctly initialize the prefs (so as to reasonably approximate the behavior when running the app), things break because some of the reference outputs assume that the prefs are unset. This deserves fixing. For now, simply make sure that cloud_base_url is set for all the tests that try to parse files. Additionally, the semantics how cloud_base_url is saved to disk have changed, so adjust the test for those prefs accordingly. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-04-19cloudstorage: create consistent local directory namesGravatar Dirk Hohndel
With the new names for the cloud server we'd get different local cache directory names depending on which server gets used. In order to avoid that, normalize the name before generating the hash that determines the local directory name. Additionally, the old code had an extra '/' in the URL, due to the way the URL was assembled. Again, to match the existing hash for people upgrading from older Subsurface versions, add that to our normalized name as well. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-04-19cloudstorage: try to pick between multiple cloud serversGravatar Dirk Hohndel
The backend infrastructure will soon be able to support more than one cloud server which automagically stay in sync with each other. One critical requirement for that to work is that once a session was started with one of the servers, the complete session happens with that server - we must not switch from server to server while doing a git transaction. To make sure that's the case, we aren't trying to use DNS tricks to make this load balancing scheme work, but instead try to determine at program start which server is the best one to use. Right now this is super simplistic. Two servers, one in the US, one in Europe. By default we use the European server (most of our users appear to be in Europe), but if we can figure out that the client is actually in the Americas, use the US server. We might improve that heuristic over time, but as a first attempt it seems not entirely bogus. The way this is implemented is a simple combination of two free webservices that together appear to give us a very reliable estimate which continent the user is located on. api.ipify.org gives us our external IP address ip-api.com gives us the continent that IP address is on If any of this fails or takes too long to respond, we simply ignore it since either server will work. One oddity is that if we decide to change servers we only change the settings that are stored on disk, not the runtime preferences. This goes back to the comment above that we have to avoid changing servers in mid sync. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-04-19cloudstorage: add API to just update on-disk settingGravatar Dirk Hohndel
This way we can change the host that we will use next time the app runs. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-04-19cloudstorage: some cleanup of cloud url handlingGravatar Dirk Hohndel
We know the preference is never empty, so stop testing for this. But don't maintain two different preferences with basically the same content. Instead add the '/git' suffix where needed and keep this all in one place. Simplify the extraction of the branch name from the cloud URL. Also a typo fix and a new comment. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-04-19cloudstorage: remove ancient SSL hackGravatar Dirk Hohndel
This was a hack for a very early SSL certificate that was rejected on some platforms. We haven't used that one in ages, so let's just remove the whole hack - but always show in the console output when there was an SSL error. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-04-10profile: remove enableToolbar() signalGravatar Berthold Stoeger
When showing the "empty-state", the profile toolbar was disabled. This was done via a "reverse" signal from the profile to the MainWindow. Instead control the toolbar in the MainWindow directly. Break out the plot-dive functionality into a member function and there test whether a dive is shown or not. The signal makes no sense in the context of mobile or printing. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-10profile: remove force parameter from ProfileWidget2::plotDive()Gravatar Berthold Stoeger
The last user was removed in 2789bb05b133a7cf54081d58d4f5c51c8977e951. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-10profile: remove [disable|enable]Shortcuts() signalsGravatar Berthold Stoeger
When switching to the "plan" or "add" (which should rather be called "edit", by the way) mode of the profile, the "shortcuts" for copy&paste, undo&redo, etc. are disabled. When switching to "profile" mode, they are reenabled. This was done in a most convoluted way: - The MainWindow calls the set*State() function of the profile. - The Profile emits [disable|enable]Shortcuts() signals. - The MainWindow catches these signals and does the enabling or disabling. Not only is this very hard to reason about, it is also in contradiction to the profile being part of the display layer. Moreover, in editCurrentDive() the MainWindow disabled the shortcuts itself, so this was all redundant. For the sake of sanity, let's just move this logic to the MainWindow, unslotify the [disable|enable]Shortcuts() functions and make them private. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02planner: split DivePlannerPointsModel::remove() in twoGravatar Berthold Stoeger
There are two cases in this function: with and without holding the control-key. The former deletes one point, the latter all points starting with the selected point to the end. The code was interlaced making it very hard to reason about. Notably, it was buggy: with control, all points could be deleted, leading to a crash. Split the function in two versions, with their own bound checking. This produces a bit of duplicate code, which might be broken out later. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02planner: avoid starting unneeded variation threadGravatar Berthold Stoeger
When updating the dive profile, a thread is started to calculate plan-variations. This is done even when only editing the profile or when variation calculation is disabled by the user. The thread then exits if it shouldn't calculate the variations. Turn this around: test whether variations should be calculated before starting the thread. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02planner: remove DivePlannerPointsModel::recalc flagGravatar Berthold Stoeger
There was no user of that flag left. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02planner: call removeDeco() explicitlyGravatar Berthold Stoeger
removeDeco() was called by addStop() if the recalc flag was set. If the caller didn't want to call removeDeco() it had to clear and restore the flag. Instead, call removeDeco() explicitly when needed. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02planner: don't clear recalc in DivePlannerPointsModel::clear()Gravatar Berthold Stoeger
There are no more external users of this flag, therefore clearing that flag is a no-op. Moreover, clear the cylinders array and the preserved_until flag befor emitting the model-reset signal. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02planner: split DivePlannerPointsModel::removePoints() in twoGravatar Berthold Stoeger
Split the function in one external version, that updates the dive profile and cylinders and one internal version, that does no recalculations. In the latter case, the caller is responsible for updating the dive. Thus, the recalculation flag-clearing can be removed from removeDeco(). Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02planner: don't export recalc flag of DivePlannerPointsModelGravatar Berthold Stoeger
This is not queried anymore, so remove the accessor function. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02profile/planner: don't update dive in ProfileWidget2::plotDive()Gravatar Berthold Stoeger
In planner or profile-edit mode, the plotDive() function takes the current plan and turns it into a dive profile. Not only is this a layering violation (the display layer modifying the dive), it is also fundamentally flawed. The control-flow is out of control, if you wish. There are numerous reasons why the profile needs to be replot, many of which do not need a recalculated dive profile. Move the code that updates the dive-profile to the DivePlannerPointsModel. Thus, the profile recalculations and replots can be pooled. This will break the planner, since there now might be missing calls to the profile recalculation. But it already has some positive effects: when removing multiple points, the profile is only recalculated once. This will need much more work, but it is a start. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02planner: split addStop() into external and internal versionsGravatar Berthold Stoeger
The DivePlannerPointsModel::addStop() function is called by the profile to add a planner-stop. It is also used internally to create profiles. If we ever want to include this in the undo system, we have to split these into to versions. One will ultimately place an undo command and update the profile, the other one doesn't. For now, this makes the external interface simpler, as some parameters are redundant. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02profile: populate dive handlers when switching to edit/plan modeGravatar Berthold Stoeger
The dive handlers are only updated by signals. This means that switching into edit-mode has to be done in steps: 1) initialize the DivePointsPlannerModel 2) switch profile mode 3) load dive into DivePointsPlannerModel 2) and 3) cannot be exchanged, or the dive handlers are not initialized. To avoid this sandwitching of profile- and model-initialization, populate the dive handlers when switching the profile mode. Thus, the profile can be switched into edit/plan mode when the DivePointsPlannerModel is fully initialized. This will be important in upcoming commits, when the initialization of the dive is moved from the profile to the DivePointsPlannerModel. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02cleanup: make DivePlannerPointsModel::removeDeco() privateGravatar Berthold Stoeger
No outside users. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02cleanup: remove unused function DivePlannerPointsModel::size()Gravatar Berthold Stoeger
This is not a virtual function and does not seem to be called anywhere..? Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02cleanup: remove unused member DivePlannerPointsModel::addingDecoGravatar Berthold Stoeger
This was never used. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02planner: split createTemporaryPlan() function.Gravatar Berthold Stoeger
The DivePlannerPointsModel::createTemporaryPlan() function had two distinct and independent parts: 1) create the data points. 2) create the dive sample and calculate variations. The second part was only exectuted if the recalc flag was set. Out of the two callers, one was explicitly disabling and setting the recalc flag to avoid the second part. The much more logical thing is to simply split the function in two and only call the first part. To avoid any functional change, the second caller (the profile) still tests for the recalc flag. However, if it shouldn't replot a new plan, why calculate it in the first place!? And why does the display function change the plan at all? This appears all very ill-thought out and should be changed in due course. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02cleanup: unify whitespace in switch statementGravatar Berthold Stoeger
The way the blocks in DivePlannerPointsModel::setData()'s switch statement were demarked messed with my mind. There were at least three variants. Let's try to be consistent. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
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-02profile: remove redundant replot() calls in key eventsGravatar Berthold Stoeger
When moving "dive handlers" with the cursor keys, the profile was replot twice: - First the recalculation of the planner model was suspended. - The "stop" was moved. - This led to a replot by a signal from the planner model. However, the old profile was shown, since the recalculation was suspended. - The recalculation was reenabled. - The profile war replot, resulting now in the correct profile. A classical case of bit rot. Instead, don't suspend calculation in the first place. This shows the correct profile on the first replot and the second replot can be removed. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02profile: make ItemPos initialization constantGravatar Berthold Stoeger
The ItemPos structure describes the position of various chart elements on the scene. It had two problems: - The identifiers were starting with an underscore followed by a capital letter. This is reserved to the compiler. - The global object was initialized in the ProfileWidget's constructor. This means that if there are multiple ProfileWidgets, the structure is reinitialized even though it is constant. Remove the underscores (what was the point anyway?) and initialize the structure in its own constructor. Moreover, make the object const to drive the point home. If this ever needs to be variable, each ProfileWidget should get its own copy of the object. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02desktop: query DivePlannerPointsModel for planner stateGravatar Berthold Stoeger
MainTab::updateDiveInfo() is not executed when in the planner. To decide whether the application is in the planner state, it queried the profile. Instead, query the DivePlannerPointsModel. Currently, there is no autoritative carrier of that flag. However, the MainTab has a dependency on DivePlannerPointsModel anyway, and therefore this removes a dependency on the profile. This brings us closer to a state where we can have multiple profiles. Ultimately, it is hoped that the whole check can be removed at this place, making the point moot. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02planner: set profile to planner state in main windowGravatar Berthold Stoeger
Remove mainwindow-access from the planner, by setting the profile to planner state in the owner of the profile, viz. the MainWindow. The MainWindow sets the application state to planner, so it seems legit that it also sets the profile state. This removes a further interdependency. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02desktop: remove check for editMode in maintabGravatar Berthold Stoeger
The accept / reject message is only shown in edit-mode, no need to check it. This is a step in simplification / removal of the edit mode. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02profile: display arbitrary diveGravatar Berthold Stoeger
So far the profile operated on the global displayed_dive. Instead, take the dive to be displayed as a parameter to the plotDive() functions. This is necessary if we want to have multiple concurrent profile objects. Think for example for printing or for mobile where multiple dive objects are active at the same time. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02profile: don't check for stepping past maximum time / depthGravatar Berthold Stoeger
When moving a planner point with the cursor, nothing is wrong with extending the dive time by stepping beyond the current maximum. Same for depth. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02profile: fix logic in keyDeleteAction()Gravatar Berthold Stoeger
The code took care to not delete planner-points when no points are selected. However, it assumed that all selected objects are planner-points. But then it checked whether the selected object actually is a planner-point. So which is it? Remove the outter check for an empty selection. This makes things more logical and more robust, should there ever be other objects that can be selected. 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>