2 Widgets for the Midnight Commander
4 Copyright (C) 1994-2016
5 Free Software Foundation, Inc.
8 Radek Doulik, 1994, 1995
9 Miguel de Icaza, 1994, 1995
11 Andrej Borsenkow, 1996
13 Andrew Borodin <aborodin@vmail.ru>, 2009, 2010, 2011, 2012, 2013
15 This file is part of the Midnight Commander.
17 The Midnight Commander is free software: you can redistribute it
18 and/or modify it under the terms of the GNU General Public License as
19 published by the Free Software Foundation, either version 3 of the License,
20 or (at your option) any later version.
22 The Midnight Commander is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
27 You should have received a copy of the GNU General Public License
28 along with this program. If not, see <http://www.gnu.org/licenses/>.
32 * \brief Source: save, load and show history
41 #include <sys/types.h>
44 #include "lib/global.h"
46 #include "lib/tty/tty.h" /* LINES, COLS */
47 #include "lib/mcconfig.h" /* for history loading and saving */
48 #include "lib/fileloc.h"
49 #include "lib/strutil.h"
50 #include "lib/util.h" /* list_append_unique */
51 #include "lib/widget.h"
53 /*** global variables ****************************************************************************/
55 /* how much history items are used */
56 int num_history_items_recorded
= 60;
58 /*** file scope macro definitions ****************************************************************/
60 /*** file scope type declarations ****************************************************************/
69 /*** file scope variables ************************************************************************/
71 /*** file scope functions ************************************************************************/
74 history_dlg_reposition (WDialog
* dlg_head
)
76 history_dlg_data
*data
;
80 if ((dlg_head
== NULL
) || (dlg_head
->data
== NULL
))
81 return MSG_NOT_HANDLED
;
83 data
= (history_dlg_data
*) dlg_head
->data
;
88 if (he
<= y
|| y
> (LINES
- 6))
96 he
= min (he
, LINES
- y
);
99 if (data
->widget
->x
> 2)
100 x
= data
->widget
->x
- 2;
102 wi
= data
->maxlen
+ 4;
110 dlg_set_position (dlg_head
, y
, x
, y
+ he
, x
+ wi
);
115 /* --------------------------------------------------------------------------------------------- */
118 history_dlg_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
123 return history_dlg_reposition (DIALOG (w
));
126 return dlg_default_callback (w
, sender
, msg
, parm
, data
);
130 /* --------------------------------------------------------------------------------------------- */
131 /*** public functions ****************************************************************************/
132 /* --------------------------------------------------------------------------------------------- */
135 * Load the history from the ${XDG_CACHE_HOME}/mc/history file.
136 * It is called with the widgets history name and returns the GList list.
140 history_get (const char *input_name
)
146 if (num_history_items_recorded
== 0) /* this is how to disable */
148 if ((input_name
== NULL
) || (*input_name
== '\0'))
151 profile
= mc_config_get_full_path (MC_HISTORY_FILE
);
152 cfg
= mc_config_init (profile
, TRUE
);
154 hist
= history_load (cfg
, input_name
);
156 mc_config_deinit (cfg
);
162 /* --------------------------------------------------------------------------------------------- */
165 * Load history from the mc_config
168 history_load (mc_config_t
* cfg
, const char *name
)
174 GIConv conv
= INVALID_CONV
;
177 if (name
== NULL
|| *name
== '\0')
180 /* get number of keys */
181 keys
= mc_config_get_keys (cfg
, name
, &keys_num
);
184 /* create charset conversion handler to convert strings
185 from utf-8 to system codepage */
186 if (!mc_global
.utf8_display
)
187 conv
= str_crt_conv_from ("UTF-8");
189 buffer
= g_string_sized_new (64);
191 for (i
= 0; i
< keys_num
; i
++)
196 g_snprintf (key
, sizeof (key
), "%lu", (unsigned long) i
);
197 this_entry
= mc_config_get_string_raw (cfg
, name
, key
, "");
199 if (this_entry
== NULL
)
202 if (conv
== INVALID_CONV
)
203 hist
= list_append_unique (hist
, this_entry
);
206 g_string_set_size (buffer
, 0);
207 if (str_convert (conv
, this_entry
, buffer
) == ESTR_FAILURE
)
208 hist
= list_append_unique (hist
, this_entry
);
211 hist
= list_append_unique (hist
, g_strndup (buffer
->str
, buffer
->len
));
217 g_string_free (buffer
, TRUE
);
218 if (conv
!= INVALID_CONV
)
219 str_close_conv (conv
);
221 /* return pointer to the last entry in the list */
222 return g_list_last (hist
);
225 /* --------------------------------------------------------------------------------------------- */
228 * Save history to the mc_config, but don't save config to file
231 history_save (mc_config_t
* cfg
, const char *name
, GList
* h
)
233 GIConv conv
= INVALID_CONV
;
237 if (name
== NULL
|| *name
== '\0' || h
== NULL
)
240 /* go to end of list */
243 /* go back 60 places */
244 for (i
= 0; (i
< num_history_items_recorded
- 1) && (h
->prev
!= NULL
); i
++)
245 h
= g_list_previous (h
);
248 mc_config_del_group (cfg
, name
);
250 /* create charset conversion handler to convert strings
251 from system codepage to UTF-8 */
252 if (!mc_global
.utf8_display
)
253 conv
= str_crt_conv_to ("UTF-8");
255 buffer
= g_string_sized_new (64);
256 /* dump history into profile */
257 for (i
= 0; h
!= NULL
; h
= g_list_next (h
))
260 char *text
= (char *) h
->data
;
262 /* We shouldn't have null entries, but let's be sure */
266 g_snprintf (key
, sizeof (key
), "%d", i
++);
268 if (conv
== INVALID_CONV
)
269 mc_config_set_string_raw (cfg
, name
, key
, text
);
272 g_string_set_size (buffer
, 0);
273 if (str_convert (conv
, text
, buffer
) == ESTR_FAILURE
)
274 mc_config_set_string_raw (cfg
, name
, key
, text
);
276 mc_config_set_string_raw (cfg
, name
, key
, buffer
->str
);
280 g_string_free (buffer
, TRUE
);
281 if (conv
!= INVALID_CONV
)
282 str_close_conv (conv
);
285 /* --------------------------------------------------------------------------------------------- */
288 history_show (GList
** history
, Widget
* widget
, int current
)
290 GList
*z
, *hlist
= NULL
, *hi
;
291 size_t maxlen
, count
= 0;
294 WListbox
*query_list
;
295 history_dlg_data hist_data
;
297 if (*history
== NULL
)
300 maxlen
= str_term_width1 (_("History")) + 2;
302 for (z
= *history
; z
!= NULL
; z
= g_list_previous (z
))
307 i
= str_term_width1 ((char *) z
->data
);
308 maxlen
= max (maxlen
, i
);
311 entry
= g_new0 (WLEntry
, 1);
312 /* history is being reverted here */
313 entry
->text
= g_strdup ((char *) z
->data
);
314 hlist
= g_list_prepend (hlist
, entry
);
317 hist_data
.widget
= widget
;
318 hist_data
.count
= count
;
319 hist_data
.maxlen
= maxlen
;
322 dlg_create (TRUE
, 0, 0, 4, 4, dialog_colors
, history_dlg_callback
, NULL
,
323 "[History-query]", _("History"), DLG_COMPACT
);
324 query_dlg
->data
= &hist_data
;
326 query_list
= listbox_new (1, 1, 2, 2, TRUE
, NULL
);
328 /* this call makes list stick to all sides of dialog, effectively make
329 it be resized with dialog */
330 add_widget_autopos (query_dlg
, query_list
, WPOS_KEEP_ALL
, NULL
);
332 /* to avoid diplicating of (calculating sizes in two places)
333 code, call dlg_hist_callback function here, to set dialog and
335 The main idea - create 4x4 dialog and add 2x2 list in
336 center of it, and let dialog function resize it to needed
338 send_message (query_dlg
, NULL
, MSG_RESIZE
, 0, NULL
);
340 if (WIDGET (query_dlg
)->y
< widget
->y
)
342 /* draw list entries from bottom upto top */
343 listbox_set_list (query_list
, hlist
);
344 if (current
< 0 || (size_t) current
>= count
)
345 listbox_select_last (query_list
);
347 listbox_select_entry (query_list
, count
- 1 - (size_t) current
);
351 /* draw list entries from top downto bottom */
352 /* revert history direction */
353 hlist
= g_list_reverse (hlist
);
354 listbox_set_list (query_list
, hlist
);
356 listbox_select_entry (query_list
, current
);
359 if (dlg_run (query_dlg
) != B_CANCEL
)
363 listbox_get_current (query_list
, &q
, NULL
);
367 /* get modified history from dialog */
369 for (hi
= listbox_get_first_link (query_list
); hi
!= NULL
; hi
= g_list_next (hi
))
371 WLEntry
*entry
= LENTRY (hi
->data
);
373 /* history is being reverted here again */
374 z
= g_list_prepend (z
, entry
->text
);
378 /* restore history direction */
379 if (WIDGET (query_dlg
)->y
< widget
->y
)
380 z
= g_list_reverse (z
);
382 dlg_destroy (query_dlg
);
384 g_list_free_full (*history
, g_free
);
385 *history
= g_list_last (z
);
390 /* --------------------------------------------------------------------------------------------- */