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