Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
database_gui.c
Go to the documentation of this file.
1/*
2 * This file is part of darktable,
3 * Copyright (C) 2016 johannes hanika.
4 * Copyright (C) 2016, 2020 Tobias Ellinghaus.
5 * Copyright (C) 2020 Pascal Obry.
6 * Copyright (C) 2021 Sakari Kapanen.
7 * Copyright (C) 2022 Martin Baƙinka.
8 *
9 * darktable is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * darktable is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with darktable. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23
25
26#include "database/database.h"
27#include "system/macros.h"
28#include "system/mem_alloc.h"
29#include "widgets/dialog.h"
30
31#include <glib/gi18n.h>
32#include <glib/gstdio.h>
33#include <stdio.h>
34
36{
39
40 gboolean error = TRUE;
41
42 if(!err.lock_acquired)
43 {
44 char lck_pathname[1024];
45 snprintf(lck_pathname, sizeof(lck_pathname), "%s.lock", err.dbfilename);
47 char *slash_pos = g_strrstr(lck_dirname, "/");
48 if(!IS_NULL_PTR(slash_pos)) *slash_pos = '\0';
49 // clang-format off
51 _("\n"
52 " Sorry, Ansel could not be started because the database is locked.\n"
53 "\n"
54 " How to solve this problem?\n"
55 "\n"
56 " 1 - If another Ansel instance is already running, \n"
57 " click \"Quit\" and either use that instance or close it before trying to start Ansel again. \n"
58 " (process ID <i><b>%d</b></i> created the database lock files)\n"
59 "\n"
60 " 2 - If you cannot find any running instance of Ansel, try restarting your session or your computer. \n"
61 " This will close all running programs and should release any database locks. \n"
62 "\n"
63 " 3 - If you have already tried the above steps, or you are certain that no other instances of Ansel are running, \n"
64 " this likely means the previous instance ended unexpectedly. \n"
65 " Click the \"Delete database lock files\" button to remove <i>data.db.lock</i> and <i>library.db.lock</i>. \n"
66 " Ansel will then attempt to load the database again. \n"
67 "\n\n"
68 " <i><u>Caution!</u> Do not delete these files without first undertaking the above checks, \n"
69 " otherwise you risk generating serious inconsistencies in your database.</i>\n"),
70 err.other_pid);
71 // clang-format on
72
73 const int choice = dt_gui_show_standalone_three_choice_dialog(_("Error starting Ansel"), label_text,
74 _("Quit"), _("Retry"), _("Delete database lock files and try again"));
75
76 if(choice == 1)
77 {
78 // Just try to acquire the lock again: useful once the other instance that held it has
79 // since closed. dt_database_show_error() returning FALSE makes the caller's init loop
80 // (darktable.c) re-run dt_database_init() without touching any lock file.
81 error = FALSE;
82 }
83 else if(choice == 2)
84 {
87 (_("Confirmation"),
88 _("\n<u>Caution!</u> Are you sure you want to delete the database lock files?\n"
89 "This action should only be performed if you are certain no other Ansel instances are running.\n"), _("Quit"), _("Yes"));
91 {
92 // deleting files is the backend's job; this module only obtained consent
93 const int status = dt_database_delete_lock_files(err.dbfilename);
94
95 if(status==0)
96 {
98 _("\nThe database lock files have been deleted successfully.\n"),
99 _("Continue"), NULL);
100 error = FALSE;
101 }
102
103 else
104 {
105 // The dialog copies the markup rather than taking ownership, so this is ours to free.
107 _("\nAt least one lock file could not be removed.\n"
108 "You may try to manually delete the files <i>data.db.lock</i> and <i>library.db.lock</i>\n"
109 "in folder <a href=\"file:///%s\">%s</a>.\n"), lck_dirname, lck_dirname);
112 }
113 }
114 }
115
118 }
119
121 return error;
122}
123
124/* The schema is out of date. The module states that; how long it might take and what the
125 * buttons say is ours. */
127{
128 char *label_text = g_markup_printf_escaped(_("the database schema has to be upgraded for\n"
129 "\n"
130 "<span style='italic'>%s</span>\n"
131 "\nthis might take a long time in case of a large database\n\n"
132 "do you want to proceed or quit now to do a backup\n"),
133 context->dbfilename);
134
135 const gboolean proceed =
136 dt_gui_show_standalone_yes_no_dialog(_("ansel - schema migration"), label_text,
137 _("close Ansel"), _("upgrade database"));
138
141}
142
143/* A VACUUM would reclaim some space. The module hands over the byte count and when the
144 * user would next be asked; the three "click later to..." sentences are ours to pick
145 * between, because the module has no business composing translated prose. */
147{
148 const char *later_info = "";
149 if(context->ask_on_startup)
150 later_info = _("click later to be asked on next startup");
151 else if(context->ask_on_close && !context->at_close)
152 later_info = _("click later to be asked when closing Ansel");
153 else if(context->ask_on_close)
154 later_info = _("click later to be asked next time when closing Ansel");
155
156 char *size_info = g_format_size(context->reclaimable_bytes);
157 char *label_text = g_markup_printf_escaped(_("the database could use some maintenance\n"
158 "\n"
159 "there's <span style='italic'>%s</span> to be freed"
160 "\n\n"
161 "do you want to proceed now?\n\n"
162 "%s\n"
163 "you can always change maintenance preferences in core options"),
165
166 const gboolean proceed =
167 dt_gui_show_standalone_yes_no_dialog(_("ansel - schema maintenance"), label_text,
168 _("later"), _("yes"));
169
173}
174
175/* The prompts the database puts, now that it only states them.
176 *
177 * They were built inline in common/database.c with no has_gui guard at all, so a headless
178 * run reached gtk_dialog_new_with_buttons() on a GTK that ansel-cli never initialises.
179 * Registration is what gates them now, and darktable.c only registers when there is a GUI.
180 */
182{
183 const char *const dbfilename = context->dbfilename;
184 const char *const quick_check = context->quick_check;
185 const gboolean snapshot_available = context->snapshot_available;
186
187 if(context->prompt == DT_DATABASE_PROMPT_UPGRADE) return _prompt_upgrade(context);
188 if(context->prompt == DT_DATABASE_PROMPT_MAINTENANCE) return _prompt_maintenance(context);
189
191 GtkWidget *dialog = NULL;
192 char *label_text = NULL;
193
194 if(context->prompt == DT_DATABASE_PROMPT_READONLY)
195 {
196 dialog = gtk_dialog_new_with_buttons(_("Ansel - Database is read-only"), NULL, dflags,
197 _("Close Ansel"), GTK_RESPONSE_CLOSE, NULL);
199 label_text = g_markup_printf_escaped(_("<span weight='bold'>Ansel library database is read-only</span>\n\n"
200 "This happens if you don't have permissions to write on the filesystem\n"
201 "or if you have restored a write-protected backup snapshot.\n\n"
202 "Please change the filesystem access permissions for:\n\n"
203 "\t<span style='italic'>%s</span>"),
204 dbfilename);
205 }
206 else
207 {
208 const char *label_options;
209 if(snapshot_available)
210 {
211 dialog = gtk_dialog_new_with_buttons(_("ansel - error opening database"), NULL, dflags,
212 _("close Ansel"), GTK_RESPONSE_CLOSE,
213 _("attempt restore"), GTK_RESPONSE_ACCEPT,
214 _("delete database"), GTK_RESPONSE_REJECT, NULL);
216 label_options = _("do you want to close Ansel now to manually restore\n"
217 "the database from a backup, attempt an automatic restore\n"
218 "from the most recent snapshot or delete the corrupted database\n"
219 "and start with a new one?");
220 }
221 else
222 {
223 dialog = gtk_dialog_new_with_buttons(_("ansel - error opening database"), NULL, dflags,
224 _("close Ansel"), GTK_RESPONSE_CLOSE,
225 _("delete database"), GTK_RESPONSE_REJECT, NULL);
227 label_options = _("do you want to close Ansel now to manually restore\n"
228 "the database from a backup or delete the corrupted database\n"
229 "and start with a new one?");
230 }
231
232 // quick_check is sqlite output, i.e. arbitrary text landing in a markup label. Escaping
233 // is the handler's job because only the handler knows it is markup at all.
234 label_text = g_markup_printf_escaped(_("an error has occurred while trying to open the database from\n"
235 "\n"
236 "<span style='italic'>%s</span>\n"
237 "\n"
238 "it seems that the database is corrupted.\n"
239 "%s%s"),
240 dbfilename, IS_NULL_PTR(quick_check) ? "" : quick_check, label_options);
241 }
242
244 GtkWidget *label = gtk_label_new(NULL);
249
250 const int resp = gtk_dialog_run(GTK_DIALOG(dialog));
251 gtk_widget_destroy(dialog);
252
253 switch(resp)
254 {
259 default:
260 // Covers the window being closed outright, which must not be read as consent to
261 // delete anything.
263 }
264}
265
270
271
272// clang-format off
273// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
274// vim: shiftwidth=2 expandtab tabstop=2 cindent
275// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
276// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
void dt_database_take_error(dt_database_error_t *error)
Definition database.c:2705
void dt_database_error_free(dt_database_error_t *error)
Definition database.c:2722
void dt_database_set_prompt_handler(dt_database_prompt_handler_t handler)
Definition database.c:3033
int dt_database_delete_lock_files(const char *dbfilename)
Definition database.c:2731
dt_database_response_t
Definition database.h:209
@ DT_DATABASE_RESPONSE_CLOSE
Definition database.h:212
@ DT_DATABASE_RESPONSE_PROCEED
Definition database.h:218
@ DT_DATABASE_RESPONSE_RESTORE
Definition database.h:214
@ DT_DATABASE_RESPONSE_DELETE
Definition database.h:216
@ DT_DATABASE_PROMPT_UPGRADE
Definition database.h:202
@ DT_DATABASE_PROMPT_MAINTENANCE
Definition database.h:205
@ DT_DATABASE_PROMPT_READONLY
Definition database.h:197
static dt_database_response_t _prompt_upgrade(const dt_database_prompt_context_t *context)
void dt_database_gui_register_handlers(void)
gboolean dt_database_show_error(void)
static dt_database_response_t _database_prompt(const dt_database_prompt_context_t *context)
static dt_database_response_t _prompt_maintenance(const dt_database_prompt_context_t *context)
int dt_gui_show_standalone_three_choice_dialog(const char *title, const char *markup, const char *first_text, const char *second_text, const char *third_text)
Definition dialog.c:176
gboolean dt_gui_show_standalone_yes_no_dialog(const char *title, const char *markup, const char *no_text, const char *yes_text)
Definition dialog.c:79
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition macros.h:65
#define dt_free(ptr)
Definition mem_alloc.h:97
dt_database_prompt_t prompt
Definition database.h:225