Set WOP_TOP_SELECT options for panel widgets: WPanel, WView and WTree.
[midnight-commander.git] / src / filemanager / hotlist.c
blobf4e016e3802c120c21fe8693fd165f1d69090103
1 /*
2 Directory hotlist -- for the Midnight Commander
4 Copyright (C) 1994-2016
5 Free Software Foundation, Inc.
7 Written by:
8 Radek Doulik, 1994
9 Janne Kukonlehto, 1995
10 Andrej Borsenkow, 1996
11 Norbert Warmuth, 1997
12 Andrew Borodin <aborodin@vmail.ru>, 2012, 2013
14 Janne did the original Hotlist code, Andrej made the groupable
15 hotlist; the move hotlist and revamped the file format and made
16 it stronger.
18 This file is part of the Midnight Commander.
20 The Midnight Commander is free software: you can redistribute it
21 and/or modify it under the terms of the GNU General Public License as
22 published by the Free Software Foundation, either version 3 of the License,
23 or (at your option) any later version.
25 The Midnight Commander is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 GNU General Public License for more details.
30 You should have received a copy of the GNU General Public License
31 along with this program. If not, see <http://www.gnu.org/licenses/>.
34 /** \file hotlist.c
35 * \brief Source: directory hotlist
38 #include <config.h>
40 #include <ctype.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <unistd.h>
47 #include "lib/global.h"
49 #include "lib/tty/tty.h" /* COLS */
50 #include "lib/tty/key.h" /* KEY_M_CTRL */
51 #include "lib/skin.h" /* colors */
52 #include "lib/mcconfig.h" /* Load/save directories hotlist */
53 #include "lib/fileloc.h"
54 #include "lib/strutil.h"
55 #include "lib/vfs/vfs.h"
56 #include "lib/util.h"
57 #include "lib/widget.h"
59 #include "src/setup.h" /* For profile_bname */
60 #include "src/history.h"
62 #include "midnight.h" /* current_panel */
63 #include "command.h" /* cmdline */
65 #include "hotlist.h"
67 /*** global variables ****************************************************************************/
69 /*** file scope macro definitions ****************************************************************/
71 #define UX 3
72 #define UY 2
74 #define BX UX
75 #define BY (LINES - 6)
77 #define LABELS 3
78 #define B_ADD_CURRENT B_USER
79 #define B_REMOVE (B_USER + 1)
80 #define B_NEW_GROUP (B_USER + 2)
81 #define B_NEW_ENTRY (B_USER + 3)
82 #define B_ENTER_GROUP (B_USER + 4)
83 #define B_UP_GROUP (B_USER + 5)
84 #define B_INSERT (B_USER + 6)
85 #define B_APPEND (B_USER + 7)
86 #define B_MOVE (B_USER + 8)
87 #ifdef ENABLE_VFS
88 #define B_FREE_ALL_VFS (B_USER + 9)
89 #define B_REFRESH_VFS (B_USER + 10)
90 #endif
92 #define TKN_GROUP 0
93 #define TKN_ENTRY 1
94 #define TKN_STRING 2
95 #define TKN_URL 3
96 #define TKN_ENDGROUP 4
97 #define TKN_COMMENT 5
98 #define TKN_EOL 125
99 #define TKN_EOF 126
100 #define TKN_UNKNOWN 127
102 #define SKIP_TO_EOL \
104 int _tkn; \
105 while ((_tkn = hot_next_token ()) != TKN_EOF && _tkn != TKN_EOL) ; \
108 #define CHECK_TOKEN(_TKN_) \
109 tkn = hot_next_token (); \
110 if (tkn != _TKN_) \
112 hotlist_state.readonly = TRUE; \
113 hotlist_state.file_error = TRUE; \
114 while (tkn != TKN_EOL && tkn != TKN_EOF) \
115 tkn = hot_next_token (); \
116 break; \
119 /*** file scope type declarations ****************************************************************/
121 enum HotListType
123 HL_TYPE_GROUP,
124 HL_TYPE_ENTRY,
125 HL_TYPE_COMMENT,
126 HL_TYPE_DOTDOT
129 static struct
132 * these parameters are intended to be user configurable
134 int expanded; /* expanded view of all groups at startup */
137 * these reflect run time state
140 gboolean loaded; /* hotlist is loaded */
141 gboolean readonly; /* hotlist readonly */
142 gboolean file_error; /* parse error while reading file */
143 gboolean running; /* we are running dlg (and have to
144 update listbox */
145 gboolean moving; /* we are in moving hotlist currently */
146 gboolean modified; /* hotlist was modified */
147 hotlist_t type; /* LIST_HOTLIST || LIST_VFSLIST */
148 } hotlist_state;
150 /* Directory hotlist */
151 struct hotlist
153 enum HotListType type;
154 char *directory;
155 char *label;
156 struct hotlist *head;
157 struct hotlist *up;
158 struct hotlist *next;
161 /*** file scope variables ************************************************************************/
163 static gboolean hotlist_has_dot_dot = TRUE;
165 static WDialog *hotlist_dlg, *movelist_dlg;
166 static WGroupbox *hotlist_group, *movelist_group;
167 static WListbox *l_hotlist, *l_movelist;
168 static WLabel *pname;
170 static struct
172 int ret_cmd, flags, y, x, len;
173 const char *text;
174 int type;
175 widget_pos_flags_t pos_flags;
176 } hotlist_but[] =
178 /* *INDENT-OFF* */
179 { B_ENTER, DEFPUSH_BUTTON, 0, 0, 0, N_("Change &to"),
180 LIST_HOTLIST | LIST_VFSLIST | LIST_MOVELIST, WPOS_KEEP_LEFT | WPOS_KEEP_BOTTOM },
181 #ifdef ENABLE_VFS
182 { B_FREE_ALL_VFS, NORMAL_BUTTON, 0, 20, 0, N_("&Free VFSs now"),
183 LIST_VFSLIST, WPOS_KEEP_LEFT | WPOS_KEEP_BOTTOM },
184 { B_REFRESH_VFS, NORMAL_BUTTON, 0, 43, 0, N_("&Refresh"),
185 LIST_VFSLIST, WPOS_KEEP_LEFT | WPOS_KEEP_BOTTOM },
186 #endif
187 { B_ADD_CURRENT, NORMAL_BUTTON, 0, 20, 0, N_("&Add current"),
188 LIST_HOTLIST, WPOS_KEEP_LEFT | WPOS_KEEP_BOTTOM },
189 { B_UP_GROUP, NORMAL_BUTTON, 0, 42, 0, N_("&Up"),
190 LIST_HOTLIST | LIST_MOVELIST, WPOS_KEEP_LEFT | WPOS_KEEP_BOTTOM },
191 { B_CANCEL, NORMAL_BUTTON, 0, 53, 0, N_("&Cancel"),
192 LIST_HOTLIST | LIST_VFSLIST | LIST_MOVELIST, WPOS_KEEP_RIGHT | WPOS_KEEP_BOTTOM },
193 { B_NEW_GROUP, NORMAL_BUTTON, 1, 0, 0, N_("New &group"),
194 LIST_HOTLIST, WPOS_KEEP_LEFT | WPOS_KEEP_BOTTOM },
195 { B_NEW_ENTRY, NORMAL_BUTTON, 1, 15, 0, N_("New &entry"),
196 LIST_HOTLIST, WPOS_KEEP_LEFT | WPOS_KEEP_BOTTOM },
197 { B_INSERT, NORMAL_BUTTON, 1, 0, 0, N_("&Insert"),
198 LIST_MOVELIST, WPOS_KEEP_LEFT | WPOS_KEEP_BOTTOM },
199 { B_APPEND, NORMAL_BUTTON, 1, 15, 0, N_("A&ppend"),
200 LIST_MOVELIST, WPOS_KEEP_LEFT | WPOS_KEEP_BOTTOM },
201 { B_REMOVE, NORMAL_BUTTON, 1, 30, 0, N_("&Remove"),
202 LIST_HOTLIST, WPOS_KEEP_LEFT | WPOS_KEEP_BOTTOM },
203 { B_MOVE, NORMAL_BUTTON, 1, 42, 0, N_("&Move"),
204 LIST_HOTLIST, WPOS_KEEP_LEFT | WPOS_KEEP_BOTTOM }
205 /* *INDENT-ON* */
208 static const size_t hotlist_but_num = G_N_ELEMENTS (hotlist_but);
210 static struct hotlist *hotlist = NULL;
212 static struct hotlist *current_group;
214 static GString *tkn_buf = NULL;
216 static char *hotlist_file_name;
217 static FILE *hotlist_file;
218 static time_t hotlist_file_mtime;
220 static int list_level = 0;
222 /* --------------------------------------------------------------------------------------------- */
223 /*** file scope functions ************************************************************************/
224 /* --------------------------------------------------------------------------------------------- */
226 static void init_movelist (struct hotlist *item);
227 static void add_new_group_cmd (void);
228 static void add_new_entry_cmd (void);
229 static void remove_from_hotlist (struct hotlist *entry);
230 static void load_hotlist (void);
231 static void add_dotdot_to_list (void);
233 /* --------------------------------------------------------------------------------------------- */
234 /** If current->data is 0, then we are dealing with a VFS pathname */
236 static void
237 update_path_name (void)
239 const char *text = "";
240 char *p;
241 WListbox *list = hotlist_state.moving ? l_movelist : l_hotlist;
242 Widget *w = WIDGET (list);
244 if (!listbox_is_empty (list))
246 char *ctext = NULL;
247 void *cdata = NULL;
249 listbox_get_current (list, &ctext, &cdata);
250 if (cdata == NULL)
251 text = ctext;
252 else
254 struct hotlist *hlp = (struct hotlist *) cdata;
256 if (hlp->type == HL_TYPE_ENTRY || hlp->type == HL_TYPE_DOTDOT)
257 text = hlp->directory;
258 else if (hlp->type == HL_TYPE_GROUP)
259 text = _("Subgroup - press ENTER to see list");
263 p = g_strconcat (" ", current_group->label, " ", (char *) NULL);
264 if (hotlist_state.moving)
265 groupbox_set_title (movelist_group, str_trunc (p, w->cols - 2));
266 else
268 groupbox_set_title (hotlist_group, str_trunc (p, w->cols - 2));
269 label_set_text (pname, str_trunc (text, w->cols));
271 g_free (p);
274 /* --------------------------------------------------------------------------------------------- */
276 static void
277 fill_listbox (WListbox * list)
279 struct hotlist *current;
280 GString *buff;
282 buff = g_string_new ("");
284 for (current = current_group->head; current != NULL; current = current->next)
285 switch (current->type)
287 case HL_TYPE_GROUP:
289 /* buff clean up */
290 g_string_truncate (buff, 0);
291 g_string_append (buff, "->");
292 g_string_append (buff, current->label);
293 listbox_add_item (list, LISTBOX_APPEND_AT_END, 0, buff->str, current, FALSE);
295 break;
296 case HL_TYPE_DOTDOT:
297 case HL_TYPE_ENTRY:
298 listbox_add_item (list, LISTBOX_APPEND_AT_END, 0, current->label, current, FALSE);
299 default:
300 break;
303 g_string_free (buff, TRUE);
306 /* --------------------------------------------------------------------------------------------- */
308 static void
309 unlink_entry (struct hotlist *entry)
311 struct hotlist *current = current_group->head;
313 if (current == entry)
314 current_group->head = entry->next;
315 else
317 while (current != NULL && current->next != entry)
318 current = current->next;
319 if (current != NULL)
320 current->next = entry->next;
322 entry->next = entry->up = NULL;
325 /* --------------------------------------------------------------------------------------------- */
327 #ifdef ENABLE_VFS
328 static void
329 add_name_to_list (const char *path)
331 listbox_add_item (l_hotlist, LISTBOX_APPEND_AT_END, 0, path, NULL, FALSE);
333 #endif /* !ENABLE_VFS */
335 /* --------------------------------------------------------------------------------------------- */
337 static int
338 hotlist_run_cmd (int action)
340 switch (action)
342 case B_MOVE:
344 struct hotlist *saved = current_group;
345 struct hotlist *item = NULL;
346 struct hotlist *moveto_item = NULL;
347 struct hotlist *moveto_group = NULL;
348 int ret;
350 if (listbox_is_empty (l_hotlist))
351 return 0; /* empty group - nothing to do */
353 listbox_get_current (l_hotlist, NULL, (void **) &item);
354 init_movelist (item);
355 hotlist_state.moving = TRUE;
356 ret = dlg_run (movelist_dlg);
357 hotlist_state.moving = FALSE;
358 listbox_get_current (l_movelist, NULL, (void **) &moveto_item);
359 moveto_group = current_group;
360 dlg_destroy (movelist_dlg);
361 current_group = saved;
362 if (ret == B_CANCEL)
363 return 0;
364 if (moveto_item == item)
365 return 0; /* If we insert/append a before/after a
366 it hardly changes anything ;) */
367 unlink_entry (item);
368 listbox_remove_current (l_hotlist);
369 item->up = moveto_group;
370 if (moveto_group->head == NULL)
371 moveto_group->head = item;
372 else if (moveto_item == NULL)
373 { /* we have group with just comments */
374 struct hotlist *p = moveto_group->head;
376 /* skip comments */
377 while (p->next != NULL)
378 p = p->next;
379 p->next = item;
381 else if (ret == B_ENTER || ret == B_APPEND)
383 if (moveto_item->next == NULL)
384 moveto_item->next = item;
385 else
387 item->next = moveto_item->next;
388 moveto_item->next = item;
391 else if (moveto_group->head == moveto_item)
393 moveto_group->head = item;
394 item->next = moveto_item;
396 else
398 struct hotlist *p = moveto_group->head;
400 while (p->next != moveto_item)
401 p = p->next;
402 item->next = p->next;
403 p->next = item;
405 listbox_remove_list (l_hotlist);
406 fill_listbox (l_hotlist);
407 repaint_screen ();
408 hotlist_state.modified = TRUE;
409 return 0;
411 case B_REMOVE:
413 struct hotlist *entry = NULL;
415 listbox_get_current (l_hotlist, NULL, (void **) &entry);
416 remove_from_hotlist (entry);
418 return 0;
420 case B_NEW_GROUP:
421 add_new_group_cmd ();
422 return 0;
424 case B_ADD_CURRENT:
425 add2hotlist_cmd ();
426 return 0;
428 case B_NEW_ENTRY:
429 add_new_entry_cmd ();
430 return 0;
432 case B_ENTER:
433 case B_ENTER_GROUP:
435 WListbox *list;
436 void *data;
437 struct hotlist *hlp;
439 list = hotlist_state.moving ? l_movelist : l_hotlist;
440 listbox_get_current (list, NULL, &data);
442 if (data == NULL)
443 return 1;
445 hlp = (struct hotlist *) data;
447 if (hlp->type == HL_TYPE_ENTRY)
448 return (action == B_ENTER ? 1 : 0);
449 if (hlp->type != HL_TYPE_DOTDOT)
451 listbox_remove_list (list);
452 current_group = hlp;
453 fill_listbox (list);
454 return 0;
456 /* Fall through - go up */
458 /* Fall through if list empty - just go up */
460 case B_UP_GROUP:
462 WListbox *list = hotlist_state.moving ? l_movelist : l_hotlist;
464 listbox_remove_list (list);
465 current_group = current_group->up;
466 fill_listbox (list);
467 return 0;
470 #ifdef ENABLE_VFS
471 case B_FREE_ALL_VFS:
472 vfs_expire (TRUE);
473 /* fall through */
475 case B_REFRESH_VFS:
476 listbox_remove_list (l_hotlist);
477 listbox_add_item (l_hotlist, LISTBOX_APPEND_AT_END, 0, mc_config_get_home_dir (), NULL,
478 FALSE);
479 vfs_fill_names (add_name_to_list);
480 return 0;
481 #endif /* ENABLE_VFS */
483 default:
484 return 1;
488 /* --------------------------------------------------------------------------------------------- */
490 static int
491 hotlist_button_callback (WButton * button, int action)
493 int ret;
495 (void) button;
496 ret = hotlist_run_cmd (action);
497 update_path_name ();
498 return ret;
501 /* --------------------------------------------------------------------------------------------- */
503 static inline cb_ret_t
504 hotlist_handle_key (WDialog * h, int key)
506 switch (key)
508 case KEY_M_CTRL | '\n':
509 goto l1;
511 case '\n':
512 case KEY_ENTER:
513 if (hotlist_button_callback (NULL, B_ENTER) != 0)
515 h->ret_value = B_ENTER;
516 dlg_stop (h);
518 return MSG_HANDLED;
520 case KEY_RIGHT:
521 /* enter to the group */
522 if (hotlist_state.type == LIST_VFSLIST)
523 return MSG_NOT_HANDLED;
524 return hotlist_button_callback (NULL, B_ENTER_GROUP) == 0 ? MSG_HANDLED : MSG_NOT_HANDLED;
526 case KEY_LEFT:
527 /* leave the group */
528 if (hotlist_state.type == LIST_VFSLIST)
529 return MSG_NOT_HANDLED;
530 return hotlist_button_callback (NULL, B_UP_GROUP) == 0 ? MSG_HANDLED : MSG_NOT_HANDLED;
532 case KEY_DC:
533 if (hotlist_state.moving)
534 return MSG_NOT_HANDLED;
535 hotlist_button_callback (NULL, B_REMOVE);
536 return MSG_HANDLED;
539 case ALT ('\n'):
540 case ALT ('\r'):
541 if (!hotlist_state.moving)
543 void *ldata = NULL;
545 listbox_get_current (l_hotlist, NULL, &ldata);
547 if (ldata != NULL)
549 struct hotlist *hlp = (struct hotlist *) ldata;
551 if (hlp->type == HL_TYPE_ENTRY)
553 char *tmp;
555 tmp = g_strconcat ("cd ", hlp->directory, (char *) NULL);
556 input_insert (cmdline, tmp, FALSE);
557 g_free (tmp);
558 h->ret_value = B_CANCEL;
559 dlg_stop (h);
563 return MSG_HANDLED; /* ignore key */
565 default:
566 return MSG_NOT_HANDLED;
570 /* --------------------------------------------------------------------------------------------- */
572 static cb_ret_t
573 hotlist_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
575 WDialog *h = DIALOG (w);
577 switch (msg)
579 case MSG_INIT:
580 case MSG_NOTIFY: /* MSG_NOTIFY is fired by the listbox to tell us the item has changed. */
581 update_path_name ();
582 return MSG_HANDLED;
584 case MSG_UNHANDLED_KEY:
585 return hotlist_handle_key (h, parm);
587 case MSG_POST_KEY:
588 /* always stay on hotlist */
589 dlg_select_widget (h == hotlist_dlg ? l_hotlist : l_movelist);
590 return MSG_HANDLED;
592 case MSG_RESIZE:
593 /* simply call dlg_set_size() with new size */
594 dlg_set_size (h, LINES - (h == hotlist_dlg ? 2 : 6), COLS - 6);
595 return MSG_HANDLED;
597 default:
598 return dlg_default_callback (w, sender, msg, parm, data);
602 /* --------------------------------------------------------------------------------------------- */
604 static lcback_ret_t
605 hotlist_listbox_callback (WListbox * list)
607 WDialog *dlg = WIDGET (list)->owner;
609 if (!listbox_is_empty (list))
611 void *data = NULL;
613 listbox_get_current (list, NULL, &data);
615 if (data != NULL)
617 struct hotlist *hlp = (struct hotlist *) data;
619 if (hlp->type == HL_TYPE_ENTRY)
621 dlg->ret_value = B_ENTER;
622 dlg_stop (dlg);
623 return LISTBOX_DONE;
625 else
627 hotlist_button_callback (NULL, B_ENTER);
628 send_message (dlg, NULL, MSG_POST_KEY, '\n', NULL);
629 return LISTBOX_CONT;
632 else
634 dlg->ret_value = B_ENTER;
635 dlg_stop (dlg);
636 return LISTBOX_DONE;
640 hotlist_button_callback (NULL, B_UP_GROUP);
641 send_message (dlg, NULL, MSG_POST_KEY, 'u', NULL);
642 return LISTBOX_CONT;
645 /* --------------------------------------------------------------------------------------------- */
647 * Expands all button names (once) and recalculates button positions.
648 * returns number of columns in the dialog box, which is 10 chars longer
649 * then buttonbar.
651 * If common width of the window (i.e. in xterm) is less than returned
652 * width - sorry :) (anyway this did not handled in previous version too)
655 static int
656 init_i18n_stuff (int list_type, int cols)
658 size_t i;
660 static gboolean i18n_flag = FALSE;
662 if (!i18n_flag)
664 for (i = 0; i < hotlist_but_num; i++)
666 #ifdef ENABLE_NLS
667 hotlist_but[i].text = _(hotlist_but[i].text);
668 #endif /* ENABLE_NLS */
669 hotlist_but[i].len = str_term_width1 (hotlist_but[i].text) + 3;
670 if (hotlist_but[i].flags == DEFPUSH_BUTTON)
671 hotlist_but[i].len += 2;
674 i18n_flag = TRUE;
677 /* Dynamic resizing of buttonbars */
679 int len[2], count[2]; /* at most two lines of buttons */
680 int cur_x[2];
682 len[0] = len[1] = 0;
683 count[0] = count[1] = 0;
684 cur_x[0] = cur_x[1] = 0;
686 /* Count len of buttonbars, assuming 1 extra space between buttons */
687 for (i = 0; i < hotlist_but_num; i++)
688 if ((hotlist_but[i].type & list_type) != 0)
690 int row;
692 row = hotlist_but[i].y;
693 ++count[row];
694 len[row] += hotlist_but[i].len + 1;
697 (len[0])--;
698 (len[1])--;
700 cols = MAX (cols, MAX (len[0], len[1]));
702 /* arrange buttons */
703 for (i = 0; i < hotlist_but_num; i++)
704 if ((hotlist_but[i].type & list_type) != 0)
706 int row;
708 row = hotlist_but[i].y;
710 if (hotlist_but[i].x != 0)
712 /* not first int the row */
713 if (hotlist_but[i].ret_cmd == B_CANCEL)
714 hotlist_but[i].x = cols - hotlist_but[i].len - 6;
715 else
716 hotlist_but[i].x = cur_x[row];
719 cur_x[row] += hotlist_but[i].len + 1;
723 return cols;
726 /* --------------------------------------------------------------------------------------------- */
728 static void
729 init_hotlist (hotlist_t list_type)
731 size_t i;
732 const char *title, *help_node;
733 int lines, cols;
734 int y;
735 int dh = 0;
736 WGroupbox *path_box;
737 Widget *hotlist_widget;
739 do_refresh ();
741 lines = LINES - 2;
742 cols = init_i18n_stuff (list_type, COLS - 6);
744 hotlist_state.expanded =
745 mc_config_get_int (mc_global.main_config, "HotlistConfig", "expanded_view_of_groups", 0);
747 #ifdef ENABLE_VFS
748 if (list_type == LIST_VFSLIST)
750 title = _("Active VFS directories");
751 help_node = "[vfshot]"; /* FIXME - no such node */
752 dh = 1;
754 else
755 #endif /* !ENABLE_VFS */
757 title = _("Directory hotlist");
758 help_node = "[Hotlist]";
761 hotlist_dlg =
762 dlg_create (TRUE, 0, 0, lines, cols, WPOS_CENTER, FALSE, dialog_colors, hotlist_callback,
763 NULL, help_node, title);
765 y = UY;
766 hotlist_group = groupbox_new (y, UX, lines - 10 + dh, cols - 2 * UX, _("Top level group"));
767 hotlist_widget = WIDGET (hotlist_group);
768 add_widget_autopos (hotlist_dlg, hotlist_widget, WPOS_KEEP_ALL, NULL);
770 l_hotlist =
771 listbox_new (y + 1, UX + 1, hotlist_widget->lines - 2, hotlist_widget->cols - 2, FALSE,
772 hotlist_listbox_callback);
774 /* Fill the hotlist with the active VFS or the hotlist */
775 #ifdef ENABLE_VFS
776 if (list_type == LIST_VFSLIST)
778 listbox_add_item (l_hotlist, LISTBOX_APPEND_AT_END, 0, mc_config_get_home_dir (), NULL,
779 FALSE);
780 vfs_fill_names (add_name_to_list);
782 else
783 #endif /* !ENABLE_VFS */
784 fill_listbox (l_hotlist);
786 /* insert before groupbox to view scrollbar */
787 add_widget_autopos (hotlist_dlg, l_hotlist, WPOS_KEEP_ALL, NULL);
789 y += hotlist_widget->lines;
791 path_box = groupbox_new (y, UX, 3, hotlist_widget->cols, _("Directory path"));
792 add_widget_autopos (hotlist_dlg, path_box, WPOS_KEEP_BOTTOM | WPOS_KEEP_HORZ, NULL);
794 pname = label_new (y + 1, UX + 2, "");
795 add_widget_autopos (hotlist_dlg, pname, WPOS_KEEP_BOTTOM | WPOS_KEEP_LEFT, NULL);
796 y += WIDGET (path_box)->lines;
798 add_widget_autopos (hotlist_dlg, hline_new (y++, -1, -1), WPOS_KEEP_BOTTOM, NULL);
800 for (i = 0; i < hotlist_but_num; i++)
801 if ((hotlist_but[i].type & list_type) != 0)
802 add_widget_autopos (hotlist_dlg,
803 button_new (y + hotlist_but[i].y, UX + hotlist_but[i].x,
804 hotlist_but[i].ret_cmd, hotlist_but[i].flags,
805 hotlist_but[i].text, hotlist_button_callback),
806 hotlist_but[i].pos_flags, NULL);
808 dlg_select_widget (l_hotlist);
811 /* --------------------------------------------------------------------------------------------- */
813 static void
814 init_movelist (struct hotlist *item)
816 size_t i;
817 char *hdr;
818 int lines, cols;
819 int y;
820 Widget *movelist_widget;
822 do_refresh ();
824 lines = LINES - 6;
825 cols = init_i18n_stuff (LIST_MOVELIST, COLS - 6);
827 hdr = g_strdup_printf (_("Moving %s"), item->label);
829 movelist_dlg =
830 dlg_create (TRUE, 0, 0, lines, cols, WPOS_CENTER, FALSE, dialog_colors, hotlist_callback,
831 NULL, "[Hotlist]", hdr);
833 g_free (hdr);
835 y = UY;
836 movelist_group = groupbox_new (y, UX, lines - 7, cols - 2 * UX, _("Directory label"));
837 movelist_widget = WIDGET (movelist_group);
838 add_widget_autopos (movelist_dlg, movelist_widget, WPOS_KEEP_ALL, NULL);
840 l_movelist =
841 listbox_new (y + 1, UX + 1, movelist_widget->lines - 2, movelist_widget->cols - 2, FALSE,
842 hotlist_listbox_callback);
843 fill_listbox (l_movelist);
844 /* insert before groupbox to view scrollbar */
845 add_widget_autopos (movelist_dlg, l_movelist, WPOS_KEEP_ALL, NULL);
847 y += movelist_widget->lines;
849 add_widget_autopos (movelist_dlg, hline_new (y++, -1, -1), WPOS_KEEP_BOTTOM, NULL);
851 for (i = 0; i < hotlist_but_num; i++)
852 if ((hotlist_but[i].type & LIST_MOVELIST) != 0)
853 add_widget_autopos (movelist_dlg,
854 button_new (y + hotlist_but[i].y, UX + hotlist_but[i].x,
855 hotlist_but[i].ret_cmd, hotlist_but[i].flags,
856 hotlist_but[i].text, hotlist_button_callback),
857 hotlist_but[i].pos_flags, NULL);
859 dlg_select_widget (l_movelist);
862 /* --------------------------------------------------------------------------------------------- */
864 * Destroy the list dialog.
865 * Don't confuse with done_hotlist() for the list in memory.
868 static void
869 hotlist_done (void)
871 dlg_destroy (hotlist_dlg);
872 l_hotlist = NULL;
873 #if 0
874 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
875 #endif
876 repaint_screen ();
879 /* --------------------------------------------------------------------------------------------- */
881 static inline char *
882 find_group_section (struct hotlist *grp)
884 return g_strconcat (grp->directory, ".Group", (char *) NULL);
887 /* --------------------------------------------------------------------------------------------- */
889 static struct hotlist *
890 add2hotlist (char *label, char *directory, enum HotListType type, listbox_append_t pos)
892 struct hotlist *new;
893 struct hotlist *current = NULL;
896 * Hotlist is neither loaded nor loading.
897 * Must be called by "Ctrl-x a" before using hotlist.
899 if (current_group == NULL)
900 load_hotlist ();
902 listbox_get_current (l_hotlist, NULL, (void **) &current);
904 /* Make sure '..' stays at the top of the list. */
905 if ((current != NULL) && (current->type == HL_TYPE_DOTDOT))
906 pos = LISTBOX_APPEND_AFTER;
908 new = g_new0 (struct hotlist, 1);
910 new->type = type;
911 new->label = label;
912 new->directory = directory;
913 new->up = current_group;
915 if (type == HL_TYPE_GROUP)
917 current_group = new;
918 add_dotdot_to_list ();
919 current_group = new->up;
922 if (current_group->head == NULL)
924 /* first element in group */
925 current_group->head = new;
927 else if (pos == LISTBOX_APPEND_AFTER)
929 new->next = current->next;
930 current->next = new;
932 else if (pos == LISTBOX_APPEND_BEFORE && current == current_group->head)
934 /* should be inserted before first item */
935 new->next = current;
936 current_group->head = new;
938 else if (pos == LISTBOX_APPEND_BEFORE)
940 struct hotlist *p = current_group->head;
942 while (p->next != current)
943 p = p->next;
945 new->next = current;
946 p->next = new;
948 else
949 { /* append at the end */
950 struct hotlist *p = current_group->head;
952 while (p->next != NULL)
953 p = p->next;
955 p->next = new;
958 if (hotlist_state.running && type != HL_TYPE_COMMENT && type != HL_TYPE_DOTDOT)
960 if (type == HL_TYPE_GROUP)
962 char *lbl;
964 lbl = g_strconcat ("->", new->label, (char *) NULL);
965 listbox_add_item (l_hotlist, pos, 0, lbl, new, FALSE);
966 g_free (lbl);
968 else
969 listbox_add_item (l_hotlist, pos, 0, new->label, new, FALSE);
970 listbox_select_entry (l_hotlist, l_hotlist->pos);
973 return new;
976 /* --------------------------------------------------------------------------------------------- */
978 static int
979 add_new_entry_input (const char *header, const char *text1, const char *text2,
980 const char *help, char **r1, char **r2)
982 quick_widget_t quick_widgets[] = {
983 /* *INDENT-OFF* */
984 QUICK_LABELED_INPUT (text1, input_label_above, *r1, "input-lbl", r1, NULL,
985 FALSE, FALSE, INPUT_COMPLETE_NONE),
986 QUICK_SEPARATOR (FALSE),
987 QUICK_LABELED_INPUT (text2, input_label_above, *r2, "input-lbl", r2, NULL,
988 FALSE, FALSE, INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_CD),
989 QUICK_START_BUTTONS (TRUE, TRUE),
990 QUICK_BUTTON (N_("&Append"), B_APPEND, NULL, NULL),
991 QUICK_BUTTON (N_("&Insert"), B_INSERT, NULL, NULL),
992 QUICK_BUTTON (N_("&Cancel"), B_CANCEL, NULL, NULL),
993 QUICK_END
994 /* *INDENT-ON* */
997 quick_dialog_t qdlg = {
998 -1, -1, 64,
999 header, help,
1000 quick_widgets, NULL, NULL
1003 int ret;
1005 ret = quick_dialog (&qdlg);
1007 return (ret != B_CANCEL) ? ret : 0;
1010 /* --------------------------------------------------------------------------------------------- */
1012 static void
1013 add_new_entry_cmd (void)
1015 char *title, *url, *to_free;
1016 int ret;
1018 /* Take current directory as default value for input fields */
1019 to_free = title = url = vfs_path_to_str_flags (current_panel->cwd_vpath, 0, VPF_STRIP_PASSWORD);
1021 ret = add_new_entry_input (_("New hotlist entry"), _("Directory label:"),
1022 _("Directory path:"), "[Hotlist]", &title, &url);
1023 g_free (to_free);
1025 if (ret == 0)
1026 return;
1027 if (title == NULL || *title == '\0' || url == NULL || *url == '\0')
1029 g_free (title);
1030 g_free (url);
1031 return;
1034 if (ret == B_ENTER || ret == B_APPEND)
1035 add2hotlist (title, url, HL_TYPE_ENTRY, LISTBOX_APPEND_AFTER);
1036 else
1037 add2hotlist (title, url, HL_TYPE_ENTRY, LISTBOX_APPEND_BEFORE);
1039 hotlist_state.modified = TRUE;
1042 /* --------------------------------------------------------------------------------------------- */
1044 static int
1045 add_new_group_input (const char *header, const char *label, char **result)
1047 quick_widget_t quick_widgets[] = {
1048 /* *INDENT-OFF* */
1049 QUICK_LABELED_INPUT (label, input_label_above, "", "input", result, NULL,
1050 FALSE, FALSE, INPUT_COMPLETE_NONE),
1051 QUICK_START_BUTTONS (TRUE, TRUE),
1052 QUICK_BUTTON (N_("&Append"), B_APPEND, NULL, NULL),
1053 QUICK_BUTTON (N_("&Insert"), B_INSERT, NULL, NULL),
1054 QUICK_BUTTON (N_("&Cancel"), B_CANCEL, NULL, NULL),
1055 QUICK_END
1056 /* *INDENT-ON* */
1059 quick_dialog_t qdlg = {
1060 -1, -1, 64,
1061 header, "[Hotlist]",
1062 quick_widgets, NULL, NULL
1065 int ret;
1067 ret = quick_dialog (&qdlg);
1069 return (ret != B_CANCEL) ? ret : 0;
1072 /* --------------------------------------------------------------------------------------------- */
1074 static void
1075 add_new_group_cmd (void)
1077 char *label;
1078 int ret;
1080 ret = add_new_group_input (_("New hotlist group"), _("Name of new group:"), &label);
1081 if (ret == 0 || label == NULL || *label == '\0')
1082 return;
1084 if (ret == B_ENTER || ret == B_APPEND)
1085 add2hotlist (label, 0, HL_TYPE_GROUP, LISTBOX_APPEND_AFTER);
1086 else
1087 add2hotlist (label, 0, HL_TYPE_GROUP, LISTBOX_APPEND_BEFORE);
1089 hotlist_state.modified = TRUE;
1092 /* --------------------------------------------------------------------------------------------- */
1094 static void
1095 remove_group (struct hotlist *grp)
1097 struct hotlist *current = grp->head;
1099 while (current != NULL)
1101 struct hotlist *next = current->next;
1103 if (current->type == HL_TYPE_GROUP)
1104 remove_group (current);
1106 g_free (current->label);
1107 g_free (current->directory);
1108 g_free (current);
1110 current = next;
1114 /* --------------------------------------------------------------------------------------------- */
1116 static void
1117 remove_from_hotlist (struct hotlist *entry)
1119 if (entry == NULL)
1120 return;
1122 if (entry->type == HL_TYPE_DOTDOT)
1123 return;
1125 if (confirm_directory_hotlist_delete)
1127 char text[BUF_MEDIUM];
1128 int result;
1130 if (safe_delete)
1131 query_set_sel (1);
1133 g_snprintf (text, sizeof (text), _("Are you sure you want to remove entry \"%s\"?"),
1134 str_trunc (entry->label, 30));
1135 result = query_dialog (Q_ ("DialogTitle|Delete"), text, D_ERROR | D_CENTER, 2,
1136 _("&Yes"), _("&No"));
1137 if (result != 0)
1138 return;
1141 if (entry->type == HL_TYPE_GROUP)
1143 struct hotlist *head = entry->head;
1145 if (head != NULL && (head->type != HL_TYPE_DOTDOT || head->next != NULL))
1147 char text[BUF_MEDIUM];
1148 int result;
1150 g_snprintf (text, sizeof (text), _("Group \"%s\" is not empty.\nRemove it?"),
1151 str_trunc (entry->label, 30));
1152 result = query_dialog (Q_ ("DialogTitle|Delete"), text, D_ERROR | D_CENTER, 2,
1153 _("&Yes"), _("&No"));
1154 if (result != 0)
1155 return;
1158 remove_group (entry);
1161 unlink_entry (entry);
1163 g_free (entry->label);
1164 g_free (entry->directory);
1165 g_free (entry);
1166 /* now remove list entry from screen */
1167 listbox_remove_current (l_hotlist);
1168 hotlist_state.modified = TRUE;
1171 /* --------------------------------------------------------------------------------------------- */
1173 static void
1174 load_group (struct hotlist *grp)
1176 gchar **profile_keys, **keys;
1177 char *group_section;
1178 struct hotlist *current = 0;
1180 group_section = find_group_section (grp);
1182 keys = mc_config_get_keys (mc_global.main_config, group_section, NULL);
1184 current_group = grp;
1186 for (profile_keys = keys; *profile_keys != NULL; profile_keys++)
1187 add2hotlist (mc_config_get_string (mc_global.main_config, group_section, *profile_keys, ""),
1188 g_strdup (*profile_keys), HL_TYPE_GROUP, LISTBOX_APPEND_AT_END);
1190 g_free (group_section);
1191 g_strfreev (keys);
1193 keys = mc_config_get_keys (mc_global.main_config, grp->directory, NULL);
1195 for (profile_keys = keys; *profile_keys != NULL; profile_keys++)
1196 add2hotlist (mc_config_get_string (mc_global.main_config, group_section, *profile_keys, ""),
1197 g_strdup (*profile_keys), HL_TYPE_ENTRY, LISTBOX_APPEND_AT_END);
1199 g_strfreev (keys);
1201 for (current = grp->head; current; current = current->next)
1202 load_group (current);
1205 /* --------------------------------------------------------------------------------------------- */
1207 static int
1208 hot_skip_blanks (void)
1210 int c;
1212 while ((c = getc (hotlist_file)) != EOF && c != '\n' && g_ascii_isspace (c))
1214 return c;
1217 /* --------------------------------------------------------------------------------------------- */
1219 static int
1220 hot_next_token (void)
1222 int c, ret = 0;
1223 size_t l;
1225 if (tkn_buf == NULL)
1226 tkn_buf = g_string_new ("");
1227 g_string_set_size (tkn_buf, 0);
1229 again:
1230 c = hot_skip_blanks ();
1231 switch (c)
1233 case EOF:
1234 ret = TKN_EOF;
1235 break;
1236 case '\n':
1237 ret = TKN_EOL;
1238 break;
1239 case '#':
1240 while ((c = getc (hotlist_file)) != EOF && c != '\n')
1241 g_string_append_c (tkn_buf, c);
1242 ret = TKN_COMMENT;
1243 break;
1244 case '"':
1245 while ((c = getc (hotlist_file)) != EOF && c != '"')
1247 if (c == '\\')
1249 c = getc (hotlist_file);
1250 if (c == EOF)
1252 g_string_free (tkn_buf, TRUE);
1253 return TKN_EOF;
1256 g_string_append_c (tkn_buf, c == '\n' ? ' ' : c);
1258 ret = (c == EOF) ? TKN_EOF : TKN_STRING;
1259 break;
1260 case '\\':
1261 c = getc (hotlist_file);
1262 if (c == EOF)
1264 g_string_free (tkn_buf, TRUE);
1265 return TKN_EOF;
1267 if (c == '\n')
1268 goto again;
1270 /* fall through; it is taken as normal character */
1272 default:
1275 g_string_append_c (tkn_buf, g_ascii_toupper (c));
1277 while ((c = fgetc (hotlist_file)) != EOF && (g_ascii_isalnum (c) || !isascii (c)));
1278 if (c != EOF)
1279 ungetc (c, hotlist_file);
1280 l = tkn_buf->len;
1281 if (strncmp (tkn_buf->str, "GROUP", l) == 0)
1282 ret = TKN_GROUP;
1283 else if (strncmp (tkn_buf->str, "ENTRY", l) == 0)
1284 ret = TKN_ENTRY;
1285 else if (strncmp (tkn_buf->str, "ENDGROUP", l) == 0)
1286 ret = TKN_ENDGROUP;
1287 else if (strncmp (tkn_buf->str, "URL", l) == 0)
1288 ret = TKN_URL;
1289 else
1290 ret = TKN_UNKNOWN;
1291 break;
1293 return ret;
1296 /* --------------------------------------------------------------------------------------------- */
1298 static void
1299 hot_load_group (struct hotlist *grp)
1301 int tkn;
1302 struct hotlist *new_grp;
1303 char *label, *url;
1305 current_group = grp;
1307 while ((tkn = hot_next_token ()) != TKN_ENDGROUP)
1308 switch (tkn)
1310 case TKN_GROUP:
1311 CHECK_TOKEN (TKN_STRING);
1312 new_grp =
1313 add2hotlist (g_strndup (tkn_buf->str, tkn_buf->len), 0, HL_TYPE_GROUP,
1314 LISTBOX_APPEND_AT_END);
1315 SKIP_TO_EOL;
1316 hot_load_group (new_grp);
1317 current_group = grp;
1318 break;
1319 case TKN_ENTRY:
1321 CHECK_TOKEN (TKN_STRING);
1322 label = g_strndup (tkn_buf->str, tkn_buf->len);
1323 CHECK_TOKEN (TKN_URL);
1324 CHECK_TOKEN (TKN_STRING);
1325 url = tilde_expand (tkn_buf->str);
1326 add2hotlist (label, url, HL_TYPE_ENTRY, LISTBOX_APPEND_AT_END);
1327 SKIP_TO_EOL;
1329 break;
1330 case TKN_COMMENT:
1331 label = g_strndup (tkn_buf->str, tkn_buf->len);
1332 add2hotlist (label, 0, HL_TYPE_COMMENT, LISTBOX_APPEND_AT_END);
1333 break;
1334 case TKN_EOF:
1335 hotlist_state.readonly = TRUE;
1336 hotlist_state.file_error = TRUE;
1337 return;
1338 case TKN_EOL:
1339 /* skip empty lines */
1340 break;
1341 default:
1342 hotlist_state.readonly = TRUE;
1343 hotlist_state.file_error = TRUE;
1344 SKIP_TO_EOL;
1345 break;
1347 SKIP_TO_EOL;
1350 /* --------------------------------------------------------------------------------------------- */
1352 static void
1353 hot_load_file (struct hotlist *grp)
1355 int tkn;
1356 struct hotlist *new_grp;
1357 char *label, *url;
1359 current_group = grp;
1361 while ((tkn = hot_next_token ()) != TKN_EOF)
1362 switch (tkn)
1364 case TKN_GROUP:
1365 CHECK_TOKEN (TKN_STRING);
1366 new_grp =
1367 add2hotlist (g_strndup (tkn_buf->str, tkn_buf->len), 0, HL_TYPE_GROUP,
1368 LISTBOX_APPEND_AT_END);
1369 SKIP_TO_EOL;
1370 hot_load_group (new_grp);
1371 current_group = grp;
1372 break;
1373 case TKN_ENTRY:
1375 CHECK_TOKEN (TKN_STRING);
1376 label = g_strndup (tkn_buf->str, tkn_buf->len);
1377 CHECK_TOKEN (TKN_URL);
1378 CHECK_TOKEN (TKN_STRING);
1379 url = tilde_expand (tkn_buf->str);
1380 add2hotlist (label, url, HL_TYPE_ENTRY, LISTBOX_APPEND_AT_END);
1381 SKIP_TO_EOL;
1383 break;
1384 case TKN_COMMENT:
1385 label = g_strndup (tkn_buf->str, tkn_buf->len);
1386 add2hotlist (label, 0, HL_TYPE_COMMENT, LISTBOX_APPEND_AT_END);
1387 break;
1388 case TKN_EOL:
1389 /* skip empty lines */
1390 break;
1391 default:
1392 hotlist_state.readonly = TRUE;
1393 hotlist_state.file_error = TRUE;
1394 SKIP_TO_EOL;
1395 break;
1399 /* --------------------------------------------------------------------------------------------- */
1401 static void
1402 clean_up_hotlist_groups (const char *section)
1404 char *grp_section;
1406 grp_section = g_strconcat (section, ".Group", (char *) NULL);
1407 if (mc_config_has_group (mc_global.main_config, section))
1408 mc_config_del_group (mc_global.main_config, section);
1410 if (mc_config_has_group (mc_global.main_config, grp_section))
1412 char **profile_keys, **keys;
1414 keys = mc_config_get_keys (mc_global.main_config, grp_section, NULL);
1416 for (profile_keys = keys; *profile_keys != NULL; profile_keys++)
1417 clean_up_hotlist_groups (*profile_keys);
1419 g_strfreev (keys);
1420 mc_config_del_group (mc_global.main_config, grp_section);
1422 g_free (grp_section);
1425 /* --------------------------------------------------------------------------------------------- */
1427 static void
1428 load_hotlist (void)
1430 gboolean remove_old_list = FALSE;
1431 struct stat stat_buf;
1433 if (hotlist_state.loaded)
1435 stat (hotlist_file_name, &stat_buf);
1436 if (hotlist_file_mtime < stat_buf.st_mtime)
1437 done_hotlist ();
1438 else
1439 return;
1442 if (hotlist_file_name == NULL)
1443 hotlist_file_name = mc_config_get_full_path (MC_HOTLIST_FILE);
1445 hotlist = g_new0 (struct hotlist, 1);
1446 hotlist->type = HL_TYPE_GROUP;
1447 hotlist->label = g_strdup (_("Top level group"));
1448 hotlist->up = hotlist;
1450 * compatibility :-(
1452 hotlist->directory = g_strdup ("Hotlist");
1454 hotlist_file = fopen (hotlist_file_name, "r");
1455 if (hotlist_file == NULL)
1457 int result;
1459 load_group (hotlist);
1460 hotlist_state.loaded = TRUE;
1462 * just to be sure we got copy
1464 hotlist_state.modified = TRUE;
1465 result = save_hotlist ();
1466 hotlist_state.modified = FALSE;
1467 if (result != 0)
1468 remove_old_list = TRUE;
1469 else
1470 message (D_ERROR, _("Hotlist Load"),
1472 ("MC was unable to write %s file,\nyour old hotlist entries were not deleted"),
1473 MC_USERCONF_DIR PATH_SEP_STR MC_HOTLIST_FILE);
1475 else
1477 hot_load_file (hotlist);
1478 fclose (hotlist_file);
1479 hotlist_state.loaded = TRUE;
1482 if (remove_old_list)
1484 GError *mcerror = NULL;
1486 clean_up_hotlist_groups ("Hotlist");
1487 if (!mc_config_save_file (mc_global.main_config, &mcerror))
1488 setup_save_config_show_error (mc_global.main_config->ini_path, &mcerror);
1490 mc_error_message (&mcerror, NULL);
1493 stat (hotlist_file_name, &stat_buf);
1494 hotlist_file_mtime = stat_buf.st_mtime;
1495 current_group = hotlist;
1498 /* --------------------------------------------------------------------------------------------- */
1500 static void
1501 hot_save_group (struct hotlist *grp)
1503 struct hotlist *current;
1504 int i;
1505 char *s;
1507 #define INDENT(n) \
1508 do { \
1509 for (i = 0; i < n; i++) \
1510 putc (' ', hotlist_file); \
1511 } while (0)
1513 for (current = grp->head; current != NULL; current = current->next)
1514 switch (current->type)
1516 case HL_TYPE_GROUP:
1517 INDENT (list_level);
1518 fputs ("GROUP \"", hotlist_file);
1519 for (s = current->label; *s != '\0'; s++)
1521 if (*s == '"' || *s == '\\')
1522 putc ('\\', hotlist_file);
1523 putc (*s, hotlist_file);
1525 fputs ("\"\n", hotlist_file);
1526 list_level += 2;
1527 hot_save_group (current);
1528 list_level -= 2;
1529 INDENT (list_level);
1530 fputs ("ENDGROUP\n", hotlist_file);
1531 break;
1532 case HL_TYPE_ENTRY:
1533 INDENT (list_level);
1534 fputs ("ENTRY \"", hotlist_file);
1535 for (s = current->label; *s != '\0'; s++)
1537 if (*s == '"' || *s == '\\')
1538 putc ('\\', hotlist_file);
1539 putc (*s, hotlist_file);
1541 fputs ("\" URL \"", hotlist_file);
1542 for (s = current->directory; *s != '\0'; s++)
1544 if (*s == '"' || *s == '\\')
1545 putc ('\\', hotlist_file);
1546 putc (*s, hotlist_file);
1548 fputs ("\"\n", hotlist_file);
1549 break;
1550 case HL_TYPE_COMMENT:
1551 fprintf (hotlist_file, "#%s\n", current->label);
1552 break;
1553 case HL_TYPE_DOTDOT:
1554 /* do nothing */
1555 break;
1556 default:
1557 break;
1561 /* --------------------------------------------------------------------------------------------- */
1563 static void
1564 add_dotdot_to_list (void)
1566 if (current_group != hotlist && hotlist_has_dot_dot)
1567 add2hotlist (g_strdup (".."), g_strdup (".."), HL_TYPE_DOTDOT, LISTBOX_APPEND_AT_END);
1570 /* --------------------------------------------------------------------------------------------- */
1571 /*** public functions ****************************************************************************/
1572 /* --------------------------------------------------------------------------------------------- */
1574 void
1575 add2hotlist_cmd (void)
1577 char *lc_prompt;
1578 const char *cp = N_("Label for \"%s\":");
1579 int l;
1580 char *label_string, *label;
1582 #ifdef ENABLE_NLS
1583 cp = _(cp);
1584 #endif
1586 l = str_term_width1 (cp);
1587 label_string = vfs_path_to_str_flags (current_panel->cwd_vpath, 0, VPF_STRIP_PASSWORD);
1588 lc_prompt = g_strdup_printf (cp, str_trunc (label_string, COLS - 2 * UX - (l + 8)));
1589 label =
1590 input_dialog (_("Add to hotlist"), lc_prompt, MC_HISTORY_HOTLIST_ADD, label_string,
1591 INPUT_COMPLETE_NONE);
1592 g_free (lc_prompt);
1594 if (label == NULL || *label == '\0')
1596 g_free (label_string);
1597 g_free (label);
1599 else
1601 add2hotlist (label, label_string, HL_TYPE_ENTRY, LISTBOX_APPEND_AT_END);
1602 hotlist_state.modified = TRUE;
1606 /* --------------------------------------------------------------------------------------------- */
1608 char *
1609 hotlist_show (hotlist_t list_type)
1611 char *target = NULL;
1612 int res;
1614 hotlist_state.type = list_type;
1615 load_hotlist ();
1617 init_hotlist (list_type);
1619 /* display file info */
1620 tty_setcolor (SELECTED_COLOR);
1622 hotlist_state.running = TRUE;
1623 res = dlg_run (hotlist_dlg);
1624 hotlist_state.running = FALSE;
1625 save_hotlist ();
1627 if (res == B_ENTER)
1629 char *text = NULL;
1630 struct hotlist *hlp = NULL;
1632 listbox_get_current (l_hotlist, &text, (void **) &hlp);
1633 target = g_strdup (hlp != NULL ? hlp->directory : text);
1636 hotlist_done ();
1637 return target;
1640 /* --------------------------------------------------------------------------------------------- */
1642 gboolean
1643 save_hotlist (void)
1645 gboolean saved = FALSE;
1646 struct stat stat_buf;
1648 if (!hotlist_state.readonly && hotlist_state.modified && hotlist_file_name != NULL)
1650 mc_util_make_backup_if_possible (hotlist_file_name, ".bak");
1652 hotlist_file = fopen (hotlist_file_name, "w");
1653 if (hotlist_file == NULL)
1654 mc_util_restore_from_backup_if_possible (hotlist_file_name, ".bak");
1655 else
1657 hot_save_group (hotlist);
1658 fclose (hotlist_file);
1659 stat (hotlist_file_name, &stat_buf);
1660 hotlist_file_mtime = stat_buf.st_mtime;
1661 hotlist_state.modified = FALSE;
1662 saved = TRUE;
1666 return saved;
1669 /* --------------------------------------------------------------------------------------------- */
1671 * Unload list from memory.
1672 * Don't confuse with hotlist_done() for GUI.
1675 void
1676 done_hotlist (void)
1678 if (hotlist != NULL)
1680 remove_group (hotlist);
1681 g_free (hotlist->label);
1682 g_free (hotlist->directory);
1683 MC_PTR_FREE (hotlist);
1686 hotlist_state.loaded = FALSE;
1688 MC_PTR_FREE (hotlist_file_name);
1689 l_hotlist = NULL;
1690 current_group = NULL;
1692 if (tkn_buf != NULL)
1694 g_string_free (tkn_buf, TRUE);
1695 tkn_buf = NULL;
1699 /* --------------------------------------------------------------------------------------------- */