2 Widgets for the Midnight Commander
4 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
5 2004, 2005, 2006, 2007, 2009, 2010, 2011, 2012
6 The Free Software Foundation, Inc.
9 Radek Doulik, 1994, 1995
10 Miguel de Icaza, 1994, 1995
12 Andrej Borsenkow, 1996
14 Andrew Borodin <aborodin@vmail.ru>, 2009, 2010, 2011, 2012
16 This file is part of the Midnight Commander.
18 The Midnight Commander is free software: you can redistribute it
19 and/or modify it under the terms of the GNU General Public License as
20 published by the Free Software Foundation, either version 3 of the License,
21 or (at your option) any later version.
23 The Midnight Commander is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
28 You should have received a copy of the GNU General Public License
29 along with this program. If not, see <http://www.gnu.org/licenses/>.
33 * \brief Source: save, load and show history
42 #include <sys/types.h>
46 #include "lib/global.h"
48 #include "lib/tty/tty.h" /* LINES, COLS */
49 #include "lib/mcconfig.h" /* for history loading and saving */
50 #include "lib/fileloc.h"
51 #include "lib/strutil.h"
52 #include "lib/util.h" /* list_append_unique */
53 #include "lib/widget.h"
55 /*** global variables ****************************************************************************/
57 /* how much history items are used */
58 int num_history_items_recorded
= 60;
60 /*** file scope macro definitions ****************************************************************/
62 /*** file scope type declarations ****************************************************************/
71 /*** file scope variables ************************************************************************/
73 /*** file scope functions ************************************************************************/
76 history_dlg_reposition (WDialog
* dlg_head
)
78 history_dlg_data
*data
;
82 if ((dlg_head
== NULL
) || (dlg_head
->data
== NULL
))
83 return MSG_NOT_HANDLED
;
85 data
= (history_dlg_data
*) dlg_head
->data
;
90 if (he
<= y
|| y
> (LINES
- 6))
98 he
= min (he
, LINES
- y
);
101 if (data
->widget
->x
> 2)
102 x
= data
->widget
->x
- 2;
104 wi
= data
->maxlen
+ 4;
112 dlg_set_position (dlg_head
, y
, x
, y
+ he
, x
+ wi
);
117 /* --------------------------------------------------------------------------------------------- */
120 history_dlg_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
125 return history_dlg_reposition (DIALOG (w
));
128 return dlg_default_callback (w
, sender
, msg
, parm
, data
);
132 /* --------------------------------------------------------------------------------------------- */
133 /*** public functions ****************************************************************************/
134 /* --------------------------------------------------------------------------------------------- */
137 * Load the history from the ${XDG_CACHE_HOME}/mc/history file.
138 * It is called with the widgets history name and returns the GList list.
142 history_get (const char *input_name
)
148 if (num_history_items_recorded
== 0) /* this is how to disable */
150 if ((input_name
== NULL
) || (*input_name
== '\0'))
153 profile
= mc_config_get_full_path (MC_HISTORY_FILE
);
154 cfg
= mc_config_init (profile
, TRUE
);
156 hist
= history_load (cfg
, input_name
);
158 mc_config_deinit (cfg
);
164 /* --------------------------------------------------------------------------------------------- */
167 * Load history form the mc_config
170 history_load (struct mc_config_t
* cfg
, const char *name
)
176 GIConv conv
= INVALID_CONV
;
179 if (name
== NULL
|| *name
== '\0')
182 /* get number of keys */
183 keys
= mc_config_get_keys (cfg
, name
, &keys_num
);
186 /* create charset conversion handler to convert strings
187 from utf-8 to system codepage */
188 if (!mc_global
.utf8_display
)
189 conv
= str_crt_conv_from ("UTF-8");
191 buffer
= g_string_sized_new (64);
193 for (i
= 0; i
< keys_num
; i
++)
198 g_snprintf (key
, sizeof (key
), "%lu", (unsigned long) i
);
199 this_entry
= mc_config_get_string_raw (cfg
, name
, key
, "");
201 if (this_entry
== NULL
)
204 if (conv
== INVALID_CONV
)
205 hist
= list_append_unique (hist
, this_entry
);
208 g_string_set_size (buffer
, 0);
209 if (str_convert (conv
, this_entry
, buffer
) == ESTR_FAILURE
)
210 hist
= list_append_unique (hist
, this_entry
);
213 hist
= list_append_unique (hist
, g_strndup (buffer
->str
, buffer
->len
));
219 g_string_free (buffer
, TRUE
);
220 if (conv
!= INVALID_CONV
)
221 str_close_conv (conv
);
223 /* return pointer to the last entry in the list */
224 return g_list_last (hist
);
227 /* --------------------------------------------------------------------------------------------- */
230 * Save history to the mc_config, but don't save config to file
233 history_save (struct mc_config_t
*cfg
, const char *name
, GList
* h
)
235 GIConv conv
= INVALID_CONV
;
239 if (name
== NULL
|| *name
== '\0' || h
== NULL
)
242 /* go to end of list */
245 /* go back 60 places */
246 for (i
= 0; (i
< num_history_items_recorded
- 1) && (h
->prev
!= NULL
); i
++)
247 h
= g_list_previous (h
);
250 mc_config_del_group (cfg
, name
);
252 /* create charset conversion handler to convert strings
253 from system codepage to UTF-8 */
254 if (!mc_global
.utf8_display
)
255 conv
= str_crt_conv_to ("UTF-8");
257 buffer
= g_string_sized_new (64);
258 /* dump history into profile */
259 for (i
= 0; h
!= NULL
; h
= g_list_next (h
))
262 char *text
= (char *) h
->data
;
264 /* We shouldn't have null entries, but let's be sure */
268 g_snprintf (key
, sizeof (key
), "%d", i
++);
270 if (conv
== INVALID_CONV
)
271 mc_config_set_string_raw (cfg
, name
, key
, text
);
274 g_string_set_size (buffer
, 0);
275 if (str_convert (conv
, text
, buffer
) == ESTR_FAILURE
)
276 mc_config_set_string_raw (cfg
, name
, key
, text
);
278 mc_config_set_string_raw (cfg
, name
, key
, buffer
->str
);
282 g_string_free (buffer
, TRUE
);
283 if (conv
!= INVALID_CONV
)
284 str_close_conv (conv
);
287 /* --------------------------------------------------------------------------------------------- */
290 history_show (GList
** history
, Widget
* widget
, int current
)
292 GList
*z
, *hlist
= NULL
, *hi
;
293 size_t maxlen
, i
, count
= 0;
296 WListbox
*query_list
;
297 history_dlg_data hist_data
;
299 if (*history
== NULL
)
302 maxlen
= str_term_width1 (_("History")) + 2;
304 for (z
= *history
; z
!= NULL
; z
= g_list_previous (z
))
308 i
= str_term_width1 ((char *) z
->data
);
309 maxlen
= max (maxlen
, i
);
312 entry
= g_new0 (WLEntry
, 1);
313 /* history is being reverted here */
314 entry
->text
= g_strdup ((char *) z
->data
);
315 hlist
= g_list_prepend (hlist
, entry
);
318 hist_data
.widget
= widget
;
319 hist_data
.count
= count
;
320 hist_data
.maxlen
= maxlen
;
323 create_dlg (TRUE
, 0, 0, 4, 4, dialog_colors
, history_dlg_callback
, NULL
,
324 "[History-query]", _("History"), DLG_COMPACT
);
325 query_dlg
->data
= &hist_data
;
327 query_list
= listbox_new (1, 1, 2, 2, TRUE
, NULL
);
329 /* this call makes list stick to all sides of dialog, effectively make
330 it be resized with dialog */
331 add_widget_autopos (query_dlg
, query_list
, WPOS_KEEP_ALL
, NULL
);
333 /* to avoid diplicating of (calculating sizes in two places)
334 code, call dlg_hist_callback function here, to set dialog and
336 The main idea - create 4x4 dialog and add 2x2 list in
337 center of it, and let dialog function resize it to needed
339 send_message (query_dlg
, NULL
, MSG_RESIZE
, 0, NULL
);
341 if (WIDGET (query_dlg
)->y
< widget
->y
)
343 /* draw list entries from bottom upto top */
344 listbox_set_list (query_list
, hlist
);
345 if (current
< 0 || (size_t) current
>= count
)
346 listbox_select_last (query_list
);
348 listbox_select_entry (query_list
, count
- 1 - (size_t) current
);
352 /* draw list entries from top downto bottom */
353 /* revert history direction */
354 hlist
= g_list_reverse (hlist
);
355 listbox_set_list (query_list
, hlist
);
357 listbox_select_entry (query_list
, current
);
360 if (run_dlg (query_dlg
) != B_CANCEL
)
364 listbox_get_current (query_list
, &q
, NULL
);
368 /* get modified history from dialog */
370 for (hi
= query_list
->list
; hi
!= NULL
; hi
= g_list_next (hi
))
372 WLEntry
*entry
= LENTRY (hi
->data
);
374 /* history is being reverted here again */
375 z
= g_list_prepend (z
, entry
->text
);
379 /* restore history direction */
380 if (WIDGET (query_dlg
)->y
< widget
->y
)
381 z
= g_list_reverse (z
);
383 destroy_dlg (query_dlg
);
385 g_list_foreach (*history
, (GFunc
) g_free
, NULL
);
386 g_list_free (*history
);
387 *history
= g_list_last (z
);
392 /* --------------------------------------------------------------------------------------------- */