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