<guimenu>Select</guimenu>\r
menu gives access to the marks operations of setting, filtering and intersection.\r
</para>\r
- <para>There are 6 individual marks, any of which can be associated with an image simply by pressing the 1 to 6 keys on the keyboard.</para>\r
+ <para>There are 10 individual marks, any of which can be associated with an image simply by pressing the 0 to 9 keys on the keyboard, where key 0 represents mark 10.</para>\r
<para>\r
If the\r
<guimenu>Show Marks</guimenu>\r
- menu has been selected, each image will have a set of 6 check-boxes displayed adjacent to it in the file pane in both icon and list mode. In addition a set of 6 check-boxes will be shown at the top of the files pane. Clicking any of these will filter the displayed list.\r
+ menu has been selected, each image will have a set of 10 check-boxes displayed adjacent to it in the file pane in both icon and list mode. In addition a set of 10 check-boxes will be shown at the top of the files pane. Clicking any of these will filter the displayed list.\r
</para>\r
<para>\r
If the\r
is being displayed, the currently set marks for the image are shown. It is not necessary to include an entry into the overlay template for this to happen.\r
</para>\r
<para>\r
- A keyword can be associated with a single mark by right-clicking on the keyword in the sidebar panel. When a meta-data write operation for a file is triggered either <link linkend="Buttons">manually</link> or as defined in\r
+ A keyword can be associated with a single mark by right-clicking on the keyword in the sidebar panel. When a meta-data write operation for a file is triggered either\r
+ <link linkend="Buttons">manually</link>\r
+ or as defined in\r
<link linkend="GuideOptionsMetadata" endterm="titleGuideOptionsMetadata" />\r
, the keyword data indicated by the current set of mark-to-keyword links will be written.\r
</para>\r
- <para>Neither marks, nor the associations between keywords and marks, are preserved when Geeqie is shut down.</para>\r
+ <para>\r
+ The associations between keywords and marks is preserved when Geeqie is shut down. The current setting of marks can also be optionally saved - the setting is in the\r
+ <link linkend="Behaviour">Behavior tab of Preferences</link>\r
+ .\r
+ </para>\r
<para />\r
<para />\r
</section>\r
<para>Displays marks in the file list</para>\r
</listitem>\r
</varlistentry>\r
+ <varlistentry>\r
+ <term>\r
+ <menuchoice>\r
+ <guimenu>Clear marks</guimenu>\r
+ </menuchoice>\r
+ </term>\r
+ <listitem>\r
+ <para>Clear all marks for all images</para>\r
+ <warning>\r
+ <para>Marks that are linked to keywords will also be cleared. This may result in a metadata write operation being triggered.</para>\r
+ </warning>\r
+ </listitem>\r
+ </varlistentry>\r
<varlistentry>\r
<term>\r
<menuchoice>\r
<para>If selected, a single click will enter a directory, rather than the GTK+ default of a double click.</para>\r
</listitem>\r
</varlistentry>\r
+ <varlistentry>\r
+ <term>\r
+ <guilabel>Save marks on exit</guilabel>\r
+ </term>\r
+ <listitem>\r
+ <para>Save all marks that have been set. Note that marks that are linked to a keyword will always be saved irrespective of this setting.</para>\r
+ </listitem>\r
+ </varlistentry>\r
<varlistentry>\r
<term>\r
<guilabel>Recent folder list maximum size</guilabel>\r
#include "metadata.h"
#include "trash.h"
#include "histogram.h"
+#include "secure_save.h"
#include "exif.h"
return TRUE;
}
+
+/*
+ *-----------------------------------------------------------------------------
+ * Saving marks list, clearing marks
+ * Uses file_data_pool
+ *-----------------------------------------------------------------------------
+ */
+
+static void marks_get_files(gpointer key, gpointer value, gpointer userdata)
+{
+ gchar *file_name = key;
+ GString *result = userdata;
+ FileData *fd;
+
+ if (isfile(file_name))
+ {
+ fd = value;
+ if (fd && fd->marks > 0)
+ {
+ g_string_append_printf(result, "%s,%i\n", fd->path, fd->marks);
+ }
+ }
+}
+
+gboolean marks_list_load(const gchar *path)
+{
+ FILE *f;
+ gchar s_buf[1024];
+ gchar *pathl;
+ gchar *file_path;
+ gchar *marks_value;
+
+ pathl = path_from_utf8(path);
+ f = fopen(pathl, "r");
+ g_free(pathl);
+ if (!f) return FALSE;
+
+ /* first line must start with Marks comment */
+ if (!fgets(s_buf, sizeof(s_buf), f) ||
+ strncmp(s_buf, "#Marks", 6) != 0)
+ {
+ fclose(f);
+ return FALSE;
+ }
+
+ while (fgets(s_buf, sizeof(s_buf), f))
+ {
+ if (s_buf[0]=='#') continue;
+ file_path = strtok(s_buf, ",");
+ marks_value = strtok(NULL, ",");
+ if (isfile(file_path))
+ {
+ FileData *fd = file_data_new_group(file_path);
+ file_data_ref(fd);
+ gint n = 0;
+ while (n <= 9)
+ {
+ gint mark_no = 1 << n;
+ if (atoi(marks_value) & mark_no)
+ {
+ file_data_set_mark(fd, n , 1);
+ }
+ n++;
+ }
+ }
+ }
+
+ fclose(f);
+ return TRUE;
+}
+
+gboolean marks_list_save(gchar *path, gboolean save)
+{
+ SecureSaveInfo *ssi;
+ gchar *pathl;
+ GString *marks = g_string_new("");
+
+ pathl = path_from_utf8(path);
+ ssi = secure_open(pathl);
+ g_free(pathl);
+ if (!ssi)
+ {
+ log_printf(_("Error: Unable to write marks lists to: %s\n"), path);
+ return FALSE;
+ }
+
+ secure_fprintf(ssi, "#Marks lists\n");
+
+ if (save)
+ {
+ g_hash_table_foreach(file_data_pool, marks_get_files, marks);
+ }
+ secure_fprintf(ssi, "%s", marks->str);
+ g_string_free(marks, FALSE);
+
+ secure_fprintf(ssi, "#end\n");
+ return (secure_close(ssi) == 0);
+}
+
+static void marks_clear(gpointer key, gpointer value, gpointer userdata)
+{
+ gchar *file_name = key;
+ gint mark_no;
+ gint n;
+ FileData *fd;
+
+ if (isfile(file_name))
+ {
+ fd = value;
+ if (fd && fd->marks > 0)
+ {
+ n = 0;
+ while (n <= 9)
+ {
+ mark_no = 1 << n;
+ if (fd->marks & mark_no)
+ {
+ file_data_set_mark(fd, n , 0);
+ }
+ n++;
+ }
+ }
+ }
+}
+
+void marks_clear_all()
+{
+ g_hash_table_foreach(file_data_pool, marks_clear, NULL);
+}
/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
void read_exif_time_data(FileData *file);
void read_exif_time_digitized_data(FileData *file);
+
+gboolean marks_list_save(gchar *path, gboolean clear);
+gboolean marks_list_load(const gchar *path);
+void marks_clear_all();
#endif
/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
return nw;
}
+
+static void clear_marks_cancel_cb(GenericDialog *gd, gpointer data)
+{
+ generic_dialog_close(gd);
+}
+
+static void clear_marks_help_cb(GenericDialog *gd, gpointer data)
+{
+ help_window_show("GuideMainWindowMenus.html");
+}
+
+void layout_menu_clear_marks_ok_cb(GenericDialog *gd, gpointer data)
+{
+ marks_clear_all();
+ generic_dialog_close(gd);
+}
+
+static void layout_menu_clear_marks_cb(GtkAction *action, gpointer data)
+{
+ GenericDialog *gd;
+
+ gd = generic_dialog_new(_("Clear Marks"),
+ "marks_clear", NULL, FALSE, clear_marks_cancel_cb, NULL);
+ generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, "Clear all marks?",
+ "This will clear all marks for all images,\nincluding those linked to keywords",
+ TRUE);
+ generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, layout_menu_clear_marks_ok_cb, TRUE);
+ generic_dialog_add_button(gd, GTK_STOCK_HELP, NULL,
+ clear_marks_help_cb, FALSE);
+
+ gtk_widget_show(gd->dialog);
+}
+
static void layout_menu_new_window_cb(GtkAction *action, gpointer data)
{
layout_menu_new_window(action, data);
{ "SplitDownPane", NULL, N_("_Down Pane"), "<alt>Down", N_("Down Pane"), CB(layout_menu_split_pane_updown_cb) },
{ "WriteRotation", NULL, N_("_Write orientation to file"), NULL, N_("Write orientation to file"), CB(layout_menu_write_rotate_cb) },
{ "WriteRotationKeepDate", NULL, N_("_Write orientation to file (preserve timestamp)"), NULL, N_("Write orientation to file (preserve timestamp)"), CB(layout_menu_write_rotate_keep_date_cb) },
-
+ { "ClearMarks", NULL, N_("Clear Marks..."), NULL, N_("Clear Marks"), CB(layout_menu_clear_marks_cb) },
};
static GtkToggleActionEntry menu_toggle_entries[] = {
" <placeholder name='ClipboardSection'/>"
" <separator/>"
" <menuitem action='ShowMarks'/>"
+" <menuitem action='ClearMarks'/>"
" <placeholder name='MarksSection'/>"
" <separator/>"
" </menu>"
*/
#define RC_HISTORY_NAME "history"
+#define RC_MARKS_NAME "marks"
static void setup_env_path(void)
{
g_free(path);
}
+static void marks_load(void)
+{
+ gchar *path;
+
+ path = g_build_filename(get_rc_dir(), RC_MARKS_NAME, NULL);
+ marks_list_load(path);
+ g_free(path);
+}
+
+static void marks_save(gboolean save)
+{
+ gchar *path;
+
+ path = g_build_filename(get_rc_dir(), RC_MARKS_NAME, NULL);
+ marks_list_save(path, save);
+ g_free(path);
+}
+
static void mkdir_if_not_exists(const gchar *path)
{
if (isdir(path)) return;
if (metadata_write_queue_confirm(FALSE, exit_program_write_metadata_cb, NULL)) return;
+ options->marks_save ? marks_save(TRUE) : marks_save(FALSE);
+
if (exit_confirm_dlg()) return;
exit_program_final();
remote_connection = remote_server_init(buf, cd);
g_free(buf);
+ marks_load();
+
DEBUG_1("%s main: gtk_main", get_exec_time());
gtk_main();
#ifdef HAVE_GTHREAD
options->fullscreen.disable_saver = TRUE;
options->fullscreen.screen = -1;
+ options->marks_save = TRUE;
+
memset(&options->image.border_color, 0, sizeof(options->image.border_color));
memset(&options->image.alpha_color_1, 0, sizeof(options->image.alpha_color_1));
memset(&options->image.alpha_color_2, 0, sizeof(options->image.alpha_color_2));
gint log_window_lines;
+ gboolean marks_save; // save marks on exit
+
/* info sidebar component heights */
struct {
gint height;
options->info_comment.height = c_options->info_comment.height;
options->info_rating.height = c_options->info_rating.height;
+ options->marks_save = c_options->marks_save;
+
#ifdef DEBUG
set_debug_level(debug_c);
#endif
GtkWidget *ct_button;
GtkWidget *spin;
GtkWidget *table;
+ GtkWidget *marks;
vbox = scrolled_notebook_page(notebook, _("Behavior"));
pref_checkbox_new_int(group, _("List directory view uses single click to enter"),
options->view_dir_list_single_click_enter, &c_options->view_dir_list_single_click_enter);
+ marks = pref_checkbox_new_int(group, _("Save marks on exit"),
+ options->marks_save, &c_options->marks_save);
+ gtk_widget_set_tooltip_text(marks,"Note that marks linked to a keyword will be saved irrespective of this setting");
+
pref_spin_new_int(group, _("Recent folder list maximum size"), NULL,
1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
WRITE_NL(); WRITE_UINT(*options, log_window_lines);
WRITE_NL(); WRITE_BOOL(*options, log_window.timer_data);
+ WRITE_NL(); WRITE_BOOL(*options, marks_save);
+
/* File operations Options */
WRITE_NL(); WRITE_BOOL(*options, file_ops.enable_in_place_rename);
WRITE_NL(); WRITE_BOOL(*options, file_ops.confirm_delete);
if (READ_INT(*options, log_window_lines)) continue;
if (READ_BOOL(*options, log_window.timer_data)) continue;
+ if (READ_BOOL(*options, marks_save)) continue;
+
/* Properties dialog options */
if (READ_CHAR(*options, properties.tabs_order)) continue;