/* $Id$ Copyright (C) 2009-2010 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 plugins/e2p_tag.c @brief plugin to log selected items and reselect them later */ #include "emelfm2.h" #include "e2_plugins.h" #include "e2_fileview.h" #include "e2_filelist.h" #ifdef E2_VFSTMP FIXME app.vdir_cache is for vpath* s i.e path + spacedata /* static (GHashFunc) hash_func, () { } static (GEqualFunc) key_equal_func () { } static (GDestroyNotify) key_destroy_func () { } gpointer hash key (PlaceInfo *spacedata, gchar *path) { return NULL; } */ #endif /** @brief log the names of selected items, if any, in the specified pane @param from the button, menu item etc which was activated @param art action runtime data @return TRUE if action completed successfully, else FALSE */ static gboolean _e2p_tag_selected (gpointer from, E2_ActionRuntime *art) { E2_ListChoice p; E2_PaneRuntime *rt; ViewInfo *view; GtkTreeModel *model; GHashTable *selitems; GList *selpaths, *rowpath; E2_DirHistoryEntry *hist; rt = e2_pane_get_runtime (from, art->data, NULL); view = (ViewInfo *)rt; #ifdef E2_VFS VPATH ddata = { view->dir, view->spacedata }; //CHECKME path encoding ? vpath *vdir = g_hash_table_lookup (app.vdir_cache, &ddata); if (G_UNLIKELY(vdir == NULL)) return FALSE; #endif p = (rt == curr_pane) ? PANEACTIVE : PANEINACTIVE; e2_filelist_disable_one_refresh (p); WAIT_FOR_REFRESH(view) selpaths = gtk_tree_selection_get_selected_rows (view->selection, &model); if (selpaths == NULL) { e2_filelist_enable_one_refresh (p); return FALSE; } #ifdef E2_VFS hist = g_hash_table_lookup (app.dir_history, vdir); #else hist = g_hash_table_lookup (app.dir_history, view->dir); #endif if (hist->selitems != NULL) g_hash_table_destroy (hist->selitems); hist->selitems = selitems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); for (rowpath = selpaths; rowpath != NULL; rowpath = rowpath->next) { GtkTreeIter iter; GtkTreePath *path; FileInfo *info; path = (GtkTreePath *) rowpath->data; if (gtk_tree_model_get_iter (model, &iter, path)) { gtk_tree_model_get (model, &iter, FINFO, &info, -1); //info doesn't persist g_hash_table_insert (selitems, g_strdup(info->filename), GINT_TO_POINTER(1)); } gtk_tree_path_free (path); } g_list_free (selpaths); e2_filelist_enable_one_refresh (p); return TRUE; } /** @brief re-select the 'tagged' items, if any, in the specified pane @param from the button, menu item etc which was activated @param art action runtime data @return TRUE if action completed successfully, else FALSE */ static gboolean _e2p_retag (gpointer from, E2_ActionRuntime *art) { E2_ListChoice p; E2_PaneRuntime *rt; ViewInfo *view; E2_DirHistoryEntry *hist; GtkTreeModel *model; GtkTreeIter iter; rt = e2_pane_get_runtime (from, art->data, NULL); view = (ViewInfo *)rt; //get history item for this dir #ifdef E2_VFS vpath *vdir = g_hash_table_find (?, ); if (G_UNLIKELY(vdir == NULL)) return FALSE; hist = g_hash_table_lookup (app.dir_history, vdir); #else hist = g_hash_table_lookup (app.dir_history, view->dir); #endif if (G_UNLIKELY(hist == NULL || hist->selitems == NULL)) return FALSE; //should never happen p = (rt == curr_pane) ? PANEACTIVE : PANEINACTIVE; e2_filelist_disable_one_refresh (p); WAIT_FOR_REFRESH(view) model = view->model; if (gtk_tree_model_get_iter_first (model, &iter)); { //it's not empty now GHashTable *selitems; GtkTreeSelection *sel; selitems = hist->selitems; sel = view->selection; gtk_tree_selection_unselect_all (sel); //start with clean slate do { FileInfo *info; gtk_tree_model_get (model, &iter, FINFO, &info, -1); //We only check for name, no other statbuf parameters are stored ATM if (g_hash_table_lookup(selitems, info->filename) != NULL) gtk_tree_selection_select_iter (sel, &iter); } while (gtk_tree_model_iter_next (model, &iter)); } e2_filelist_enable_one_refresh (p); return TRUE; } //aname must be confined to this module static gchar *aname; static gchar *aname2; /** @brief plugin initialization function, called by main program @param p ptr to plugin data struct @return TRUE if the initialization succeeds, else FALSE */ gboolean init_plugin (Plugin *p) { #define ANAME "tag" aname = _("tag"); aname2 = _("retag"); //these are data for the "parent" plugin item p->signature = ANAME VERSION; p->menu_name = _("_Tag"); //no tip will work for a submenu item, but we want to avoid silly default //string in config dialog until the plugin is actually loaded //this string will be replaced by "" when plugin is loaded ?? p->description = ""; p->icon = "plugin_"ANAME E2ICONTB; //use icon file pathname if appropriate //child UI data gchar *sig1 = "0-"ANAME VERSION; gchar *label1 = (gchar *)p->menu_name; // gchar *icon1 = ""; //no icon "plugin_"ANAME E2ICONTB; //use icon file pathname if appropriate gchar *tip1 = _("Log the selected item(s) in active pane"); gchar *sig2 = "1-"ANAME VERSION; gchar *label2 = _("_Retag"); // gchar *icon2 = ""; gchar *tip2 = _("Re-select any logged item(s) in active pane"); if (p->action == NULL) { gboolean retval; Plugin *pc = e2_plugins_create_child (p); if (pc != NULL) { //for reconciling with config treestore data, signatures must reflect //0-based index of each child's order in the list of children pc->signature = sig1; //begin with "n-", n=0,1, ... //these will generallly be discarded in favour of config treestore data //meaning that any non-constant string will leak pc->menu_name = label1; //or whatever // pc->description = _("Copy selected item(s), with displayed progress details"); pc->description = tip1; //or whatever // pc->icon = "plugin_copy"E2ICONTB; //use icon file pathname if appropriate //YUK _A(6) here makes the parent item file-specific, which prevents //_A(7) working for retag action //don't free name string here E2_Action plugact = {g_strconcat (_A(6),".",aname,NULL),_e2p_tag_selected,TRUE,E2_ACTION_TYPE_ITEM,0,NULL,NULL}; pc->action = e2_plugins_action_register (&plugact); if G_LIKELY((pc->action != NULL)) retval = TRUE; else { g_free (plugact.name); retval = FALSE; } } else retval = FALSE; //this will not be used, but MUST be set to allow checking whether to show //the item in the context menu if (retval) p->action = pc->action; pc = e2_plugins_create_child (p); if (pc != NULL) { pc->signature = sig2; //for reconciling with config treestore data pc->menu_name = label2; pc->description = tip2; // pc->icon = "plugin_copy"E2ICONTB; //use icon file pathname if appropriate //don't free name here FIXME some name not file-specific E2_Action plugact = {g_strconcat (_A(6),".",aname2,NULL),_e2p_retag,TRUE,E2_ACTION_TYPE_ITEM,0,NULL,NULL}; pc->action = e2_plugins_action_register (&plugact); if G_LIKELY((pc->action != NULL)) retval = TRUE; else { g_free (plugact.name); retval = FALSE; } } else retval = FALSE; if (retval && (p->action == NULL)) p->action = pc->action; return retval; } else //setup children UI data for pushing into a config dialog { E2_Sextet *uidata; uidata = e2_utils_sextet_new (); p->child_list = g_list_append (p->child_list, uidata); uidata->a = label1; uidata->b = ""; //no icon uidata->c = tip1; uidata->d = sig1; uidata = e2_utils_sextet_new (); p->child_list = g_list_append (p->child_list, uidata); uidata->a = label2; uidata->b = ""; uidata->c = tip2; uidata->d = sig2; } return FALSE; } /** @brief cleanup transient things for this plugin @param p pointer to data struct for the plugin @return TRUE if all cleanups were completed */ gboolean clean_plugin (Plugin *p) { gchar *action_name = g_strconcat (_A(6),".",aname,NULL); gboolean ret1 = e2_plugins_action_unregister (action_name); g_free (action_name); action_name = g_strconcat (_A(6),".",aname2,NULL); gboolean ret2 = e2_plugins_action_unregister (action_name); g_free (action_name); return (ret1 && ret2); }