1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include <gegl.h>
21 #include <gtk/gtk.h>
22
23 #include "libgimpbase/gimpbase.h"
24 #include "libgimpwidgets/gimpwidgets.h"
25
26 #include "actions-types.h"
27
28 #include "config/gimpguiconfig.h"
29
30 #include "core/gimp.h"
31 #include "core/gimpcontainer.h"
32 #include "core/gimpimage.h"
33 #include "core/gimpimagefile.h"
34 #include "core/gimpviewable.h"
35
36 #include "file/gimp-file.h"
37
38 #include "plug-in/gimppluginmanager-file.h"
39
40 #include "widgets/gimpaction.h"
41 #include "widgets/gimpactiongroup.h"
42 #include "widgets/gimpactionimpl.h"
43 #include "widgets/gimphelp-ids.h"
44
45 #include "display/gimpdisplay.h"
46
47 #include "actions.h"
48 #include "file-actions.h"
49 #include "file-commands.h"
50
51 #include "gimp-intl.h"
52
53
54 /* local function prototypes */
55
56 static void file_actions_last_opened_update (GimpContainer *container,
57 GimpImagefile *unused,
58 GimpActionGroup *group);
59 static void file_actions_last_opened_reorder (GimpContainer *container,
60 GimpImagefile *unused1,
61 gint unused2,
62 GimpActionGroup *group);
63 static void file_actions_close_all_update (GimpContainer *images,
64 GimpObject *unused,
65 GimpActionGroup *group);
66 static gchar * file_actions_create_label (const gchar *format,
67 GFile *file);
68
69
70 static const GimpActionEntry file_actions[] =
71 {
72 { "file-menu", NULL, NC_("file-action", "_File") },
73 { "file-create-menu", NULL, NC_("file-action", "Crea_te") },
74 { "file-open-recent-menu", NULL, NC_("file-action", "Open _Recent") },
75
76 { "file-open", GIMP_ICON_IMAGE_OPEN,
77 NC_("file-action", "_Open..."), "<primary>O",
78 NC_("file-action", "Open an image file"),
79 file_open_cmd_callback,
80 GIMP_HELP_FILE_OPEN },
81
82 { "file-open-as-layers", GIMP_ICON_LAYER,
83 NC_("file-action", "Op_en as Layers..."), "<primary><alt>O",
84 NC_("file-action", "Open an image file as layers"),
85 file_open_as_layers_cmd_callback,
86 GIMP_HELP_FILE_OPEN_AS_LAYER },
87
88 { "file-open-location", GIMP_ICON_WEB,
89 NC_("file-action", "Open _Location..."), NULL,
90 NC_("file-action", "Open an image file from a specified location"),
91 file_open_location_cmd_callback,
92 GIMP_HELP_FILE_OPEN_LOCATION },
93
94 { "file-create-template", NULL,
95 NC_("file-action", "Create _Template..."), NULL,
96 NC_("file-action", "Create a new template from this image"),
97 file_create_template_cmd_callback,
98 GIMP_HELP_FILE_CREATE_TEMPLATE },
99
100 { "file-revert", GIMP_ICON_IMAGE_RELOAD,
101 NC_("file-action", "Re_vert"), NULL,
102 NC_("file-action", "Reload the image file from disk"),
103 file_revert_cmd_callback,
104 GIMP_HELP_FILE_REVERT },
105
106 { "file-close-all", GIMP_ICON_CLOSE_ALL,
107 NC_("file-action", "C_lose All"), "<primary><shift>W",
108 NC_("file-action", "Close all opened images"),
109 file_close_all_cmd_callback,
110 GIMP_HELP_FILE_CLOSE_ALL },
111
112 { "file-copy-location", GIMP_ICON_EDIT_COPY,
113 NC_("file-action", "Copy _Image Location"), NULL,
114 NC_("file-action", "Copy image file location to clipboard"),
115 file_copy_location_cmd_callback,
116 GIMP_HELP_FILE_COPY_LOCATION },
117
118 { "file-show-in-file-manager", GIMP_ICON_FILE_MANAGER,
119 NC_("file-action", "Show in _File Manager"), "<primary><alt>F",
120 NC_("file-action", "Show image file location in the file manager"),
121 file_show_in_file_manager_cmd_callback,
122 GIMP_HELP_FILE_SHOW_IN_FILE_MANAGER },
123
124 { "file-quit", GIMP_ICON_APPLICATION_EXIT,
125 NC_("file-action", "_Quit"), "<primary>Q",
126 NC_("file-action", "Quit the GNU Image Manipulation Program"),
127 file_quit_cmd_callback,
128 GIMP_HELP_FILE_QUIT }
129 };
130
131 static const GimpEnumActionEntry file_save_actions[] =
132 {
133 { "file-save", GIMP_ICON_DOCUMENT_SAVE,
134 NC_("file-action", "_Save"), "<primary>S",
135 NC_("file-action", "Save this image"),
136 GIMP_SAVE_MODE_SAVE, FALSE,
137 GIMP_HELP_FILE_SAVE },
138
139 { "file-save-as", GIMP_ICON_DOCUMENT_SAVE_AS,
140 NC_("file-action", "Save _As..."), "<primary><shift>S",
141 NC_("file-action", "Save this image with a different name"),
142 GIMP_SAVE_MODE_SAVE_AS, FALSE,
143 GIMP_HELP_FILE_SAVE_AS },
144
145 { "file-save-a-copy", NULL,
146 NC_("file-action", "Save a Cop_y..."), NULL,
147 NC_("file-action",
148 "Save a copy of this image, without affecting the source file "
149 "(if any) or the current state of the image"),
150 GIMP_SAVE_MODE_SAVE_A_COPY, FALSE,
151 GIMP_HELP_FILE_SAVE_A_COPY },
152
153 { "file-save-and-close", NULL,
154 NC_("file-action", "Save and Close..."), NULL,
155 NC_("file-action", "Save this image and close its window"),
156 GIMP_SAVE_MODE_SAVE_AND_CLOSE, FALSE,
157 GIMP_HELP_FILE_SAVE },
158
159 { "file-export", NULL,
160 NC_("file-action", "E_xport..."), "<primary>E",
161 NC_("file-action", "Export the image"),
162 GIMP_SAVE_MODE_EXPORT, FALSE,
163 GIMP_HELP_FILE_EXPORT },
164
165 { "file-overwrite", NULL,
166 NC_("file-action", "Over_write"), "",
167 NC_("file-action", "Export the image back to the imported file in the import format"),
168 GIMP_SAVE_MODE_OVERWRITE, FALSE,
169 GIMP_HELP_FILE_OVERWRITE },
170
171 { "file-export-as", NULL,
172 NC_("file-action", "E_xport As..."), "<primary><shift>E",
173 NC_("file-action", "Export the image to various file formats such as PNG or JPEG"),
174 GIMP_SAVE_MODE_EXPORT_AS, FALSE,
175 GIMP_HELP_FILE_EXPORT_AS }
176 };
177
178 void
file_actions_setup(GimpActionGroup * group)179 file_actions_setup (GimpActionGroup *group)
180 {
181 GimpEnumActionEntry *entries;
182 gint n_entries;
183 gint i;
184
185 gimp_action_group_add_actions (group, "file-action",
186 file_actions,
187 G_N_ELEMENTS (file_actions));
188
189 gimp_action_group_add_enum_actions (group, "file-action",
190 file_save_actions,
191 G_N_ELEMENTS (file_save_actions),
192 file_save_cmd_callback);
193
194 n_entries = GIMP_GUI_CONFIG (group->gimp->config)->last_opened_size;
195
196 entries = g_new0 (GimpEnumActionEntry, n_entries);
197
198 for (i = 0; i < n_entries; i++)
199 {
200 entries[i].name = g_strdup_printf ("file-open-recent-%02d",
201 i + 1);
202 entries[i].icon_name = GIMP_ICON_DOCUMENT_OPEN,
203 entries[i].label = entries[i].name;
204 entries[i].tooltip = NULL;
205 entries[i].value = i;
206 entries[i].value_variable = FALSE;
207
208 if (i < 9)
209 entries[i].accelerator = g_strdup_printf ("<primary>%d", i + 1);
210 else if (i == 9)
211 entries[i].accelerator = g_strdup ("<primary>0");
212 else
213 entries[i].accelerator = NULL;
214 }
215
216 gimp_action_group_add_enum_actions (group, NULL, entries, n_entries,
217 file_open_recent_cmd_callback);
218
219 for (i = 0; i < n_entries; i++)
220 {
221 gimp_action_group_set_action_visible (group, entries[i].name, FALSE);
222 gimp_action_group_set_action_always_show_image (group, entries[i].name,
223 TRUE);
224 gimp_action_group_set_action_context (group, entries[i].name,
225 gimp_get_user_context (group->gimp));
226
227 g_free ((gchar *) entries[i].name);
228 if (entries[i].accelerator)
229 g_free ((gchar *) entries[i].accelerator);
230 }
231
232 g_free (entries);
233
234 g_signal_connect_object (group->gimp->documents, "add",
235 G_CALLBACK (file_actions_last_opened_update),
236 group, 0);
237 g_signal_connect_object (group->gimp->documents, "remove",
238 G_CALLBACK (file_actions_last_opened_update),
239 group, 0);
240 g_signal_connect_object (group->gimp->documents, "reorder",
241 G_CALLBACK (file_actions_last_opened_reorder),
242 group, 0);
243
244 file_actions_last_opened_update (group->gimp->documents, NULL, group);
245
246 /* also listen to image adding/removal so we catch the case where
247 * the last image is closed but its display stays open.
248 */
249 g_signal_connect_object (group->gimp->images, "add",
250 G_CALLBACK (file_actions_close_all_update),
251 group, 0);
252 g_signal_connect_object (group->gimp->images, "remove",
253 G_CALLBACK (file_actions_close_all_update),
254 group, 0);
255
256 file_actions_close_all_update (group->gimp->displays, NULL, group);
257 }
258
259 void
file_actions_update(GimpActionGroup * group,gpointer data)260 file_actions_update (GimpActionGroup *group,
261 gpointer data)
262 {
263 Gimp *gimp = action_data_get_gimp (data);
264 GimpImage *image = action_data_get_image (data);
265 GimpDrawable *drawable = NULL;
266 GFile *file = NULL;
267 GFile *source = NULL;
268 GFile *export = NULL;
269 gboolean show_overwrite = FALSE;
270
271 if (image)
272 {
273 drawable = gimp_image_get_active_drawable (image);
274
275 file = gimp_image_get_file (image);
276 source = gimp_image_get_imported_file (image);
277 export = gimp_image_get_exported_file (image);
278 }
279
280 show_overwrite =
281 (source &&
282 gimp_plug_in_manager_file_procedure_find (gimp->plug_in_manager,
283 GIMP_FILE_PROCEDURE_GROUP_EXPORT,
284 source, NULL));
285
286 #define SET_VISIBLE(action,condition) \
287 gimp_action_group_set_action_visible (group, action, (condition) != 0)
288 #define SET_SENSITIVE(action,condition) \
289 gimp_action_group_set_action_sensitive (group, action, (condition) != 0)
290
291 SET_SENSITIVE ("file-save", drawable);
292 SET_SENSITIVE ("file-save-as", drawable);
293 SET_SENSITIVE ("file-save-a-copy", drawable);
294 SET_SENSITIVE ("file-save-and-close", drawable);
295 SET_SENSITIVE ("file-revert", file || source);
296 SET_SENSITIVE ("file-export", drawable);
297 SET_VISIBLE ("file-export", ! show_overwrite);
298 SET_SENSITIVE ("file-overwrite", show_overwrite);
299 SET_VISIBLE ("file-overwrite", show_overwrite);
300 SET_SENSITIVE ("file-export-as", drawable);
301 SET_SENSITIVE ("file-create-template", image);
302 SET_SENSITIVE ("file-copy-location", file || source || export);
303 SET_SENSITIVE ("file-show-in-file-manager", file || source || export);
304
305 if (file)
306 {
307 gimp_action_group_set_action_label (group,
308 "file-save",
309 C_("file-action", "_Save"));
310 }
311 else
312 {
313 gimp_action_group_set_action_label (group,
314 "file-save",
315 C_("file-action", "_Save..."));
316 }
317
318 if (export)
319 {
320 gchar *label = file_actions_create_label (_("Export to %s"), export);
321 gimp_action_group_set_action_label (group, "file-export", label);
322 g_free (label);
323 }
324 else if (show_overwrite)
325 {
326 gchar *label = file_actions_create_label (_("Over_write %s"), source);
327 gimp_action_group_set_action_label (group, "file-overwrite", label);
328 g_free (label);
329 }
330 else
331 {
332 gimp_action_group_set_action_label (group,
333 "file-export",
334 C_("file-action", "E_xport..."));
335 }
336
337 /* needed for the empty display */
338 SET_SENSITIVE ("file-close-all", image);
339
340 #undef SET_SENSITIVE
341 }
342
343
344 /* private functions */
345
346 static void
file_actions_last_opened_update(GimpContainer * container,GimpImagefile * unused,GimpActionGroup * group)347 file_actions_last_opened_update (GimpContainer *container,
348 GimpImagefile *unused,
349 GimpActionGroup *group)
350 {
351 gint num_documents;
352 gint i;
353 gint n = GIMP_GUI_CONFIG (group->gimp->config)->last_opened_size;
354
355 num_documents = gimp_container_get_n_children (container);
356
357 for (i = 0; i < n; i++)
358 {
359 GimpAction *action;
360 gchar *name = g_strdup_printf ("file-open-recent-%02d", i + 1);
361
362 action = gimp_action_group_get_action (group, name);
363
364 if (i < num_documents)
365 {
366 GimpImagefile *imagefile = (GimpImagefile *)
367 gimp_container_get_child_by_index (container, i);
368
369 if (GIMP_ACTION_IMPL (action)->viewable != (GimpViewable *) imagefile)
370 {
371 GFile *file;
372 const gchar *name;
373 gchar *basename;
374 gchar *escaped;
375
376 file = gimp_imagefile_get_file (imagefile);
377
378 name = gimp_file_get_utf8_name (file);
379 basename = g_path_get_basename (name);
380
381 escaped = gimp_escape_uline (basename);
382
383 g_free (basename);
384
385 g_object_set (action,
386 "label", escaped,
387 "tooltip", name,
388 "visible", TRUE,
389 "viewable", imagefile,
390 NULL);
391
392 g_free (escaped);
393 }
394 }
395 else
396 {
397 g_object_set (action,
398 "label", name,
399 "tooltip", NULL,
400 "visible", FALSE,
401 "viewable", NULL,
402 NULL);
403 }
404
405 g_free (name);
406 }
407 }
408
409 static void
file_actions_last_opened_reorder(GimpContainer * container,GimpImagefile * unused1,gint unused2,GimpActionGroup * group)410 file_actions_last_opened_reorder (GimpContainer *container,
411 GimpImagefile *unused1,
412 gint unused2,
413 GimpActionGroup *group)
414 {
415 file_actions_last_opened_update (container, unused1, group);
416 }
417
418 static void
file_actions_close_all_update(GimpContainer * images,GimpObject * unused,GimpActionGroup * group)419 file_actions_close_all_update (GimpContainer *images,
420 GimpObject *unused,
421 GimpActionGroup *group)
422 {
423 GimpContainer *container = group->gimp->displays;
424 gint n_displays = gimp_container_get_n_children (container);
425 gboolean sensitive = (n_displays > 0);
426
427 if (n_displays == 1)
428 {
429 GimpDisplay *display;
430
431 display = GIMP_DISPLAY (gimp_container_get_first_child (container));
432
433 if (! gimp_display_get_image (display))
434 sensitive = FALSE;
435 }
436
437 gimp_action_group_set_action_sensitive (group, "file-close-all", sensitive);
438 }
439
440 static gchar *
file_actions_create_label(const gchar * format,GFile * file)441 file_actions_create_label (const gchar *format,
442 GFile *file)
443 {
444 gchar *basename = g_path_get_basename (gimp_file_get_utf8_name (file));
445 gchar *escaped_basename = gimp_escape_uline (basename);
446 gchar *label = g_strdup_printf (format, escaped_basename);
447
448 g_free (escaped_basename);
449 g_free (basename);
450
451 return label;
452 }
453