Commit graph

368 commits

Author SHA1 Message Date
Dirk Hohndel
2241a28499 build-system: make map support its own thing
Making this simply depend on Qt5 or Qt6 was short-sighted as work on QtLocation
upstream continues. Instead break this out as its own option.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2022-04-18 07:24:38 +02:00
Michael Andreen
be2bdb8650 undo: Clear undo stack on file close
The undo stack is only relevant to the dives that were loaded at the
time the command was executed. If a file is closed, by specifically
closing it or opening another file, then the undo commands will
reference dives that aren't available anymore. Clearing the undo stack
ensures that we don't crash or accidentally do some undefined
modifications to the currently open file.

Signed-off-by: Michael Andreen <michael@andreen.dev>
2022-04-03 08:34:39 -07:00
Berthold Stoeger
ee9344eccf desktop: make MainWindow a "global object"
Thus, we don't have to delete it explicitly on exit.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2022-03-16 13:06:06 -07:00
Berthold Stoeger
fd35fbb349 desktop: prevent exit only in plan but not in edit mode
Currently, when the profile is in edit mode, the user can't
save, exit, plan a new dive and is requested to save the
current dive. However, this makes no sense anymore, since
the profile always switches to edit mode when showing a
manually added dive.

If the user has any unsaved profile changes, the usual
dirty checks of the undo-system apply.

Only show above behavior when in the planner. There it is
useful because, these are not included in the undo system.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2022-03-12 18:33:34 +01:00
Berthold Stoeger
2657ec9016 cleanup: remove MainWindow::refreshProfile()
This only calls MainWindow::showProfile(), so simply call
that directly.

Moreover make two "public slots" private member functions,
since these were only called locally.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2022-03-12 18:32:22 +01:00
Berthold Stoeger
5aa67c134b desktop: remove edit mode of maintab
This was only used for profile-editing, which is now managed
by the profile-widget.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2022-03-12 18:32:22 +01:00
Berthold Stoeger
fce48367cd undo: more fine-grained undo of profile editing
Place undo commands for every change of the profile, not
only on "saving". Move the edit-mode from the mainwindow
and the maintab to the profile widget.

This is still very rough. For example, the only way to exit
the edit mode is changing the current dive.

The undo-commands are placed by the desktop-profile widget.
We might think about moving that down to the profile-view so
that this will be useable on mobile.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2022-03-12 18:32:22 +01:00
Dirk Hohndel
e61509b032 Qt6: deal with changes to window and layout geometry APIs
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2022-03-12 08:28:32 -08:00
Dirk Hohndel
47d900bee5 Qt6: don't build MapWidget
Since Qt6 doesn't include QtLocation anymore, we can't build MapWidget.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2022-03-12 08:28:32 -08:00
Dirk Hohndel
df610752c7 cleanup: don't add QKeySequence values
These should be handled as logical OR operations as they are bits.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2022-03-12 08:28:32 -08:00
Berthold Stoeger
f8fbff9f7d profile: set profile-mode in ProfileWidget, not MainWindow
The mode of the profile (profile, edit, plan) was set in
MainWindow and ProfileWidget. For consistency move the one
setProfileState() call from MainWindow to ProfileWidget.
This removes a direct access to the profile-view and
therefore improves encapsulation.

Also, clear the profile, when no dive is shown to remove
any potentially dangling references.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
12fd102e4f profile: remove empty state from profile
This was moved to the desktop version. Enter the profile in
the constructor. Somewhat surprisingly, this seems to work.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
13d4f595cb profile: remove profile widget code from mainwindow
Create a new class that encapsulates the profile-widget UI.

This is called ProfileWidget, which might be confusing since
the actual display is called ProfileWidget2. However, the
plan is to rename the latter to ProfileView. After all, it
is also used to print and to show the profile on mobile.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Berthold Stoeger
6b615ccb4b desktop: fold configureToolBar() into plotCurrentDive()
The MainWindow::configureToolBar() function is called every
time plotCurrentDive() is called. Moreover, this is the only
time that it is called. We might just fold the former into
the latter.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-12-17 11:54:23 -08:00
Dirk Hohndel
8ac0519a99 desktop: explicitly enable shortcuts
The changes in commit 4daf687876 ("profile: remove [disable|enable]Shortcuts()
signals") resulted in us no longer enabling the shortcuts on the desktop (at
least on macOS where I debugged this). This placement of the call feels like a
bit of overkill, but at least it shouldn't be wrong.

Fixes #3293

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-07-23 10:20:50 -07:00
Robert C. Helling
6b2e56e513 Handle dives with no samples
This occurs upon importing dives for example via CSV.

Make sure the profile display is cleared when selecting
such a dive rather than showing a different dive.

Allow editing the profile for such a dive.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
2021-07-03 14:38:19 -07:00
Berthold Stoeger
4a7cf0e970 profile: rename ADD state to EDIT state
The ADD state is not used for adding dives since adding dives
was made undoable. Therefore, rename it to EDIT state, since
that is what it is used for.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-07-03 14:30:46 -07:00
Berthold Stoeger
267c82d85f cleanup: remove MainWindow::turnOffNdlTts()
This flag is handled directly by the profile code
since 2015 (000c9cc21c).

The function therefore can be removed.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-21 10:04:26 -07:00
Dirk Hohndel
7fa031b648 cloudstorage: try to pick between multiple cloud servers
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-19 12:51:01 -07:00
Dirk Hohndel
c5eb806adb cloudstorage: some cleanup of cloud url handling
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-19 12:51:01 -07:00
Berthold Stoeger
8939b6a99b profile: remove enableToolbar() signal
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-10 14:15:35 -07:00
Berthold Stoeger
8c72ac6b9b profile: remove force parameter from ProfileWidget2::plotDive()
The last user was removed in 2789bb05b1.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-10 14:15:35 -07:00
Berthold Stoeger
4daf687876 profile: remove [disable|enable]Shortcuts() signals
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-10 14:15:35 -07:00
Berthold Stoeger
71e117669d profile: populate dive handlers when switching to edit/plan mode
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-02 13:53:23 -07:00
Berthold Stoeger
b4c307c775 planner: set profile to planner state in main window
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-02 13:53:23 -07:00
Berthold Stoeger
2789bb05b1 profile: display arbitrary dive
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-02 13:53:23 -07:00
Berthold Stoeger
1ec0790d50 planner: remove displayed_dive from DivePlannerModel
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-02 13:53:23 -07:00
Berthold Stoeger
e419ebf55a planner: move clearing of model into loadFromDive() function
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-02 13:53:23 -07:00
Berthold Stoeger
b9673df60b profile: pass DivePlannerPointsModel at construction time
This model is only needed when in plan mode. To enable multiple
profilewidgets at the same time (e.g. for the mobile app or
for printing), make the pointer to DivePlannerPointsModel a
member variable that is initialized at construction time.

Moreover, allow passing null as the DivePlannerPointsModel,
in which case planning will be disabled. This will be useful
for simple printing.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
5b3cb5898f desktop: fold ApplicationState into MainWindow
The application state is a desktop-only thing. The mobile UI
also has its application state, but that is something completely
different.

The last remaining user of the application state was to flag
whether the planner is active. Since this has all been
unglobalized, the ApplicationState structure can be moved
from core to the desktop UI. And there it can be made local
to the MainWindow class.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-02-17 07:26:55 -08:00
Berthold Stoeger
42cff9b3a5 planner: pass in_planner down to TemplateLayout
The TemplateLayout prints different dives depending on
whether the planner is active. Instead of accessing a
global variable, pass the status down from the MainWindow.
That's all quite convoluted, since there are multiple
layers involved.

On the positive side, the in_planner() function has now
no users an can be removed.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-02-17 07:26:55 -08:00
Berthold Stoeger
18049bc8d0 cleanup: remove unused includes in mainwindow.cpp
The printing code moved elsewhere, so these includes are not
needed.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-02-17 07:26:55 -08:00
Berthold Stoeger
f1203d365a desktop: improve splitter defaults
On first startup, use the splitter values suggested by Dirk:
Top/Bottom: 60/40
Info/Profile: 50/50
List/Map: 60/40

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-02-06 10:00:39 -08:00
Berthold Stoeger
aefbde93ce desktop: be smarter about filling splitters
On state change, the splitters were completely emptied and
refilled. Instead try to reuse already existing splitter
slots. This reduces annoying flickering.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-02-06 10:00:39 -08:00
Berthold Stoeger
64dae43bdd desktop: do own memory management of quadrant widgets
The memory management of the quadrant widgets is a total mess:
When setting the widget, the QSplitters take ownership, which
means that they will delete the widget in their destructor.

This is inherently incompatible with singletons, which must
not be deleted.

To avoid all these troubles, remove the widgets from the
QSplitters in the desctructor of the MainWindow. This of
course means that we now have to take care about deletion
of the widgets.

For local widgets use std::unique_ptr, for singletons use
a static variable that is deleted on application exit.

Sadly, for the map widget we can't use a normal singleton,
because the QML MapWidget's memory management is buggy.
Add a comment in the source code explaining this.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-02-06 10:00:39 -08:00
Berthold Stoeger
8a36a100ce desktop: don't allow view change in planner
When in planner mode, don't allow the user to change the application
state. This brought us nothing but troubles and inconsistencies.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-02-06 10:00:39 -08:00
Berthold Stoeger
1ed2f1681a desktop: remove the view-state
There was the "application state", which decided what to show
in the "quadrants" and the "view state" which decided which
quadrant to show. These interacted in a hard-to-grasp way.

The "view state" is used to show the map or dive list in
full screen.

I simply couldn't get these two orthogonal states to interact
properly. Moreover the thing was buggy: If a quadrant was hidden,
the user could still show it, by dragging from the side of the
window, at least under KDE.

To solve these woes, merge the two states into a single
application state. If the widget of a quadrant is set to null,
don't show it. So the four "view states" are now "application
states" where three of the four quadrants are not shown.

This also changes the memory management of the widgets:
widgets that are not shown are now removed from the QSplitter
objects. This makes it possible that the same widget is
shown in *different* quadrants.

While writing this, I stumbled upon a Qt bug, which is known
since 2014:
https://forum.qt.io/topic/43176/qsplitter-sizes-return-0

When restoring the quadrant sizes there was a test whether
the quadrant size is 0. If that was the case, a default size
was set. This seems not to work if the widgets were recently
added. Since this test now always fails, make the quadrants
non-collapsible and thus guarantee that 0 is never saved as
a size.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-02-06 10:00:39 -08:00
Berthold Stoeger
106f7a8e0e desktop: add statistics widget dummy and application state
Add a new "statistics" application state. In the statistics state
show the statistics widget and the filter in the top quadrants.
The idea is to allow filtering and doing statistics at the same
time.

Sadly, we can't use the filter-widget in different quadrants,
because Qt's ownership model is completely broken / inflexible.
It does not support a widget having different parents and
thus a widget can only belong to one QStackedWidget.

Hiding the map in the statistics view is quite hacky:
Since the view of the quadrants is not determined by the
"ApplicationState", we have to restore the original quadrant
visibility when exiting the stats mode. Therefore, set the
original visibility-state when changing application state.

The MainWindow-quadrant code really needs to be rewritten!

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-03 13:41:15 -08:00
Berthold Stoeger
fa6eb6144b printing: move #includes from headers to source files
To decrease include-file interdependencies.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-12-17 13:03:56 -08:00
Berthold Stoeger
2e328c7633 cleanup: remove unused #undefs in mainwindow.cpp
These macros were removed 2016-ish.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-12-12 15:52:40 -08:00
Berthold Stoeger
0ea5374f62 profile: move connect() calls to profile
The mainwindow was connecting preferences changes to the profile.
Do this directly in the profile.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-12-12 15:52:40 -08:00
Berthold Stoeger
41751a5899 cleanup: remove unused signal ProfileWidget2::updateDiveInfo
Last user was remove in 0bd821183d.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-12-12 15:52:40 -08:00
Berthold Stoeger
bb76cb56d4 desktop: move planner-code to diveplanner.cpp
Around 2015 there was a push to move planner UI code from
mainwindow.cpp to diveplanner.cpp. That never was completed,
presumably because the planner is actually three widgets.

Collect these widgets in one PlannerWidgets class and move
the code there.

This is not a full dis-entanglement, as the plannerwidgets
have to access the profile via the mainwindow. But at least
it collects the planner UI code at a single place.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-12-12 15:52:40 -08:00
Berthold Stoeger
369c5b0dc6 desktop: init dive list header actions in constructor
The main window called a function to init the header actions
(i.e. the context menu) of the dive-list. There is no reason why
this shouldn't be done in the constructor of the dive list, since
it only accesses the QSettings, which are available at application
startup. This improves modularity of the code (by a tiny, tiny bit).

Moreover, the initialization function was at the same time the
header-reloading function. That function can now be folded
into the settings-changed function, since that is the only
remaining user.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-12-12 15:52:40 -08:00
Berthold Stoeger
2d7be7a0e3 preferences: create global settingsChanged signal
So far, the PreferencesDialog emitted a settingsChanged signal.
This meant that models that listened to that signal had to
conditionally compile out the code for mobile or the connection
had to be made in MainWindow.

Instead, introduce a global signal that does this and move
the connects to the listeners to remove inter-dependencies.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-12-12 15:52:40 -08:00
Berthold Stoeger
71389cfa92 cleanup: remove empty function MainTab::reload()
This used to reload the completion models. Moreover, remove two
obsolete member-function declarations.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-11-14 10:01:50 -08:00
Berthold Stoeger
c263487e7c cleanup: remove MainWindow::setFileClean()
This function was used to unify both methods of tracking unsaved
changes. Since desktop now only uses the undo system, it can
be replaced by a single call to "Command::setClean()".

Arguably, the UI is the wrong place to do this and the appropriate
calls should be done by the core. However, let's play it safe
for now and avoid any breaking change.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-10-25 13:59:04 -07:00
Berthold Stoeger
fa6235d035 cleanup: remove MainWindow::unsavedChanges() function
This function was used to unify both methods of checking for
unsaved changes: the global unsaved_changes() flag and the
Command::clean() function of the undo-system.

However, all desktop functions are now undoable and therefore
the function is not needed and can be replaced by calls
to !Command::clean().

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-10-25 13:59:04 -07:00
Berthold Stoeger
8a20d019c2 desktop: remove DiveComputerManagementDialog
This is now done in a TabWidget with undo-support.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-10-25 13:59:04 -07:00
Berthold Stoeger
39a4090c0a devices: add devices in Command::importTable()
Add a device_table parameters to Command::importTable() and
add_imported_dives(). The content of this table will be added
to the global device list (respectively removed on undo).

This is currently a no-op, as the parser doesn't yet fill
out the device table, but adds devices directly to the global
device table.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-10-24 09:51:37 -07:00