1 /* nautilus-error-reporting.h - implementation of file manager functions that report
2 * errors to the user.
3 *
4 * Copyright (C) 2000 Eazel, Inc.
5 *
6 * The Gnome Library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * The Gnome Library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with the Gnome Library; see the file COPYING.LIB. If not,
18 * see <http://www.gnu.org/licenses/>.
19 *
20 * Authors: John Sullivan <sullivan@eazel.com>
21 */
22
23 #include <config.h>
24
25 #include "nautilus-error-reporting.h"
26
27 #include <string.h>
28 #include <glib/gi18n.h>
29 #include "nautilus-file.h"
30 #include <eel/eel-string.h>
31 #include <eel/eel-stock-dialogs.h>
32
33 #include "nautilus-ui-utilities.h"
34
35 #define DEBUG_FLAG NAUTILUS_DEBUG_DIRECTORY_VIEW
36 #include "nautilus-debug.h"
37
38 #define NEW_NAME_TAG "Nautilus: new name"
39
40 static void finish_rename (NautilusFile *file,
41 gboolean stop_timer,
42 GError *error);
43
44 static char *
get_truncated_name_for_file(NautilusFile * file)45 get_truncated_name_for_file (NautilusFile *file)
46 {
47 g_autofree char *file_name = NULL;
48
49 g_assert (NAUTILUS_IS_FILE (file));
50
51 file_name = nautilus_file_get_display_name (file);
52
53 return eel_str_middle_truncate (file_name, MAXIMUM_DISPLAYED_FILE_NAME_LENGTH);
54 }
55
56 void
nautilus_report_error_loading_directory(NautilusFile * file,GError * error,GtkWindow * parent_window)57 nautilus_report_error_loading_directory (NautilusFile *file,
58 GError *error,
59 GtkWindow *parent_window)
60 {
61 g_autofree char *truncated_name = NULL;
62 g_autofree char *message = NULL;
63
64 if (error == NULL ||
65 error->message == NULL)
66 {
67 return;
68 }
69
70 if (error->domain == G_IO_ERROR &&
71 error->code == G_IO_ERROR_NOT_MOUNTED)
72 {
73 /* This case is retried automatically */
74 return;
75 }
76
77 truncated_name = get_truncated_name_for_file (file);
78
79 if (error->domain == G_IO_ERROR)
80 {
81 switch (error->code)
82 {
83 case G_IO_ERROR_PERMISSION_DENIED:
84 {
85 message = g_strdup_printf (_("You do not have the permissions necessary to view the contents of “%s”."),
86 truncated_name);
87 }
88 break;
89
90 case G_IO_ERROR_NOT_FOUND:
91 {
92 message = g_strdup_printf (_("“%s” could not be found. Perhaps it has recently been deleted."),
93 truncated_name);
94 }
95 break;
96
97 default:
98 {
99 g_autofree char *truncated_error_message = NULL;
100
101 truncated_error_message = eel_str_middle_truncate (error->message,
102 MAXIMUM_DISPLAYED_ERROR_MESSAGE_LENGTH);
103
104 message = g_strdup_printf (_("Sorry, could not display all the contents of “%s”: %s"), truncated_name,
105 truncated_error_message);
106 }
107 break;
108 }
109 }
110 else
111 {
112 message = g_strdup (error->message);
113 }
114
115 show_dialog (_("This location could not be displayed."),
116 message,
117 parent_window,
118 GTK_MESSAGE_ERROR);
119 }
120
121 void
nautilus_report_error_setting_group(NautilusFile * file,GError * error,GtkWindow * parent_window)122 nautilus_report_error_setting_group (NautilusFile *file,
123 GError *error,
124 GtkWindow *parent_window)
125 {
126 g_autofree char *truncated_name = NULL;
127 g_autofree char *message = NULL;
128
129 if (error == NULL)
130 {
131 return;
132 }
133
134 truncated_name = get_truncated_name_for_file (file);
135
136 if (error->domain == G_IO_ERROR)
137 {
138 switch (error->code)
139 {
140 case G_IO_ERROR_PERMISSION_DENIED:
141 {
142 message = g_strdup_printf (_("You do not have the permissions necessary to change the group of “%s”."),
143 truncated_name);
144 }
145 break;
146
147 default:
148 {
149 }
150 break;
151 }
152 }
153
154 if (message == NULL)
155 {
156 g_autofree char *truncated_error_message = NULL;
157
158 truncated_error_message = eel_str_middle_truncate (error->message,
159 MAXIMUM_DISPLAYED_ERROR_MESSAGE_LENGTH);
160
161 /* We should invent decent error messages for every case we actually experience. */
162 g_warning ("Hit unhandled case %s:%d in nautilus_report_error_setting_group",
163 g_quark_to_string (error->domain), error->code);
164 /* fall through */
165 message = g_strdup_printf (_("Sorry, could not change the group of “%s”: %s"), truncated_name,
166 truncated_error_message);
167 }
168
169
170 show_dialog (_("The group could not be changed."), message, parent_window, GTK_MESSAGE_ERROR);
171 }
172
173 void
nautilus_report_error_setting_owner(NautilusFile * file,GError * error,GtkWindow * parent_window)174 nautilus_report_error_setting_owner (NautilusFile *file,
175 GError *error,
176 GtkWindow *parent_window)
177 {
178 g_autofree char *truncated_name = NULL;
179 g_autofree char *truncated_error_message = NULL;
180 g_autofree char *message = NULL;
181
182 if (error == NULL)
183 {
184 return;
185 }
186
187 truncated_name = get_truncated_name_for_file (file);
188
189 truncated_error_message = eel_str_middle_truncate (error->message,
190 MAXIMUM_DISPLAYED_ERROR_MESSAGE_LENGTH);
191 message = g_strdup_printf (_("Sorry, could not change the owner of “%s”: %s"),
192 truncated_name, truncated_error_message);
193
194 show_dialog (_("The owner could not be changed."), message, parent_window, GTK_MESSAGE_ERROR);
195 }
196
197 void
nautilus_report_error_setting_permissions(NautilusFile * file,GError * error,GtkWindow * parent_window)198 nautilus_report_error_setting_permissions (NautilusFile *file,
199 GError *error,
200 GtkWindow *parent_window)
201 {
202 g_autofree char *truncated_name = NULL;
203 g_autofree char *truncated_error_message = NULL;
204 g_autofree char *message = NULL;
205
206 if (error == NULL)
207 {
208 return;
209 }
210
211 truncated_name = get_truncated_name_for_file (file);
212
213 truncated_error_message = eel_str_middle_truncate (error->message,
214 MAXIMUM_DISPLAYED_ERROR_MESSAGE_LENGTH);
215 message = g_strdup_printf (_("Sorry, could not change the permissions of “%s”: %s"),
216 truncated_name, truncated_error_message);
217
218 show_dialog (_("The permissions could not be changed."),
219 message,
220 parent_window,
221 GTK_MESSAGE_ERROR);
222 }
223
224 typedef struct _NautilusRenameData
225 {
226 char *name;
227 NautilusFileOperationCallback callback;
228 gpointer callback_data;
229 } NautilusRenameData;
230
231 void
nautilus_report_error_renaming_file(NautilusFile * file,const char * new_name,GError * error,GtkWindow * parent_window)232 nautilus_report_error_renaming_file (NautilusFile *file,
233 const char *new_name,
234 GError *error,
235 GtkWindow *parent_window)
236 {
237 g_autofree char *truncated_old_name = NULL;
238 g_autofree char *truncated_new_name = NULL;
239 g_autofree char *message = NULL;
240
241 /* Truncate names for display since very long file names with no spaces
242 * in them won't get wrapped, and can create insanely wide dialog boxes.
243 */
244 truncated_old_name = get_truncated_name_for_file (file);
245 truncated_new_name = eel_str_middle_truncate (new_name, MAXIMUM_DISPLAYED_FILE_NAME_LENGTH);
246
247 if (error->domain == G_IO_ERROR)
248 {
249 switch (error->code)
250 {
251 case G_IO_ERROR_EXISTS:
252 {
253 message = g_strdup_printf (_("The name “%s” is already used in this location. "
254 "Please use a different name."),
255 truncated_new_name);
256 }
257 break;
258
259 case G_IO_ERROR_NOT_FOUND:
260 {
261 message = g_strdup_printf (_("There is no “%s” in this location. "
262 "Perhaps it was just moved or deleted?"),
263 truncated_old_name);
264 }
265 break;
266
267 case G_IO_ERROR_PERMISSION_DENIED:
268 {
269 message = g_strdup_printf (_("You do not have the permissions necessary to rename “%s”."),
270 truncated_old_name);
271 }
272 break;
273
274 case G_IO_ERROR_INVALID_FILENAME:
275 {
276 if (strchr (new_name, '/') != NULL)
277 {
278 message = g_strdup_printf (_("The name “%s” is not valid because it contains the character “/”. "
279 "Please use a different name."),
280 truncated_new_name);
281 }
282 else
283 {
284 message = g_strdup_printf (_("The name “%s” is not valid. "
285 "Please use a different name."),
286 truncated_new_name);
287 }
288 }
289 break;
290
291 case G_IO_ERROR_FILENAME_TOO_LONG:
292 {
293 message = g_strdup_printf (_("The name “%s” is too long. "
294 "Please use a different name."),
295 truncated_new_name);
296 }
297 break;
298
299 default:
300 {
301 }
302 break;
303 }
304 }
305
306 if (message == NULL)
307 {
308 g_autofree char *truncated_error_message = NULL;
309
310 truncated_error_message = eel_str_middle_truncate (error->message,
311 MAXIMUM_DISPLAYED_ERROR_MESSAGE_LENGTH);
312
313 /* We should invent decent error messages for every case we actually experience. */
314 g_warning ("Hit unhandled case %s:%d in nautilus_report_error_renaming_file",
315 g_quark_to_string (error->domain), error->code);
316 /* fall through */
317 message = g_strdup_printf (_("Sorry, could not rename “%s” to “%s”: %s"),
318 truncated_old_name, truncated_new_name,
319 truncated_error_message);
320 }
321
322 show_dialog (_("The item could not be renamed."), message, parent_window, GTK_MESSAGE_ERROR);
323 }
324
325 static void
nautilus_rename_data_free(NautilusRenameData * data)326 nautilus_rename_data_free (NautilusRenameData *data)
327 {
328 g_free (data->name);
329 g_free (data);
330 }
331
332 static void
rename_callback(NautilusFile * file,GFile * result_location,GError * error,gpointer callback_data)333 rename_callback (NautilusFile *file,
334 GFile *result_location,
335 GError *error,
336 gpointer callback_data)
337 {
338 NautilusRenameData *data;
339 gboolean cancelled = FALSE;
340
341 g_assert (NAUTILUS_IS_FILE (file));
342 g_assert (callback_data == NULL);
343
344 data = g_object_get_data (G_OBJECT (file), NEW_NAME_TAG);
345 g_assert (data != NULL);
346
347 if (error)
348 {
349 if (!(error->domain == G_IO_ERROR && error->code == G_IO_ERROR_CANCELLED))
350 {
351 /* If rename failed, notify the user. */
352 nautilus_report_error_renaming_file (file, data->name, error, NULL);
353 }
354 else
355 {
356 cancelled = TRUE;
357 }
358 }
359
360 finish_rename (file, !cancelled, error);
361 }
362
363 static void
cancel_rename_callback(gpointer callback_data)364 cancel_rename_callback (gpointer callback_data)
365 {
366 nautilus_file_cancel (NAUTILUS_FILE (callback_data), rename_callback, NULL);
367 }
368
369 static void
finish_rename(NautilusFile * file,gboolean stop_timer,GError * error)370 finish_rename (NautilusFile *file,
371 gboolean stop_timer,
372 GError *error)
373 {
374 NautilusRenameData *data;
375
376 data = g_object_get_data (G_OBJECT (file), NEW_NAME_TAG);
377 if (data == NULL)
378 {
379 return;
380 }
381
382 /* Cancel both the rename and the timed wait. */
383 nautilus_file_cancel (file, rename_callback, NULL);
384 if (stop_timer)
385 {
386 eel_timed_wait_stop (cancel_rename_callback, file);
387 }
388
389 if (data->callback != NULL)
390 {
391 data->callback (file, NULL, error, data->callback_data);
392 }
393
394 /* Let go of file name. */
395 g_object_set_data (G_OBJECT (file), NEW_NAME_TAG, NULL);
396 }
397
398 void
nautilus_rename_file(NautilusFile * file,const char * new_name,NautilusFileOperationCallback callback,gpointer callback_data)399 nautilus_rename_file (NautilusFile *file,
400 const char *new_name,
401 NautilusFileOperationCallback callback,
402 gpointer callback_data)
403 {
404 g_autoptr (GError) error = NULL;
405 NautilusRenameData *data;
406 g_autofree char *truncated_old_name = NULL;
407 g_autofree char *truncated_new_name = NULL;
408 g_autofree char *wait_message = NULL;
409 g_autofree char *uri = NULL;
410
411 g_return_if_fail (NAUTILUS_IS_FILE (file));
412 g_return_if_fail (new_name != NULL);
413
414 /* Stop any earlier rename that's already in progress. */
415 error = g_error_new (G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
416 finish_rename (file, TRUE, error);
417
418 data = g_new0 (NautilusRenameData, 1);
419 data->name = g_strdup (new_name);
420 data->callback = callback;
421 data->callback_data = callback_data;
422
423 /* Attach the new name to the file. */
424 g_object_set_data_full (G_OBJECT (file),
425 NEW_NAME_TAG,
426 data, (GDestroyNotify) nautilus_rename_data_free);
427
428 /* Start the timed wait to cancel the rename. */
429 truncated_old_name = get_truncated_name_for_file (file);
430 truncated_new_name = eel_str_middle_truncate (new_name, MAXIMUM_DISPLAYED_FILE_NAME_LENGTH);
431 wait_message = g_strdup_printf (_("Renaming “%s” to “%s”."),
432 truncated_old_name,
433 truncated_new_name);
434 eel_timed_wait_start (cancel_rename_callback, file, wait_message,
435 NULL); /* FIXME bugzilla.gnome.org 42395: Parent this? */
436
437 uri = nautilus_file_get_uri (file);
438 DEBUG ("Renaming file %s to %s", uri, new_name);
439
440 /* Start the rename. */
441 nautilus_file_rename (file, new_name,
442 rename_callback, NULL);
443 }
444