~ubuntu-branches/ubuntu/vivid/rawstudio/vivid

« back to all changes in this revision

Viewing changes to src/rs-actions.c

  • Committer: Bazaar Package Importer
  • Author(s): Bernd Zeimetz
  • Date: 2011-07-28 17:36:32 UTC
  • mfrom: (2.1.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20110728173632-5czluz9ye3c83zc5
Tags: 2.0-1
* [3750b2cf] Merge commit 'upstream/2.0'
* [63637468] Removing Patch, not necessary anymore.
* [2fb580dc] Add new build-dependencies.
* [c57d953b] Run dh_autoreconf due to patches in configure.in
* [13febe39] Add patch to remove the libssl requirement.
* [5ae773fe] Replace libjpeg62-dev by libjpeg8-dev :)
* [1969d755] Don't build static libraries.
* [7cfe0a2e] Add a patch to fix the plugin directory path.
  As plugins are shared libraries, they need to go into /usr/lib,
  not into /usr/share.
  Thanks to Andrew McMillan
* [c1d0d9dd] Don't install .la files for all plugins and libraries.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2006-2009 Anders Brander <anders@brander.dk> and 
3
 
 * Anders Kvist <akv@lnxbx.dk>
 
2
 * * Copyright (C) 2006-2011 Anders Brander <anders@brander.dk>, 
 
3
 * * Anders Kvist <akv@lnxbx.dk> and Klaus Post <klauspost@gmail.com>
4
4
 *
5
5
 * This program is free software; you can redistribute it and/or
6
6
 * modify it under the terms of the GNU General Public License
22
22
#include <gtk/gtk.h>
23
23
#include <config.h>
24
24
#include "gettext.h"
25
 
#include "color.h"
26
 
#include "rawstudio.h"
 
25
#include "application.h"
27
26
#include "rs-actions.h"
28
27
#include "conf_interface.h"
29
28
#include "rs-store.h"
30
29
#include "rs-photo.h"
31
30
#include "filename.h"
32
31
#include "gtk-interface.h"
33
 
#include "gtk-save-dialog.h"
34
32
#include "gtk-progress.h"
35
33
#include "gtk-helper.h"
36
34
#include "rs-external-editor.h"
37
35
#include "rs-cache.h"
38
36
#include "rs-preview-widget.h"
39
37
#include "rs-batch.h"
40
 
#include "rs-metadata.h"
 
38
#include "rs-save-dialog.h"
 
39
#include "rs-library.h"
 
40
#include "rs-tag-gui.h"
 
41
#include "rs-lens-db-editor.h"
 
42
#include "rs-camera-db.h"
 
43
#include "rs-toolbox.h"
 
44
#include "rs-tethered-shooting.h"
41
45
 
42
46
static GtkActionGroup *core_action_group = NULL;
43
 
GStaticMutex rs_actions_spinlock = G_STATIC_MUTEX_INIT;
 
47
static GStaticMutex rs_actions_spinlock = G_STATIC_MUTEX_INIT;
44
48
 
45
49
#define ACTION(Action) void rs_action_##Action(GtkAction *action, RS_BLOB *rs); \
46
50
        void rs_action_##Action(GtkAction *action, RS_BLOB *rs)
52
56
#define RADIOACTION(Action) void rs_action_##Action(GtkRadioAction *radioaction, GtkRadioAction *current, RS_BLOB *rs); \
53
57
        void rs_action_##Action(GtkRadioAction *radioaction, GtkRadioAction *current, RS_BLOB *rs)
54
58
 
 
59
static gint copy_dialog_get_mask(void);
 
60
static void copy_dialog_set_mask(gint mask);
 
61
 
55
62
ACTION(todo)
56
63
{
57
64
        GString *gs = g_string_new("Action not implemented: ");
61
68
        g_string_free(gs, TRUE);
62
69
}
63
70
 
64
 
ACTION(file_menu)
 
71
void 
 
72
rs_core_actions_update_menu_items(RS_BLOB *rs)
65
73
{
 
74
        /* File Menu */
66
75
        rs_core_action_group_set_sensivity("QuickExport", RS_IS_PHOTO(rs->photo));
67
76
        rs_core_action_group_set_sensivity("ExportAs", RS_IS_PHOTO(rs->photo));
68
77
        rs_core_action_group_set_sensivity("ExportToGimp", RS_IS_PHOTO(rs->photo));
69
 
}
70
78
 
71
 
ACTION(edit_menu)
72
 
{
 
79
        /* Edit Menu */
73
80
        rs_core_action_group_set_sensivity("RevertSettings", RS_IS_PHOTO(rs->photo));
74
81
        rs_core_action_group_set_sensivity("CopySettings", RS_IS_PHOTO(rs->photo));
 
82
        rs_core_action_group_set_sensivity("CopyImage", RS_IS_PHOTO(rs->photo));
75
83
        rs_core_action_group_set_sensivity("PasteSettings", !!(rs->settings_buffer));
76
 
}
 
84
        rs_core_action_group_set_sensivity("SaveDefaultSettings", RS_IS_PHOTO(rs->photo));
77
85
 
78
 
ACTION(photo_menu)
79
 
{
 
86
        /* Photo Menu */
80
87
        GList *selected = NULL, *selected_iters = NULL;
81
88
        gint num_selected, selected_groups;
82
89
        gboolean photos_selected;
96
103
        rs_core_action_group_set_sensivity("Uncrop", (RS_IS_PHOTO(rs->photo) && rs->photo->crop));
97
104
        rs_core_action_group_set_sensivity("Straighten", RS_IS_PHOTO(rs->photo));
98
105
        rs_core_action_group_set_sensivity("Unstraighten", (RS_IS_PHOTO(rs->photo) && (rs->photo->angle != 0.0)));
 
106
        rs_core_action_group_set_sensivity("TagPhoto", RS_IS_PHOTO(rs->photo));
99
107
        rs_core_action_group_set_sensivity("Group", (num_selected > 1));
100
108
        rs_core_action_group_set_sensivity("Ungroup", (selected_groups > 0));
 
109
        rs_core_action_group_set_sensivity("RotateClockwise", RS_IS_PHOTO(rs->photo));
 
110
        rs_core_action_group_set_sensivity("RotateCounterClockwise", RS_IS_PHOTO(rs->photo));
 
111
        rs_core_action_group_set_sensivity("Flip", RS_IS_PHOTO(rs->photo));
 
112
        rs_core_action_group_set_sensivity("Mirror", RS_IS_PHOTO(rs->photo));
101
113
#ifndef EXPERIMENTAL
102
114
        rs_core_action_group_set_visibility("Group", FALSE);
103
115
        rs_core_action_group_set_visibility("Ungroup", FALSE);
104
116
        rs_core_action_group_set_visibility("AutoGroup", FALSE);
105
117
#endif
 
118
 
 
119
        /* View Menu */
 
120
        rs_core_action_group_set_sensivity("Lightsout", !rs->window_fullscreen);
 
121
 
 
122
        /* Batch Menu */
 
123
        rs_core_action_group_set_sensivity("AddToBatch", (num_selected >= 1) || (rs->photo && !rs_batch_exists_in_queue(rs->queue, rs->photo->filename, rs->current_setting)));
 
124
        rs_core_action_group_set_sensivity("RemoveFromBatch", (num_selected >= 1) || (rs->photo && rs_batch_exists_in_queue(rs->queue, rs->photo->filename, rs->current_setting)));
 
125
        rs_core_action_group_set_sensivity("ProcessBatch", (rs_batch_num_entries(rs->queue)>0));
 
126
 
 
127
        /* Preview */
 
128
        rs_core_action_group_set_sensivity("Crop", RS_IS_PHOTO(rs->photo));
 
129
        rs_core_action_group_set_sensivity("Uncrop", (RS_IS_PHOTO(rs->photo) && rs->photo->crop));
 
130
        rs_core_action_group_set_sensivity("Straighten", RS_IS_PHOTO(rs->photo));
 
131
        rs_core_action_group_set_sensivity("Unstraighten", (RS_IS_PHOTO(rs->photo) && (rs->photo->angle != 0.0)));
 
132
 
106
133
        g_list_free(selected);
 
134
 
 
135
}
 
136
 
 
137
ACTION(file_menu)
 
138
{
 
139
        rs_core_actions_update_menu_items(rs);
 
140
}
 
141
 
 
142
ACTION(edit_menu)
 
143
{
 
144
        rs_core_actions_update_menu_items(rs);
 
145
}
 
146
 
 
147
 
 
148
ACTION(photo_menu)
 
149
{
 
150
        rs_core_actions_update_menu_items(rs);
 
151
}
 
152
 
 
153
ACTION(view_menu)
 
154
{
 
155
        rs_core_actions_update_menu_items(rs);
107
156
}
108
157
 
109
158
ACTION(batch_menu)
110
159
{
111
 
        GList *selected = NULL;
112
 
        gint num_selected;
113
 
        gboolean photos_selected;
114
 
 
115
 
        selected = rs_store_get_selected_names(rs->store);
116
 
        num_selected = g_list_length(selected);
117
 
 
118
 
        photos_selected = (RS_IS_PHOTO(rs->photo) || (num_selected > 0));
119
 
 
120
 
        rs_core_action_group_set_sensivity("AddToBatch", photos_selected && !rs_batch_exists_in_queue(rs->queue, rs->photo->filename, rs->current_setting));
121
 
        rs_core_action_group_set_sensivity("RemoveFromBatch", photos_selected && rs->photo && rs_batch_exists_in_queue(rs->queue, rs->photo->filename, rs->current_setting));
122
 
        rs_core_action_group_set_sensivity("ProcessBatch", (rs_batch_num_entries(rs->queue)>0));
123
 
        g_list_free(selected);
 
160
        rs_core_actions_update_menu_items(rs);
124
161
}
125
162
 
126
163
ACTION(preview_popup)
127
164
{
128
 
        rs_core_action_group_set_sensivity("Crop", RS_IS_PHOTO(rs->photo));
129
 
        rs_core_action_group_set_sensivity("Uncrop", (RS_IS_PHOTO(rs->photo) && rs->photo->crop));
130
 
        rs_core_action_group_set_sensivity("Straighten", RS_IS_PHOTO(rs->photo));
131
 
        rs_core_action_group_set_sensivity("Unstraighten", (RS_IS_PHOTO(rs->photo) && (rs->photo->angle != 0.0)));
 
165
        rs_core_actions_update_menu_items(rs);
132
166
}
 
167
 
133
168
ACTION(open)
134
169
{
135
170
        GtkWidget *fc;
158
193
                gtk_widget_destroy (fc);
159
194
 
160
195
        g_free(lwd);
 
196
        rs_core_actions_update_menu_items(rs);
161
197
}
162
198
 
163
199
ACTION(quick_export)
164
200
{
165
 
        gchar *dirname;
166
 
        gchar *conf_export_directory;
167
 
        gchar *conf_export_filename;
168
 
        GString *export_path;
169
 
        GString *save;
170
 
        gchar *parsed_filename;
171
 
        RS_FILETYPE *filetype;
172
 
        GString *status;
173
 
 
174
 
        if (!rs->photo) return;
175
 
 
176
 
        dirname = g_path_get_dirname(rs->photo->filename);
 
201
        gchar *directory;
 
202
        gchar *filename_template;
 
203
        gchar *parsed_filename = NULL;
 
204
        gchar *parsed_dir = NULL;
 
205
        gchar *output_identifier;
 
206
 
 
207
        directory = rs_conf_get_string("quick-export-directory");
 
208
        filename_template = rs_conf_get_string("quick-export-filename");
 
209
        output_identifier = rs_conf_get_string("quick-export-filetype");
 
210
 
 
211
        /* Initialize directory to home dir if nothing is saved in config */
 
212
        if (!directory)
 
213
        {
 
214
                const char *homedir = g_getenv("HOME");
 
215
                if (!homedir)
 
216
                        homedir = g_get_home_dir();
 
217
                directory = g_strdup(homedir);
 
218
        }
 
219
 
 
220
        /* Initialize filename_template to default if nothing is saved in config */
 
221
        if (!filename_template)
 
222
                filename_template = g_strdup(DEFAULT_CONF_EXPORT_FILENAME);
 
223
 
 
224
        /* Output as Jpeg, if nothing is saved in config */
 
225
        if (!output_identifier)
 
226
                output_identifier = g_strdup("RSJpeg");
 
227
 
 
228
        RSOutput *output = rs_output_new(output_identifier);
 
229
 
 
230
        GString *filename = NULL;
 
231
        /* Build new filename */
 
232
        if (NULL == g_strrstr(filename_template, "%p"))
 
233
        {
 
234
                filename = g_string_new(directory);
 
235
                g_string_append(filename, G_DIR_SEPARATOR_S);
 
236
                g_string_append(filename, filename_template);
 
237
        } 
 
238
        else
 
239
                filename = g_string_new(filename_template);
177
240
        
178
 
        conf_export_directory = rs_conf_get_string(CONF_EXPORT_DIRECTORY);
179
 
        if (!conf_export_directory)
180
 
                conf_export_directory = g_strdup(DEFAULT_CONF_EXPORT_DIRECTORY);
181
 
 
182
 
        conf_export_filename = rs_conf_get_string(CONF_EXPORT_FILENAME);
183
 
        if (!conf_export_filename)
184
 
                conf_export_filename = DEFAULT_CONF_EXPORT_FILENAME;
185
 
 
186
 
        rs_conf_get_filetype(CONF_EXPORT_FILETYPE, &filetype);
187
 
 
188
 
        if (conf_export_directory)
 
241
        g_string_append(filename, ".");
 
242
        g_string_append(filename, rs_output_get_extension(output));
 
243
 
 
244
        parsed_filename = filename_parse(filename->str, rs->photo->filename, rs->current_setting);
 
245
 
 
246
        if (parsed_filename && output)
189
247
        {
190
 
                if (conf_export_directory[0]==G_DIR_SEPARATOR)
 
248
                /* Create directory, if it doesn't exist */
 
249
                parsed_dir = g_path_get_dirname(parsed_filename);
 
250
                if (FALSE == g_file_test(parsed_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
 
251
                        if (g_mkdir_with_parents(parsed_dir, 0x1ff))
 
252
                        {
 
253
                                gui_status_notify(_("Could not create output directory."));
 
254
                                return;
 
255
                        }
 
256
 
 
257
                guint msg = gui_status_push(_("Exporting..."));
 
258
                gui_set_busy(TRUE);
 
259
                GTK_CATCHUP();
 
260
                g_object_set(output, "filename", parsed_filename, NULL);
 
261
                rs_output_set_from_conf(output, "quick-export");
 
262
 
 
263
                if (rs_photo_save(rs->photo, rs->filter_end, output, -1, -1, FALSE, 1.0, rs->current_setting))
191
264
                {
192
 
                        g_free(dirname);
193
 
                        dirname = conf_export_directory;
 
265
                        gchar *status = g_strdup_printf("%s (%s)", _("File exported"), parsed_filename);
 
266
                        gui_status_notify(status);
 
267
                        g_free(status);
194
268
                }
195
269
                else
196
 
                {
197
 
                        export_path = g_string_new(dirname);
198
 
                        g_string_append(export_path, G_DIR_SEPARATOR_S);
199
 
                        g_string_append(export_path, conf_export_directory);
200
 
                        g_free(dirname);
201
 
                        dirname = export_path->str;
202
 
                        g_string_free(export_path, FALSE);
203
 
                        g_free(conf_export_directory);
204
 
                }
205
 
                g_mkdir_with_parents(dirname, 00755);
 
270
                        gui_status_notify(_("Export failed"));
 
271
 
 
272
                gui_status_pop(msg);
 
273
                gui_set_busy(FALSE);
206
274
        }
207
 
        
208
 
        save = g_string_new(dirname);
209
 
        if (dirname[strlen(dirname)-1] != G_DIR_SEPARATOR)
210
 
                g_string_append(save, G_DIR_SEPARATOR_S);
211
 
        g_string_append(save, conf_export_filename);
212
 
 
213
 
        g_string_append(save, filetype->ext);
214
 
 
215
 
        parsed_filename = filename_parse(save->str, rs->photo->filename, rs->current_setting);
216
 
        g_string_free(save, TRUE);
217
 
 
218
 
        rs_photo_save(rs->photo, parsed_filename, filetype->filetype, -1, -1, FALSE, 1.0, rs->current_setting, rs->cms);
219
 
        status = g_string_new("");
220
 
        g_string_printf(status, "%s (%s)", _("File exported"), parsed_filename);
221
 
        gui_status_notify(status->str);
222
 
        g_string_free(status, TRUE);
 
275
 
 
276
        g_object_unref(output);
 
277
        g_free(directory);
223
278
        g_free(parsed_filename);
 
279
        g_free(parsed_dir);
 
280
        g_free(output_identifier);
 
281
        g_string_free(filename, TRUE);
224
282
}
225
283
 
226
284
ACTION(export_as)
227
285
{
228
 
        gui_save_file_dialog(rs);
 
286
        if (RS_IS_PHOTO(rs->photo))
 
287
        {
 
288
                RSSaveDialog *dialog = rs_save_dialog_new();
 
289
                rs_save_dialog_set_photo(dialog, rs->photo, rs->current_setting);
 
290
                gtk_widget_show(GTK_WIDGET(dialog));
 
291
        }
 
292
        else
 
293
                gui_status_notify(_("Export failed"));
229
294
}
230
295
 
231
296
ACTION(export_to_gimp)
232
297
{
233
298
        if (!RS_IS_PHOTO(rs->photo)) return;
234
299
 
235
 
        if (!rs_external_editor_gimp(rs->photo, rs->current_setting, rs->cms))
 
300
        guint status = gui_status_push(_("Exporting to GIMP..."));
 
301
        GTK_CATCHUP();
 
302
        if (!rs_external_editor_gimp(rs->photo, rs->filter_end, rs->current_setting))
236
303
        {
237
304
                GtkWidget *dialog = gui_dialog_make_from_text(GTK_STOCK_DIALOG_WARNING, 
238
305
                        _("Error exporting"),
242
309
                gtk_dialog_run(GTK_DIALOG(dialog));
243
310
                gtk_widget_destroy(dialog);
244
311
        }
 
312
        gui_status_pop(status);
245
313
}
246
314
 
247
315
ACTION(reload)
248
316
{
249
317
        rs_store_remove(rs->store, NULL, NULL);
250
318
        rs_store_load_directory(rs->store, NULL);
 
319
        rs_core_actions_update_menu_items(rs);
251
320
}
252
321
 
253
322
ACTION(delete_flagged)
321
390
        if (rs->photo)
322
391
                rs_photo_close(rs->photo);
323
392
        rs_conf_set_integer(CONF_LAST_PRIORITY_PAGE, rs_store_get_current_page(rs->store));
 
393
        rs_io_idle_cancel_class(METADATA_CLASS);
 
394
        rs_io_idle_cancel_class(PRELOAD_CLASS);
 
395
        rs_io_idle_cancel_class(RESTORE_TAGS_CLASS);
 
396
        
 
397
        RS_PROGRESS *progress;
 
398
        gint total_items = rs_io_get_jobs_left();
 
399
        if (total_items)
 
400
        {
 
401
                progress = gui_progress_new(_("Waiting for jobs to finish"), total_items);
 
402
                gtk_widget_hide(rs->window);
 
403
                gint items = total_items;
 
404
                while (items > 0)
 
405
                {
 
406
                        g_usleep(100*1000);
 
407
                        items = rs_io_get_jobs_left();
 
408
                        gui_progress_set_current(progress, total_items-items);
 
409
                        GUI_CATCHUP();
 
410
                }
 
411
        }
324
412
        gtk_main_quit();
325
413
}
326
414
 
 
415
 
 
416
ACTION(copy_image)
 
417
{
 
418
        if (!rs->photo)
 
419
                return;
 
420
        guint msg = gui_status_push(_("Copying image to clipboard"));
 
421
        gui_set_busy(TRUE);
 
422
        GTK_CATCHUP();
 
423
 
 
424
        if (rs_photo_copy_to_clipboard(rs->photo, rs->filter_end, -1, -1, FALSE, 1.0, rs->current_setting))
 
425
                gui_status_notify(_("Image copied to clipboard"));
 
426
        else
 
427
                gui_status_notify(_("ERROR: Could not copy image to clipboard"));
 
428
        gui_set_busy(FALSE);
 
429
        gui_status_pop(msg);
 
430
}
 
431
 
327
432
ACTION(revert_settings)
328
433
{
329
434
        if (RS_IS_PHOTO(rs->photo))
330
435
                rs_cache_load(rs->photo);
331
436
}
332
437
 
 
438
static const gint COPY_MASK_ALL = MASK_PROFILE|MASK_EXPOSURE|MASK_SATURATION|MASK_HUE|
 
439
        MASK_CONTRAST|MASK_WB|MASK_SHARPEN|MASK_DENOISE_LUMA|MASK_DENOISE_CHROMA|
 
440
        MASK_CHANNELMIXER|MASK_TCA|MASK_VIGNETTING|MASK_CURVE;
 
441
 
 
442
/* Widgets for copy dialog */
 
443
static GtkWidget *cb_profile, *cb_exposure, *cb_saturation, *cb_hue, *cb_contrast, *cb_whitebalance, *cb_curve, *cb_sharpen, *cb_denoise_luma, *cb_denoise_chroma, *cb_channelmixer, *cb_tca, *cb_vignetting, *b_all_none;
 
444
 
 
445
static void
 
446
all_none_clicked(GtkButton *button, gpointer user_data)
 
447
{
 
448
        gint mask= copy_dialog_get_mask();
 
449
        if (mask == COPY_MASK_ALL)
 
450
                mask = 0;
 
451
        else
 
452
                mask = COPY_MASK_ALL;
 
453
 
 
454
        copy_dialog_set_mask(mask);
 
455
}
 
456
 
 
457
static GtkWidget *
 
458
create_copy_dialog(gint mask)
 
459
{
 
460
        GtkWidget *cb_box;
 
461
        GtkWidget *dialog;
 
462
        /* Build GUI */
 
463
        cb_profile = gtk_check_button_new_with_label (_("Profile"));
 
464
        cb_exposure = gtk_check_button_new_with_label (_("Exposure"));
 
465
        cb_saturation = gtk_check_button_new_with_label (_("Saturation"));
 
466
        cb_hue = gtk_check_button_new_with_label (_("Hue"));
 
467
        cb_contrast = gtk_check_button_new_with_label (_("Contrast"));
 
468
        cb_whitebalance = gtk_check_button_new_with_label (_("White balance"));
 
469
        cb_sharpen = gtk_check_button_new_with_label (_("Sharpen"));
 
470
        cb_denoise_luma = gtk_check_button_new_with_label (_("Denoise"));
 
471
        cb_denoise_chroma = gtk_check_button_new_with_label (_("Color denoise"));
 
472
        cb_channelmixer = gtk_check_button_new_with_label (_("Channel mixer"));
 
473
        cb_tca = gtk_check_button_new_with_label (_("TCA"));
 
474
        cb_vignetting = gtk_check_button_new_with_label (_("Vignetting"));
 
475
        cb_curve = gtk_check_button_new_with_label (_("Curve"));
 
476
        b_all_none = gtk_button_new_with_label (_("Select All/None"));
 
477
 
 
478
        g_signal_connect(b_all_none, "clicked", G_CALLBACK(all_none_clicked), NULL);
 
479
 
 
480
        copy_dialog_set_mask(mask);
 
481
        cb_box = gtk_vbox_new(FALSE, 0);
 
482
 
 
483
        gtk_box_pack_start (GTK_BOX (cb_box), cb_profile, FALSE, TRUE, 0);
 
484
        gtk_box_pack_start (GTK_BOX (cb_box), cb_exposure, FALSE, TRUE, 0);
 
485
        gtk_box_pack_start (GTK_BOX (cb_box), cb_saturation, FALSE, TRUE, 0);
 
486
        gtk_box_pack_start (GTK_BOX (cb_box), cb_hue, FALSE, TRUE, 0);
 
487
        gtk_box_pack_start (GTK_BOX (cb_box), cb_contrast, FALSE, TRUE, 0);
 
488
        gtk_box_pack_start (GTK_BOX (cb_box), cb_whitebalance, FALSE, TRUE, 0);
 
489
        gtk_box_pack_start (GTK_BOX (cb_box), cb_sharpen, FALSE, TRUE, 0);
 
490
        gtk_box_pack_start (GTK_BOX (cb_box), cb_denoise_luma, FALSE, TRUE, 0);
 
491
        gtk_box_pack_start (GTK_BOX (cb_box), cb_denoise_chroma, FALSE, TRUE, 0);
 
492
        gtk_box_pack_start (GTK_BOX (cb_box), cb_channelmixer, FALSE, TRUE, 0);
 
493
        gtk_box_pack_start (GTK_BOX (cb_box), cb_tca, FALSE, TRUE, 0);
 
494
        gtk_box_pack_start (GTK_BOX (cb_box), cb_vignetting, FALSE, TRUE, 0);
 
495
        gtk_box_pack_start (GTK_BOX (cb_box), cb_curve, FALSE, TRUE, 0);
 
496
        gtk_box_pack_start (GTK_BOX (cb_box), b_all_none, FALSE, TRUE, 0);
 
497
 
 
498
        dialog = gui_dialog_make_from_widget(GTK_STOCK_DIALOG_QUESTION, _("Select settings to copy"), cb_box);
 
499
 
 
500
        gtk_dialog_add_buttons(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
 
501
        gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
 
502
        return dialog;
 
503
}
 
504
 
 
505
static void
 
506
copy_dialog_set_mask(gint mask)
 
507
{
 
508
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_profile), !!(mask & MASK_PROFILE));
 
509
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_exposure), !!(mask & MASK_EXPOSURE));
 
510
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_saturation), !!(mask & MASK_SATURATION));
 
511
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_hue), !!(mask & MASK_HUE));
 
512
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_contrast), !!(mask & MASK_CONTRAST));
 
513
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_whitebalance), !!(mask & MASK_WB));
 
514
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_sharpen), !!(mask & MASK_SHARPEN));
 
515
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_denoise_luma), !!(mask & MASK_DENOISE_LUMA));
 
516
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_denoise_chroma), !!(mask & MASK_DENOISE_CHROMA));
 
517
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_channelmixer), !!(mask & MASK_CHANNELMIXER));
 
518
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_tca), !!(mask & MASK_TCA));
 
519
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_vignetting), !!(mask & MASK_VIGNETTING));
 
520
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_curve), !!(mask & MASK_CURVE));
 
521
}
 
522
 
 
523
static gint
 
524
copy_dialog_get_mask(void)
 
525
{
 
526
        gint mask = 0;
 
527
        if (GTK_TOGGLE_BUTTON(cb_profile)->active)
 
528
                mask |= MASK_PROFILE;
 
529
        if (GTK_TOGGLE_BUTTON(cb_exposure)->active)
 
530
                mask |= MASK_EXPOSURE;
 
531
        if (GTK_TOGGLE_BUTTON(cb_saturation)->active)
 
532
                mask |= MASK_SATURATION;
 
533
        if (GTK_TOGGLE_BUTTON(cb_hue)->active)
 
534
                mask |= MASK_HUE;
 
535
        if (GTK_TOGGLE_BUTTON(cb_contrast)->active)
 
536
                mask |= MASK_CONTRAST;
 
537
        if (GTK_TOGGLE_BUTTON(cb_whitebalance)->active)
 
538
                mask |= MASK_WB;
 
539
        if (GTK_TOGGLE_BUTTON(cb_sharpen)->active)
 
540
                mask |= MASK_SHARPEN;
 
541
        if (GTK_TOGGLE_BUTTON(cb_denoise_luma)->active)
 
542
                mask |= MASK_DENOISE_LUMA;
 
543
        if (GTK_TOGGLE_BUTTON(cb_denoise_chroma)->active)
 
544
                mask |= MASK_DENOISE_CHROMA;
 
545
        if (GTK_TOGGLE_BUTTON(cb_channelmixer)->active)
 
546
                mask |= MASK_CHANNELMIXER;
 
547
        if (GTK_TOGGLE_BUTTON(cb_tca)->active)
 
548
                mask |= MASK_TCA;
 
549
        if (GTK_TOGGLE_BUTTON(cb_vignetting)->active)
 
550
                mask |= MASK_VIGNETTING;
 
551
        if (GTK_TOGGLE_BUTTON(cb_curve)->active)
 
552
                mask |= MASK_CURVE;
 
553
        return mask;
 
554
}
 
555
 
333
556
ACTION(copy_settings)
334
557
{
 
558
        gint mask = COPY_MASK_ALL; /* Should be RSSettingsMask, is gint to satisfy rs_conf_get_integer() */
 
559
        GtkWidget *dialog;
 
560
 
335
561
        if (!rs->settings_buffer)
336
562
                rs->settings_buffer = rs_settings_new();
337
 
        rs_settings_copy(rs->settings[rs->current_setting], MASK_ALL, rs->settings_buffer);
338
 
        gui_status_notify(_("Copied settings"));
 
563
        if (!rs->photo)
 
564
                return;
 
565
 
 
566
        rs_conf_get_integer(CONF_PASTE_MASK, &mask);
 
567
        dialog = create_copy_dialog(mask);
 
568
        gtk_widget_show_all(dialog);
 
569
 
 
570
        if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
 
571
        {
 
572
                mask = copy_dialog_get_mask();
 
573
                rs_conf_set_integer(CONF_PASTE_MASK, mask);
 
574
                rs_settings_copy(rs->photo->settings[rs->current_setting], MASK_ALL, rs->settings_buffer);
 
575
                rs->dcp_buffer = rs_photo_get_dcp_profile(rs->photo);
 
576
                rs->icc_buffer = rs_photo_get_icc_profile(rs->photo);
 
577
                gui_status_notify(_("Copied settings"));
 
578
        }
 
579
        gtk_widget_destroy (dialog);
339
580
}
340
581
 
341
582
ACTION(paste_settings)
342
583
{
343
 
        gint mask = 0xffffff; /* Should be RSSettingsMask, is gint to satisfy rs_conf_get_integer() */
344
 
 
345
 
        GtkWidget *dialog, *cb_box;
346
 
        GtkWidget *cb_exposure, *cb_saturation, *cb_hue, *cb_contrast, *cb_whitebalance, *cb_curve, *cb_sharpen;
347
 
 
 
584
        gint mask = COPY_MASK_ALL; /* Should be RSSettingsMask, is gint to satisfy rs_conf_get_integer() */
 
585
 
 
586
        gui_set_busy(TRUE);
 
587
        guint msg = gui_status_push(_("Pasting settings to images"));
 
588
        GTK_CATCHUP();
348
589
        if (rs->settings_buffer)
349
590
        {
350
 
                /* Build GUI */
351
 
                cb_exposure = gtk_check_button_new_with_label (_("Exposure"));
352
 
                cb_saturation = gtk_check_button_new_with_label (_("Saturation"));
353
 
                cb_hue = gtk_check_button_new_with_label (_("Hue"));
354
 
                cb_contrast = gtk_check_button_new_with_label (_("Contrast"));
355
 
                cb_whitebalance = gtk_check_button_new_with_label (_("White balance"));
356
 
                cb_sharpen = gtk_check_button_new_with_label (_("Sharpen"));
357
 
                cb_curve = gtk_check_button_new_with_label (_("Curve"));
358
 
 
359
591
                rs_conf_get_integer(CONF_PASTE_MASK, &mask);
360
 
 
361
 
                if (mask & MASK_EXPOSURE)
362
 
                        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_exposure), TRUE);
363
 
                if (mask & MASK_SATURATION)
364
 
                        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_saturation), TRUE);
365
 
                if (mask & MASK_HUE)
366
 
                        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_hue), TRUE);
367
 
                if (mask & MASK_CONTRAST)
368
 
                        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_contrast), TRUE);
369
 
                if (mask & MASK_WARMTH && mask & MASK_TINT)
370
 
                        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_whitebalance), TRUE);
371
 
                if (mask & MASK_SHARPEN)
372
 
                        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_sharpen), TRUE);
373
 
                if (mask & MASK_CURVE)
374
 
                        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_curve), TRUE);
375
 
 
376
 
                cb_box = gtk_vbox_new(FALSE, 0);
377
 
 
378
 
                gtk_box_pack_start (GTK_BOX (cb_box), cb_exposure, FALSE, TRUE, 0);
379
 
                gtk_box_pack_start (GTK_BOX (cb_box), cb_saturation, FALSE, TRUE, 0);
380
 
                gtk_box_pack_start (GTK_BOX (cb_box), cb_hue, FALSE, TRUE, 0);
381
 
                gtk_box_pack_start (GTK_BOX (cb_box), cb_contrast, FALSE, TRUE, 0);
382
 
                gtk_box_pack_start (GTK_BOX (cb_box), cb_whitebalance, FALSE, TRUE, 0);
383
 
                gtk_box_pack_start (GTK_BOX (cb_box), cb_sharpen, FALSE, TRUE, 0);
384
 
                gtk_box_pack_start (GTK_BOX (cb_box), cb_curve, FALSE, TRUE, 0);
385
 
 
386
 
                dialog = gui_dialog_make_from_widget(GTK_STOCK_DIALOG_QUESTION, _("Select settings to paste"), cb_box);
387
 
 
388
 
                gtk_dialog_add_buttons(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_APPLY, GTK_RESPONSE_APPLY, NULL);
389
 
                gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_APPLY);
390
 
 
391
 
                gtk_widget_show_all(dialog);
392
 
 
393
 
                mask=0;
394
 
 
395
 
                if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_APPLY)
396
 
                {
397
 
                        if (GTK_TOGGLE_BUTTON(cb_exposure)->active)
398
 
                                mask |= MASK_EXPOSURE;
399
 
                        if (GTK_TOGGLE_BUTTON(cb_saturation)->active)
400
 
                                mask |= MASK_SATURATION;
401
 
                        if (GTK_TOGGLE_BUTTON(cb_hue)->active)
402
 
                                mask |= MASK_HUE;
403
 
                        if (GTK_TOGGLE_BUTTON(cb_contrast)->active)
404
 
                                mask |= MASK_CONTRAST;
405
 
                        if (GTK_TOGGLE_BUTTON(cb_whitebalance)->active)
406
 
                                mask |= MASK_WB;
407
 
                        if (GTK_TOGGLE_BUTTON(cb_sharpen)->active)
408
 
                                mask |= MASK_SHARPEN;
409
 
                        if (GTK_TOGGLE_BUTTON(cb_curve)->active)
410
 
                                mask |= MASK_CURVE;
411
 
                        rs_conf_set_integer(CONF_PASTE_MASK, mask);
412
 
                }
413
 
                gtk_widget_destroy (dialog);
414
 
 
415
592
                if(mask > 0)
416
593
                {
 
594
                        RSMetadata *metadata;
417
595
                        RS_PHOTO *photo;
418
596
                        gint cur;
419
597
                        GList *selected = NULL;
428
606
                                /* This is nothing but a hack around rs_cache_*() */
429
607
                                photo = rs_photo_new();
430
608
                                photo->filename = g_strdup(g_list_nth_data(selected, cur));
 
609
 
 
610
                                /* Make sure we rotate this right */
 
611
                                metadata = rs_metadata_new_from_file(photo->filename);
 
612
                                switch (metadata->orientation)
 
613
                                {
 
614
                                        case 90: ORIENTATION_90(photo->orientation);
 
615
                                                break;
 
616
                                        case 180: ORIENTATION_180(photo->orientation);
 
617
                                                break;
 
618
                                        case 270: ORIENTATION_270(photo->orientation);
 
619
                                                break;
 
620
                                }
 
621
                                g_object_unref(metadata);
 
622
 
431
623
                                new_mask = rs_cache_load(photo);
432
624
                                rs_settings_copy(rs->settings_buffer, mask, photo->settings[rs->current_setting]);
 
625
                                if (mask & MASK_PROFILE)
 
626
                                {
 
627
                                        if (rs->dcp_buffer)
 
628
                                                rs_photo_set_dcp_profile(photo, rs->dcp_buffer);
 
629
                                        else if (rs->icc_buffer)
 
630
                                                rs_photo_set_icc_profile(photo, rs->icc_buffer);
 
631
                                }       
433
632
                                rs_cache_save(photo, new_mask | mask);
434
633
                                g_object_unref(photo);
435
634
                        }
436
635
                        g_list_free(selected);
437
636
 
438
637
                        /* Apply to current photo */
439
 
                        rs_settings_copy(rs->settings_buffer, mask, rs->settings[rs->current_setting]); 
440
 
 
 
638
                        if (rs->photo && (mask & MASK_PROFILE))
 
639
                        {
 
640
                                if (rs->dcp_buffer)
 
641
                                        rs_photo_set_dcp_profile(rs->photo, rs->dcp_buffer);
 
642
                                else if (rs->icc_buffer)
 
643
                                        rs_photo_set_icc_profile(rs->photo, rs->icc_buffer);
 
644
                        }
 
645
 
 
646
                        if (rs->photo)
 
647
                                rs_settings_copy(rs->settings_buffer, mask, rs->photo->settings[rs->current_setting]); 
 
648
 
 
649
                        /* Update WB if wb_ascii is set */
 
650
                        if (mask & MASK_WB && rs->photo->settings[rs->current_setting]->wb_ascii)
 
651
                        {
 
652
                                if (g_strcmp0(rs->photo->settings[rs->current_setting]->wb_ascii, PRESET_WB_AUTO) == 0)
 
653
                                        rs_photo_set_wb_auto(rs->photo, rs->current_setting);
 
654
                                else if (g_strcmp0(rs->photo->settings[rs->current_setting]->wb_ascii, PRESET_WB_CAMERA) == 0)
 
655
                                        rs_photo_set_wb_from_camera(rs->photo, rs->current_setting);
 
656
                        }
441
657
                        gui_status_notify(_("Pasted settings"));
442
658
                }
443
659
                else
445
661
        }
446
662
        else 
447
663
                gui_status_notify(_("Buffer empty"));
 
664
        gui_status_pop(msg);
 
665
        GTK_CATCHUP();
 
666
        gui_set_busy(FALSE);
448
667
}
449
668
 
450
669
ACTION(reset_settings)
451
670
{
452
 
        rs_settings_reset(rs->settings[rs->current_setting], MASK_ALL);
453
 
 
454
 
        if (RS_IS_PHOTO(rs->photo))
455
 
                rs_photo_apply_settings(rs->photo, rs->current_setting, rs->settings[rs->current_setting], MASK_ALL);
 
671
        if (RS_IS_PHOTO(rs->photo))
 
672
        {
 
673
                rs_settings_commit_start(rs->photo->settings[rs->current_setting]);
 
674
                RSCameraDb *db = rs_camera_db_get_singleton();
 
675
                gpointer p;
 
676
                RSSettings *s[3];
 
677
                gint snapshot = rs->current_setting;
 
678
 
 
679
                if (rs_camera_db_photo_get_defaults(db, rs->photo, s, &p) && s[snapshot] && RS_IS_SETTINGS(s[snapshot]))
 
680
                {
 
681
                        rs_settings_copy(s[snapshot], MASK_ALL, rs->photo->settings[snapshot]);
 
682
                        if (rs->photo->dcp && p && RS_IS_DCP_FILE(p))
 
683
                                rs_photo_set_dcp_profile(rs->photo, p);
 
684
                }
 
685
                else
 
686
                        rs_settings_reset(rs->photo->settings[snapshot], MASK_ALL);
 
687
 
 
688
                rs_photo_set_wb_from_camera(rs->photo, snapshot);
 
689
                rs_settings_commit_stop(rs->photo->settings[snapshot]);
 
690
        }
 
691
}
 
692
 
 
693
ACTION(save_default_settings)
 
694
{
 
695
        if (RS_IS_PHOTO(rs->photo))
 
696
                rs_camera_db_save_defaults(rs_camera_db_get_singleton(), rs->photo);
456
697
}
457
698
 
458
699
ACTION(preferences)
485
726
        gui_setprio(rs, PRIO_U);
486
727
}
487
728
 
 
729
void
 
730
set_wb_on_multiple_photos(GList *selected, gint current_setting, const gchar *wb_ascii)
 
731
{
 
732
        gint num_selected = g_list_length(selected);
 
733
        gui_set_busy(TRUE);
 
734
        GTK_CATCHUP();
 
735
 
 
736
        if (num_selected > 1)
 
737
        {
 
738
                RS_PHOTO *photo;
 
739
                gint cur, load_mask;
 
740
 
 
741
                for(cur=0;cur<num_selected;cur++)
 
742
                {
 
743
                        /* This is nothing but a hack around rs_cache_*() */
 
744
                        photo = rs_photo_new();
 
745
                        photo->filename = g_strdup(g_list_nth_data(selected, cur));
 
746
                        if (rs_metadata_load(photo->metadata, photo->filename))
 
747
                        {
 
748
                                /* Rotate photo inplace */
 
749
                                switch (photo->metadata->orientation)
 
750
                                {
 
751
                                        case 90: ORIENTATION_90(photo->orientation);
 
752
                                                break;
 
753
                                        case 180: ORIENTATION_180(photo->orientation);
 
754
                                                break;
 
755
                                        case 270: ORIENTATION_270(photo->orientation);
 
756
                                                break;
 
757
                                }
 
758
                        }
 
759
                        load_mask = rs_cache_load(photo);
 
760
                        rs_settings_set_wb(photo->settings[current_setting], 0.0, 0.0, wb_ascii);
 
761
                        rs_cache_save(photo, load_mask | MASK_WB);
 
762
                        g_object_unref(photo);
 
763
                }
 
764
        }
 
765
        g_list_free(selected);
 
766
        gui_set_busy(FALSE);
 
767
}
 
768
 
488
769
ACTION(auto_wb)
489
770
{
490
 
        if (RS_IS_PHOTO(rs->photo))
 
771
        if (RS_IS_PHOTO(rs->photo) && rs_store_is_photo_selected(rs->store, rs->photo->filename))
491
772
        {
492
773
                gui_status_notify(_("Adjusting to auto white balance"));
493
774
                rs_photo_set_wb_auto(rs->photo, rs->current_setting);
494
775
        }
 
776
 
 
777
        /* Apply to all selected photos */
 
778
        set_wb_on_multiple_photos(rs_store_get_selected_names(rs->store), rs->current_setting, PRESET_WB_AUTO);
495
779
}
496
780
 
497
781
ACTION(camera_wb)
498
782
{
499
 
        if (RS_IS_PHOTO(rs->photo))
 
783
        if (RS_IS_PHOTO(rs->photo) && rs_store_is_photo_selected(rs->store, rs->photo->filename))
500
784
        {
501
 
                if (rs->photo->metadata->cam_mul[R] == -1.0)
 
785
                if (rs->photo && !rs->photo->dcp)
 
786
                        rs_photo_set_wb_from_camera(rs->photo, rs->current_setting);
 
787
                else if (rs->photo && rs->photo->metadata && rs->photo->metadata->cam_mul[R] == -1.0)
502
788
                        gui_status_notify(_("No white balance to set from"));
503
789
                else
504
790
                {
505
791
                        gui_status_notify(_("Adjusting to camera white balance"));
506
 
                        rs_photo_set_wb_from_mul(rs->photo, rs->current_setting, rs->photo->metadata->cam_mul);
 
792
                        rs_photo_set_wb_from_camera(rs->photo, rs->current_setting);
507
793
                }
508
794
        }
 
795
 
 
796
        /* Apply to all selected photos */
 
797
        set_wb_on_multiple_photos(rs_store_get_selected_names(rs->store), rs->current_setting, PRESET_WB_CAMERA);
509
798
}
510
799
 
511
800
ACTION(crop)
512
801
{
513
802
        rs_preview_widget_crop_start(RS_PREVIEW_WIDGET(rs->preview));
 
803
        rs_core_actions_update_menu_items(rs);
514
804
}
515
805
 
516
806
ACTION(uncrop)
517
807
{
518
808
        rs_preview_widget_uncrop(RS_PREVIEW_WIDGET(rs->preview));
 
809
        rs_core_actions_update_menu_items(rs);
519
810
}
520
811
 
521
812
ACTION(straighten)
528
819
        rs_preview_widget_unstraighten(RS_PREVIEW_WIDGET(rs->preview));
529
820
}
530
821
 
 
822
ACTION(rotate_clockwise)
 
823
{
 
824
        if (rs->photo)
 
825
                rs_photo_rotate(rs->photo, 1, 0.0);
 
826
}
 
827
 
 
828
ACTION(rotate_counter_clockwise)
 
829
{
 
830
        if (rs->photo)
 
831
                rs_photo_rotate(rs->photo, 3, 0.0);
 
832
}
 
833
 
 
834
ACTION(flip)
 
835
{
 
836
        if (rs->photo)
 
837
                rs_photo_flip(rs->photo);
 
838
}
 
839
 
 
840
ACTION(mirror)
 
841
{
 
842
        if (rs->photo)
 
843
                rs_photo_mirror(rs->photo);
 
844
}
 
845
 
531
846
ACTION(group_photos)
532
847
{
533
848
        rs_store_group_photos(rs->store);
543
858
        rs_store_auto_group(rs->store);
544
859
}
545
860
 
 
861
typedef struct TagPhotoData {
 
862
        RS_BLOB *rs;
 
863
        GtkEntry *entry;
 
864
} TagPhotoData;
 
865
 
 
866
static void 
 
867
tag_photo_input_changed(GtkWidget *button, gpointer user_data)
 
868
{
 
869
        GHashTableIter iter;
 
870
        gpointer key, value;
 
871
        RSLibrary *library = rs_library_get_singleton();
 
872
        TagPhotoData *info = (TagPhotoData*)(user_data);
 
873
        RS_BLOB *rs = info->rs;
 
874
        GtkEntry *entry = info->entry;
 
875
 
 
876
        GList * selected = rs_store_get_selected_names(rs->store);
 
877
        gint num_selected = g_list_length(selected);
 
878
        gint cur, i;
 
879
        GHashTable* directories = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
 
880
 
 
881
        const char* entry_text = gtk_entry_get_text(entry);
 
882
        if (num_selected > 0 && entry_text)
 
883
        {
 
884
                GList *tags = rs_split_string(entry_text, " .,/;:~^*|&");
 
885
                for(i = 0; i < g_list_length(tags); i++)
 
886
                {
 
887
                        gchar *tag = (gchar *) g_list_nth_data(tags, i);
 
888
                        gint tag_id = rs_library_add_tag(library, tag);
 
889
                        g_free(tag);
 
890
 
 
891
                        for(cur=0;cur<num_selected;cur++)
 
892
                        {
 
893
                                gchar* filename = g_list_nth_data(selected, cur);
 
894
                                rs_io_idle_add_tag(filename, tag_id, FALSE, -1);
 
895
                                
 
896
                                if (0 == i)
 
897
                                {
 
898
                                        gchar* dir = g_path_get_dirname(filename);
 
899
                                        if (NULL == g_hash_table_lookup(directories, dir))
 
900
                                                g_hash_table_insert(directories, dir, filename);
 
901
                                        else
 
902
                                                g_free(dir);
 
903
                                }
 
904
                        }
 
905
                }
 
906
 
 
907
                g_hash_table_iter_init (&iter, directories);
 
908
                while (g_hash_table_iter_next (&iter, &key, &value)) 
 
909
                {
 
910
                        rs_io_idle_add_tag(value, -2, FALSE, -1);
 
911
                }
 
912
                g_hash_table_remove_all(directories);
 
913
                g_list_free(tags);
 
914
        }
 
915
        GdkWindow *window = gtk_widget_get_parent_window(GTK_WIDGET(entry));
 
916
        gdk_window_destroy(window);
 
917
        g_list_free(selected);
 
918
        g_free(info);
 
919
}
 
920
 
 
921
ACTION(tag_photo)
 
922
{
 
923
        GtkWidget *popup = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
924
        gtk_window_set_transient_for(GTK_WINDOW(popup), GTK_WINDOW(rs->window));
 
925
        gtk_window_set_type_hint(GTK_WINDOW(popup), GDK_WINDOW_TYPE_HINT_UTILITY);
 
926
        GtkWidget *label = gtk_label_new(_("Tags, separated by spaces:"));
 
927
        GtkWidget *box = gtk_hbox_new(FALSE, 10);
 
928
        GtkWidget *entry = rs_library_tag_entry_new(rs_library_get_singleton());
 
929
        GtkWidget *apply_button = gtk_button_new_from_stock(GTK_STOCK_APPLY);
 
930
 
 
931
        gtk_window_set_title(GTK_WINDOW(popup), _("Add tags to selected photo(s)."));
 
932
        gtk_window_set_position(GTK_WINDOW(popup), GTK_WIN_POS_MOUSE);
 
933
        gtk_box_pack_start(GTK_BOX(box), label, FALSE, TRUE, 5);
 
934
        gtk_box_pack_start(GTK_BOX(box), entry, FALSE, TRUE, 0);
 
935
        gtk_box_pack_start(GTK_BOX(box), apply_button, FALSE, FALSE, 5);
 
936
        gtk_container_set_border_width(GTK_CONTAINER(box), 10);
 
937
 
 
938
        gtk_container_add(GTK_CONTAINER(popup), box);
 
939
        gtk_widget_show_all(popup);
 
940
 
 
941
        TagPhotoData *info = g_malloc(sizeof(TagPhotoData));
 
942
        info->rs = rs;
 
943
        info->entry = GTK_ENTRY(entry);
 
944
 
 
945
        g_signal_connect(entry, "activate", G_CALLBACK(tag_photo_input_changed), info);
 
946
        g_signal_connect(apply_button, "clicked", G_CALLBACK(tag_photo_input_changed), info);
 
947
}
 
948
 
546
949
ACTION(previous_photo)
547
950
{
548
951
        gchar *current_filename = NULL;
565
968
        rs_store_select_prevnext(rs->store, current_filename, 2);
566
969
}
567
970
 
568
 
ACTION(zoom_to_fit)
569
 
{
570
 
        rs_preview_widget_set_zoom_to_fit(RS_PREVIEW_WIDGET(rs->preview));
571
 
}
572
 
 
573
 
ACTION(zoom_to_100)
574
 
{
575
 
        rs_preview_widget_set_zoom(RS_PREVIEW_WIDGET(rs->preview), 1.0);
 
971
TOGGLEACTION(zoom_to_fit)
 
972
{
 
973
        rs_preview_widget_set_zoom_to_fit(RS_PREVIEW_WIDGET(rs->preview), gtk_toggle_action_get_active(toggleaction));
576
974
}
577
975
 
578
976
TOGGLEACTION(iconbox)
585
983
        gui_widget_show(rs->toolbox, gtk_toggle_action_get_active(toggleaction), CONF_SHOW_TOOLBOX_FULLSCREEN, CONF_SHOW_TOOLBOX);
586
984
}
587
985
 
 
986
TOGGLEACTION(show_filenames)
 
987
{
 
988
        rs_store_set_show_filenames(rs->store, gtk_toggle_action_get_active(toggleaction));
 
989
        rs_conf_set_boolean(CONF_SHOW_FILENAMES, gtk_toggle_action_get_active(toggleaction));
 
990
}
 
991
 
 
992
TOGGLEACTION(load_8bit)
 
993
{
 
994
        rs_conf_set_boolean(CONF_LOAD_GDK, gtk_toggle_action_get_active(toggleaction));
 
995
}
 
996
 
588
997
TOGGLEACTION(fullscreen)
589
998
{
590
999
        if (gtk_toggle_action_get_active(toggleaction))
591
1000
        {
 
1001
                rs->window_fullscreen = TRUE;
592
1002
                gtk_window_fullscreen(GTK_WINDOW(rs->window));
593
 
                rs_conf_set_boolean(CONF_FULLSCREEN, TRUE);
594
1003
        }
595
1004
        else
596
1005
        {
 
1006
                rs->window_fullscreen = FALSE;
597
1007
                gtk_window_unfullscreen(GTK_WINDOW(rs->window));
598
 
                rs_conf_set_boolean(CONF_FULLSCREEN, FALSE);
 
1008
        }
 
1009
        rs_conf_set_boolean(CONF_FULLSCREEN, rs->window_fullscreen);
 
1010
 
 
1011
        /* Update Toolox and Iconbox */
 
1012
        gui_fullscreen_changed(rs->iconbox, rs->window_fullscreen, "Iconbox",
 
1013
                                                                                                 DEFAULT_CONF_SHOW_ICONBOX_FULLSCREEN, DEFAULT_CONF_SHOW_ICONBOX,
 
1014
                                                                                                 CONF_SHOW_ICONBOX_FULLSCREEN, CONF_SHOW_ICONBOX);
 
1015
        gui_fullscreen_changed(rs->toolbox, rs->window_fullscreen, "Toolbox",
 
1016
                                                                                                 DEFAULT_CONF_SHOW_TOOLBOX_FULLSCREEN, DEFAULT_CONF_SHOW_TOOLBOX,
 
1017
                                                                                                 CONF_SHOW_TOOLBOX_FULLSCREEN, CONF_SHOW_TOOLBOX);
 
1018
        rs_core_action_group_set_sensivity("Lightsout", !rs->window_fullscreen);
 
1019
}
 
1020
 
 
1021
TOGGLEACTION(fullscreen_preview)
 
1022
{
 
1023
        if (gtk_toggle_action_get_active(toggleaction))
 
1024
        {
 
1025
                rs_core_action_group_set_sensivity("Lightsout", FALSE);
 
1026
                gui_select_preview_screen(rs);
 
1027
        }
 
1028
        else
 
1029
        {
 
1030
                gui_disable_preview_screen(rs);
 
1031
                rs_core_action_group_set_sensivity("Lightsout", !rs->window_fullscreen);
599
1032
        }
600
1033
}
601
1034
 
608
1041
        rs_preview_widget_set_show_exposure_mask(RS_PREVIEW_WIDGET(rs->preview), gtk_toggle_action_get_active(toggleaction));
609
1042
}
610
1043
 
 
1044
TOGGLEACTION(load_selected)
 
1045
{
 
1046
        gtk_toggle_action_set_active(toggleaction, !rs_store_set_open_selected(rs->store, !gtk_toggle_action_get_active(toggleaction)));
 
1047
}
611
1048
TOGGLEACTION(split)
612
1049
{
613
1050
        rs_preview_widget_set_split(RS_PREVIEW_WIDGET(rs->preview), gtk_toggle_action_get_active(toggleaction));
614
1051
}
615
1052
 
 
1053
#if GTK_CHECK_VERSION(2,12,0)
 
1054
TOGGLEACTION(lightsout)
 
1055
{
 
1056
        rs_preview_widget_set_lightsout(RS_PREVIEW_WIDGET(rs->preview), gtk_toggle_action_get_active(toggleaction));
 
1057
}
 
1058
#endif
 
1059
 
616
1060
ACTION(add_to_batch)
617
1061
{
618
1062
        GString *gs = g_string_new("");
619
1063
        GList *selected = NULL;
620
 
        gint num_selected, cur;
 
1064
        gint num_selected, cur, num_added = 0;
 
1065
 
 
1066
        gui_set_busy(TRUE);
 
1067
        guint msg = gui_status_push(_("Adding images to batch queue"));
 
1068
        GTK_CATCHUP();
621
1069
 
622
1070
        selected = rs_store_get_selected_names(rs->store);
623
1071
        num_selected = g_list_length(selected);
624
1072
 
625
 
        if (RS_IS_PHOTO(rs->photo) && num_selected == 1)
 
1073
        if (RS_IS_PHOTO(rs->photo) && rs_store_is_photo_selected(rs->store, rs->photo->filename))
626
1074
        {
627
1075
                rs_cache_save(rs->photo, MASK_ALL);
628
1076
 
629
1077
                if (rs_batch_add_to_queue(rs->queue, rs->photo->filename, rs->current_setting))
630
 
                        g_string_printf(gs, _(" %s added to batch queue"), rs->photo->filename);
631
 
                else
632
 
                        g_string_printf(gs, _("%s already added to batch queue"), rs->photo->filename);
633
 
        }
634
 
        else
635
 
        {
636
 
                /* Deal with selected icons */
637
 
                for(cur=0;cur<num_selected;cur++)
638
 
                        rs_batch_add_to_queue(rs->queue, g_list_nth_data(selected, cur), rs->current_setting);
639
 
                g_string_printf(gs, _("%d photos added to batch queue"), num_selected);
640
 
        }
 
1078
                        num_added++;
 
1079
        }
 
1080
        /* Deal with selected icons */
 
1081
        for(cur=0;cur<num_selected;cur++)
 
1082
                if (rs_batch_add_to_queue(rs->queue, g_list_nth_data(selected, cur), rs->current_setting))
 
1083
                        num_added++;
 
1084
        g_string_printf(gs, _("%d photos added to batch queue"), num_added);
 
1085
 
641
1086
        g_list_free(selected);
642
1087
        gui_status_notify(gs->str);
643
1088
        g_string_free(gs, TRUE);
 
1089
        rs_core_actions_update_menu_items(rs);
 
1090
 
 
1091
        gui_set_busy(FALSE);
 
1092
        gui_status_pop(msg);
644
1093
}
645
1094
 
646
1095
ACTION(add_view_to_batch)
684
1133
                GList *selected = NULL;
685
1134
                gint num_selected, i;
686
1135
 
687
 
                rs_store_get_names(rs->store, NULL, &selected, NULL);
 
1136
                gui_set_busy(TRUE);
 
1137
                rs_store_get_names(rs->store, &selected, NULL, NULL);
688
1138
                selected = rs_store_sort_selected(selected);
689
1139
                num_selected = g_list_length(selected);
690
1140
 
 
1141
                if (0 == num_selected && RS_IS_PHOTO(rs->photo))
 
1142
                {
 
1143
                        selected = g_list_append(selected, g_strdup(rs->photo->filename));
 
1144
                        num_selected++;
 
1145
                }
 
1146
 
691
1147
                for (i=0;i<num_selected;i++)
692
1148
                {
693
1149
                        gchar *fullname = g_list_nth_data(selected, i);
713
1169
                        + ((gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb_b))) ? num_selected : 0)
714
1170
                        + ((gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb_c))) ? num_selected : 0));
715
1171
 
 
1172
                gui_set_busy(FALSE);
716
1173
                gui_status_notify(gs->str);
717
1174
        }
718
1175
 
719
1176
        gtk_widget_destroy (dialog);
720
1177
        g_string_free(gs, TRUE);
 
1178
        rs_core_actions_update_menu_items(rs);
721
1179
}
722
1180
 
723
1181
ACTION(remove_from_batch)
724
1182
{
725
 
        /* FIXME: Deal with mutiple selected photos! */
726
 
        if (RS_IS_PHOTO(rs->photo))
 
1183
        GList *selected = NULL;
 
1184
        GString *gs = g_string_new("");
 
1185
        gint num_selected, i, num_removed = 0;
 
1186
 
 
1187
        gui_set_busy(TRUE);
 
1188
        guint msg = gui_status_push(_("Removing images from batch queue"));
 
1189
        GTK_CATCHUP();
 
1190
 
 
1191
        rs_store_get_names(rs->store, &selected, NULL, NULL);
 
1192
        selected = rs_store_sort_selected(selected);
 
1193
        num_selected = g_list_length(selected);
 
1194
 
 
1195
        for (i=0;i<num_selected;i++)
727
1196
        {
728
 
                if (rs_batch_remove_from_queue(rs->queue, rs->photo->filename, rs->current_setting))
729
 
                        gui_status_notify(_("Removed from batch queue"));
730
 
                else
731
 
                        gui_status_notify(_("Not in batch queue"));
 
1197
                gchar *fullname = g_list_nth_data(selected, i);
 
1198
                if (rs_batch_remove_from_queue(rs->queue, fullname, rs->current_setting))
 
1199
                        num_removed++;
732
1200
        }
 
1201
        g_list_foreach(selected, (GFunc) g_free, NULL);
 
1202
        g_list_free(selected);
 
1203
        g_string_printf(gs, _("%d photos removed from batch queue"), num_removed);
 
1204
        gui_set_busy(FALSE);
 
1205
        gui_status_pop(msg);
 
1206
        gui_status_notify(gs->str);
 
1207
        g_string_free(gs, TRUE);
 
1208
}
 
1209
 
 
1210
/* This is protected by gdk_thread */
 
1211
static GThread* process_thread = 0;
 
1212
 
 
1213
static gpointer
 
1214
start_process_batch(gpointer data)
 
1215
{
 
1216
        RS_QUEUE *queue = data;
 
1217
 
 
1218
        rs_batch_process(queue);
 
1219
 
 
1220
        gdk_threads_enter();
 
1221
        process_thread = NULL;
 
1222
        gdk_threads_leave();
 
1223
        return NULL;
733
1224
}
734
1225
 
735
1226
ACTION(ProcessBatch)
738
1229
        if (RS_IS_PHOTO(rs->photo))
739
1230
                rs_cache_save(rs->photo, MASK_ALL);
740
1231
 
741
 
        rs_batch_process(rs->queue);
 
1232
        if (NULL == process_thread)
 
1233
                        process_thread = g_thread_create_full(start_process_batch, rs->queue, 0, FALSE, FALSE, G_THREAD_PRIORITY_LOW, NULL);
 
1234
}
 
1235
 
 
1236
ACTION(lens_db_editor)
 
1237
{
 
1238
        rs_lens_db_editor();
 
1239
}
 
1240
 
 
1241
ACTION(tethered_shooting)
 
1242
{
 
1243
        rs_tethered_shooting_open(rs);
 
1244
}
 
1245
 
 
1246
ACTION(filter_graph)
 
1247
{
 
1248
        rs_filter_graph(rs->filter_input);
 
1249
}
 
1250
 
 
1251
ACTION(add_profile)
 
1252
{
 
1253
        GtkWidget *dialog = gtk_file_chooser_dialog_new(
 
1254
                _("Add Profile ..."),
 
1255
                rawstudio_window,
 
1256
                GTK_FILE_CHOOSER_ACTION_OPEN,
 
1257
                GTK_STOCK_CANCEL,
 
1258
                GTK_RESPONSE_CANCEL,
 
1259
                GTK_STOCK_OPEN,
 
1260
                GTK_RESPONSE_ACCEPT,
 
1261
                NULL);
 
1262
 
 
1263
        GtkFileFilter *filter_all = gtk_file_filter_new();
 
1264
 
 
1265
        GtkFileFilter *filter_profiles = gtk_file_filter_new();
 
1266
        gtk_file_filter_set_name(filter_profiles, _("All Profiles"));
 
1267
        gtk_file_filter_add_pattern(filter_profiles, "*.dcp");
 
1268
        gtk_file_filter_add_pattern(filter_profiles, "*.DCP");
 
1269
        gtk_file_filter_add_pattern(filter_profiles, "*.icc");
 
1270
        gtk_file_filter_add_pattern(filter_profiles, "*.ICC");
 
1271
        gtk_file_filter_add_pattern(filter_profiles, "*.icm");
 
1272
        gtk_file_filter_add_pattern(filter_profiles, "*.ICM");
 
1273
        gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter_profiles);
 
1274
 
 
1275
        GtkFileFilter *filter_dcp = gtk_file_filter_new();
 
1276
        gtk_file_filter_set_name(filter_dcp, _("Camera Profiles (DCP)"));
 
1277
        gtk_file_filter_add_pattern(filter_dcp, "*.dcp");
 
1278
        gtk_file_filter_add_pattern(filter_dcp, "*.DCP");
 
1279
        gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter_dcp);
 
1280
 
 
1281
        GtkFileFilter *filter_icc = gtk_file_filter_new();
 
1282
        gtk_file_filter_set_name(filter_icc, _("Color Profiles (ICC and ICM)"));
 
1283
        gtk_file_filter_add_pattern(filter_icc, "*.icc");
 
1284
        gtk_file_filter_add_pattern(filter_icc, "*.ICC");
 
1285
        gtk_file_filter_add_pattern(filter_icc, "*.icm");
 
1286
        gtk_file_filter_add_pattern(filter_icc, "*.ICM");
 
1287
        gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter_icc);
 
1288
 
 
1289
        gtk_file_filter_set_name(filter_all, _("All files"));
 
1290
        gtk_file_filter_add_pattern(filter_all, "*");
 
1291
        gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter_all);
 
1292
 
 
1293
        if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
 
1294
        {
 
1295
                RSProfileFactory *factory = rs_profile_factory_new_default();
 
1296
                gchar *path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
 
1297
                gchar *basename = g_path_get_basename(path);
 
1298
                const gchar *userdir = rs_profile_factory_get_user_profile_directory();
 
1299
                g_mkdir_with_parents(userdir, 00755);
 
1300
                gchar *new_path = g_build_filename(userdir, basename, NULL);
 
1301
 
 
1302
                if (rs_file_copy(path, new_path))
 
1303
                        rs_profile_factory_add_profile(factory, new_path);
 
1304
                g_free(path);
 
1305
                g_free(basename);
 
1306
                g_free(new_path);
 
1307
        }
 
1308
 
 
1309
        gtk_widget_destroy (dialog);
 
1310
}
 
1311
 
 
1312
ACTION(online_documentation)
 
1313
{
 
1314
        const gchar *link = "http://rawstudio.org/documentation/";
 
1315
 
 
1316
#ifdef WIN32
 
1317
#warning This is untested
 
1318
        gchar* argv[]= {
 
1319
                getenv("ComSpec"),
 
1320
                "/c",
 
1321
                "start",
 
1322
                "uri click", /* start needs explicit title incase link has spaces or quotes */
 
1323
                (gchar*) link,
 
1324
                NULL
 
1325
        };
 
1326
#else
 
1327
        gchar *argv[]= {
 
1328
                "gnome-open", /* this feels like cheating! */
 
1329
                (gchar *) link,
 
1330
                NULL
 
1331
                };
 
1332
#endif
 
1333
        GError *error = NULL;
 
1334
        gint status = 0;
 
1335
        gboolean res;
 
1336
 
 
1337
        res = g_spawn_sync(
 
1338
                NULL /*PWD*/,
 
1339
                argv,
 
1340
                NULL /*envp*/,
 
1341
                G_SPAWN_SEARCH_PATH, /*flags*/
 
1342
                NULL, /*setup_func*/
 
1343
                NULL, /*user data for setup*/
 
1344
                NULL,
 
1345
                NULL, /* stdin/out/error */
 
1346
                &status,
 
1347
                &error);
 
1348
 
 
1349
        if(!res)
 
1350
        {
 
1351
                g_error("%s: %s\n", g_quark_to_string(error->domain), error->message);
 
1352
                g_error_free(error);
 
1353
                return ;
 
1354
        }
742
1355
}
743
1356
 
744
1357
ACTION(about)
746
1359
        const static gchar *authors[] = {
747
1360
                "Anders Brander <anders@brander.dk>",
748
1361
                "Anders Kvist <anders@kvistmail.dk>",
 
1362
                "Klaus Post <klauspost@gmail.com>",
749
1363
                NULL
750
1364
        };
751
1365
        const static gchar *artists[] = {
753
1367
                "Rune Stowasser <rune.stowasser@gmail.com>",
754
1368
                NULL
755
1369
        };
 
1370
 
 
1371
        const static gchar *translators =
 
1372
                "Simone Contini\n"
 
1373
                "Paweł Gołaszewski\n"
 
1374
                "Alexandre Prokoudine\n"
 
1375
                "Jakub Friedl\n"
 
1376
                "Carsten Mathaes\n"
 
1377
                "Edouard Gomez\n"
 
1378
                "Martin Egger\n"
 
1379
                "Krzysztof Kościuszkiewicz\n"
 
1380
                "Einar Ryeng\n"
 
1381
                "Olli Hänninen\n"
 
1382
                "Carlos Dávila\n"
 
1383
                "Patrik Jarl\n"
 
1384
                "Olav Lavell\n"
 
1385
                "Rafael Sachetto Oliveira\n"
 
1386
                "Paco Rivière\n"
 
1387
                "Tuomas Haarala\n"
 
1388
                "Martin Nilsson\n"
 
1389
                "Ryo Fujita\n"
 
1390
                "Roman Schulz\n"
 
1391
                "Stian Grindvoll\n"
 
1392
                "Dariusz Duma";
 
1393
 
756
1394
        gtk_show_about_dialog(GTK_WINDOW(rawstudio_window),
 
1395
                "program-name", "Rawstudio",
757
1396
                "authors", authors,
758
1397
                "artists", artists,
759
 
                "translator-credits", "Simone Contini\nPaweł Gołaszewski\nAlexandre Prokoudine\nJakub Friedl\nCarsten Mathaes\nEdouard Gomez\nMartin Egger\nKrzysztof Kościuszkiewicz\nEinar Ryeng\nOlli Hänninen\nCarlos Dávila\nPatrik Jarl\nOlav Lavell\nRafael Sachetto Oliveira\nPaco Rivière",
 
1398
                "translator-credits", translators, 
760
1399
                "comments", _("A raw image converter for GTK+/GNOME"),
761
 
                "version", VERSION,
 
1400
                "version", RAWSTUDIO_VERSION,
762
1401
                "website", "http://rawstudio.org/",
763
1402
                "name", "Rawstudio",
764
1403
                NULL
786
1425
GtkActionGroup *
787
1426
rs_get_core_action_group(RS_BLOB *rs)
788
1427
{
 
1428
        gboolean show_filenames;
 
1429
        gboolean load_8bit = FALSE;
 
1430
 
 
1431
        rs_conf_get_boolean_with_default(CONF_SHOW_FILENAMES, &show_filenames, DEFAULT_CONF_SHOW_FILENAMES);
 
1432
        rs_conf_get_boolean_with_default(CONF_LOAD_GDK, &load_8bit, FALSE);
 
1433
 
789
1434
        /* FIXME: This should be static */
790
1435
        GtkActionEntry actionentries[] = {
791
1436
        { "FileMenu", NULL, _("_File"), NULL, NULL, ACTION_CB(file_menu) },
793
1438
        { "PhotoMenu", NULL, _("_Photo"), NULL, NULL, ACTION_CB(photo_menu) },
794
1439
        { "PriorityMenu", NULL, _("_Set Priority") },
795
1440
        { "WhiteBalanceMenu", "NULL", _("_White Balance") },
796
 
        { "ViewMenu", NULL, _("_View") },
 
1441
        { "ViewMenu", NULL, _("_View"), NULL, NULL, ACTION_CB(view_menu) },
797
1442
        { "SortByMenu", NULL, _("_Sort by") },
798
1443
        { "BatchMenu", NULL, _("_Batch"), NULL, NULL, ACTION_CB(batch_menu) },
799
1444
        { "HelpMenu", NULL, _("_Help") },
800
1445
        { "PreviewPopup", NULL, NULL, NULL, NULL, ACTION_CB(preview_popup) },
 
1446
        { "SnapshotMenu", NULL, _("_Snapshot") },
801
1447
 
802
1448
        /* File menu */
803
1449
        { "Open", GTK_STOCK_OPEN, _("_Open Directory"), "<control>O", NULL, ACTION_CB(open) },
804
1450
        { "QuickExport", GTK_STOCK_SAVE, _("_Quick Export"), "<control>S", NULL, ACTION_CB(quick_export) },
805
1451
        { "ExportAs", GTK_STOCK_SAVE_AS, _("_Export As"), "<control><shift>S", NULL, ACTION_CB(export_as) },
806
1452
        { "ExportToGimp", GTK_STOCK_EXECUTE, _("_Export to Gimp"), "<control>G", NULL, ACTION_CB(export_to_gimp) },
 
1453
        { "CopyImage", GTK_STOCK_COPY, _("_Copy Image to Clipboard"), "<control><shift>C", NULL, ACTION_CB(copy_image) },
807
1454
        { "Reload", GTK_STOCK_REFRESH, _("_Reload directory"), "<control>R", NULL, ACTION_CB(reload) },
808
1455
        { "DeleteFlagged", GTK_STOCK_DELETE, _("_Delete flagged photos"), "<control><shift>D", NULL, ACTION_CB(delete_flagged) },
809
1456
        { "Quit", GTK_STOCK_QUIT, _("_Quit"), "<control>Q", NULL, ACTION_CB(quit) },
813
1460
        { "CopySettings", GTK_STOCK_COPY, _("_Copy settings"), "<control>C", NULL, ACTION_CB(copy_settings) },
814
1461
        { "PasteSettings", GTK_STOCK_PASTE, _("_Paste settings"), "<control>V", NULL, ACTION_CB(paste_settings) },
815
1462
        { "ResetSettings", GTK_STOCK_REFRESH, _("_Reset settings"), NULL, NULL, ACTION_CB(reset_settings) },
 
1463
        { "SaveDefaultSettings", NULL, _("_Save camera default settings"), NULL, NULL, ACTION_CB(save_default_settings) },
816
1464
        { "Preferences", GTK_STOCK_PREFERENCES, _("_Preferences"), NULL, NULL, ACTION_CB(preferences) },
817
1465
 
818
1466
        /* Photo menu */
823
1471
        { "RemovePriority", NULL, _("_Remove priority"), "0", NULL, ACTION_CB(priority_0) },
824
1472
        { "AutoWB", NULL, _("_Auto"), "A", NULL, ACTION_CB(auto_wb) },
825
1473
        { "CameraWB", NULL, _("_Camera"), "C", NULL, ACTION_CB(camera_wb) },
826
 
        { "Crop", NULL, _("_Crop"), "<shift>C", NULL, ACTION_CB(crop) },
 
1474
        { "Crop", RS_STOCK_CROP, _("_Crop"), "<shift>C", NULL, ACTION_CB(crop) },
827
1475
        { "Uncrop", NULL, _("_Uncrop"), "<shift>V", NULL, ACTION_CB(uncrop) },
828
 
        { "Straighten", NULL, _("_Straighten"), NULL, NULL, ACTION_CB(straighten) },
 
1476
        { "Straighten", RS_STOCK_ROTATE, _("_Straighten"), NULL, NULL, ACTION_CB(straighten) },
829
1477
        { "Unstraighten", NULL, _("_Unstraighten"), NULL, NULL, ACTION_CB(unstraighten) },
830
1478
        { "Group", NULL, _("_Group"), NULL, NULL, ACTION_CB(group_photos) },
831
1479
        { "Ungroup", NULL, _("_Ungroup"), NULL, NULL, ACTION_CB(ungroup_photos) },
832
1480
        { "AutoGroup", NULL, _("_Auto group"), NULL, NULL, ACTION_CB(auto_group_photos) },
 
1481
        { "TagPhoto", NULL, _("_Tag Photo..."), "<alt>T", NULL, ACTION_CB(tag_photo) },
 
1482
        { "RotateClockwise", RS_STOCK_ROTATE_CLOCKWISE, _("Rotate Clockwise"), "<alt>Right", NULL, ACTION_CB(rotate_clockwise) },
 
1483
        { "RotateCounterClockwise", RS_STOCK_ROTATE_COUNTER_CLOCKWISE, _("Rotate Counter Clockwise"), "<alt>Left", NULL, ACTION_CB(rotate_counter_clockwise) },
 
1484
        { "Flip", RS_STOCK_FLIP, _("Flip"), NULL, NULL, ACTION_CB(flip) },
 
1485
        { "Mirror", RS_STOCK_MIRROR, _("Mirror"), NULL, NULL, ACTION_CB(mirror) },
833
1486
 
834
1487
        /* View menu */
835
1488
        { "PreviousPhoto", GTK_STOCK_GO_BACK, _("_Previous photo"), "<control>Left", NULL, ACTION_CB(previous_photo) },
836
1489
        { "NextPhoto", GTK_STOCK_GO_FORWARD, _("_Next Photo"), "<control>Right", NULL, ACTION_CB(next_photo) },
837
 
        { "ZommToFit", GTK_STOCK_ZOOM_FIT, _("_Zoom to fit"), "slash", NULL, ACTION_CB(zoom_to_fit) },
838
 
        { "ZoomTo100", GTK_STOCK_ZOOM_100, _("_Zoom to 100%"), "asterisk", NULL, ACTION_CB(zoom_to_100) },
839
 
 
 
1490
        { "LensDbEditor", NULL, _("_Lens Library"), "<control>L", NULL, ACTION_CB(lens_db_editor) },
 
1491
        { "TetheredShooting", NULL, _("_Tethered Shooting"), "F9", NULL, ACTION_CB(tethered_shooting) },
 
1492
        
840
1493
        /* Batch menu */
841
 
        { "AddToBatch", GTK_STOCK_ADD, _("_Add to batch queue"), "<control>B", NULL, ACTION_CB(add_to_batch) },
842
 
        { "AddViewToBatch", NULL, _("_Add current view to queue"), NULL, NULL, ACTION_CB(add_view_to_batch) },
843
 
        { "RemoveFromBatch", GTK_STOCK_REMOVE, _("_Remove from batch queue"), "<control><alt>B", NULL, ACTION_CB(remove_from_batch) },
 
1494
        { "AddToBatch", GTK_STOCK_ADD, _("_Add to batch queue"), "Insert", NULL, ACTION_CB(add_to_batch) },
 
1495
        { "AddViewToBatch", NULL, _("_Add view to queue..."), "<control>Insert", NULL, ACTION_CB(add_view_to_batch) },
 
1496
        { "RemoveFromBatch", GTK_STOCK_REMOVE, _("_Remove from batch queue"), "<control>Delete", NULL, ACTION_CB(remove_from_batch) },
844
1497
        { "ProcessBatch", GTK_STOCK_EXECUTE, _("_Start"), NULL, NULL, ACTION_CB(ProcessBatch) },
845
1498
 
846
1499
        /* help menu */
 
1500
        { "OnlineDocumentation", GTK_STOCK_HELP, _("_Online Documentation"), NULL, NULL, ACTION_CB(online_documentation) },
847
1501
        { "About", GTK_STOCK_ABOUT, _("_About"), NULL, NULL, ACTION_CB(about) },
 
1502
        { "FilterGraph", NULL, "_Filter Graph", NULL, NULL, ACTION_CB(filter_graph) },
 
1503
 
 
1504
        /* Not in any menu (yet) */
 
1505
        { "AddProfile", NULL, _("Add Profile ..."), NULL, NULL, ACTION_CB(add_profile) },
848
1506
        };
849
1507
        static guint n_actionentries = G_N_ELEMENTS (actionentries);
850
1508
 
851
1509
        GtkToggleActionEntry toggleentries[] = {
 
1510
        { "ZommToFit", GTK_STOCK_ZOOM_FIT, _("_Zoom to fit"), "asterisk", NULL, ACTION_CB(zoom_to_fit), TRUE },
852
1511
        { "Iconbox", NULL, _("_Iconbox"), "<control>I", NULL, ACTION_CB(iconbox), TRUE },
853
1512
        { "Toolbox", NULL, _("_Toolbox"), "<control>T", NULL, ACTION_CB(toolbox), TRUE },
854
1513
        { "Fullscreen", GTK_STOCK_FULLSCREEN, _("_Fullscreen"), "F11", NULL, ACTION_CB(fullscreen), FALSE },
 
1514
        { "FullscreenPreview", GTK_STOCK_FULLSCREEN, _("_Show Photo On Secondary Monitor"), "F10", NULL, ACTION_CB(fullscreen_preview), FALSE },
 
1515
        { "ShowFilenames", NULL, _("Show Filenames in Iconbox"), NULL, NULL, ACTION_CB(show_filenames), show_filenames },
 
1516
        { "Load8Bit", NULL, _("Load non-RAW images"), NULL, NULL, ACTION_CB(load_8bit), load_8bit },
 
1517
        { "LoadSelected", NULL, _("Do not Load Selected Images"), "Pause", NULL, ACTION_CB(load_selected), FALSE },
855
1518
        { "ExposureMask", NULL, _("_Exposure mask"), "<control>E", NULL, ACTION_CB(exposure_mask), FALSE },
856
 
        { "Split", NULL, _("_Split"), NULL, NULL, ACTION_CB(split), FALSE },
 
1519
        { "Split", NULL, _("_Split"), "<control>D", NULL, ACTION_CB(split), FALSE },
 
1520
#if GTK_CHECK_VERSION(2,12,0)
 
1521
        { "Lightsout", NULL, _("_Lights out"), "F12", NULL, ACTION_CB(lightsout), FALSE },
 
1522
#endif
857
1523
        };
858
1524
        static guint n_toggleentries = G_N_ELEMENTS (toggleentries);
859
1525
 
923
1589
        if (core_action_group)
924
1590
                gtk_action_set_visible(gtk_action_group_get_action(core_action_group, name), visible);
925
1591
}
 
1592
 
 
1593
/**
 
1594
 * Add actions to global action group, see documentation for gtk_action_group_add_actions
 
1595
 */
 
1596
void
 
1597
rs_core_action_group_add_actions(const GtkActionEntry *entries, guint n_entries, gpointer user_data)
 
1598
{
 
1599
        g_static_mutex_lock(&rs_actions_spinlock);
 
1600
        
 
1601
        if (core_action_group)
 
1602
                gtk_action_group_add_actions(core_action_group, entries, n_entries, user_data);
 
1603
        else
 
1604
                g_warning("core_action_group is NULL");
 
1605
        g_static_mutex_unlock(&rs_actions_spinlock);
 
1606
}
 
1607
 
 
1608
/**
 
1609
 * Add radio action to global action group, see documentation for gtk_action_group_add_radio_actions()
 
1610
 */
 
1611
void
 
1612
rs_core_action_group_add_radio_actions(const GtkRadioActionEntry *entries, guint n_entries, gint value, GCallback on_change, gpointer user_data)
 
1613
{
 
1614
        g_static_mutex_lock(&rs_actions_spinlock);
 
1615
        
 
1616
        if (core_action_group)
 
1617
                gtk_action_group_add_radio_actions(core_action_group, entries, n_entries, value, on_change, user_data);
 
1618
        else
 
1619
                g_warning("core_action_group is NULL");
 
1620
        g_static_mutex_unlock(&rs_actions_spinlock);
 
1621
}
 
1622
 
 
1623
/**
 
1624
 * Get a GtkAction by name
 
1625
 * @param name The name of the action
 
1626
 * @return A GtkAction or NULL (should not be unreffed)
 
1627
 */
 
1628
extern GtkAction *
 
1629
rs_core_action_group_get_action(const gchar *name)
 
1630
{
 
1631
        GtkAction *action = NULL;
 
1632
 
 
1633
        g_static_mutex_lock(&rs_actions_spinlock);
 
1634
 
 
1635
        if (core_action_group)
 
1636
                action = gtk_action_group_get_action(core_action_group, name);
 
1637
        else
 
1638
                g_warning("core_action_group is NULL");
 
1639
 
 
1640
        g_static_mutex_unlock(&rs_actions_spinlock);
 
1641
 
 
1642
        return action;
 
1643
}