1779 lines
52 KiB
C
1779 lines
52 KiB
C
/*
|
|
* moobookmarkmgr.c
|
|
*
|
|
* Copyright (C) 2004-2006 by Yevgen Muntyan <muntyan@math.tamu.edu>
|
|
*
|
|
* This program 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 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* See COPYING file that comes with this distribution.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "moofileview/moobookmarkmgr.h"
|
|
#include "moofileview/moobookmarkmgr-glade.h"
|
|
#include "moofileview/moofileentry.h"
|
|
#include "mooutils/mooglade.h"
|
|
#include "mooutils/mooprefs.h"
|
|
#include "mooutils/moocompat.h"
|
|
#include "mooutils/moomarshals.h"
|
|
#include "mooutils/mooactionfactory.h"
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <gtk/gtk.h>
|
|
|
|
#if GLIB_CHECK_VERSION(2,6,0)
|
|
# include <glib/gstdio.h>
|
|
#endif
|
|
|
|
#define COLUMN_BOOKMARK MOO_BOOKMARK_MGR_COLUMN_BOOKMARK
|
|
|
|
struct _MooBookmarkMgrPrivate {
|
|
GtkListStore *store;
|
|
GSList *users;
|
|
GtkWidget *editor;
|
|
gboolean loading;
|
|
guint last_user_id;
|
|
guint update_idle;
|
|
};
|
|
|
|
typedef struct _UserInfo UserInfo;
|
|
|
|
|
|
static void moo_bookmark_mgr_finalize (GObject *object);
|
|
static void moo_bookmark_mgr_changed (MooBookmarkMgr *mgr);
|
|
static void emit_changed (MooBookmarkMgr *mgr);
|
|
static void moo_bookmark_mgr_add_separator (MooBookmarkMgr *mgr);
|
|
|
|
static void moo_bookmark_mgr_load (MooBookmarkMgr *mgr);
|
|
static void moo_bookmark_mgr_save (MooBookmarkMgr *mgr);
|
|
|
|
static void mgr_remove_user (MooBookmarkMgr *mgr,
|
|
UserInfo *info);
|
|
static gboolean mgr_update_menus (MooBookmarkMgr *mgr);
|
|
|
|
|
|
/* MOO_TYPE_BOOKMARK_MGR */
|
|
G_DEFINE_TYPE (MooBookmarkMgr, _moo_bookmark_mgr, G_TYPE_OBJECT)
|
|
|
|
enum {
|
|
PROP_0,
|
|
};
|
|
|
|
enum {
|
|
CHANGED,
|
|
ACTIVATE,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
static guint signals[LAST_SIGNAL];
|
|
|
|
static void
|
|
_moo_bookmark_mgr_class_init (MooBookmarkMgrClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
gobject_class->finalize = moo_bookmark_mgr_finalize;
|
|
|
|
klass->changed = moo_bookmark_mgr_changed;
|
|
|
|
signals[CHANGED] =
|
|
g_signal_new ("changed",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooBookmarkMgrClass, changed),
|
|
NULL, NULL,
|
|
_moo_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
|
|
signals[ACTIVATE] =
|
|
g_signal_new ("activate",
|
|
G_OBJECT_CLASS_TYPE (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (MooBookmarkMgrClass, activate),
|
|
NULL, NULL,
|
|
_moo_marshal_VOID__BOXED_OBJECT,
|
|
G_TYPE_NONE, 2,
|
|
MOO_TYPE_BOOKMARK, G_TYPE_OBJECT);
|
|
}
|
|
|
|
|
|
static void
|
|
_moo_bookmark_mgr_init (MooBookmarkMgr *mgr)
|
|
{
|
|
mgr->priv = g_new0 (MooBookmarkMgrPrivate, 1);
|
|
|
|
mgr->priv->store = gtk_list_store_new (1, MOO_TYPE_BOOKMARK);
|
|
|
|
g_signal_connect_swapped (mgr->priv->store, "row-changed",
|
|
G_CALLBACK (emit_changed), mgr);
|
|
g_signal_connect_swapped (mgr->priv->store, "rows-reordered",
|
|
G_CALLBACK (emit_changed), mgr);
|
|
g_signal_connect_swapped (mgr->priv->store, "row-inserted",
|
|
G_CALLBACK (emit_changed), mgr);
|
|
g_signal_connect_swapped (mgr->priv->store, "row-deleted",
|
|
G_CALLBACK (emit_changed), mgr);
|
|
}
|
|
|
|
|
|
static void
|
|
moo_bookmark_mgr_finalize (GObject *object)
|
|
{
|
|
GSList *l, *users;
|
|
MooBookmarkMgr *mgr = MOO_BOOKMARK_MGR (object);
|
|
|
|
g_object_unref (mgr->priv->store);
|
|
|
|
if (mgr->priv->update_idle)
|
|
g_source_remove (mgr->priv->update_idle);
|
|
|
|
if (mgr->priv->editor)
|
|
{
|
|
gtk_widget_destroy (mgr->priv->editor);
|
|
g_object_unref (mgr->priv->editor);
|
|
}
|
|
|
|
users = g_slist_copy (mgr->priv->users);
|
|
for (l = users; l != NULL; l = l->next)
|
|
mgr_remove_user (mgr, l->data);
|
|
g_assert (mgr->priv->users == NULL);
|
|
g_slist_free (users);
|
|
|
|
g_free (mgr->priv);
|
|
mgr->priv = NULL;
|
|
|
|
G_OBJECT_CLASS (_moo_bookmark_mgr_parent_class)->finalize (object);
|
|
}
|
|
|
|
|
|
static void
|
|
emit_changed (MooBookmarkMgr *mgr)
|
|
{
|
|
g_signal_emit (mgr, signals[CHANGED], 0);
|
|
}
|
|
|
|
|
|
static void
|
|
moo_bookmark_mgr_changed (MooBookmarkMgr *mgr)
|
|
{
|
|
if (!mgr->priv->loading)
|
|
moo_bookmark_mgr_save (mgr);
|
|
if (!mgr->priv->update_idle)
|
|
mgr->priv->update_idle = g_idle_add ((GSourceFunc) mgr_update_menus, mgr);
|
|
}
|
|
|
|
|
|
void
|
|
_moo_bookmark_mgr_add (MooBookmarkMgr *mgr,
|
|
MooBookmark *bookmark)
|
|
{
|
|
GtkTreeIter iter;
|
|
|
|
g_return_if_fail (MOO_IS_BOOKMARK_MGR (mgr));
|
|
g_return_if_fail (bookmark != NULL);
|
|
|
|
/* XXX validate bookmark */
|
|
|
|
gtk_list_store_append (mgr->priv->store, &iter);
|
|
gtk_list_store_set (mgr->priv->store, &iter,
|
|
COLUMN_BOOKMARK, bookmark, -1);
|
|
}
|
|
|
|
|
|
static void
|
|
moo_bookmark_mgr_add_separator (MooBookmarkMgr *mgr)
|
|
{
|
|
GtkTreeIter iter;
|
|
g_return_if_fail (MOO_IS_BOOKMARK_MGR (mgr));
|
|
gtk_list_store_append (mgr->priv->store, &iter);
|
|
}
|
|
|
|
|
|
MooBookmarkMgr*
|
|
_moo_bookmark_mgr_new (void)
|
|
{
|
|
MooBookmarkMgr *mgr = g_object_new (MOO_TYPE_BOOKMARK_MGR, NULL);
|
|
moo_bookmark_mgr_load (mgr);
|
|
return mgr;
|
|
}
|
|
|
|
|
|
GtkTreeModel *
|
|
_moo_bookmark_mgr_get_model (MooBookmarkMgr *mgr)
|
|
{
|
|
g_return_val_if_fail (MOO_IS_BOOKMARK_MGR (mgr), NULL);
|
|
return GTK_TREE_MODEL (mgr->priv->store);
|
|
}
|
|
|
|
|
|
gboolean
|
|
_moo_bookmark_mgr_is_empty (MooBookmarkMgr *mgr)
|
|
{
|
|
GtkTreeIter iter;
|
|
g_return_val_if_fail (MOO_IS_BOOKMARK_MGR (mgr), TRUE);
|
|
return !gtk_tree_model_get_iter_first (GTK_TREE_MODEL (mgr->priv->store), &iter);
|
|
}
|
|
|
|
|
|
MooBookmark*
|
|
_moo_bookmark_new (const char *label,
|
|
const char *path,
|
|
const char *icon)
|
|
{
|
|
MooBookmark *bookmark;
|
|
|
|
bookmark = g_new0 (MooBookmark, 1);
|
|
|
|
bookmark->path = g_strdup (path);
|
|
bookmark->display_path = path ? g_filename_display_name (path) : NULL;
|
|
bookmark->label = g_strdup (label);
|
|
bookmark->icon_stock_id = g_strdup (icon);
|
|
|
|
return bookmark;
|
|
}
|
|
|
|
|
|
MooBookmark*
|
|
_moo_bookmark_copy (MooBookmark *bookmark)
|
|
{
|
|
MooBookmark *copy;
|
|
|
|
g_return_val_if_fail (bookmark != NULL, NULL);
|
|
|
|
copy = g_new0 (MooBookmark, 1);
|
|
|
|
copy->path = g_strdup (bookmark->path);
|
|
copy->display_path = g_strdup (bookmark->display_path);
|
|
copy->label = g_strdup (bookmark->label);
|
|
copy->icon_stock_id = g_strdup (bookmark->icon_stock_id);
|
|
if (bookmark->pixbuf)
|
|
copy->pixbuf = g_object_ref (bookmark->pixbuf);
|
|
|
|
return copy;
|
|
}
|
|
|
|
|
|
void
|
|
_moo_bookmark_free (MooBookmark *bookmark)
|
|
{
|
|
if (bookmark)
|
|
{
|
|
g_free (bookmark->path);
|
|
g_free (bookmark->display_path);
|
|
g_free (bookmark->label);
|
|
g_free (bookmark->icon_stock_id);
|
|
if (bookmark->pixbuf)
|
|
g_object_unref (bookmark->pixbuf);
|
|
g_free (bookmark);
|
|
}
|
|
}
|
|
|
|
|
|
GType
|
|
_moo_bookmark_get_type (void)
|
|
{
|
|
static GType type = 0;
|
|
if (!type)
|
|
type = g_boxed_type_register_static ("MooBookmark",
|
|
(GBoxedCopyFunc) _moo_bookmark_copy,
|
|
(GBoxedFreeFunc) _moo_bookmark_free);
|
|
return type;
|
|
}
|
|
|
|
|
|
void
|
|
_moo_bookmark_set_path (MooBookmark *bookmark,
|
|
const char *path)
|
|
{
|
|
char *display_path;
|
|
g_return_if_fail (bookmark != NULL);
|
|
g_return_if_fail (path != NULL);
|
|
|
|
display_path = g_filename_to_utf8 (path, -1, NULL, NULL, NULL);
|
|
g_return_if_fail (display_path != NULL);
|
|
|
|
g_free (bookmark->path);
|
|
g_free (bookmark->display_path);
|
|
bookmark->display_path = display_path;
|
|
bookmark->path = g_strdup (path);
|
|
}
|
|
|
|
|
|
void
|
|
_moo_bookmark_set_display_path (MooBookmark *bookmark,
|
|
const char *display_path)
|
|
{
|
|
char *path;
|
|
g_return_if_fail (bookmark != NULL);
|
|
g_return_if_fail (display_path != NULL);
|
|
|
|
path = g_filename_from_utf8 (display_path, -1, NULL, NULL, NULL);
|
|
g_return_if_fail (path != NULL);
|
|
|
|
g_free (bookmark->path);
|
|
g_free (bookmark->display_path);
|
|
bookmark->path = path;
|
|
bookmark->display_path = g_strdup (display_path);
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/* Loading and saving
|
|
*/
|
|
#define BOOKMARKS_ROOT "FileSelector/bookmarks"
|
|
#define ELEMENT_BOOKMARK "bookmark"
|
|
#define ELEMENT_SEPARATOR "separator"
|
|
#define PROP_LABEL "label"
|
|
#define PROP_ICON "icon"
|
|
|
|
static void
|
|
moo_bookmark_mgr_load (MooBookmarkMgr *mgr)
|
|
{
|
|
MooMarkupDoc *xml;
|
|
MooMarkupNode *root, *node;
|
|
|
|
xml = moo_prefs_get_markup ();
|
|
g_return_if_fail (xml != NULL);
|
|
|
|
root = moo_markup_get_element (MOO_MARKUP_NODE (xml), BOOKMARKS_ROOT);
|
|
|
|
if (!root)
|
|
return;
|
|
|
|
mgr->priv->loading = TRUE;
|
|
|
|
for (node = root->children; node != NULL; node = node->next)
|
|
{
|
|
if (!MOO_MARKUP_IS_ELEMENT (node))
|
|
continue;
|
|
|
|
if (!strcmp (node->name, ELEMENT_BOOKMARK))
|
|
{
|
|
MooBookmark *bookmark;
|
|
const char *label = moo_markup_get_prop (node, PROP_LABEL);
|
|
const char *icon = moo_markup_get_prop (node, PROP_ICON);
|
|
const char *path_utf8 = moo_markup_get_content (node);
|
|
char *path;
|
|
|
|
if (!path_utf8 || !path_utf8[0])
|
|
{
|
|
g_warning ("%s: empty path in bookmark", G_STRLOC);
|
|
continue;
|
|
}
|
|
|
|
path = g_filename_from_utf8 (path_utf8, -1, NULL, NULL, NULL);
|
|
|
|
if (!path)
|
|
{
|
|
g_warning ("%s: could not convert '%s' to filename encoding",
|
|
G_STRLOC, path_utf8);
|
|
continue;
|
|
}
|
|
|
|
bookmark = _moo_bookmark_new (label ? label : path_utf8, path, icon);
|
|
_moo_bookmark_mgr_add (mgr, bookmark);
|
|
|
|
_moo_bookmark_free (bookmark);
|
|
g_free (path);
|
|
}
|
|
else if (!strcmp (node->name, ELEMENT_SEPARATOR))
|
|
{
|
|
moo_bookmark_mgr_add_separator (mgr);
|
|
}
|
|
else
|
|
{
|
|
g_warning ("%s: invalid '%s' element", G_STRLOC, node->name);
|
|
}
|
|
}
|
|
|
|
mgr->priv->loading = FALSE;
|
|
}
|
|
|
|
|
|
static void
|
|
moo_bookmark_mgr_save (MooBookmarkMgr *mgr)
|
|
{
|
|
MooMarkupDoc *xml;
|
|
MooMarkupNode *root;
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
|
|
xml = moo_prefs_get_markup ();
|
|
g_return_if_fail (xml != NULL);
|
|
|
|
model = GTK_TREE_MODEL (mgr->priv->store);
|
|
|
|
root = moo_markup_get_element (MOO_MARKUP_NODE (xml), BOOKMARKS_ROOT);
|
|
|
|
if (root)
|
|
moo_markup_delete_node (root);
|
|
|
|
if (!gtk_tree_model_get_iter_first (model, &iter))
|
|
return;
|
|
|
|
root = moo_markup_create_element (MOO_MARKUP_NODE (xml), BOOKMARKS_ROOT);
|
|
g_return_if_fail (root != NULL);
|
|
|
|
do
|
|
{
|
|
MooBookmark *bookmark = NULL;
|
|
MooMarkupNode *elm;
|
|
|
|
gtk_tree_model_get (model, &iter, COLUMN_BOOKMARK, &bookmark, -1);
|
|
|
|
if (!bookmark)
|
|
{
|
|
moo_markup_create_element (root, ELEMENT_SEPARATOR);
|
|
continue;
|
|
}
|
|
|
|
/* XXX validate bookmark */
|
|
elm = moo_markup_create_text_element (root, ELEMENT_BOOKMARK,
|
|
bookmark->display_path);
|
|
moo_markup_set_prop (elm, PROP_LABEL, bookmark->label);
|
|
if (bookmark->icon_stock_id)
|
|
moo_markup_set_prop (elm, PROP_ICON, bookmark->icon_stock_id);
|
|
|
|
_moo_bookmark_free (bookmark);
|
|
}
|
|
while (gtk_tree_model_iter_next (model, &iter));
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/* Bookmarks menu
|
|
*/
|
|
|
|
struct _UserInfo {
|
|
GObject *user;
|
|
MooUIXML *xml;
|
|
GtkActionGroup *actions;
|
|
char *path;
|
|
guint user_id;
|
|
guint merge_id;
|
|
GSList *bm_actions;
|
|
};
|
|
|
|
static UserInfo*
|
|
user_info_new (GObject *user,
|
|
GtkActionGroup *actions,
|
|
MooUIXML *xml,
|
|
const char *path,
|
|
guint user_id)
|
|
{
|
|
UserInfo *info;
|
|
|
|
g_return_val_if_fail (G_IS_OBJECT (user), NULL);
|
|
g_return_val_if_fail (GTK_IS_ACTION_GROUP (actions), NULL);
|
|
g_return_val_if_fail (MOO_IS_UI_XML (xml), NULL);
|
|
g_return_val_if_fail (path, NULL);
|
|
g_return_val_if_fail (user_id > 0, NULL);
|
|
|
|
info = g_new0 (UserInfo, 1);
|
|
info->user = user;
|
|
info->actions = actions;
|
|
info->xml = xml;
|
|
info->path = g_strdup (path);
|
|
info->user_id = user_id;
|
|
|
|
return info;
|
|
}
|
|
|
|
|
|
static void
|
|
user_info_free (UserInfo *info)
|
|
{
|
|
if (info)
|
|
{
|
|
g_free (info->path);
|
|
g_free (info);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
item_activated (GtkAction *action,
|
|
MooBookmarkMgr *mgr)
|
|
{
|
|
MooBookmark *bookmark;
|
|
gpointer user;
|
|
|
|
g_return_if_fail (GTK_IS_ACTION (action));
|
|
g_return_if_fail (MOO_IS_BOOKMARK_MGR (mgr));
|
|
|
|
bookmark = g_object_get_data (G_OBJECT (action), "moo-bookmark");
|
|
user = g_object_get_data (G_OBJECT (action), "moo-bookmark-user");
|
|
|
|
g_return_if_fail (bookmark != NULL && user != NULL);
|
|
|
|
g_signal_emit (mgr, signals[ACTIVATE], 0, bookmark, user);
|
|
}
|
|
|
|
|
|
static void
|
|
make_menu (MooBookmarkMgr *mgr,
|
|
UserInfo *info)
|
|
{
|
|
GtkTreeModel *model = GTK_TREE_MODEL (mgr->priv->store);
|
|
GtkTreeIter iter;
|
|
GString *markup;
|
|
|
|
if (!gtk_tree_model_get_iter_first (model, &iter))
|
|
return;
|
|
|
|
info->merge_id = moo_ui_xml_new_merge_id (info->xml);
|
|
markup = g_string_new (NULL);
|
|
|
|
do
|
|
{
|
|
MooBookmark *bookmark = NULL;
|
|
GtkAction *action;
|
|
char *action_id;
|
|
|
|
gtk_tree_model_get (model, &iter, COLUMN_BOOKMARK, &bookmark, -1);
|
|
|
|
if (!bookmark)
|
|
{
|
|
g_string_append (markup, "<separator/>");
|
|
continue;
|
|
}
|
|
|
|
action_id = g_strdup_printf ("MooBookmarkAction-%p", bookmark);
|
|
|
|
action = moo_action_group_add_action (info->actions, action_id,
|
|
"label", bookmark->label ? bookmark->label :
|
|
bookmark->display_path,
|
|
"stock-id", bookmark->icon_stock_id,
|
|
"tooltip", bookmark->display_path,
|
|
"no-accel", TRUE,
|
|
NULL);
|
|
g_object_ref (action);
|
|
g_object_set_data_full (G_OBJECT (action), "moo-bookmark",
|
|
bookmark, (GDestroyNotify) _moo_bookmark_free);
|
|
g_object_set_data (G_OBJECT (action), "moo-bookmark-user", info->user);
|
|
g_signal_connect (action, "activate", G_CALLBACK (item_activated), mgr);
|
|
|
|
info->bm_actions = g_slist_prepend (info->bm_actions, action);
|
|
|
|
g_string_append_printf (markup, "<item action=\"%s\"/>", action_id);
|
|
|
|
g_free (action_id);
|
|
}
|
|
while (gtk_tree_model_iter_next (model, &iter));
|
|
|
|
moo_ui_xml_insert_markup (info->xml, info->merge_id,
|
|
info->path, -1, markup->str);
|
|
g_string_free (markup, TRUE);
|
|
}
|
|
|
|
|
|
static void
|
|
destroy_menu (UserInfo *info)
|
|
{
|
|
GSList *l;
|
|
|
|
for (l = info->bm_actions; l != NULL; l = l->next)
|
|
{
|
|
GtkAction *action = l->data;
|
|
gtk_action_group_remove_action (info->actions, action);
|
|
g_object_unref (action);
|
|
}
|
|
|
|
g_slist_free (info->bm_actions);
|
|
info->bm_actions = NULL;
|
|
|
|
if (info->merge_id > 0)
|
|
{
|
|
moo_ui_xml_remove_ui (info->xml, info->merge_id);
|
|
info->merge_id = 0;
|
|
}
|
|
}
|
|
|
|
|
|
static gboolean
|
|
mgr_update_menus (MooBookmarkMgr *mgr)
|
|
{
|
|
GSList *l;
|
|
GtkTreeIter first;
|
|
GtkTreeModel *model = GTK_TREE_MODEL (mgr->priv->store);
|
|
gboolean empty;
|
|
|
|
mgr->priv->update_idle = 0;
|
|
|
|
empty = !gtk_tree_model_get_iter_first (model, &first);
|
|
|
|
for (l = mgr->priv->users; l != NULL; l = l->next)
|
|
{
|
|
UserInfo *info = l->data;
|
|
|
|
destroy_menu (info);
|
|
|
|
if (!empty)
|
|
make_menu (mgr, info);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void
|
|
_moo_bookmark_mgr_add_user (MooBookmarkMgr *mgr,
|
|
gpointer user,
|
|
GtkActionGroup *actions,
|
|
MooUIXML *xml,
|
|
const char *path)
|
|
{
|
|
guint merge_id;
|
|
UserInfo *info;
|
|
|
|
g_return_if_fail (MOO_IS_BOOKMARK_MGR (mgr));
|
|
g_return_if_fail (G_IS_OBJECT (user));
|
|
g_return_if_fail (GTK_IS_ACTION_GROUP (actions));
|
|
g_return_if_fail (MOO_IS_UI_XML (xml));
|
|
g_return_if_fail (path != NULL);
|
|
|
|
merge_id = moo_ui_xml_new_merge_id (xml);
|
|
info = user_info_new (user, actions, xml, path,
|
|
++mgr->priv->last_user_id);
|
|
mgr->priv->users = g_slist_prepend (mgr->priv->users, info);
|
|
|
|
make_menu (mgr, info);
|
|
}
|
|
|
|
|
|
static void
|
|
mgr_remove_user (MooBookmarkMgr *mgr,
|
|
UserInfo *info)
|
|
{
|
|
destroy_menu (info);
|
|
user_info_free (info);
|
|
mgr->priv->users = g_slist_remove (mgr->priv->users, info);
|
|
}
|
|
|
|
|
|
void
|
|
_moo_bookmark_mgr_remove_user (MooBookmarkMgr *mgr,
|
|
gpointer user)
|
|
{
|
|
GSList *l, *infos = NULL;
|
|
|
|
g_return_if_fail (MOO_IS_BOOKMARK_MGR (mgr));
|
|
|
|
for (l = mgr->priv->users; l != NULL; l = l->next)
|
|
{
|
|
UserInfo *info = l->data;
|
|
|
|
if (info->user == user)
|
|
infos = g_slist_prepend (infos, info);
|
|
}
|
|
|
|
for (l = infos; l != NULL; l = l->next)
|
|
{
|
|
UserInfo *info = l->data;
|
|
mgr_remove_user (mgr, info);
|
|
}
|
|
|
|
g_slist_free (infos);
|
|
}
|
|
|
|
|
|
// static void create_menu_items (MooBookmarkMgr *mgr,
|
|
// GtkMenuShell *menu,
|
|
// int position,
|
|
// MooBookmarkFunc func,
|
|
// gpointer data)
|
|
// {
|
|
// GtkTreeIter iter;
|
|
// GtkTreeModel *model = GTK_TREE_MODEL (mgr->priv->store);
|
|
//
|
|
// if (!gtk_tree_model_get_iter_first (model, &iter))
|
|
// return;
|
|
//
|
|
// do
|
|
// {
|
|
// MooBookmark *bookmark = NULL;
|
|
// GtkWidget *item, *icon;
|
|
//
|
|
// gtk_tree_model_get (model, &iter, COLUMN_BOOKMARK, &bookmark, -1);
|
|
//
|
|
// if (!bookmark)
|
|
// {
|
|
// item = gtk_separator_menu_item_new ();
|
|
// }
|
|
// else
|
|
// {
|
|
// if (bookmark->label)
|
|
// item = gtk_image_menu_item_new_with_label (bookmark->label);
|
|
// else
|
|
// item = gtk_image_menu_item_new ();
|
|
//
|
|
// if (bookmark->pixbuf)
|
|
// icon = gtk_image_new_from_pixbuf (bookmark->pixbuf);
|
|
// else if (bookmark->icon_stock_id)
|
|
// icon = gtk_image_new_from_stock (bookmark->icon_stock_id,
|
|
// GTK_ICON_SIZE_MENU);
|
|
// else
|
|
// icon = NULL;
|
|
//
|
|
// if (icon)
|
|
// {
|
|
// gtk_widget_show (icon);
|
|
// gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), icon);
|
|
// }
|
|
//
|
|
// g_signal_connect (item, "activate",
|
|
// G_CALLBACK (menu_item_activated), mgr);
|
|
// }
|
|
//
|
|
// g_object_set_data_full (G_OBJECT (item), "moo-bookmark-mgr",
|
|
// g_object_ref (mgr), g_object_unref);
|
|
// g_object_set_data_full (G_OBJECT (item), "moo-bookmark",
|
|
// bookmark, (GDestroyNotify) _moo_bookmark_free);
|
|
// g_object_set_data (G_OBJECT (item), "moo-bookmark-func", func);
|
|
// g_object_set_data (G_OBJECT (item), "moo-bookmark-data", data);
|
|
//
|
|
// gtk_widget_show (item);
|
|
// gtk_menu_shell_insert (menu, item, position);
|
|
// if (position >= 0)
|
|
// position++;
|
|
// }
|
|
// while (gtk_tree_model_iter_next (model, &iter));
|
|
// }
|
|
|
|
|
|
#if 0
|
|
static void moo_bookmark_mgr_update_menu(GtkMenuShell *menu,
|
|
MooBookmarkMgr *mgr)
|
|
{
|
|
MooBookmarkFunc func;
|
|
gpointer data;
|
|
GList *items;
|
|
int position = 0;
|
|
|
|
g_return_if_fail (MOO_IS_BOOKMARK_MGR (mgr));
|
|
g_return_if_fail (GTK_IS_MENU_SHELL (menu));
|
|
|
|
g_return_if_fail (g_object_get_data (G_OBJECT (menu), "moo-bookmark-mgr") == mgr);
|
|
|
|
func = g_object_get_data (G_OBJECT (menu), "moo-bookmark-func");
|
|
data = g_object_get_data (G_OBJECT (menu), "moo-bookmark-data");
|
|
|
|
items = gtk_container_get_children (GTK_CONTAINER (menu));
|
|
|
|
if (items)
|
|
{
|
|
GList *l;
|
|
GList *my_items = NULL;
|
|
|
|
for (l = items; l != NULL; l = l->next)
|
|
{
|
|
if (g_object_get_data (G_OBJECT (l->data), "moo-bookmark-mgr") == mgr)
|
|
{
|
|
my_items = g_list_prepend (my_items, l->data);
|
|
if (position < 0)
|
|
position = g_list_position (items, l);
|
|
}
|
|
}
|
|
|
|
for (l = my_items; l != NULL; l = l->next)
|
|
gtk_container_remove (GTK_CONTAINER (menu), l->data);
|
|
|
|
g_list_free (items);
|
|
g_list_free (my_items);
|
|
}
|
|
|
|
create_menu_items (mgr, menu, position, func, data);
|
|
}
|
|
#endif
|
|
|
|
|
|
/***************************************************************************/
|
|
/* Bookmark editor
|
|
*/
|
|
|
|
static GtkTreeModel *copy_bookmarks (GtkListStore *store);
|
|
static void copy_bookmarks_back (GtkListStore *store,
|
|
GtkTreeModel *model);
|
|
static void init_editor_dialog (GtkTreeView *treeview,
|
|
MooGladeXML *xml);
|
|
static void dialog_response (GtkWidget *dialog,
|
|
int response,
|
|
MooBookmarkMgr *mgr);
|
|
static void dialog_show (GtkWidget *dialog,
|
|
MooBookmarkMgr *mgr);
|
|
|
|
GtkWidget *
|
|
_moo_bookmark_mgr_get_editor (MooBookmarkMgr *mgr)
|
|
{
|
|
GtkWidget *dialog;
|
|
MooGladeXML *xml;
|
|
GtkTreeView *treeview;
|
|
|
|
if (mgr->priv->editor)
|
|
return mgr->priv->editor;
|
|
|
|
xml = moo_glade_xml_new_from_buf (MOO_BOOKMARK_MGR_GLADE_UI, -1, NULL);
|
|
|
|
dialog = moo_glade_xml_get_widget (xml, "dialog");
|
|
g_assert (dialog != NULL);
|
|
|
|
g_object_set_data_full (G_OBJECT (dialog), "dialog-glade-xml",
|
|
xml, (GDestroyNotify) g_object_unref);
|
|
|
|
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
|
|
|
|
treeview = GTK_TREE_VIEW (moo_glade_xml_get_widget (xml, "treeview"));
|
|
init_editor_dialog (treeview, xml);
|
|
|
|
g_signal_connect (dialog, "response",
|
|
G_CALLBACK (dialog_response), mgr);
|
|
g_signal_connect (dialog, "delete-event",
|
|
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
|
|
g_signal_connect (dialog, "show",
|
|
G_CALLBACK (dialog_show), mgr);
|
|
|
|
mgr->priv->editor = dialog;
|
|
gtk_object_sink (g_object_ref (dialog));
|
|
|
|
return dialog;
|
|
}
|
|
|
|
|
|
static void
|
|
dialog_show (GtkWidget *dialog,
|
|
MooBookmarkMgr *mgr)
|
|
{
|
|
MooGladeXML *xml;
|
|
GtkTreeView *treeview;
|
|
GtkTreeModel *model;
|
|
|
|
xml = g_object_get_data (G_OBJECT (dialog), "dialog-glade-xml");
|
|
g_return_if_fail (xml != NULL);
|
|
|
|
model = copy_bookmarks (mgr->priv->store);
|
|
treeview = GTK_TREE_VIEW (moo_glade_xml_get_widget (xml, "treeview"));
|
|
gtk_tree_view_set_model (treeview, model);
|
|
g_object_unref (model);
|
|
}
|
|
|
|
|
|
static void
|
|
dialog_response (GtkWidget *dialog,
|
|
int response,
|
|
MooBookmarkMgr *mgr)
|
|
{
|
|
MooGladeXML *xml;
|
|
GtkTreeView *treeview;
|
|
GtkTreeModel *model;
|
|
|
|
if (response != GTK_RESPONSE_OK)
|
|
{
|
|
gtk_widget_hide (dialog);
|
|
return;
|
|
}
|
|
|
|
xml = g_object_get_data (G_OBJECT (dialog), "dialog-glade-xml");
|
|
g_return_if_fail (xml != NULL);
|
|
|
|
treeview = GTK_TREE_VIEW (moo_glade_xml_get_widget (xml, "treeview"));
|
|
model = gtk_tree_view_get_model (treeview);
|
|
copy_bookmarks_back (mgr->priv->store, model);
|
|
gtk_widget_hide (dialog);
|
|
}
|
|
|
|
|
|
static gboolean
|
|
copy_value (GtkTreeModel *src,
|
|
G_GNUC_UNUSED GtkTreePath *path,
|
|
GtkTreeIter *iter,
|
|
GtkListStore *dest)
|
|
{
|
|
GtkTreeIter dest_iter;
|
|
MooBookmark *bookmark;
|
|
|
|
gtk_tree_model_get (src, iter, COLUMN_BOOKMARK, &bookmark, -1);
|
|
gtk_list_store_append (dest, &dest_iter);
|
|
gtk_list_store_set (dest, &dest_iter, COLUMN_BOOKMARK, bookmark, -1);
|
|
_moo_bookmark_free (bookmark);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static GtkTreeModel *
|
|
copy_bookmarks (GtkListStore *store)
|
|
{
|
|
GtkListStore *copy;
|
|
copy = gtk_list_store_new (1, MOO_TYPE_BOOKMARK);
|
|
gtk_tree_model_foreach (GTK_TREE_MODEL (store),
|
|
(GtkTreeModelForeachFunc) copy_value,
|
|
copy);
|
|
return GTK_TREE_MODEL (copy);
|
|
}
|
|
|
|
|
|
static void
|
|
copy_bookmarks_back (GtkListStore *store,
|
|
GtkTreeModel *model)
|
|
{
|
|
gtk_list_store_clear (store);
|
|
gtk_tree_model_foreach (model,
|
|
(GtkTreeModelForeachFunc) copy_value,
|
|
store);
|
|
}
|
|
|
|
|
|
static void icon_data_func (GtkTreeViewColumn *column,
|
|
GtkCellRenderer *cell,
|
|
GtkTreeModel *model,
|
|
GtkTreeIter *iter);
|
|
static void label_data_func (GtkTreeViewColumn *column,
|
|
GtkCellRenderer *cell,
|
|
GtkTreeModel *model,
|
|
GtkTreeIter *iter);
|
|
static void path_data_func (GtkTreeViewColumn *column,
|
|
GtkCellRenderer *cell,
|
|
GtkTreeModel *model,
|
|
GtkTreeIter *iter);
|
|
|
|
static void selection_changed (GtkTreeSelection *selection,
|
|
MooGladeXML *xml);
|
|
static void new_clicked (MooGladeXML *xml);
|
|
static void delete_clicked (MooGladeXML *xml);
|
|
static void separator_clicked (MooGladeXML *xml);
|
|
|
|
static void label_edited (GtkCellRenderer *cell,
|
|
char *path,
|
|
char *text,
|
|
MooGladeXML *xml);
|
|
static void path_edited (GtkCellRenderer *cell,
|
|
char *path,
|
|
char *text,
|
|
MooGladeXML *xml);
|
|
static void path_editing_started(GtkCellRenderer *cell,
|
|
GtkCellEditable *editable);
|
|
static void path_entry_realize (GtkWidget *entry);
|
|
static void path_entry_unrealize(GtkWidget *entry);
|
|
|
|
static void init_icon_combo (GtkComboBox *combo,
|
|
MooGladeXML *xml);
|
|
static void combo_update_icon (GtkComboBox *combo,
|
|
MooGladeXML *xml);
|
|
|
|
|
|
static void
|
|
init_editor_dialog (GtkTreeView *treeview,
|
|
MooGladeXML *xml)
|
|
{
|
|
GtkTreeViewColumn *column;
|
|
GtkCellRenderer *cell;
|
|
GtkTreeSelection *selection;
|
|
GtkWidget *button, *icon_combo;
|
|
MooFileEntryCompletion *completion;
|
|
|
|
icon_combo = moo_glade_xml_get_widget (xml, "icon_combo");
|
|
init_icon_combo (GTK_COMBO_BOX (icon_combo), xml);
|
|
|
|
selection = gtk_tree_view_get_selection (treeview);
|
|
gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
|
|
g_signal_connect (selection, "changed",
|
|
G_CALLBACK (selection_changed), xml);
|
|
selection_changed (selection, xml);
|
|
|
|
button = moo_glade_xml_get_widget (xml, "delete_button");
|
|
g_signal_connect_swapped (button, "clicked",
|
|
G_CALLBACK (delete_clicked), xml);
|
|
|
|
button = moo_glade_xml_get_widget (xml, "new_button");
|
|
g_signal_connect_swapped (button, "clicked",
|
|
G_CALLBACK (new_clicked), xml);
|
|
|
|
button = moo_glade_xml_get_widget (xml, "separator_button");
|
|
g_signal_connect_swapped (button, "clicked",
|
|
G_CALLBACK (separator_clicked), xml);
|
|
|
|
/* Icon */
|
|
cell = gtk_cell_renderer_pixbuf_new ();
|
|
column = gtk_tree_view_column_new_with_attributes ("Icon", cell, NULL);
|
|
gtk_tree_view_column_set_cell_data_func (column, cell,
|
|
(GtkTreeCellDataFunc) icon_data_func,
|
|
NULL, NULL);
|
|
gtk_tree_view_append_column (treeview, column);
|
|
g_object_set_data (G_OBJECT (treeview),
|
|
"moo-bookmarks-icon-column",
|
|
column);
|
|
|
|
/* Label */
|
|
cell = gtk_cell_renderer_text_new ();
|
|
g_object_set (cell, "editable", TRUE, NULL);
|
|
g_signal_connect (cell, "edited",
|
|
G_CALLBACK (label_edited), xml);
|
|
|
|
column = gtk_tree_view_column_new_with_attributes ("Label", cell, NULL);
|
|
gtk_tree_view_column_set_cell_data_func (column, cell,
|
|
(GtkTreeCellDataFunc) label_data_func,
|
|
NULL, NULL);
|
|
gtk_tree_view_append_column (treeview, column);
|
|
g_object_set_data (G_OBJECT (treeview),
|
|
"moo-bookmarks-label-column",
|
|
column);
|
|
|
|
/* Path */
|
|
cell = gtk_cell_renderer_text_new ();
|
|
g_object_set (cell, "editable", TRUE, NULL);
|
|
g_signal_connect (cell, "edited",
|
|
G_CALLBACK (path_edited), xml);
|
|
g_signal_connect (cell, "editing-started",
|
|
G_CALLBACK (path_editing_started), NULL);
|
|
|
|
column = gtk_tree_view_column_new_with_attributes ("Path", cell, NULL);
|
|
gtk_tree_view_column_set_cell_data_func (column, cell,
|
|
(GtkTreeCellDataFunc) path_data_func,
|
|
NULL, NULL);
|
|
gtk_tree_view_append_column (treeview, column);
|
|
g_object_set_data (G_OBJECT (treeview),
|
|
"moo-bookmarks-path-column",
|
|
column);
|
|
|
|
completion = g_object_new (MOO_TYPE_FILE_ENTRY_COMPLETION,
|
|
"directories-only", TRUE,
|
|
"show-hidden", FALSE,
|
|
NULL);
|
|
g_object_set_data_full (G_OBJECT (cell), "moo-file-entry-completion",
|
|
completion, g_object_unref);
|
|
}
|
|
|
|
|
|
static MooBookmark *
|
|
get_bookmark (GtkTreeModel *model,
|
|
GtkTreeIter *iter)
|
|
{
|
|
MooBookmark *bookmark = NULL;
|
|
gtk_tree_model_get (model, iter, COLUMN_BOOKMARK, &bookmark, -1);
|
|
return bookmark;
|
|
}
|
|
|
|
|
|
static void
|
|
set_bookmark (GtkListStore *store,
|
|
GtkTreeIter *iter,
|
|
MooBookmark *bookmark)
|
|
{
|
|
gtk_list_store_set (store, iter, COLUMN_BOOKMARK, bookmark, -1);
|
|
}
|
|
|
|
|
|
static void
|
|
icon_data_func (G_GNUC_UNUSED GtkTreeViewColumn *column,
|
|
GtkCellRenderer *cell,
|
|
GtkTreeModel *model,
|
|
GtkTreeIter *iter)
|
|
{
|
|
MooBookmark *bookmark = get_bookmark (model, iter);
|
|
|
|
if (!bookmark)
|
|
g_object_set (cell,
|
|
"pixbuf", NULL,
|
|
"stock-id", NULL,
|
|
NULL);
|
|
else
|
|
g_object_set (cell,
|
|
"pixbuf", bookmark->pixbuf,
|
|
"stock-id", bookmark->icon_stock_id,
|
|
"stock-size", GTK_ICON_SIZE_MENU,
|
|
NULL);
|
|
|
|
_moo_bookmark_free (bookmark);
|
|
}
|
|
|
|
|
|
static void
|
|
label_data_func (G_GNUC_UNUSED GtkTreeViewColumn *column,
|
|
GtkCellRenderer *cell,
|
|
GtkTreeModel *model,
|
|
GtkTreeIter *iter)
|
|
{
|
|
MooBookmark *bookmark = get_bookmark (model, iter);
|
|
|
|
if (!bookmark)
|
|
g_object_set (cell,
|
|
"text", "-------",
|
|
"editable", FALSE,
|
|
NULL);
|
|
else
|
|
g_object_set (cell,
|
|
"text", bookmark->label,
|
|
"editable", TRUE,
|
|
NULL);
|
|
|
|
_moo_bookmark_free (bookmark);
|
|
}
|
|
|
|
|
|
static void
|
|
path_data_func (G_GNUC_UNUSED GtkTreeViewColumn *column,
|
|
GtkCellRenderer *cell,
|
|
GtkTreeModel *model,
|
|
GtkTreeIter *iter)
|
|
{
|
|
MooBookmark *bookmark = get_bookmark (model, iter);
|
|
|
|
if (!bookmark)
|
|
g_object_set (cell,
|
|
"text", NULL,
|
|
"editable", FALSE,
|
|
NULL);
|
|
else
|
|
g_object_set (cell,
|
|
"text", bookmark->display_path,
|
|
"editable", TRUE,
|
|
NULL);
|
|
|
|
_moo_bookmark_free (bookmark);
|
|
}
|
|
|
|
|
|
static void
|
|
selection_changed (GtkTreeSelection *selection,
|
|
MooGladeXML *xml)
|
|
{
|
|
GtkWidget *button, *selected_hbox;
|
|
int selected;
|
|
|
|
button = moo_glade_xml_get_widget (xml, "delete_button");
|
|
selected_hbox = moo_glade_xml_get_widget (xml, "selected_hbox");
|
|
|
|
selected = gtk_tree_selection_count_selected_rows (selection);
|
|
|
|
gtk_widget_set_sensitive (button, selected);
|
|
|
|
if (selected == 1)
|
|
{
|
|
GtkTreeIter iter;
|
|
GtkTreeModel *model;
|
|
MooBookmark *bookmark;
|
|
GList *rows = gtk_tree_selection_get_selected_rows (selection, &model);
|
|
g_return_if_fail (rows != NULL);
|
|
gtk_tree_model_get_iter (model, &iter, rows->data);
|
|
bookmark = get_bookmark (model, &iter);
|
|
if (bookmark)
|
|
{
|
|
GtkWidget *icon_combo;
|
|
gtk_widget_set_sensitive (selected_hbox, TRUE);
|
|
icon_combo = moo_glade_xml_get_widget (xml, "icon_combo");
|
|
combo_update_icon (GTK_COMBO_BOX (icon_combo), xml);
|
|
_moo_bookmark_free (bookmark);
|
|
}
|
|
else
|
|
{
|
|
gtk_widget_set_sensitive (selected_hbox, FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gtk_widget_set_sensitive (selected_hbox, FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
new_clicked (MooGladeXML *xml)
|
|
{
|
|
GtkTreeIter iter;
|
|
GtkTreePath *path;
|
|
GtkWidget *treeview;
|
|
GtkTreeViewColumn *column;
|
|
GtkListStore *store;
|
|
MooBookmark *bookmark;
|
|
|
|
treeview = moo_glade_xml_get_widget (xml, "treeview");
|
|
store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)));
|
|
|
|
bookmark = _moo_bookmark_new ("New bookmark", NULL,
|
|
GTK_STOCK_DIRECTORY);
|
|
gtk_list_store_append (store, &iter);
|
|
set_bookmark (store, &iter, bookmark);
|
|
|
|
column = g_object_get_data (G_OBJECT (treeview),
|
|
"moo-bookmarks-label-column");
|
|
path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
|
|
gtk_tree_view_set_cursor (GTK_TREE_VIEW (treeview), path, column, TRUE);
|
|
|
|
g_object_set_data (G_OBJECT (store),
|
|
"moo-bookmarks-modified",
|
|
GINT_TO_POINTER (TRUE));
|
|
|
|
gtk_tree_path_free (path);
|
|
_moo_bookmark_free (bookmark);
|
|
}
|
|
|
|
|
|
static void
|
|
delete_clicked (MooGladeXML *xml)
|
|
{
|
|
GtkTreeIter iter;
|
|
GtkTreePath *path;
|
|
GtkWidget *treeview;
|
|
GtkTreeSelection *selection;
|
|
GtkListStore *store;
|
|
GList *paths, *rows = NULL, *l;
|
|
|
|
treeview = moo_glade_xml_get_widget (xml, "treeview");
|
|
store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)));
|
|
|
|
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
|
|
paths = gtk_tree_selection_get_selected_rows (selection, NULL);
|
|
|
|
if (!paths)
|
|
return;
|
|
|
|
for (l = paths; l != NULL; l = l->next)
|
|
rows = g_list_prepend (rows,
|
|
gtk_tree_row_reference_new (GTK_TREE_MODEL (store),
|
|
l->data));
|
|
|
|
for (l = rows; l != NULL; l = l->next)
|
|
{
|
|
if (gtk_tree_row_reference_valid (l->data))
|
|
{
|
|
path = gtk_tree_row_reference_get_path (l->data);
|
|
gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
|
|
gtk_list_store_remove (store, &iter);
|
|
gtk_tree_path_free (path);
|
|
}
|
|
}
|
|
|
|
g_object_set_data (G_OBJECT (store),
|
|
"moo-bookmarks-modified",
|
|
GINT_TO_POINTER (TRUE));
|
|
|
|
g_list_foreach (paths, (GFunc) gtk_tree_path_free, NULL);
|
|
g_list_foreach (rows, (GFunc) gtk_tree_row_reference_free, NULL);
|
|
g_list_free (paths);
|
|
g_list_free (rows);
|
|
}
|
|
|
|
|
|
static void
|
|
separator_clicked (MooGladeXML *xml)
|
|
{
|
|
GtkTreeIter iter;
|
|
GtkWidget *treeview;
|
|
GtkListStore *store;
|
|
|
|
treeview = moo_glade_xml_get_widget (xml, "treeview");
|
|
store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)));
|
|
gtk_list_store_append (store, &iter);
|
|
}
|
|
|
|
|
|
static void
|
|
label_edited (G_GNUC_UNUSED GtkCellRenderer *cell,
|
|
char *path_string,
|
|
char *text,
|
|
MooGladeXML *xml)
|
|
{
|
|
GtkTreeIter iter;
|
|
GtkTreePath *path;
|
|
GtkWidget *treeview;
|
|
GtkListStore *store;
|
|
MooBookmark *bookmark;
|
|
|
|
treeview = moo_glade_xml_get_widget (xml, "treeview");
|
|
store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)));
|
|
|
|
path = gtk_tree_path_new_from_string (path_string);
|
|
|
|
if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
|
|
{
|
|
gtk_tree_path_free (path);
|
|
return;
|
|
}
|
|
|
|
bookmark = get_bookmark (GTK_TREE_MODEL (store), &iter);
|
|
g_return_if_fail (bookmark != NULL);
|
|
|
|
if (!bookmark->label || strcmp (bookmark->label, text))
|
|
{
|
|
g_free (bookmark->label);
|
|
bookmark->label = g_strdup (text);
|
|
set_bookmark (store, &iter, bookmark);
|
|
g_object_set_data (G_OBJECT (store),
|
|
"moo-bookmarks-modified",
|
|
GINT_TO_POINTER (TRUE));
|
|
}
|
|
|
|
_moo_bookmark_free (bookmark);
|
|
gtk_tree_path_free (path);
|
|
}
|
|
|
|
|
|
static void
|
|
path_edited (G_GNUC_UNUSED GtkCellRenderer *cell,
|
|
char *path_string,
|
|
char *text,
|
|
MooGladeXML *xml)
|
|
{
|
|
GtkTreeIter iter;
|
|
GtkTreePath *path;
|
|
GtkWidget *treeview;
|
|
GtkListStore *store;
|
|
MooBookmark *bookmark;
|
|
MooFileEntryCompletion *cmpl;
|
|
|
|
treeview = moo_glade_xml_get_widget (xml, "treeview");
|
|
store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)));
|
|
|
|
path = gtk_tree_path_new_from_string (path_string);
|
|
|
|
if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
|
|
{
|
|
gtk_tree_path_free (path);
|
|
return;
|
|
}
|
|
|
|
bookmark = get_bookmark (GTK_TREE_MODEL (store), &iter);
|
|
g_return_if_fail (bookmark != NULL);
|
|
|
|
if (!bookmark->display_path || strcmp (bookmark->display_path, text))
|
|
{
|
|
_moo_bookmark_set_display_path (bookmark, text);
|
|
set_bookmark (store, &iter, bookmark);
|
|
g_object_set_data (G_OBJECT (store),
|
|
"moo-bookmarks-modified",
|
|
GINT_TO_POINTER (TRUE));
|
|
}
|
|
|
|
_moo_bookmark_free (bookmark);
|
|
gtk_tree_path_free (path);
|
|
|
|
cmpl = g_object_get_data (G_OBJECT (cell), "moo-file-entry-completion");
|
|
g_return_if_fail (cmpl != NULL);
|
|
g_object_set (cmpl, "entry", NULL, NULL);
|
|
}
|
|
|
|
|
|
static void
|
|
path_editing_started (GtkCellRenderer *cell,
|
|
GtkCellEditable *editable)
|
|
{
|
|
MooFileEntryCompletion *cmpl =
|
|
g_object_get_data (G_OBJECT (cell), "moo-file-entry-completion");
|
|
|
|
g_return_if_fail (cmpl != NULL);
|
|
g_return_if_fail (GTK_IS_ENTRY (editable));
|
|
|
|
g_object_set (cmpl, "entry", editable, NULL);
|
|
|
|
#if 0
|
|
if (!g_object_get_data (G_OBJECT (editable), "moo-stupid-entry-workaround"))
|
|
{
|
|
g_signal_connect (editable, "realize",
|
|
G_CALLBACK (path_entry_realize), NULL);
|
|
g_signal_connect (editable, "unrealize",
|
|
G_CALLBACK (path_entry_unrealize), NULL);
|
|
g_object_set_data (G_OBJECT (editable), "moo-stupid-entry-workaround",
|
|
GINT_TO_POINTER (TRUE));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
static void
|
|
path_entry_realize (GtkWidget *entry)
|
|
{
|
|
GtkSettings *settings;
|
|
gboolean value;
|
|
|
|
g_return_if_fail (gtk_widget_has_screen (entry));
|
|
settings = gtk_settings_get_for_screen (gtk_widget_get_screen (entry));
|
|
g_return_if_fail (settings != NULL);
|
|
|
|
g_object_get (settings, "gtk-entry-select-on-focus", &value, NULL);
|
|
g_object_set (settings, "gtk-entry-select-on-focus", FALSE, NULL);
|
|
g_object_set_data (G_OBJECT (settings),
|
|
"moo-stupid-entry-workaround",
|
|
GINT_TO_POINTER (TRUE));
|
|
g_object_set_data (G_OBJECT (settings),
|
|
"moo-stupid-entry-workaround-value",
|
|
GINT_TO_POINTER (value));
|
|
|
|
gtk_editable_set_position (GTK_EDITABLE (entry), -1);
|
|
}
|
|
|
|
|
|
static void
|
|
path_entry_unrealize (GtkWidget *entry)
|
|
{
|
|
GtkSettings *settings;
|
|
gboolean value;
|
|
|
|
g_return_if_fail (gtk_widget_has_screen (entry));
|
|
settings = gtk_settings_get_for_screen (gtk_widget_get_screen (entry));
|
|
g_return_if_fail (settings != NULL);
|
|
|
|
if (g_object_get_data (G_OBJECT (settings), "moo-stupid-entry-workaround"))
|
|
{
|
|
value = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (settings),
|
|
"moo-stupid-entry-workaround-value"));
|
|
g_object_set (settings, "gtk-entry-select-on-focus", value, NULL);
|
|
g_object_set_data (G_OBJECT (settings), "moo-stupid-entry-workaround", NULL);
|
|
}
|
|
|
|
g_signal_handlers_disconnect_by_func (entry,
|
|
(gpointer) path_entry_realize,
|
|
NULL);
|
|
g_signal_handlers_disconnect_by_func (entry,
|
|
(gpointer) path_entry_unrealize,
|
|
NULL);
|
|
g_object_set_data (G_OBJECT (entry), "moo-stupid-entry-workaround", NULL);
|
|
}
|
|
|
|
|
|
static void combo_icon_data_func (GtkCellLayout *cell_layout,
|
|
GtkCellRenderer *cell,
|
|
GtkTreeModel *model,
|
|
GtkTreeIter *iter);
|
|
static void combo_label_data_func (GtkCellLayout *cell_layout,
|
|
GtkCellRenderer *cell,
|
|
GtkTreeModel *model,
|
|
GtkTreeIter *iter);
|
|
static void fill_icon_store (GtkListStore *store,
|
|
GtkStyle *style);
|
|
static void icon_store_find_pixbuf (GtkListStore *store,
|
|
GtkTreeIter *iter,
|
|
GdkPixbuf *pixbuf);
|
|
static void icon_store_find_stock (GtkListStore *store,
|
|
GtkTreeIter *iter,
|
|
const char *stock);
|
|
static void icon_store_find_empty (GtkListStore *store,
|
|
GtkTreeIter *iter);
|
|
static void icon_combo_changed (GtkComboBox *combo,
|
|
MooGladeXML *xml);
|
|
|
|
static void
|
|
init_icon_combo (GtkComboBox *combo,
|
|
MooGladeXML *xml)
|
|
{
|
|
static GtkListStore *icon_store;
|
|
GtkCellRenderer *cell;
|
|
|
|
if (!icon_store)
|
|
{
|
|
GtkWidget *dialog = moo_glade_xml_get_widget (xml, "dialog");
|
|
gtk_widget_ensure_style (dialog);
|
|
icon_store = gtk_list_store_new (3, GDK_TYPE_PIXBUF,
|
|
G_TYPE_STRING, G_TYPE_STRING);
|
|
fill_icon_store (icon_store, dialog->style);
|
|
}
|
|
|
|
gtk_cell_layout_clear (GTK_CELL_LAYOUT (combo));
|
|
gtk_combo_box_set_model (combo, GTK_TREE_MODEL (icon_store));
|
|
gtk_combo_box_set_wrap_width (combo, 3);
|
|
|
|
cell = gtk_cell_renderer_pixbuf_new ();
|
|
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, FALSE);
|
|
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo), cell,
|
|
(GtkCellLayoutDataFunc) combo_icon_data_func,
|
|
NULL, NULL);
|
|
|
|
cell = gtk_cell_renderer_text_new ();
|
|
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, FALSE);
|
|
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo), cell,
|
|
(GtkCellLayoutDataFunc) combo_label_data_func,
|
|
NULL, NULL);
|
|
|
|
g_signal_connect (combo, "changed",
|
|
G_CALLBACK (icon_combo_changed), xml);
|
|
}
|
|
|
|
|
|
static void
|
|
combo_update_icon (GtkComboBox *combo,
|
|
MooGladeXML *xml)
|
|
{
|
|
GtkTreeSelection *selection;
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
GtkWidget *treeview;
|
|
GList *rows;
|
|
MooBookmark *bookmark;
|
|
GtkListStore *icon_store;
|
|
|
|
treeview = moo_glade_xml_get_widget (xml, "treeview");
|
|
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
|
|
rows = gtk_tree_selection_get_selected_rows (selection, &model);
|
|
g_return_if_fail (rows != NULL && rows->next == NULL);
|
|
|
|
gtk_tree_model_get_iter (model, &iter, rows->data);
|
|
bookmark = get_bookmark (model, &iter);
|
|
g_return_if_fail (bookmark != NULL);
|
|
|
|
icon_store = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
|
|
|
|
if (bookmark->pixbuf)
|
|
icon_store_find_pixbuf (icon_store, &iter, bookmark->pixbuf);
|
|
else if (bookmark->icon_stock_id)
|
|
icon_store_find_stock (icon_store, &iter, bookmark->icon_stock_id);
|
|
else
|
|
icon_store_find_empty (icon_store, &iter);
|
|
|
|
g_signal_handlers_block_by_func (combo, (gpointer) icon_combo_changed, xml);
|
|
gtk_combo_box_set_active_iter (combo, &iter);
|
|
g_signal_handlers_unblock_by_func (combo, (gpointer) icon_combo_changed, xml);
|
|
|
|
_moo_bookmark_free (bookmark);
|
|
gtk_tree_path_free (rows->data);
|
|
g_list_free (rows);
|
|
}
|
|
|
|
|
|
enum {
|
|
ICON_COLUMN_PIXBUF = 0,
|
|
ICON_COLUMN_STOCK = 1,
|
|
ICON_COLUMN_LABEL = 2
|
|
};
|
|
|
|
static void
|
|
combo_icon_data_func (G_GNUC_UNUSED GtkCellLayout *cell_layout,
|
|
GtkCellRenderer *cell,
|
|
GtkTreeModel *model,
|
|
GtkTreeIter *iter)
|
|
{
|
|
char *stock = NULL;
|
|
GdkPixbuf *pixbuf = NULL;
|
|
|
|
gtk_tree_model_get (model, iter, ICON_COLUMN_PIXBUF, &pixbuf, -1);
|
|
g_object_set (cell, "pixbuf", pixbuf, NULL);
|
|
if (pixbuf)
|
|
{
|
|
g_object_unref (pixbuf);
|
|
return;
|
|
}
|
|
|
|
gtk_tree_model_get (model, iter, ICON_COLUMN_STOCK, &stock, -1);
|
|
g_object_set (cell, "stock-id", stock,
|
|
"stock-size", GTK_ICON_SIZE_MENU, NULL);
|
|
g_free (stock);
|
|
}
|
|
|
|
|
|
static void
|
|
combo_label_data_func (G_GNUC_UNUSED GtkCellLayout *cell_layout,
|
|
GtkCellRenderer *cell,
|
|
GtkTreeModel *model,
|
|
GtkTreeIter *iter)
|
|
{
|
|
char *label = NULL;
|
|
gtk_tree_model_get (model, iter, ICON_COLUMN_LABEL, &label, -1);
|
|
g_object_set (cell, "text", label, NULL);
|
|
g_free (label);
|
|
}
|
|
|
|
|
|
static void
|
|
fill_icon_store (GtkListStore *store,
|
|
GtkStyle *style)
|
|
{
|
|
GtkTreeIter iter;
|
|
GSList *stock_ids, *l;
|
|
|
|
stock_ids = gtk_stock_list_ids ();
|
|
|
|
for (l = stock_ids; l != NULL; l = l->next)
|
|
{
|
|
GtkStockItem item;
|
|
|
|
if (!gtk_style_lookup_icon_set (style, l->data))
|
|
continue;
|
|
|
|
gtk_list_store_append (store, &iter);
|
|
gtk_list_store_set (store, &iter, ICON_COLUMN_STOCK,
|
|
l->data, -1);
|
|
|
|
if (gtk_stock_lookup (l->data, &item))
|
|
{
|
|
char *label = g_strdup (item.label);
|
|
char *und = strchr (label, '_');
|
|
|
|
if (und)
|
|
{
|
|
if (und[1] == 0)
|
|
*und = 0;
|
|
else
|
|
memmove (und, und + 1, strlen (label) - (und - label));
|
|
}
|
|
|
|
gtk_list_store_set (store, &iter, ICON_COLUMN_LABEL,
|
|
label, -1);
|
|
g_free (label);
|
|
}
|
|
else
|
|
{
|
|
gtk_list_store_set (store, &iter, ICON_COLUMN_LABEL,
|
|
l->data, -1);
|
|
}
|
|
}
|
|
|
|
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
|
|
ICON_COLUMN_LABEL,
|
|
GTK_SORT_ASCENDING);
|
|
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
|
|
GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
|
|
GTK_SORT_ASCENDING);
|
|
|
|
gtk_list_store_append (store, &iter);
|
|
gtk_list_store_set (store, &iter, ICON_COLUMN_LABEL, "None", -1);
|
|
|
|
g_slist_foreach (stock_ids, (GFunc) g_free, NULL);
|
|
g_slist_free (stock_ids);
|
|
}
|
|
|
|
|
|
static void
|
|
icon_combo_changed (GtkComboBox *combo,
|
|
MooGladeXML *xml)
|
|
{
|
|
GtkTreeSelection *selection;
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter, icon_iter;
|
|
GtkWidget *treeview;
|
|
GList *rows;
|
|
MooBookmark *bookmark;
|
|
GtkTreeModel *icon_model;
|
|
GdkPixbuf *pixbuf = NULL;
|
|
char *stock = NULL;
|
|
|
|
treeview = moo_glade_xml_get_widget (xml, "treeview");
|
|
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
|
|
rows = gtk_tree_selection_get_selected_rows (selection, &model);
|
|
g_return_if_fail (rows != NULL && rows->next == NULL);
|
|
|
|
gtk_tree_model_get_iter (model, &iter, rows->data);
|
|
bookmark = get_bookmark (model, &iter);
|
|
g_return_if_fail (bookmark != NULL);
|
|
|
|
gtk_combo_box_get_active_iter (combo, &icon_iter);
|
|
icon_model = gtk_combo_box_get_model (combo);
|
|
|
|
if (bookmark->pixbuf)
|
|
g_object_unref (bookmark->pixbuf);
|
|
bookmark->pixbuf = NULL;
|
|
g_free (bookmark->icon_stock_id);
|
|
bookmark->icon_stock_id = NULL;
|
|
|
|
gtk_tree_model_get (icon_model, &icon_iter, ICON_COLUMN_PIXBUF,
|
|
&pixbuf, -1);
|
|
|
|
if (pixbuf)
|
|
bookmark->pixbuf = pixbuf;
|
|
|
|
if (!pixbuf)
|
|
{
|
|
gtk_tree_model_get (icon_model, &icon_iter, ICON_COLUMN_STOCK,
|
|
&stock, -1);
|
|
bookmark->icon_stock_id = stock;
|
|
}
|
|
|
|
set_bookmark (GTK_LIST_STORE (model), &iter, bookmark);
|
|
|
|
_moo_bookmark_free (bookmark);
|
|
gtk_tree_path_free (rows->data);
|
|
g_list_free (rows);
|
|
}
|
|
|
|
|
|
static void
|
|
icon_store_find_pixbuf (GtkListStore *store,
|
|
GtkTreeIter *iter,
|
|
GdkPixbuf *pixbuf)
|
|
{
|
|
GtkTreeModel *model = GTK_TREE_MODEL (store);
|
|
|
|
g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
|
|
|
|
if (gtk_tree_model_get_iter_first (model, iter)) do
|
|
{
|
|
GdkPixbuf *pix = NULL;
|
|
gtk_tree_model_get (model, iter, ICON_COLUMN_PIXBUF, &pix, -1);
|
|
|
|
if (pix == pixbuf)
|
|
{
|
|
if (pix)
|
|
g_object_unref (pix);
|
|
return;
|
|
}
|
|
|
|
if (pix)
|
|
g_object_unref (pix);
|
|
}
|
|
while (gtk_tree_model_iter_next (model, iter));
|
|
|
|
gtk_list_store_append (store, iter);
|
|
gtk_list_store_set (store, iter, ICON_COLUMN_PIXBUF, pixbuf, -1);
|
|
}
|
|
|
|
|
|
static void
|
|
icon_store_find_stock (GtkListStore *store,
|
|
GtkTreeIter *iter,
|
|
const char *stock)
|
|
{
|
|
GtkTreeModel *model = GTK_TREE_MODEL (store);
|
|
|
|
g_return_if_fail (stock != NULL);
|
|
|
|
if (gtk_tree_model_get_iter_first (model, iter)) do
|
|
{
|
|
char *id = NULL;
|
|
gtk_tree_model_get (model, iter, ICON_COLUMN_STOCK, &id, -1);
|
|
|
|
if (id && !strcmp (id, stock))
|
|
{
|
|
g_free (id);
|
|
return;
|
|
}
|
|
|
|
g_free (id);
|
|
}
|
|
while (gtk_tree_model_iter_next (model, iter));
|
|
|
|
gtk_list_store_append (store, iter);
|
|
gtk_list_store_set (store, iter, ICON_COLUMN_STOCK, stock, -1);
|
|
}
|
|
|
|
|
|
static void
|
|
icon_store_find_empty (GtkListStore *store,
|
|
GtkTreeIter *iter)
|
|
{
|
|
GtkTreeModel *model = GTK_TREE_MODEL (store);
|
|
|
|
if (gtk_tree_model_get_iter_first (model, iter)) do
|
|
{
|
|
char *id = NULL;
|
|
GdkPixbuf *pixbuf = NULL;
|
|
|
|
gtk_tree_model_get (model, iter, ICON_COLUMN_STOCK, &id,
|
|
ICON_COLUMN_PIXBUF, &pixbuf, -1);
|
|
|
|
if (!id && !pixbuf)
|
|
return;
|
|
|
|
g_free (id);
|
|
if (pixbuf)
|
|
g_object_unref (pixbuf);
|
|
}
|
|
while (gtk_tree_model_iter_next (model, iter));
|
|
|
|
gtk_list_store_append (store, iter);
|
|
gtk_list_store_set (store, iter, ICON_COLUMN_LABEL, "None", -1);
|
|
}
|