/* $Id$ Copyright (C) 2004-2011 tooar This file is part of emelfm2. emelfm2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. emelfm2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with emelFM2; see the file GPL. If not, see http://www.gnu.org/licenses. */ /** @file src/e2_bookmark.c @brief bookmark functions */ #include "e2_bookmark.h" #include #include "e2_dialog.h" #include "e2_task.h" #include "e2_option_tree.h" static E2_OptionSet *bookmarks_set; /*****************/ /***** utils *****/ /*****************/ /** @brief re-create all toolbars which have bookmarks Way too comlicated to create mechanism to replace only specific buttons and menus @return */ static void _e2_bookmark_recreate_toolbars (void) { E2_ToolbarData **thisbar; for (thisbar = app.bars; *thisbar != NULL; thisbar++) { if ((*thisbar)->rt->has_bookmarks) //no need to check here for bar presence e2_toolbar_recreate ((*thisbar)->rt); } } /** @brief delete bookmark at @a iter @param iter pointer to tree iter for row to be deleted @return */ static void _e2_bookmark_delete_mark (GtkTreeIter *iter) { ViewInfo *view = curr_view; e2_option_tree_del_direct (bookmarks_set, iter); _e2_bookmark_recreate_toolbars (); if (GTK_IS_MENU (app.context_menu)) gtk_menu_popdown (GTK_MENU (app.context_menu)); if (view != curr_view) e2_pane_activate_other (); gtk_widget_grab_focus (view->treeview); } /** @brief refresh the bookmarks menus @return */ static void _e2_bookmark_apply_new (void) { //FIXME = find a smarter way to do this _e2_bookmark_recreate_toolbars (); } /*********************/ /***** callbacks *****/ /*********************/ /** @brief (de)sensitize option tree buttons for selected option tree row Config dialog page buttons are de-sensitized if the row is the toolbar 'parent' @param selection pointer to selection @param model UNUSED @param path @param path_currently_selected UNUSED @param set data struct for the keybings option @return TRUE always (the row is always selectable) */ static gboolean _e2_bookmark_tree_selection_check_cb (GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, E2_OptionSet *set) { GtkTreeIter iter; if (gtk_tree_model_get_iter (set->ex.tree.model, &iter, path)) { gchar *label; gtk_tree_model_get (set->ex.tree.model, &iter, 0, &label, -1); gboolean result = strcmp (label, _C(41)); g_free (label); GtkTreeView *view = gtk_tree_selection_get_tree_view (selection); e2_option_tree_adjust_buttons (view, result); } return TRUE; } /** @brief ensure that cells in the same row as any category name are hidden Checks whether @a iter in @a model has the name of the taskbar 'parent' in column 0. If so, the cell content is hidden, @param model treemodel for the bookmarks option tree @param iter pointer to iter with data for the current model row @param cell cell renderer UNUSED @param data pointer to data UNUSED @return TRUE (cell is visible) if row is not the task bar parent */ static gboolean _e2_bookmark_visible_check_cb (GtkTreeModel *model, GtkTreeIter *iter, GtkCellRenderer *cell, gpointer data) { gchar *label; gtk_tree_model_get (model, iter, 0, &label, -1); gboolean result = strcmp (label, _C(41)); g_free (label); return result; } /** @brief decide whether tree row is draggable Checks whether column 0 of the current row has the string which is the name of the "tool bar" 'parent' row. If so, the row is not draggable @param drag_source GtkTreeDragSource data struct @param path tree path to a row on which user is initiating a drag @return TRUE if the row can be dragged */ static gboolean _e2_bookmark_tree_draggable_check_cb (GtkTreeDragSource *drag_source, GtkTreePath *path) { if (!GTK_IS_TREE_MODEL (drag_source)) return TRUE; GtkTreeModel *model = GTK_TREE_MODEL (drag_source); GtkTreeIter iter; if (gtk_tree_model_get_iter (model, &iter, path)) { gchar *label; gtk_tree_model_get (model, &iter, 0, &label, -1); gboolean result = strcmp (label, _C(41)); g_free (label); return result; } return TRUE; } /** @brief process result from delete-confirmation dialog @param dialog UNUSED the confirmation-dialog @param response the response from the dialog @param ref treerow reference for the bookmark to be deleted @return */ static void _e2_bookmark_confirm_response_cb (GtkDialog *dialog, gint response, GtkTreeRowReference *ref) { if (response == GTK_RESPONSE_YES) { if (ref != NULL) { GtkTreePath *path = gtk_tree_row_reference_get_path (ref); if (path != NULL) { GtkTreeIter iter; if (gtk_tree_model_get_iter (bookmarks_set->ex.tree.model, &iter, path)) _e2_bookmark_delete_mark (&iter); gtk_tree_path_free (path); } } } gtk_widget_destroy (GTK_WIDGET (dialog)); } /** @brief callback to add an item (directory) to the bookmarks list The activated item @a widget may be a menu item (eg in the panebar bookmarks sub-menu) or an actions-menu item (file pane or bookmarks widget). In the former case, it will have been processed as an action, and will have a string argument @a arg, with "pane1" or "pane2" or a specific UTF-8 path string, and possibly including one of "top", "child" (othewise the add is treated as "after"). When @a widget is an actions-menu item, @a arg will be NULL. This function needs to know which pane to use for the path to add to the list. For menu callbacks, @a arg needs to include "1" or "2" as appropriate. For context-menu callbacks, @a widget will have associated E2_MarkData* which includes 0 (active), 1 or 2. @param widget NULL if a bookmarks menu item widget was selected or running an action directly, else a context menu item widget @param arg NULL, or string which indicates mark-directory and/or where in the marks list to put the new bookmark e.g. "child", mark directory may be like "N," where N = ''|0|1|2 followed by a comma @return */ static void _e2_bookmark_add_cb (GtkMenuItem *widget, const gchar *arg) { gint32 pane; gboolean before = FALSE; gboolean parent = FALSE; GtkTreePath *path; gchar *s = NULL; if (widget != NULL) { E2_MarkData *mdata = (E2_MarkData *) g_object_get_data (G_OBJECT (widget), "mark-data"); if (mdata != NULL) { pane = mdata->pane_num; path = mdata->tpath; } else { pane = E2PANECUR; //default to active pane path = NULL; } } else { pane = E2PANECUR; path = NULL; } //override pane if caller wants if (arg != NULL && *arg != '\0') { gchar *n; if (strstr (arg, _A(119)) != NULL) //_(top before = TRUE; if (strstr (arg, _A(109)) != NULL) //_(child { before = TRUE; parent = TRUE; } if (strchr (arg, G_DIR_SEPARATOR) != NULL) pane = 9999; //indicator that arg includes a path string else if ((s = e2_utils_bare_strchr ((gchar *)arg, '1')) != NULL) { n = e2_utils_pass_whitespace (s+1); pane = (n == NULL || *n == ',') ? E2PANE1 : 9999; //"1" or "1,[place]" signals pane 1 } else if ((s = e2_utils_bare_strchr ((gchar *)arg, '2')) != NULL) { n = e2_utils_pass_whitespace (s+1); pane = (n == NULL || *n == ',') ? E2PANE2 : 9999; //"2" or "2,[place]" signals pane 2 } else { n = e2_utils_pass_whitespace ((gchar *)arg); pane = (n == NULL || *n == ',') ? E2PANECUR : 9999; //"" or ",[place]" signals current pane } } //get the relevant dir to add to the marks list gchar *dirname; switch (pane) { #ifdef E2_VFSTMP //FIXME dirs when not mounted local #else case E2PANE1: dirname = app.pane1.view.dir; break; case E2PANE2: dirname = app.pane2.view.dir; break; case 9999: if (before) { //find and handle extra parameter and maybe ',' //FIXME this is not robust enough } dirname = e2_utils_unquote_string (arg); if (dirname == NULL) return; g_strchug (dirname); //path may validly have trailing whitespace if (!g_path_is_absolute (dirname)) { s = dirname; dirname = e2_utils_strcat (curr_view->dir, s); g_free (s); } break; default: dirname = curr_view->dir; #endif break; } gchar *basename = g_path_get_basename (dirname); //double any '_' CHECKME what's this about ? /* if (strchr (basename, '_')) { gchar *freeme = basename; basename = e2_utils_str_replace (basename, "_", "__"); g_free (freeme); } */ void *options[4]; options[0] = basename; //menu label options[1] = GTK_STOCK_DIRECTORY; //generic icon in case it's in taskbar //strip the trailing / for paths other than root gint len = strlen (dirname); if (len > 1) { if (pane != 9999) { s = g_strdup (dirname); //non-NULL = freeme later *(s+len-1) = '\0'; } else s = dirname; options[2] = s; } else { s = (pane != 9999) ? NULL : dirname; //non-NULL = freeme later options[2] = dirname; //tip = path } options[3] = options[2]; //path // E2_OptionSet *set = e2_option_get ("bookmarks"); //internal name USE THE GLOBAL VALUE GtkTreeIter iter; GtkTreeIter iter2; if ((path != NULL) && gtk_tree_model_get_iter (bookmarks_set->ex.tree.model, &iter2, path)) e2_option_tree_add (bookmarks_set, &iter, &iter2, !parent, before, 4, options); else //with no parent, the behaviour of "before" is vice versa e2_option_tree_add (bookmarks_set, &iter, NULL, FALSE, !before, 4, options); ViewInfo *view = curr_view; _e2_bookmark_recreate_toolbars (); //kludgy way to update bookmarks data in bars if (view != curr_view) e2_pane_activate_other (); gtk_widget_grab_focus (view->treeview); if (s != NULL) g_free (s); g_free (basename); } /** @brief callback for deleting a bookmark (with any children) Assumes BGL closed @param widget UNUSED the widget which was activated @param path treestore path of bookmark to be deleted @return */ static void _e2_bookmark_delete_cb (GtkMenuItem *widget, GtkTreePath *path) { GtkTreeIter iter; if (gtk_tree_model_get_iter (bookmarks_set->ex.tree.model, &iter, path)) { gint children = gtk_tree_model_iter_n_children (bookmarks_set->ex.tree.model, &iter); if (e2_option_bool_get ("bookmarks-confirm-delete") || ((children > 0) && (e2_option_bool_get ("bookmarks-confirm-multi-delete"))) ) { gchar *name; gtk_tree_model_get (bookmarks_set->ex.tree.model, &iter, 0, &name, -1); gchar *question; gchar *prompt = _("Are you sure that you want to delete the bookmark"); //we fudge here on translating the trailing '?' if (children > 0) question = g_strdup_printf ("%s '%s' %s %d %s ?", prompt, name, _("and"), children, (children == 1) ? _("child") : _("children")); else question = g_strdup_printf ("%s '%s' ?", prompt, name); GtkWidget *dialog = e2_dialog_create (GTK_STOCK_DIALOG_QUESTION, question, _("confirm bookmark delete"), (ResponseFunc)_e2_bookmark_confirm_response_cb, gtk_tree_row_reference_new (bookmarks_set->ex.tree.model, path)); e2_dialog_set_negative_response (dialog, GTK_RESPONSE_NO); E2_Button no_btn; e2_button_derive (&no_btn, &E2_BUTTON_NO, BTN_NO_KEEP); E2_Button yes_btn; e2_button_derive (&yes_btn, &E2_BUTTON_YES, BTN_YES_DELETE); e2_dialog_show (dialog, app.main_window, 0, &no_btn, &yes_btn, NULL); g_free (question); g_free (name); } else //no confirmation _e2_bookmark_delete_mark (&iter); //changes active pane and focus-widget } } /** @brief "selection-done" signal callback for items in bookmark-actions menu @param menu the actions-menu widget @param mdata data associated with the active imem of bookmarks (sub)menu @return */ static void _e2_bookmark_change_selected_cb (GtkWidget *menu, E2_MarkData *mdata) { e2_menu_selection_done_cb (menu, NULL); //clean up actions-menu if (mdata->top_menu != NULL) { gtk_menu_popdown (GTK_MENU (mdata->top_menu)); //hide marks-menu and all subs if (mdata->mark_flags & E2_MARKFLAG_ONETIME) e2_menu_selection_done_cb (mdata->top_menu, NULL); //clean up marks-menu } } /** @brief "button-press-event" signal callback Unmodified middle button will open mark in other pane, and make that pane active, if the relevant options are in force. Unmodified right button will create and pop up a destroyable context menu, if not blocked (blocks will be in place for toolbar buttons, but not for (sub)menu items) Context menu items 'add' and 'add-child' need to know which pane (directory) to use for the mark @param widget clicked button or menu item @param event gdk event data struct @param mdata pointer to bookmark data associated with a bookmark-menu item @return TRUE (block further handlers) if certain btn 2 or 3 conditions are satisfied */ gboolean e2_bookmark_button_press_cb (GtkWidget *widget, GdkEventButton *event, E2_MarkData *mdata) { printd (DEBUG, "e2_bookmark_button_press_cb"); #ifdef E2_MOUSECUSTOM if ((event->state & E2_MODIFIER_MASK) == 0) { #endif if (event->button == 2) { if (e2_option_bool_get ("bookmarks-button2-other")) { gint other = (curr_pane == &app.pane1) ? 2 : 1; if (other != mdata->pane_num) //active pane's menu was clicked { #ifdef E2_VFSTMP //FIXME bookmark parsing and setting for v-dirs if (0) e2_pane_change_space_byuri (other_pane, "some string"); #endif e2_pane_change_dir (other_pane, mdata->mark_path); //mark string is UTF-8 if (e2_option_bool_get ("bookmarks-focus-after-open")) e2_pane_activate_other (); return TRUE; } } } else if (event->button == 3) { if ((mdata->mark_flags & E2_MARKFLAG_ACTIONS) > 0) { //actions-menu allowed for this widget gboolean parent; GtkWidget *menu, *menuitem; if (mdata->tpath != NULL) { GtkTreeIter iter; gtk_tree_model_get_iter (bookmarks_set->ex.tree.model, &iter, mdata->tpath); parent = gtk_tree_model_iter_has_child (bookmarks_set->ex.tree.model, &iter); } else parent = FALSE; menu = gtk_menu_new (); //adding a child to an existing mark prevents its operation in the menu if (parent) { //must preface callback arg with ',' to ensure correct parsing gchar *arg = e2_utils_strcat (",", _A(109)); //_(child menuitem = e2_menu_add (menu, _("_Add child"), GTK_STOCK_INDENT, _("Bookmark the current directory a child of the selected item"), _e2_bookmark_add_cb, arg); g_object_set_data_full (G_OBJECT (menuitem), "__freeme", arg, g_free); } else menuitem = e2_menu_add (menu, _("_Add after"), GTK_STOCK_ADD, _("Bookmark the current directory after the selected item"), _e2_bookmark_add_cb, NULL); g_object_set_data (G_OBJECT (menuitem), "mark-data", mdata); e2_menu_add (menu, _("_Delete"), GTK_STOCK_DELETE, _("Delete the selected bookmark, and its children if any"), _e2_bookmark_delete_cb, mdata->tpath); g_signal_connect (G_OBJECT (menu), "selection-done", G_CALLBACK (_e2_bookmark_change_selected_cb), mdata); e2_menu_popup (menu, event->button, event->time); return TRUE; } } #ifdef E2_MOUSECUSTOM } #endif return FALSE; } /*******************/ /***** actions *****/ /*******************/ /** @brief add item to bookmarks menu @param from pointer to widget activated to initiate the action @param art pointer to runtime data for the action @return TRUE always */ static gboolean _e2_bookmark_add (gpointer from, E2_ActionRuntime *art) { /* //this just checks syntax, really const gchar *position = NULL; E2_PaneRuntime *rt = e2_pane_get_runtime (from, art->data, &position); if (rt == NULL) return FALSE; */ _e2_bookmark_add_cb (NULL, (const gchar *) art->data); return TRUE; } /** @brief remove item from bookmarks menu @param from pointer to widget activated to initiate the action @param art pointer to runtime data for the action @return TRUE if the item was removed */ static gboolean _e2_bookmark_delete (gpointer from, E2_ActionRuntime *art) { gchar *arg = (gchar *) art->data; // if (arg == NULL) arg = curr_viewe->dir without trailing / if (arg != NULL) //&& *arg != '\0') { //CHECKME handle "1" or "2" for pane dir ? gboolean retval = FALSE; gchar *clean = e2_utils_unquote_string (arg); if (clean == NULL) clean = arg; GtkTreeIter iter; while (e2_tree_find_iter_from_str (bookmarks_set->ex.tree.model, 3, clean, &iter, FALSE)) { GtkTreePath *tpath; tpath = gtk_tree_model_get_path (bookmarks_set->ex.tree.model, &iter); _e2_bookmark_delete_cb (NULL, tpath); gtk_tree_path_free (tpath); retval = TRUE; } if (clean != arg) g_free (clean); return retval; } return FALSE; } /** @brief construct and pop up destroyable bookmarks-menu, in specified pane @param from pointer to widget activated to initiate the action @param art pointer to runtime data for the action @return TRUE if menu was created */ static gboolean _e2_bookmark_show (gpointer from, E2_ActionRuntime *art) { if (GTK_IS_BUTTON (from)) { art->state &= ~GDK_MOD2_MASK; if (!ACTION_CLICK(art)) return FALSE; } E2_OptionSet *set = e2_option_get ("bookmarks"); GtkTreeIter iter; if (gtk_tree_model_get_iter_first (set->ex.tree.model, &iter)) { gint32 pane; E2_PaneRuntime *rt = e2_pane_get_runtime (from, art->data, NULL); if (rt == curr_pane) //CHECKME allow default regardless of actual pane ? pane = E2PANECUR; else pane = (rt == &app.pane1) ? E2PANE1 : E2PANE2; gchar *action_name = g_strconcat (_A(0),".",_A(27),NULL); E2_Action *action = e2_action_get (action_name); g_free (action_name); GtkWidget *menu = gtk_menu_new (); e2_menu_add_bookmark_items (menu, menu, action, E2_MARKFLAG_ACTIONS | E2_MARKFLAG_ONETIME, pane, set->ex.tree.model, &iter); g_signal_connect (G_OBJECT (menu), "selection-done", G_CALLBACK (e2_menu_selection_done_cb), NULL); guint32 event_time = gtk_get_current_event_time (); gtk_menu_popup (GTK_MENU (menu), NULL, NULL, (GtkMenuPositionFunc) e2_fileview_set_menu_position, rt->view.treeview, 0, event_time); return TRUE; } return FALSE; } /** @brief open bookmark @a path, in pane @a num Action data includes "0" (from "" action), "1" or "2" (pane number) Action data includes path of directory to open, utf8 string Downstream functions expect BGL to be closed @param from pointer to widget activated to initiate the action @param art pointer to runtime data for the action @return TRUE if the cd is initiated */ static gboolean _e2_bookmark_open (gpointer from, E2_ActionRuntime *art) { const gchar *newpath = NULL; E2_PaneRuntime *rt = e2_pane_get_runtime (from, art->data, &newpath); if (rt == NULL || newpath == NULL) return FALSE; printd (DEBUG, "_e2_bookmark_open (path:%s)", newpath); //bookmark may be bad now ... if (e2_fs_cd_isok ((gchar *)newpath E2_ERR_NONE())) { #ifdef E2_VFSTMP //FIXME handle case where pane is non-mounted if (0) e2_pane_change_space_byuri (rt, "someplace"); #endif e2_pane_change_dir (rt, newpath); if (rt != curr_pane && e2_option_bool_get ("bookmarks-focus-after-open")) e2_pane_activate_other (); return TRUE; } return FALSE; } /** @brief open a dialog showing bookmarks config data @param from pointer to widget activated to initiate the action @param art pointer to runtime data for the action @return TRUE if the dialog was created */ static gboolean _e2_bookmarks_configure (gpointer from, E2_ActionRuntime *art) { return ( e2_config_dialog_single ("bookmarks", _e2_bookmark_apply_new, TRUE) //internal name, no translation != NULL); } /******************/ /***** public *****/ /******************/ /* this used only at session end, don't bother void e2_bookmark_clean () { // e2_action_unregister (_A(24)); //_("")); } */ /** @brief register bookmark-related actions @return */ void e2_bookmark_actions_register (void) { E2_Action actions[] = { {g_strconcat(_A(0),".",_A(27),NULL), _e2_bookmark_open, TRUE, E2_ACTION_TYPE_BOOKMARKS, E2_ACTION_EXCLUDE_ACCEL, NULL, NULL}, {g_strconcat(_A(0),".",_A(30),NULL), _e2_bookmark_add, TRUE, E2_ACTION_TYPE_ITEM, 0, NULL, NULL}, {g_strconcat(_A(0),".",_A(42),NULL), _e2_bookmark_delete, TRUE, E2_ACTION_TYPE_ITEM, 0, NULL, NULL}, {g_strconcat(_A(13),".",_A(24),NULL),_e2_bookmark_show, TRUE, E2_ACTION_TYPE_ITEM, 0, NULL, NULL}, {g_strconcat(_A(3),".",_C(1),NULL), _e2_bookmarks_configure,FALSE,E2_ACTION_TYPE_ITEM, 0, NULL, NULL}, }; guint i, count = sizeof (actions)/sizeof (E2_Action); for (i = 0; i < count; i++) e2_action_register (&actions[i]); } /** @brief install default tree options for boookmarks This function is called only if the default is missing from the config file @param set pointer to set data @return */ static void _e2_bookmark_tree_defaults (E2_OptionSet *set) { e2_option_tree_setup_defaults (set, g_strdup("bookmarks=<"), //internal name g_strconcat(_C(41),"|||",NULL), //needs to be same as arg to taskbar item - see e2_toolbar.c g_strconcat("\t","",_("_home"),"|gtk-home|$HOME|~",NULL), //this next is too specific for a default value // g_strconcat("\t",_("down"),"||",_("/mnt/downloads"),"|"G_DIR_SEPARATOR_S"mnt"G_DIR_SEPARATOR_S"downloads",NULL), g_strconcat("\t",_("cdrom"),"|gtk-cdrom|"G_DIR_SEPARATOR_S"media"G_DIR_SEPARATOR_S"cdrom" "|"G_DIR_SEPARATOR_S"media"G_DIR_SEPARATOR_S"cdrom",NULL), g_strconcat(G_DIR_SEPARATOR_S"||",_("root"),"|"G_DIR_SEPARATOR_S,NULL), g_strconcat(_("home"),"||",_("Your home directory"),"|~",NULL), g_strconcat(_("media"),"||"G_DIR_SEPARATOR_S"media|"G_DIR_SEPARATOR_S"media",NULL), //_I( no point in translating tip = path g_strconcat(_("mnt"),"||"G_DIR_SEPARATOR_S"mnt|"G_DIR_SEPARATOR_S"mnt",NULL), //ditto g_strconcat(_("usr"),"||"G_DIR_SEPARATOR_S"usr|"G_DIR_SEPARATOR_S"usr",NULL), //ditto g_strconcat(_("usr/local"),"||"G_DIR_SEPARATOR_S"usr"G_DIR_SEPARATOR_S"local" "|"G_DIR_SEPARATOR_S"usr"G_DIR_SEPARATOR_S"local",NULL), //ditto g_strconcat(_("trash"),"||",_("default trash directory"), "|~"G_DIR_SEPARATOR_S".local"G_DIR_SEPARATOR_S"share"G_DIR_SEPARATOR_S"Trash"G_DIR_SEPARATOR_S"files", NULL), g_strdup(">"), NULL); } /** @brief register bookmark-related options @return */ void e2_bookmark_options_register (void) { //no screen rebuilds needed after any change to these options // E2_OptionSet * SET THE GLOBAL VALUE bookmarks_set = e2_option_tree_register ("bookmarks", _C(1), _C(1), //_("bookmarks" NULL, _e2_bookmark_tree_selection_check_cb, _e2_bookmark_tree_draggable_check_cb, E2_OPTION_TREE_UP_DOWN | E2_OPTION_TREE_ADD_DEL, E2_OPTION_FLAG_BASIC | E2_OPTION_FLAG_BUILDBARS); //toolbar(s) typically include static marks-related items e2_option_tree_add_column (bookmarks_set, _("Label"), E2_OPTION_TREE_TYPE_STR, 0, G_DIR_SEPARATOR_S, 0, NULL, NULL); e2_option_tree_add_column (bookmarks_set, _("Icon"), E2_OPTION_TREE_TYPE_ICON, 0, "", 0, _e2_bookmark_visible_check_cb, NULL); e2_option_tree_add_column (bookmarks_set, _("Tooltip"), E2_OPTION_TREE_TYPE_STR, 0, "", 0, _e2_bookmark_visible_check_cb, NULL); e2_option_tree_add_column (bookmarks_set, _("Path"), E2_OPTION_TREE_TYPE_STR, 0, G_DIR_SEPARATOR_S, 0, _e2_bookmark_visible_check_cb, NULL); e2_option_tree_create_store (bookmarks_set); e2_option_tree_prepare_defaults (bookmarks_set, _e2_bookmark_tree_defaults); gchar* group_name = g_strconcat(_C(1),".",_C(27),":",_C(26),NULL); //_("bookmarks.options:miscellaneous" e2_option_bool_register ("bookmarks-button2-other", group_name, _("open bookmark in other pane on middle-button click"), _("Clicking the middle mouse button on a bookmark will open it in the other file pane"), NULL, TRUE, E2_OPTION_FLAG_ADVANCED | E2_OPTION_FLAG_FREEGROUP); e2_option_bool_register ("bookmarks-focus-after-open", group_name, _("focus file pane after opening a bookmark in it"), _("After opening a bookmark in the inactive file pane, that pane will become the active one"), NULL, TRUE, E2_OPTION_FLAG_ADVANCED); group_name = g_strconcat(_C(1),".",_C(27),":",_C(7),NULL); //_("bookmarks.options:confirmation" e2_option_bool_register ("bookmarks-confirm-delete", group_name, _("confirm any delete of a selected bookmark"), _("You will be asked to confirm, before deleting any bookmark"), "bookmarks-confirm-multi-delete", FALSE, E2_OPTION_FLAG_ADVANCED | E2_OPTION_FLAG_FREEGROUP); e2_option_bool_register ("bookmarks-confirm-multi-delete", group_name, _("confirm any delete of multiple bookmarks"), _("You will be asked to confirm, before deleting any bookmark that has 'children'"), NULL, TRUE, E2_OPTION_FLAG_ADVANCED); }