1 /* Widgets for the Midnight Commander
3 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
4 2004, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
6 Authors: 1994, 1995 Radek Doulik
7 1994, 1995 Miguel de Icaza
11 2009, 2010 Andrew Borodin
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
30 * \brief Source: save, load and show history
39 #include <sys/types.h>
43 #include "lib/global.h"
45 #include "lib/tty/tty.h" /* LINES, COLS */
46 #include "lib/mcconfig.h" /* for history loading and saving */
47 #include "lib/fileloc.h"
48 #include "lib/strutil.h"
49 #include "lib/util.h" /* list_append_unique */
50 #include "lib/widget.h"
52 /* TODO: these includes should be removed! */
53 #include "src/setup.h" /* num_history_items_recorded */
55 /*** global variables ****************************************************************************/
57 int num_history_items_recorded
= 60;
59 /*** file scope macro definitions ****************************************************************/
61 /*** file scope type declarations ****************************************************************/
70 /*** file scope variables ************************************************************************/
72 /*** file scope functions ************************************************************************/
75 history_dlg_reposition (Dlg_head
* dlg_head
)
77 history_dlg_data
*data
;
81 if ((dlg_head
== NULL
) || (dlg_head
->data
== NULL
))
82 return MSG_NOT_HANDLED
;
84 data
= (history_dlg_data
*) dlg_head
->data
;
89 if (he
<= y
|| y
> (LINES
- 6))
97 he
= min (he
, LINES
- y
);
100 if (data
->widget
->x
> 2)
101 x
= data
->widget
->x
- 2;
103 wi
= data
->maxlen
+ 4;
111 dlg_set_position (dlg_head
, y
, x
, y
+ he
, x
+ wi
);
116 /* --------------------------------------------------------------------------------------------- */
119 history_dlg_callback (Dlg_head
* h
, Widget
* sender
, dlg_msg_t msg
, int parm
, void *data
)
124 return history_dlg_reposition (h
);
127 return default_dlg_callback (h
, sender
, msg
, parm
, data
);
131 /* --------------------------------------------------------------------------------------------- */
132 /*** public functions ****************************************************************************/
133 /* --------------------------------------------------------------------------------------------- */
136 This loads the history of an input line to the widget. It is called
137 with the widgets history name on creation of the widget, and returns
141 history_get (const char *input_name
)
149 GIConv conv
= INVALID_CONV
;
152 if (num_history_items_recorded
== 0) /* this is how to disable */
154 if ((input_name
== NULL
) || (*input_name
== '\0'))
157 profile
= g_build_filename (home_dir
, MC_USERCONF_DIR
, MC_HISTORY_FILE
, NULL
);
158 cfg
= mc_config_init (profile
);
160 /* get number of keys */
161 keys
= mc_config_get_keys (cfg
, input_name
, &keys_num
);
164 /* create charset conversion handler to convert strings
165 from utf-8 to system codepage */
167 conv
= str_crt_conv_from ("UTF-8");
169 buffer
= g_string_sized_new (64);
171 for (i
= 0; i
< keys_num
; i
++)
176 g_snprintf (key
, sizeof (key
), "%lu", (unsigned long) i
);
177 this_entry
= mc_config_get_string_raw (cfg
, input_name
, key
, "");
179 if (this_entry
== NULL
)
182 if (conv
== INVALID_CONV
)
183 hist
= list_append_unique (hist
, this_entry
);
186 g_string_set_size (buffer
, 0);
187 if (str_convert (conv
, this_entry
, buffer
) == ESTR_FAILURE
)
188 hist
= list_append_unique (hist
, this_entry
);
191 hist
= list_append_unique (hist
, g_strdup (buffer
->str
));
197 g_string_free (buffer
, TRUE
);
198 if (conv
!= INVALID_CONV
)
199 str_close_conv (conv
);
200 mc_config_deinit (cfg
);
203 /* return pointer to the last entry in the list */
204 return g_list_last (hist
);
207 /* --------------------------------------------------------------------------------------------- */
210 This saves the history of an input line from the widget. It is called
211 with the widgets history name. It stores histories in the file
212 ~/.mc/history in using the profile code.
215 history_put (const char *input_name
, GList
* h
)
220 GIConv conv
= INVALID_CONV
;
223 if (num_history_items_recorded
== 0) /* this is how to disable */
225 if ((input_name
== NULL
) || (*input_name
== '\0'))
230 profile
= g_build_filename (home_dir
, MC_USERCONF_DIR
, MC_HISTORY_FILE
, NULL
);
232 i
= open (profile
, O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
);
236 /* Make sure the history is only readable by the user */
237 if (chmod (profile
, S_IRUSR
| S_IWUSR
) == -1 && errno
!= ENOENT
)
243 /* go to end of list */
246 /* go back 60 places */
247 for (i
= 0; (i
< num_history_items_recorded
- 1) && (h
->prev
!= NULL
); i
++)
248 h
= g_list_previous (h
);
250 cfg
= mc_config_init (profile
);
252 if (input_name
!= NULL
)
253 mc_config_del_group (cfg
, input_name
);
255 /* create charset conversion handler to convert strings
256 from system codepage to UTF-8 */
258 conv
= str_crt_conv_to ("UTF-8");
260 buffer
= g_string_sized_new (64);
261 /* dump history into profile */
262 for (i
= 0; h
!= NULL
; h
= g_list_next (h
))
265 char *text
= (char *) h
->data
;
267 /* We shouldn't have null entries, but let's be sure */
271 g_snprintf (key
, sizeof (key
), "%d", i
++);
273 if (conv
== INVALID_CONV
)
274 mc_config_set_string_raw (cfg
, input_name
, key
, text
);
277 g_string_set_size (buffer
, 0);
278 if (str_convert (conv
, text
, buffer
) == ESTR_FAILURE
)
279 mc_config_set_string_raw (cfg
, input_name
, key
, text
);
281 mc_config_set_string_raw (cfg
, input_name
, key
, buffer
->str
);
285 g_string_free (buffer
, TRUE
);
286 if (conv
!= INVALID_CONV
)
287 str_close_conv (conv
);
288 mc_config_save_file (cfg
, NULL
);
289 mc_config_deinit (cfg
);
293 /* --------------------------------------------------------------------------------------------- */
296 history_show (GList
** history
, Widget
* widget
)
298 GList
*z
, *hlist
= NULL
, *hi
;
299 size_t maxlen
, i
, count
= 0;
302 WListbox
*query_list
;
303 history_dlg_data hist_data
;
305 if (*history
== NULL
)
308 maxlen
= str_term_width1 (_("History")) + 2;
310 for (z
= *history
; z
!= NULL
; z
= g_list_previous (z
))
314 i
= str_term_width1 ((char *) z
->data
);
315 maxlen
= max (maxlen
, i
);
318 entry
= g_new0 (WLEntry
, 1);
319 /* history is being reverted here */
320 entry
->text
= g_strdup ((char *) z
->data
);
321 hlist
= g_list_prepend (hlist
, entry
);
324 hist_data
.widget
= widget
;
325 hist_data
.count
= count
;
326 hist_data
.maxlen
= maxlen
;
329 create_dlg (TRUE
, 0, 0, 4, 4, dialog_colors
, history_dlg_callback
,
330 "[History-query]", _("History"), DLG_COMPACT
);
331 query_dlg
->data
= &hist_data
;
333 query_list
= listbox_new (1, 1, 2, 2, TRUE
, NULL
);
335 /* this call makes list stick to all sides of dialog, effectively make
336 it be resized with dialog */
337 add_widget_autopos (query_dlg
, query_list
, WPOS_KEEP_ALL
);
339 /* to avoid diplicating of (calculating sizes in two places)
340 code, call dlg_hist_callback function here, to set dialog and
342 The main idea - create 4x4 dialog and add 2x2 list in
343 center of it, and let dialog function resize it to needed
345 history_dlg_callback (query_dlg
, NULL
, DLG_RESIZE
, 0, NULL
);
347 if (query_dlg
->y
< widget
->y
)
349 /* draw list entries from bottom upto top */
350 listbox_set_list (query_list
, hlist
);
351 listbox_select_last (query_list
);
355 /* draw list entries from top downto bottom */
356 /* revert history direction */
357 hlist
= g_list_reverse (hlist
);
358 listbox_set_list (query_list
, hlist
);
361 if (run_dlg (query_dlg
) != B_CANCEL
)
365 listbox_get_current (query_list
, &q
, NULL
);
370 /* get modified history from dialog */
372 for (hi
= query_list
->list
; hi
!= NULL
; hi
= g_list_next (hi
))
376 entry
= (WLEntry
*) hi
->data
;
377 /* history is being reverted here again */
378 z
= g_list_prepend (z
, entry
->text
);
382 /* restore history direction */
383 if (query_dlg
->y
< widget
->y
)
384 z
= g_list_reverse (z
);
386 destroy_dlg (query_dlg
);
388 g_list_foreach (*history
, (GFunc
) g_free
, NULL
);
389 g_list_free (*history
);
390 *history
= g_list_last (z
);
395 /* --------------------------------------------------------------------------------------------- */