2 * Copyright (C) 2008 - 2016 The Geeqie Team
4 * Authors: John Ellis, Vladimir Nadvornik, Laurent Monin
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "history_list.h"
24 #include "secure_save.h"
25 #include "ui_fileops.h"
29 *-----------------------------------------------------------------------------
30 * Implements a history chain. Used by the Back and Forward toolbar buttons.
31 * Selecting any folder appends the path to the end of the chain.
32 * Pressing the Back and Forward buttons moves along the chain, but does
33 * not make additions to the chain.
34 * The chain always increases and is deleted at the end of the session
35 *-----------------------------------------------------------------------------
38 static GList *history_chain = NULL;
39 static guint chain_index = G_MAXUINT;
40 static gboolean nav_button = FALSE; /** Used to prevent the nav buttons making entries to the chain **/
42 const gchar *history_chain_back()
46 chain_index = chain_index > 0 ? chain_index - 1 : 0;
48 return g_list_nth_data(history_chain, chain_index);
51 const gchar *history_chain_forward()
54 guint last = g_list_length(history_chain) - 1;
56 chain_index = chain_index < last ? chain_index + 1 : last;
58 return g_list_nth_data(history_chain, chain_index);
62 * @brief Appends a path to the history chain
63 * @param path Path selected
65 * Each time the user selects a new path it is appended to the chain
66 * except when it is identical to the current last entry
67 * The pointer is always moved to the end of the chain
69 void history_chain_append_end(const gchar *path)
75 if(chain_index == G_MAXUINT)
77 history_chain = g_list_append (history_chain, g_strdup(path));
82 work = g_list_last(history_chain);
83 if (g_strcmp0(work->data , path) != 0)
85 history_chain = g_list_append (history_chain, g_strdup(path));
86 chain_index = g_list_length(history_chain) - 1;
87 DEBUG_3("%d %s", chain_index, path);
91 chain_index = g_list_length(history_chain) - 1;
102 *-----------------------------------------------------------------------------
103 * Implements an image history chain. Whenever an image is displayed it is
104 * appended to a chain.
105 * Pressing the Image Back and Image Forward buttons moves along the chain,
106 * but does not make additions to the chain.
107 * The chain always increases and is deleted at the end of the session
108 *-----------------------------------------------------------------------------
110 static GList *image_chain = NULL;
111 static guint image_chain_index = G_MAXUINT;
112 static gboolean image_nav_button = FALSE; /** Used to prevent the nav buttons making entries to the chain **/
113 const gchar *image_chain_back()
115 image_nav_button = TRUE;
117 image_chain_index = image_chain_index > 0 ? image_chain_index - 1 : 0;
119 return g_list_nth_data(image_chain, image_chain_index);
122 const gchar *image_chain_forward()
124 image_nav_button= TRUE;
125 guint last = g_list_length(image_chain) - 1;
127 image_chain_index = image_chain_index < last ? image_chain_index + 1 : last;
129 return g_list_nth_data(image_chain, image_chain_index);
133 * @brief Appends a path to the image history chain
134 * @param path Image path selected
136 * Each time the user selects a new image it is appended to the chain
137 * except when it is identical to the current last entry
138 * The pointer is always moved to the end of the chain
140 void image_chain_append_end(const gchar *path)
144 if (!image_nav_button)
146 if(image_chain_index == G_MAXUINT)
148 image_chain = g_list_append(image_chain, g_strdup(path));
149 image_chain_index = 0;
153 work = g_list_last(image_chain);
156 if (g_strcmp0(work->data , path) != 0)
158 image_chain = g_list_append(image_chain, g_strdup(path));
159 image_chain_index = g_list_length(image_chain) - 1;
160 DEBUG_3("%d %s", image_chain_index, path);
164 image_chain_index = g_list_length(image_chain) - 1;
170 image_nav_button = FALSE;
175 *-----------------------------------------------------------------------------
177 *-----------------------------------------------------------------------------
180 #define HISTORY_DEFAULT_KEY_COUNT 16
183 typedef struct _HistoryData HistoryData;
190 static GList *history_list = NULL;
193 static gchar *quoted_from_text(const gchar *text)
197 gint l = strlen(text);
199 if (l == 0) return NULL;
201 while (c < l && text[c] !='"') c++;
208 while (e < l && text[e] !='"') e++;
213 return g_strndup(ptr, e - c);
220 gboolean history_list_load(const gchar *path)
227 pathl = path_from_utf8(path);
228 f = fopen(pathl, "r");
230 if (!f) return FALSE;
232 /* first line must start with History comment */
233 if (!fgets(s_buf, sizeof(s_buf), f) ||
234 strncmp(s_buf, "#History", 8) != 0)
240 while (fgets(s_buf, sizeof(s_buf), f))
242 if (s_buf[0]=='#') continue;
250 while (ptr[c] != ']' && ptr[c] != '\n' && ptr[c] != '\0') c++;
253 key = g_strndup(ptr, c);
259 value = quoted_from_text(s_buf);
262 history_list_add_to_key(key, value, 0);
275 gboolean history_list_save(const gchar *path)
282 pathl = path_from_utf8(path);
283 ssi = secure_open(pathl);
287 log_printf(_("Unable to write history lists to: %s\n"), path);
291 secure_fprintf(ssi, "#History lists\n\n");
293 list = g_list_last(history_list);
294 while (list && secsave_errno == SS_ERR_NONE)
302 secure_fprintf(ssi, "[%s]\n", hd->key);
304 /* save them inverted (oldest to newest)
305 * so that when reading they are added correctly
307 work = g_list_last(hd->list);
308 list_count = g_list_position(hd->list, g_list_last(hd->list)) + 1;
309 while (work && secsave_errno == SS_ERR_NONE)
311 if ((!(strcmp(hd->key, "path_list") == 0 && list_count > options->open_recent_list_maxsize)) && (!(strcmp(hd->key, "recent") == 0 && (!isfile(work->data)))))
313 secure_fprintf(ssi, "\"%s\"\n", (gchar *)work->data);
318 secure_fputc(ssi, '\n');
321 secure_fprintf(ssi, "#end\n");
323 return (secure_close(ssi) == 0);
326 static void history_list_free(HistoryData *hd)
343 static HistoryData *history_list_find_by_key(const gchar *key)
345 GList *work = history_list;
347 if (!key) return NULL;
351 HistoryData *hd = work->data;
352 if (strcmp(hd->key, key) == 0) return hd;
358 const gchar *history_list_find_last_path_by_key(const gchar *key)
362 hd = history_list_find_by_key(key);
363 if (!hd || !hd->list) return NULL;
365 return hd->list->data;
368 void history_list_free_key(const gchar *key)
371 hd = history_list_find_by_key(key);
374 history_list = g_list_remove(history_list, hd);
375 history_list_free(hd);
378 void history_list_add_to_key(const gchar *key, const gchar *path, gint max)
383 if (!key || !path) return;
385 hd = history_list_find_by_key(key);
388 hd = g_new(HistoryData, 1);
389 hd->key = g_strdup(key);
391 history_list = g_list_prepend(history_list, hd);
394 /* if already in the list, simply move it to the top */
398 gchar *buf = work->data;
400 if (strcmp(buf, path) == 0)
402 /* if not first, move it */
403 if (work != hd->list)
405 hd->list = g_list_remove(hd->list, buf);
406 hd->list = g_list_prepend(hd->list, buf);
413 hd->list = g_list_prepend(hd->list, g_strdup(path));
415 if (max == -1) max = HISTORY_DEFAULT_KEY_COUNT;
419 GList *work = hd->list;
430 while (work && len > max)
436 hd->list = g_list_delete_link(hd->list, node);
442 void history_list_item_change(const gchar *key, const gchar *oldpath, const gchar *newpath)
447 if (!oldpath) return;
448 hd = history_list_find_by_key(key);
454 gchar *buf = work->data;
455 if (strcmp(buf, oldpath) == 0)
459 work->data = g_strdup(newpath);
463 hd->list = g_list_remove(hd->list, buf);
472 void history_list_item_move(const gchar *key, const gchar *path, gint direction)
479 hd = history_list_find_by_key(key);
485 gchar *buf = work->data;
486 if (strcmp(buf, path) == 0)
490 hd->list = g_list_remove(hd->list, buf);
491 hd->list = g_list_insert(hd->list, buf, p);
499 void history_list_item_remove(const gchar *key, const gchar *path)
501 history_list_item_change(key, path, NULL);
504 GList *history_list_get_by_key(const gchar *key)
508 hd = history_list_find_by_key(key);
509 if (!hd) return NULL;
513 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */