aboutsummaryrefslogblamecommitdiffstats
path: root/src/bookmarks/ephy-bookmarksbar-model.c
blob: 4b32a04ed3490556b400092ae10b71100bd942de (plain) (tree)




















                                                                              
                   






























                                                                                                                                                       
                                    















                                                                                   
                                   









































                                                                    

                                                                                          

















































                                                                                    
                              





















                                                                                 


                                                                  






                                                                      
                          




                                                                          
                                                                                  




                                                                           
                             


































































                                                                              
                                                                 





                             



                                            


                             
             

                                            
 
                                                                 
         
                                                      
         
                                                                    
         
                                                    

         
                                                                                    

























                                                                             



                                                          









































                                                                                                      


                                               
 



                                                                          
         








                                                                    
         
                                                       
         








                                                                    

         
                                                                                           


































































                                                                                          

                                                  














                                                                                  



                                                                        







                                                       





                                                        



                                                                        

                                       

                                               






































                                                                                    
                                                                



                                                                          
                                                     

                                                     



















                                                                                       
/*
 *  Copyright (C) 2003-2004 Marco Pesenti Gritti
 *  Copyright (C) 2003-2004 Christian Persch
 *
 *  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, or (at your option)
 *  any later version.
 *
 *  This program 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 this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 *  $Id$
 */

#include "config.h"

#include "ephy-bookmarksbar-model.h"
#include "ephy-bookmarks.h"
#include "ephy-dnd.h"
#include "ephy-node-common.h"
#include "ephy-file-helpers.h"
#include "ephy-history.h"
#include "ephy-shell.h"
#include "ephy-string.h"
#include "ephy-debug.h"

#include <string.h>
#include <glib/gi18n.h>

#define EPHY_BOOKMARKSBARS_XML_FILE "epiphany-bookmarksbar.xml"
#define EPHY_BOOKMARKSBARS_XML_VERSION  "1.0"

enum
{
    PROP_0,
    PROP_BOOKMARKS
};

enum
{
    URL,
    NAME
};

#define EPHY_BOOKMARKSBAR_MODEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_BOOKMARKSBAR_MODEL, EphyBookmarksBarModelPrivate))

struct _EphyBookmarksBarModelPrivate
{
    EphyBookmarks *bookmarks;
    char *xml_file;
    guint timeout;
};

static void ephy_bookmarksbar_model_class_init (EphyBookmarksBarModelClass *klass);
static void ephy_bookmarksbar_model_init       (EphyBookmarksBarModel *t);

static GObjectClass *parent_class = NULL;

GType
ephy_bookmarksbar_model_get_type (void)
{
    static GType type = 0;

    if (G_UNLIKELY (type == 0))
    {
        static const GTypeInfo our_info = {
        sizeof (EphyBookmarksBarModelClass),
        NULL,           /* base_init */
        NULL,           /* base_finalize */
        (GClassInitFunc) ephy_bookmarksbar_model_class_init,
        NULL,
        NULL,           /* class_data */
        sizeof (EphyBookmarksBarModel),
        0,          /* n_preallocs */
        (GInstanceInitFunc) ephy_bookmarksbar_model_init
    };

    type = g_type_register_static (EGG_TYPE_TOOLBARS_MODEL,
                       "EphyBookmarksBarModel",
                       &our_info, 0);
    }

    return type;
}

static gboolean
get_toolbar_and_item_pos (EphyBookmarksBarModel *model,
              const char *name,
              int *toolbar,
              int *position)
{
    EggToolbarsModel *eggmodel = EGG_TOOLBARS_MODEL (model);
    int n_toolbars, n_items;
    int t,i;

    n_toolbars = egg_toolbars_model_n_toolbars (eggmodel);

    for (t = 0; t < n_toolbars; t++)
    {
        n_items = egg_toolbars_model_n_items (eggmodel, t);

        for (i = 0; i < n_items; i++)
        {
            const char *i_name;
            gboolean is_separator;

            egg_toolbars_model_item_nth (EGG_TOOLBARS_MODEL (model),
                             t , i, &is_separator, &i_name, NULL);
            g_return_val_if_fail (i_name != NULL, FALSE);

            if (strcmp (i_name, name) == 0)
            {
                if (toolbar) *toolbar = t;
                if (position) *position = i;

                return TRUE;
            }
        }
    }

    return FALSE;
}

static int
get_toolbar_pos (EphyBookmarksBarModel *model,
         const char *name)
{
    EggToolbarsModel *eggmodel = EGG_TOOLBARS_MODEL (model);
    int i, n_toolbars;

    n_toolbars = egg_toolbars_model_n_toolbars (eggmodel);

    for (i = 0; i < n_toolbars; i++)
    {
        const char *t_name;

        t_name = egg_toolbars_model_toolbar_nth (eggmodel, i);
        if (strcmp (name, t_name) == 0)
        {
            return i;
        }
    }

    return -1;
}

char *
ephy_bookmarksbar_model_get_action_name (EphyBookmarksBarModel *model,
                     long id)
{
    return g_strdup_printf ("GoBookmark-%ld", id);
}

EphyNode *
ephy_bookmarksbar_model_get_node (EphyBookmarksBarModel *model,
                  const char *action_name)
{
    EphyBookmarks *bookmarks = EPHY_BOOKMARKSBAR_MODEL (model)->priv->bookmarks;
    unsigned long node_id;

    if (!ephy_string_to_int (action_name + strlen ("GoBookmark-"), &node_id))
    {
        return NULL;
    }

    return ephy_bookmarks_get_from_id (bookmarks, node_id);
}

void
ephy_bookmarksbar_model_add_bookmark (EphyBookmarksBarModel *model,
                      gboolean topic,
                      long id)
{
    char *name;
    int toolbar_position;

    toolbar_position = get_toolbar_pos (model, "BookmarksBar");
    g_return_if_fail (toolbar_position != -1);

    name = ephy_bookmarksbar_model_get_action_name (model, id);
    egg_toolbars_model_add_item (EGG_TOOLBARS_MODEL (model),
                     toolbar_position, -1, name,
                     topic ? EPHY_DND_TOPIC_TYPE :
                         EPHY_DND_URL_TYPE);
    g_free (name);
}

void
ephy_bookmarksbar_model_remove_bookmark (EphyBookmarksBarModel *model,
                     long id)
{
    char *action_name;
    int toolbar, position;

    action_name = ephy_bookmarksbar_model_get_action_name (model, id);
    g_return_if_fail (action_name != NULL);

    while (get_toolbar_and_item_pos (model, action_name, &toolbar, &position))
    {
        egg_toolbars_model_remove_item (EGG_TOOLBARS_MODEL (model),
                        toolbar, position);
    }

    g_free (action_name);
}

gboolean
ephy_bookmarksbar_model_has_bookmark (EphyBookmarksBarModel *model,
                      long id)
{
    char *action_name;
    gboolean found;
    int toolbar, pos;

    action_name = ephy_bookmarksbar_model_get_action_name (model, id);
    g_return_val_if_fail (action_name != NULL, FALSE);

    found = get_toolbar_and_item_pos (model, action_name, &toolbar, &pos);

    g_free (action_name);

    return found;
}

static gboolean
save_changes_idle (EphyBookmarksBarModel *model)
{
    LOG ("Saving bookmarks toolbars model")

    egg_toolbars_model_save
        (EGG_TOOLBARS_MODEL (model),
         model->priv->xml_file,
         EPHY_BOOKMARKSBARS_XML_VERSION);

    model->priv->timeout = 0;

    /* don't run again */
    return FALSE;
}

static void
save_changes (EphyBookmarksBarModel *model)
{
    if (model->priv->timeout == 0)
    {
        model->priv->timeout =
            g_idle_add ((GSourceFunc) save_changes_idle, model);
    }
}

static void
update_flags_and_save_changes (EphyBookmarksBarModel *model)
{
    EggToolbarsModel *eggmodel = EGG_TOOLBARS_MODEL (model);
    int i, n_toolbars;
    int flag = 0;

    n_toolbars = egg_toolbars_model_n_toolbars (eggmodel);

    if (n_toolbars <= 1)
    {
        flag = EGG_TB_MODEL_NOT_REMOVABLE;
    }

    for (i = 0; i < n_toolbars; i++)
    {
        const char *t_name;

        t_name = egg_toolbars_model_toolbar_nth (eggmodel, i);
        g_return_if_fail (t_name != NULL);

        egg_toolbars_model_set_flags (eggmodel, i, flag);
    }

    save_changes (model);
}

static void
item_added_cb (EphyBookmarksBarModel *model,
           int toolbar_position,
           int position)
{
    save_changes (model);
}

static char *
impl_get_item_type (EggToolbarsModel *model,
            GdkAtom type)
{
    if (gdk_atom_intern (EPHY_DND_TOPIC_TYPE, FALSE) == type)
    {
        return g_strdup (EPHY_DND_TOPIC_TYPE);
    }
    else if (gdk_atom_intern (EPHY_DND_URL_TYPE, FALSE) == type)
    {
        return g_strdup (EPHY_DND_URL_TYPE);
    }

    return EGG_TOOLBARS_MODEL_CLASS (parent_class)->get_item_type (model, type);
}

static char *
impl_get_item_id (EggToolbarsModel *eggmodel,
          const char *type,
          const char *name)
{
    EphyBookmarksBarModel *model = EPHY_BOOKMARKSBAR_MODEL (eggmodel);
    EphyBookmarks *bookmarks = model->priv->bookmarks;

    if (strcmp (type, EPHY_DND_TOPIC_TYPE) == 0)
    {
        EphyNode *topic;

        topic = ephy_bookmarks_find_keyword (bookmarks, name, FALSE);
        if (topic == NULL) return NULL;

        return ephy_bookmarksbar_model_get_action_name
            (model, ephy_node_get_id (topic));
    }
    else if (strcmp (type, EPHY_DND_URL_TYPE) == 0)
    {
        EphyNode *node = NULL;
        gchar **netscape_url;

        netscape_url = g_strsplit (name, "\n", 2);
        if (!netscape_url || !netscape_url[URL]) {
            g_strfreev (netscape_url);
            return NULL;
        }

        node = ephy_bookmarks_find_bookmark (bookmarks, netscape_url[URL]);

        if (!node)
        {
            /* Create the bookmark, it does not exist */
            EphyHistory *gh;
            const char *icon;
            const char *title;

            title = netscape_url[NAME];
            if (title == NULL || *title == '\0')
            {
                title = _("Untitled");
            }

            node = ephy_bookmarks_add (bookmarks, title, netscape_url[URL]);

            if (node != NULL)
            {
                gh = EPHY_HISTORY (ephy_embed_shell_get_global_history (embed_shell));
                icon = ephy_history_get_icon (gh, netscape_url[URL]);

                if (icon)
                {
                    ephy_bookmarks_set_icon (bookmarks, netscape_url[URL], icon);
                }
            }
        }

        g_strfreev (netscape_url);

        if (node == NULL) return NULL;

        return ephy_bookmarksbar_model_get_action_name
            (model, ephy_node_get_id (node));
    }

    return EGG_TOOLBARS_MODEL_CLASS (parent_class)->get_item_id (eggmodel, type, name);
}

static char *
impl_get_item_data (EggToolbarsModel *eggmodel,
            const char *type,
            const char *id)
{
    EphyBookmarksBarModel *model = EPHY_BOOKMARKSBAR_MODEL (eggmodel);
    EphyNode *node;

    if (strcmp (type, EPHY_DND_TOPIC_TYPE) == 0)
    {
        char *uri;

        node = ephy_bookmarksbar_model_get_node (model, id);
        g_return_val_if_fail (node != NULL, NULL);

        uri = ephy_bookmarks_get_topic_uri
            (model->priv->bookmarks, node);

        return uri;
    }
    else if (strcmp (type, EPHY_DND_URL_TYPE) == 0)
    {
        const char *name;

        node = ephy_bookmarksbar_model_get_node (model, id);
        g_return_val_if_fail (node != NULL, NULL);

        name = ephy_node_get_property_string
            (node, EPHY_NODE_BMK_PROP_LOCATION);

        return g_strdup (name);
    }

    return EGG_TOOLBARS_MODEL_CLASS (parent_class)->get_item_data (eggmodel, type, id);
}

static void
load_toolbars (EphyBookmarksBarModel *model)
{
    EggToolbarsModel *eggmodel = EGG_TOOLBARS_MODEL (model);
    gboolean success = FALSE;

    success = egg_toolbars_model_load (eggmodel, model->priv->xml_file);
    LOG ("Loading the toolbars was %ssuccessful", success ? "" : "un")

    /* Try migration first: load the old layout, and remove every toolbar
     * except the BookmarksBar toolbar
     */
    if (success == FALSE)
    {
        char *old_xml;
        int i, n_toolbars;

        old_xml = g_build_filename (ephy_dot_dir (),
                        "epiphany-toolbars.xml",
                        NULL);
        success = egg_toolbars_model_load (eggmodel, old_xml);
        g_free (old_xml);

        if (success)
        {
            n_toolbars = egg_toolbars_model_n_toolbars (eggmodel);

            for (i = n_toolbars - 1; i >= 0; i--)
            {
                const char *t_name;

                t_name = egg_toolbars_model_toolbar_nth (eggmodel, i);
                g_return_if_fail (t_name != NULL);

                if (strcmp (t_name, "BookmarksBar") != 0)
                {
                    egg_toolbars_model_remove_toolbar (eggmodel, i);
                }
            }
        }

        LOG ("Migration was %ssuccessful", success ? "" : "un")
    }

    /* Load default set */
    if (success == FALSE)
    {
        egg_toolbars_model_load
            (eggmodel, ephy_file ("epiphany-bookmarksbar.xml"));    
        LOG ("Loading the default toolbars was %ssuccessful", success ? "" : "un")
    }
    
    /* Ensure that we have a BookmarksBar */
    if (get_toolbar_pos (model, "BookmarksBar") == -1)
    {
        egg_toolbars_model_add_toolbar
            (eggmodel, -1, "BookmarksBar");
    }
}   

static void
ephy_bookmarksbar_model_init (EphyBookmarksBarModel *model)
{
    model->priv = EPHY_BOOKMARKSBAR_MODEL_GET_PRIVATE (model);

    LOG ("EphyBookmarksBarModel initialising")

    model->priv->xml_file = g_build_filename (ephy_dot_dir (),
                          EPHY_BOOKMARKSBARS_XML_FILE,
                          NULL);

    g_signal_connect_after (model, "item_added",
                G_CALLBACK (item_added_cb), NULL);
    g_signal_connect_after (model, "item_removed",
                G_CALLBACK (save_changes), NULL);
    g_signal_connect_after (model, "toolbar_added",
                G_CALLBACK (update_flags_and_save_changes), NULL);
    g_signal_connect_after (model, "toolbar_removed",
                G_CALLBACK (update_flags_and_save_changes), NULL);
}

static void
ephy_bookmarksbar_model_dispose (GObject *object)
{
    EphyBookmarksBarModel *model = EPHY_BOOKMARKSBAR_MODEL (object);

    LOG ("EphyBookmarksBarModel disposing")

    if (model->priv->timeout != 0)
    {
        g_source_remove (model->priv->timeout);
        model->priv->timeout = 0;
    }

    save_changes_idle (model);

    G_OBJECT_CLASS (parent_class)->dispose (object);
}

static void
ephy_bookmarksbar_model_finalize (GObject *object)
{
    EphyBookmarksBarModel *model = EPHY_BOOKMARKSBAR_MODEL (object);

    g_free (model->priv->xml_file);

    LOG ("EphyBookmarksBarModel finalised")

    G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
ephy_bookmarksbar_model_set_property (GObject *object,
                        guint prop_id,
                        const GValue *value,
                        GParamSpec *pspec)
{
    EphyBookmarksBarModel *model = EPHY_BOOKMARKSBAR_MODEL (object);

    switch (prop_id)
    {
        case PROP_BOOKMARKS:
            /* we're owned by bookmarks, so don't g_object_ref() here */
            model->priv->bookmarks = g_value_get_object (value);
            load_toolbars (model);
            break;
    }
}

static void
ephy_bookmarksbar_model_get_property (GObject *object,
                        guint prop_id,
                        GValue *value,
                        GParamSpec *pspec)
{
    /* no readable properties */
    g_assert_not_reached ();
}

static void
ephy_bookmarksbar_model_class_init (EphyBookmarksBarModelClass *klass)
{
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
    EggToolbarsModelClass *eggclass = EGG_TOOLBARS_MODEL_CLASS (klass);

    parent_class = g_type_class_peek_parent (klass);

    object_class->dispose = ephy_bookmarksbar_model_dispose;
    object_class->finalize = ephy_bookmarksbar_model_finalize;
    object_class->set_property = ephy_bookmarksbar_model_set_property;
    object_class->get_property = ephy_bookmarksbar_model_get_property;

    eggclass->get_item_type = impl_get_item_type;
    eggclass->get_item_id = impl_get_item_id;
    eggclass->get_item_data = impl_get_item_data;

    g_object_class_install_property (object_class,
                     PROP_BOOKMARKS,
                     g_param_spec_object ("bookmarks",
                                  "Bookmarks",
                                  "Bookmarks",
                                  EPHY_TYPE_BOOKMARKS,
                                  G_PARAM_WRITABLE |
                                  G_PARAM_CONSTRUCT_ONLY));

    g_type_class_add_private (object_class, sizeof (EphyBookmarksBarModelPrivate));
}

EggToolbarsModel *
ephy_bookmarksbar_model_new (EphyBookmarks *bookmarks)
{
    return EGG_TOOLBARS_MODEL (g_object_new (EPHY_TYPE_BOOKMARKSBAR_MODEL,
                         "bookmarks", bookmarks,
                         NULL));
}