/*
 *  Copyright (C) 2002, 2003  Ricardo Fernández Pascual
 *
 *  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.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <glib/gi18n.h>
#include "gul-glade.h"
#include "galeon-marshal.h"
#include "bookmarks-editor.h"
#include "bookmarks-io.h"
#include "bookmarks-single-editor.h"
#include "bookmarks-single-editor-small.h"
#include "bookmarks-clipboard.h"
#include "bookmarks-context-menu.h"
#include "bookmarks-import-druid-mozilla.h"
#include "bookmarks-export-druid-mozilla.h"
#include "bookmarks-import-druid-netscape.h"
#include "bookmarks-export-druid-netscape.h"
#include "bookmarks-import-druid-konqueror.h"
#include "bookmarks-export-druid-konqueror.h"
#include "bookmarks-import-druid-epiphany.h"
#include "bookmarks-tree-view.h"
#include "gul-gobject-misc.h"
#include "gul-string.h"
#include "gul-state.h"
#include "gul-general.h"
#include "eel-gconf-extensions.h"
#include "prefs-strings.h"
#include "galeon-debug.h"
#include <gdk/gdkkeysyms.h>
#include <gtk/gtktogglebutton.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkvbox.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkhpaned.h>
#include <gtk/gtkvpaned.h>
#include <gtk/gtkcellrenderertext.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkscrolledwindow.h>
#include <gtk/gtktreeselection.h>
#include <gtk/gtktextview.h>
#include <bonobo/bonobo-window.h>
#include <bonobo/bonobo-ui-util.h>
#include <bonobo/bonobo-ui-component.h>
#include <bonobo/bonobo-file-selector-util.h>
#include <string.h>

#define NOT_IMPLEMENTED g_warning ("not implemented: " G_STRLOC);

/**
 * Private data
 */
struct _GbEditorPrivate 
{
	GbBookmarkSet *set;
	GbTreeModel *left_tree_model;
	GbTreeModel *right_tree_model;
	gint block_update;
	
	GtkWidget *main_widget;

	GbTreeView *left_tree_view;
	GbTreeView *right_tree_view;
	GtkWidget *left_box;
	GtkWidget *right_box;
	GtkWidget *hpane;

	GbSingleEditorSmall *small_editor;
	GtkWidget *edit_pane;

	gboolean show_right_tree_view;
	gboolean show_edit_pane;;

	GbClipboard *clipboard;
	
	GbLocationSource *location_source;

	/* searching */
	guint search_timeout;

	gchar *search_text;
	gchar *search_casefold_text;
	gchar **search_text_split;
	gchar **search_casefold_text_split;
	gboolean search_match_case;
	gboolean search_include_folders;
	gboolean search_include_sites;
	gboolean search_look_in_name;
	gboolean search_look_in_location;
	gboolean search_look_in_notes;
	enum
	{
		MATCH_TYPE_AND,
		MATCH_TYPE_OR,
		MATCH_TYPE_EXACT
	} search_match_type;

	GtkWidget *search_hbox;
	GtkWidget *search_placeholder_right;
	GtkWidget *search_placeholder_left;
	GtkWidget *search_text_entry;
	GtkWidget *search_options_button;
	GtkWidget *search_b_f_match_case;
	GtkWidget *search_b_f_include_folders;
	GtkWidget *search_b_f_include_sites;
	GtkWidget *search_b_f_look_in_name;
	GtkWidget *search_b_f_look_in_location;
	GtkWidget *search_b_f_look_in_notes;
	GtkWidget *search_b_f_several_and;
	GtkWidget *search_b_f_several_or;
	GtkWidget *search_b_f_several_exact;

	GtkWidget *search_extra_options_window;

	GSList *old_left_selection;
};

#define STATE_BOOKMARKS_WIDTH_DEFAULT  400
#define STATE_BOOKMARKS_HEIGHT_DEFAULT 300

#define SEARCH_TIMEOUT 250

static void		gb_editor_class_init		(GbEditorClass *klass);
static void		gb_editor_init			(GbEditor *e);
static void		gb_editor_init_widgets		(GbEditor *e);
static void		gb_editor_init_widgets_impl	(GbEditor *e);
static void 		gb_editor_ensure_init_widgets	(GbEditor *e);
static void		gb_editor_finalize_impl		(GObject *o);
static void		gb_editor_selection_changed_cb	(GtkTreeSelection *treeselection, GbEditor *e);
static void		gb_editor_right_selection_changed_cb (GtkTreeSelection *treeselection, GbEditor *e);
static void		gb_editor_show_data		(GbEditor *e);
static void		gb_editor_add_new		(GbEditor *e, GbBookmark *new_bookmark);
static void 		gb_editor_add_several		(GbEditor *e, GSList *l);
static void		gb_editor_bookmark_activated_cb	(GObject *sender,
							 GbBookmarkEventActivated *ev,
							 GbEditor *e);
static gboolean		gb_editor_window_configure_event_cb (GtkWidget *widget,
							     GdkEventConfigure *event,
							     GbEditor *e);


static void		gb_editor_bonobo_cmd_add_site		(BonoboUIComponent *uic, GbEditor *e,
								 const gchar* verbname);
static void		gb_editor_bonobo_cmd_add_smart_site	(BonoboUIComponent *uic, GbEditor *e,
								 const gchar* verbname);
static void		gb_editor_bonobo_cmd_add_folder		(BonoboUIComponent *uic, GbEditor *e,
								 const gchar* verbname);
static void		gb_editor_bonobo_cmd_add_separator	(BonoboUIComponent *uic, GbEditor *e,
								 const gchar* verbname);
static void		gb_editor_bonobo_cmd_add_alias		(BonoboUIComponent *uic, GbEditor *e,
								 const gchar* verbname);
static void		gb_editor_bonobo_cmd_add_autobookmarks	(BonoboUIComponent *uic, GbEditor *e,
								 const gchar* verbname);
static void		gb_editor_bonobo_cmd_edit_remove	(BonoboUIComponent *uic, GbEditor *e,
								 const gchar* verbname);
static void		gb_editor_bonobo_cmd_file_open		(BonoboUIComponent *uic, GbEditor *e,
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_file_close		(BonoboUIComponent *uic, GbEditor *e,
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_edit_properties	(BonoboUIComponent *uic, GbEditor *e, 
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_edit_cut		(BonoboUIComponent *uic, GbEditor *e,
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_edit_copy		(BonoboUIComponent *uic, GbEditor *e, 
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_edit_paste		(BonoboUIComponent *uic, GbEditor *e,
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_edit_set_as_default_folder (BonoboUIComponent *uic,
									 GbEditor *e,
									 const gchar *verbname);
static void		gb_editor_bonobo_cmd_import_mozilla	(BonoboUIComponent *uic, GbEditor *e,
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_import_netscape	(BonoboUIComponent *uic, GbEditor *e,
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_import_konqueror	(BonoboUIComponent *uic, GbEditor *e,
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_import_epiphany	(BonoboUIComponent *uic, GbEditor *e,
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_export_mozilla	(BonoboUIComponent *uic, GbEditor *e,
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_export_netscape	(BonoboUIComponent *uic, GbEditor *e,
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_export_konqueror	(BonoboUIComponent *uic, GbEditor *e,
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_sort_one_level	(BonoboUIComponent *uic, GbEditor *e,
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_sort_recursively	(BonoboUIComponent *uic, GbEditor *e,
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_sort_one_level_folders_first (BonoboUIComponent *uic,
									   GbEditor *e,
									   const gchar *verbname);
static void		gb_editor_bonobo_cmd_sort_recursively_folders_first (BonoboUIComponent *uic,
									     GbEditor *e,
									     const gchar *verbname);
static void		gb_editor_bonobo_cmd_edit_goto		(BonoboUIComponent *uic, GbEditor *e,
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_split_view		(BonoboUIComponent *uic, GbEditor *e,
								 const gchar *verbname);
static void		gb_editor_bonobo_cmd_edit_pane		(BonoboUIComponent *uic, GbEditor *e,
								 const gchar *verbname);
static void		gb_editor_bonobo_split_view_changed_cb	(BonoboUIComponent *component,
								 const char *path,
								 Bonobo_UIComponent_EventType type,
								 const char *state,
								 GbEditor *e);
static void		gb_editor_bonobo_edit_pane_changed_cb	(BonoboUIComponent *component,
								 const char *path,
								 Bonobo_UIComponent_EventType type,
								 const char *state,
								 GbEditor *e);
static void		gb_editor_search_start_timeout		(GbEditor *f);
static void		gb_editor_search_stop_timeout		(GbEditor *f);



BonoboUIVerb bookmarks_editor_verbs [] = {
        BONOBO_UI_VERB ("AddSite", (BonoboUIVerbFn)gb_editor_bonobo_cmd_add_site),
        BONOBO_UI_VERB ("AddSmartSite", (BonoboUIVerbFn)gb_editor_bonobo_cmd_add_smart_site),
	BONOBO_UI_VERB ("AddFolder", (BonoboUIVerbFn)gb_editor_bonobo_cmd_add_folder),
	BONOBO_UI_VERB ("AddSeparator", (BonoboUIVerbFn) gb_editor_bonobo_cmd_add_separator),
        BONOBO_UI_VERB ("AddAlias", (BonoboUIVerbFn) gb_editor_bonobo_cmd_add_alias),
        BONOBO_UI_VERB ("AddAutobookmarks", (BonoboUIVerbFn) gb_editor_bonobo_cmd_add_autobookmarks),
	/*
	  BONOBO_UI_VERB ("FileNew", (BonoboUIVerbFn) gb_editor_bonobo_cmd_file_new),
	*/
        BONOBO_UI_VERB ("FileOpen", (BonoboUIVerbFn) gb_editor_bonobo_cmd_file_open),
	/*
	  BONOBO_UI_VERB ("FileSave", (BonoboUIVerbFn) gb_editor_bonobo_cmd_file_save),
	  BONOBO_UI_VERB ("FileSaveAs", (BonoboUIVerbFn) gb_editor_bonobo_cmd_file_save_as),
	  BONOBO_UI_VERB ("FileRevert", (BonoboUIVerbFn) gb_editor_bonobo_cmd_file_revert),
	*/
	BONOBO_UI_VERB ("FileClose", (BonoboUIVerbFn) gb_editor_bonobo_cmd_file_close),
	BONOBO_UI_VERB ("EditProperties", (BonoboUIVerbFn) gb_editor_bonobo_cmd_edit_properties),
	BONOBO_UI_VERB ("EditCut", (BonoboUIVerbFn) gb_editor_bonobo_cmd_edit_cut),
        BONOBO_UI_VERB ("EditCopy", (BonoboUIVerbFn) gb_editor_bonobo_cmd_edit_copy),
        BONOBO_UI_VERB ("EditPaste", (BonoboUIVerbFn) gb_editor_bonobo_cmd_edit_paste),
        BONOBO_UI_VERB ("EditRemove", (BonoboUIVerbFn) gb_editor_bonobo_cmd_edit_remove),
	/*
	  BONOBO_UI_VERB ("EditUndo", (BonoboUIVerbFn) gb_editor_bonobo_cmd_edit_undo),
	  BONOBO_UI_VERB ("EditRedo", (BonoboUIVerbFn) gb_editor_bonobo_cmd_edit_redo),
	*/
	BONOBO_UI_VERB ("EditGoto", (BonoboUIVerbFn) gb_editor_bonobo_cmd_edit_goto),
	BONOBO_UI_VERB ("EditSetAsDefaultFolder", (BonoboUIVerbFn) 
			gb_editor_bonobo_cmd_edit_set_as_default_folder),
	/*
	  BONOBO_UI_VERB ("EditMoveUp", (BonoboUIVerbFn) gb_editor_bonobo_cmd_edit_move_up),
	  BONOBO_UI_VERB ("EditMoveDown", (BonoboUIVerbFn) gb_editor_bonobo_cmd_edit_move_down),
	  BONOBO_UI_VERB ("EditFetchFavicon", (BonoboUIVerbFn) gb_editor_bonobo_cmd_edit_fetch_favicon),
	*/
	BONOBO_UI_VERB ("SortOneLevel", (BonoboUIVerbFn) gb_editor_bonobo_cmd_sort_one_level),
	BONOBO_UI_VERB ("SortOneLevelFoldersFirst", (BonoboUIVerbFn) 
			gb_editor_bonobo_cmd_sort_one_level_folders_first),
	BONOBO_UI_VERB ("SortRecursively", (BonoboUIVerbFn) gb_editor_bonobo_cmd_sort_recursively),
	BONOBO_UI_VERB ("SortRecursivelyFoldersFirst", (BonoboUIVerbFn) 
			gb_editor_bonobo_cmd_sort_recursively_folders_first),
	BONOBO_UI_VERB ("ImportMozilla", (BonoboUIVerbFn) gb_editor_bonobo_cmd_import_mozilla),
	BONOBO_UI_VERB ("ImportNetscape", (BonoboUIVerbFn) gb_editor_bonobo_cmd_import_netscape),
	BONOBO_UI_VERB ("ImportKonqueror", (BonoboUIVerbFn) gb_editor_bonobo_cmd_import_konqueror),
	BONOBO_UI_VERB ("ImportEpiphany", (BonoboUIVerbFn) gb_editor_bonobo_cmd_import_epiphany),
	BONOBO_UI_VERB ("ExportMozilla", (BonoboUIVerbFn) gb_editor_bonobo_cmd_export_mozilla),
	BONOBO_UI_VERB ("ExportNetscape", (BonoboUIVerbFn) gb_editor_bonobo_cmd_export_netscape),
	BONOBO_UI_VERB ("ExportKonqueror", (BonoboUIVerbFn) gb_editor_bonobo_cmd_export_konqueror),

	BONOBO_UI_VERB ("SplitView", (BonoboUIVerbFn) gb_editor_bonobo_cmd_split_view),
	BONOBO_UI_VERB ("EditPane", (BonoboUIVerbFn) gb_editor_bonobo_cmd_edit_pane),
	
        BONOBO_UI_VERB_END
};

#define SPLIT_VIEW_PATH "/commands/SplitView"
#define SPLIT_VIEW_ID "SplitView"
#define EDIT_PANE_PATH "/commands/EditPane"
#define EDIT_PANE_ID "EditPane"

static gpointer g_object_class;

/* signals enums and ids */
enum GbEditorSignalsEnum {
	GB_EDITOR_BOOKMARK_ACTIVATED,
	GB_EDITOR_LAST_SIGNAL
};
static gint GbEditorSignals[GB_EDITOR_LAST_SIGNAL];

/**
 * Editor object
 */

MAKE_GET_TYPE (gb_editor, "GbEditor", GbEditor, gb_editor_class_init, 
	       gb_editor_init, G_TYPE_OBJECT);

static void
gb_editor_class_init (GbEditorClass *klass)
{
	klass->gb_editor_init_widgets = gb_editor_init_widgets_impl;
	G_OBJECT_CLASS (klass)->finalize = gb_editor_finalize_impl;
	
	GbEditorSignals[GB_EDITOR_BOOKMARK_ACTIVATED] = g_signal_new (
		"bookmark-activated", G_OBJECT_CLASS_TYPE (klass),  
		G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP,
                G_STRUCT_OFFSET (GbEditorClass, gb_editor_bookmark_activated), 
		NULL, NULL, 
		g_cclosure_marshal_VOID__POINTER,
		G_TYPE_NONE, 1, G_TYPE_POINTER);
	
	g_object_class = g_type_class_peek_parent (klass);
}

static void 
gb_editor_init (GbEditor *e)
{
	static gchar *empty_string_array[] = { "", NULL };
	GbEditorPrivate *p = g_new0 (GbEditorPrivate, 1);
	e->priv = p;
	
	p->small_editor = gb_single_editor_small_new ();

	p->search_text = g_strdup ("");
	p->search_casefold_text = g_strdup ("");
	p->search_text_split = g_strdupv (empty_string_array);
	p->search_casefold_text_split = g_strdupv (empty_string_array);
	p->search_match_case = FALSE;
	p->search_include_folders = FALSE;
	p->search_include_sites = TRUE;
	p->search_look_in_name = TRUE;
	p->search_look_in_location = TRUE;
	p->search_look_in_notes = TRUE;
	p->search_match_type = MATCH_TYPE_AND;
	p->old_left_selection = NULL;
}

static void
gb_editor_finalize_impl (GObject *o)
{
	GbEditor *e = GB_EDITOR (o);
	GbEditorPrivate *p = e->priv;
	
	gb_editor_set_location_source (e, NULL);
	
	if (p->search_timeout)
	{
		g_source_remove (p->search_timeout);
	}

	if (p->left_tree_model) g_object_unref (p->left_tree_model);
	if (p->clipboard) g_object_unref (p->clipboard);
	if (p->set) g_object_unref (p->set);
	if (p->left_tree_view) g_object_unref (p->left_tree_view);
	if (p->right_tree_view) g_object_unref (p->right_tree_view);
	if (p->right_tree_model) g_object_unref (p->right_tree_model);
	if (p->right_box) g_object_unref (p->right_box);
	if (p->left_box) g_object_unref (p->left_box);
	if (p->small_editor) g_object_unref (p->small_editor);
	if (p->edit_pane) g_object_unref (p->edit_pane);
	if (p->search_text_entry) g_object_unref (p->search_text_entry);
	if (p->search_options_button) g_object_unref (p->search_options_button);

	if (p->search_extra_options_window && GTK_IS_WIDGET (p->search_extra_options_window))
	{
		gtk_widget_destroy (p->search_extra_options_window);
	}

	g_free (p->search_text);
	g_free (p->search_casefold_text);
	g_strfreev (p->search_text_split);
	g_strfreev (p->search_casefold_text_split);

	g_slist_foreach (p->old_left_selection, (GFunc) g_object_unref, NULL);
	g_slist_free (p->old_left_selection);

	g_free (p);
	
	LOG ("GbEditor finalized");
	
	G_OBJECT_CLASS (g_object_class)->finalize (o);
}

static void
gb_editor_init_widgets (GbEditor *e)
{
	GbEditorClass *klass = GB_EDITOR_GET_CLASS (e);
	return klass->gb_editor_init_widgets (e);
}

static void
search_b_f_match_case_toggled_cb (GtkToggleButton *tb, GbEditor *f)
{
	GbEditorPrivate *p = f->priv;

	if (p->block_update > 0)
	{
		return;
	}

	p->search_match_case = gtk_toggle_button_get_active (tb);
	gb_editor_search_start_timeout (f);
}

static void
search_b_f_include_folders_toggled_cb (GtkToggleButton *tb, GbEditor *f)
{
	GbEditorPrivate *p = f->priv;

	if (p->block_update > 0)
	{
		return;
	}

	p->search_include_folders = gtk_toggle_button_get_active (tb);
	gb_editor_search_start_timeout (f);
}

static void
search_b_f_include_sites_toggled_cb (GtkToggleButton *tb, GbEditor *f)
{
	GbEditorPrivate *p = f->priv;

	if (p->block_update > 0)
	{
		return;
	}

	p->search_include_sites = gtk_toggle_button_get_active (tb);
	gb_editor_search_start_timeout (f);
}

static void
search_b_f_look_in_name_toggled_cb (GtkToggleButton *tb, GbEditor *f)
{
	GbEditorPrivate *p = f->priv;

	if (p->block_update > 0)
	{
		return;
	}

	p->search_look_in_name = gtk_toggle_button_get_active (tb);
	gb_editor_search_start_timeout (f);
}

static void
search_b_f_look_in_location_toggled_cb (GtkToggleButton *tb, GbEditor *f)
{
	GbEditorPrivate *p = f->priv;

	if (p->block_update > 0)
	{
		return;
	}

	p->search_look_in_location = gtk_toggle_button_get_active (tb);
	gb_editor_search_start_timeout (f);
}

static void
search_b_f_look_in_notes_toggled_cb (GtkToggleButton *tb, GbEditor *f)
{
	GbEditorPrivate *p = f->priv;

	if (p->block_update > 0)
	{
		return;
	}

	p->search_look_in_notes = gtk_toggle_button_get_active (tb);
	gb_editor_search_start_timeout (f);
}

static void
search_b_f_several_and_toggled_cb (GtkToggleButton *tb, GbEditor *f)
{
	GbEditorPrivate *p = f->priv;

	if (p->block_update > 0)
	{
		return;
	}

	if (gtk_toggle_button_get_active (tb))
	{
		p->search_match_type = MATCH_TYPE_AND;
	}
	gb_editor_search_start_timeout (f);
}

static void
search_b_f_several_or_toggled_cb (GtkToggleButton *tb, GbEditor *f)
{
	GbEditorPrivate *p = f->priv;

	if (p->block_update > 0)
	{
		return;
	}

	if (gtk_toggle_button_get_active (tb))
	{
		p->search_match_type = MATCH_TYPE_OR;
	}
	gb_editor_search_start_timeout (f);
}

static void
search_b_f_several_exact_toggled_cb (GtkToggleButton *tb, GbEditor *f)
{
	GbEditorPrivate *p = f->priv;

	if (p->block_update > 0)
	{
		return;
	}

	if (gtk_toggle_button_get_active (tb))
	{
		p->search_match_type = MATCH_TYPE_EXACT;
	}
	gb_editor_search_start_timeout (f);
}

static void
gb_editor_search_finish (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	

	p->block_update++;
	if (p->search_text_entry)
	{
		gtk_entry_set_text (GTK_ENTRY (p->search_text_entry), "");
	}
	p->block_update--;
	
	gb_tree_view_set_autoexpand_roots (p->left_tree_view, TRUE);

	if (!p->show_right_tree_view)
	{
		gb_tree_view_set_model (p->left_tree_view, p->left_tree_model);
	}

	if (p->show_right_tree_view)
	{
		gb_tree_view_set_model (p->right_tree_view, p->right_tree_model);
		gb_tree_view_select_list (p->left_tree_view, p->old_left_selection);
	}

	gb_editor_selection_changed_cb (NULL, e);
	gb_editor_right_selection_changed_cb (NULL, e);
}

static void
search_text_entry_changed_cb (GtkWidget *te, GbEditor *f)
{
	GbEditorPrivate *p = f->priv;

	if (p->block_update > 0)
	{
		return;
	}

	g_free (p->search_text);
	g_free (p->search_casefold_text);
	g_strfreev (p->search_text_split);
	g_strfreev (p->search_casefold_text_split);

	p->search_text = gtk_editable_get_chars (GTK_EDITABLE (p->search_text_entry), 0, -1);
	p->search_casefold_text = g_utf8_casefold (p->search_text, -1);
	p->search_text_split = gul_strsplit_multiple_delimiters_with_quotes (p->search_text, " ,", -1, NULL);
	p->search_casefold_text_split = gul_strsplit_multiple_delimiters_with_quotes (p->search_casefold_text,
										      " ,", -1, NULL);

	if (p->search_text[0] == '\0')
	{
		gb_editor_search_stop_timeout (f);
		gb_editor_search_finish (f);
	}
	else
	{
		gb_editor_search_start_timeout (f);
	}
}

static void
search_update_option_widgets (GbEditor *f)
{
	GbEditorPrivate *p = f->priv;

	p->block_update++;
	gtk_entry_set_text (GTK_ENTRY (p->search_text_entry), p->search_text);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (p->search_b_f_match_case), p->search_match_case);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (p->search_b_f_include_folders), p->search_include_folders);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (p->search_b_f_include_sites), p->search_include_sites);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (p->search_b_f_look_in_name), p->search_look_in_name);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (p->search_b_f_look_in_location), p->search_look_in_location);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (p->search_b_f_look_in_notes), p->search_look_in_notes);
	switch (p->search_match_type)
	{
	default:
	case MATCH_TYPE_AND:
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (p->search_b_f_several_and), TRUE);
		break;
	case MATCH_TYPE_OR:
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (p->search_b_f_several_or), TRUE);
		break;
	case MATCH_TYPE_EXACT:
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (p->search_b_f_several_exact), TRUE);
		break;
	}
	p->block_update--;
}

static void
search_options_button_toggled_cb (GtkToggleButton *tb, GbEditor *f)
{
	GbEditorPrivate *p = f->priv;

	if (p->block_update > 0)
	{
		return;
	}

	if (gtk_toggle_button_get_active (tb))
	{
		gtk_widget_show (p->search_extra_options_window);
	}
	else
	{
		gtk_widget_hide (p->search_extra_options_window);
	}
}

static gboolean
search_extra_options_window_delete_event_cb (GtkWidget *w, GdkEventAny *event, GbEditor *f)
{
	GbEditorPrivate *p = f->priv;
	
	p->block_update++;
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (p->search_options_button), FALSE);
	gtk_widget_hide (p->search_extra_options_window);
	p->block_update--;
		
	return TRUE;
}

static void
gb_editor_init_search_widgets (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;

	if (p->search_text_entry)
	{
		g_signal_connect (p->search_text_entry, "changed", 
				  G_CALLBACK (search_text_entry_changed_cb), e);
	}

	if (p->search_options_button)
	{
		WidgetLookup lookups[] = {
			{ "b-f-extra-options-window", &p->search_extra_options_window },
			{ "b-f-match-case", &p->search_b_f_match_case },
			{ "b-f-include-folders", &p->search_b_f_include_folders },
			{ "b-f-include-sites", &p->search_b_f_include_sites },
			{ "b-f-look-in-name", &p->search_b_f_look_in_name },
			{ "b-f-look-in-location", &p->search_b_f_look_in_location },
			{ "b-f-look-in-notes", &p->search_b_f_look_in_notes },
			{ "b-f-several-and", &p->search_b_f_several_and },
			{ "b-f-several-or", &p->search_b_f_several_or },
			{ "b-f-several-exact", &p->search_b_f_several_exact },

			{ NULL, NULL }
		};
		GladeXML *gxml = gul_glade_widget_new ("bookmarks-find.glade", "b-f-extra-options-window",
						       NULL, e);
		gul_glade_lookup_widgets (gxml, lookups);
		g_object_unref (gxml);
		
		g_signal_connect (p->search_b_f_match_case, "toggled", 
				  G_CALLBACK (search_b_f_match_case_toggled_cb), e);
		g_signal_connect (p->search_b_f_include_folders, "toggled", 
				  G_CALLBACK (search_b_f_include_folders_toggled_cb), e);
		g_signal_connect (p->search_b_f_include_sites, "toggled", 
				  G_CALLBACK (search_b_f_include_sites_toggled_cb), e);
		g_signal_connect (p->search_b_f_look_in_name, "toggled", 
				  G_CALLBACK (search_b_f_look_in_name_toggled_cb), e);
		g_signal_connect (p->search_b_f_look_in_location, "toggled", 
				  G_CALLBACK (search_b_f_look_in_location_toggled_cb), e);
		g_signal_connect (p->search_b_f_look_in_notes, "toggled", 
				  G_CALLBACK (search_b_f_look_in_notes_toggled_cb), e);
		g_signal_connect (p->search_b_f_several_and, "toggled", 
				  G_CALLBACK (search_b_f_several_and_toggled_cb), e);
		g_signal_connect (p->search_b_f_several_or, "toggled", 
				  G_CALLBACK (search_b_f_several_or_toggled_cb), e);
		g_signal_connect (p->search_b_f_several_exact, "toggled", 
				  G_CALLBACK (search_b_f_several_exact_toggled_cb), e);
		g_signal_connect (p->search_options_button, "toggled",
				  G_CALLBACK (search_options_button_toggled_cb), e);
		g_signal_connect (p->search_extra_options_window, "delete-event",
				  G_CALLBACK (search_extra_options_window_delete_event_cb), e);
		
		search_update_option_widgets (e);
	}
}





static void 
gb_editor_ensure_init_widgets (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	if (!p->main_widget)
	{
		GtkTreeSelection *s;
		p->clipboard = gb_clipboard_get_shared ();
		
		gb_editor_init_widgets (e);
		
		s = gtk_tree_view_get_selection (GTK_TREE_VIEW (p->left_tree_view));
		gtk_tree_selection_set_mode (s, GTK_SELECTION_MULTIPLE);
		g_signal_connect (s, "changed", G_CALLBACK (gb_editor_selection_changed_cb), e);
	
		s = gtk_tree_view_get_selection (GTK_TREE_VIEW (p->right_tree_view));
		gtk_tree_selection_set_mode (s, GTK_SELECTION_MULTIPLE);
		g_signal_connect (s, "changed", G_CALLBACK (gb_editor_right_selection_changed_cb), e);

		gb_editor_init_search_widgets (e);

		gb_editor_show_data (e);
	}
}

static gboolean
gb_editor_bookmark_right_double_clicked (GbTreeView *tv, GbBookmark *b, GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	g_return_val_if_fail (tv == p->right_tree_view, FALSE);

	if (GB_IS_FOLDER (b))
	{
		gb_tree_view_select (p->left_tree_view, b);
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

GbTreeView *
gb_editor_get_tree_view	(GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	if (!p->left_tree_view)
	{
		p->left_tree_view = gb_tree_view_new ();
		if (p->location_source)
		{
			gb_tree_view_set_location_source (p->left_tree_view, p->location_source);
		}
	
		g_signal_connect (p->left_tree_view, "bookmark-activated", 
				  G_CALLBACK (gb_editor_bookmark_activated_cb), e);

		gtk_widget_show (GTK_WIDGET (p->left_tree_view));
		g_object_ref (p->left_tree_view);
		gtk_object_sink (GTK_OBJECT (p->left_tree_view));

		p->right_tree_view = gb_tree_view_new ();
		if (p->location_source)
		{
			gb_tree_view_set_location_source (p->right_tree_view, p->location_source);
		}
	
		g_signal_connect (p->right_tree_view, "bookmark-activated", 
				  G_CALLBACK (gb_editor_bookmark_activated_cb), e);
		gb_tree_view_set_double_click_action (p->right_tree_view, GB_TV_ACTIVATE_NEW_WINDOW);
		g_signal_connect (p->right_tree_view, "bookmark-double-clicked",
				  G_CALLBACK (gb_editor_bookmark_right_double_clicked), e);
		
		gtk_widget_show (GTK_WIDGET (p->right_tree_view));
		g_object_ref (p->right_tree_view);
		gtk_object_sink (GTK_OBJECT (p->right_tree_view));

		gb_tree_view_set_autoexpand_roots (p->right_tree_view, FALSE);
	}
	return p->left_tree_view;
}

void
gb_editor_set_main_widget (GbEditor *e, GtkWidget *w)
{
	GbEditorPrivate *p = e->priv;

	g_return_if_fail (p->main_widget == NULL);
	g_return_if_fail (GTK_IS_WIDGET (w));

	p->main_widget = w;
	g_object_ref (p->main_widget);
}

void
gb_editor_set_search_widgets (GbEditor *e, GtkWidget *search_text_entry, 
			      GtkWidget *search_options_button)
{
	GbEditorPrivate *p = e->priv;
	p->search_text_entry = g_object_ref (search_text_entry);
	p->search_options_button = g_object_ref (search_options_button);
}

static void 
hpaned_position_middle_hack (GtkPaned *paned)
{
	gint handle_size;
	gint available;
	gint pos;
	gint border_width = GTK_CONTAINER (paned)->border_width;

	gtk_widget_style_get (GTK_WIDGET (paned), "handle_size", &handle_size, NULL);

	available = MAX (1, GTK_WIDGET (paned)->allocation.width - handle_size - 2 * border_width);
	pos = available / 2;
	gtk_paned_set_position (paned, pos);
}

static gboolean
gb_editor_key_press_event_cb (GtkWidget *widget, GdkEventKey *event)
{
	if ((event->state & GDK_CONTROL_MASK) || (event->state & GDK_MOD1_MASK) || (event->keyval == GDK_Delete) || (event->keyval == GDK_KP_Delete))
	{
		GtkWidget *entry = gtk_window_get_focus (GTK_WINDOW(widget));
		if ((GTK_IS_EDITABLE(entry) || GTK_IS_TEXT_VIEW (entry)) &&
		    gtk_widget_event (entry, (GdkEvent*)event))
			return TRUE;
	}
	return FALSE;
}

static void
gb_editor_init_widgets_impl (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	GtkWidget *contents;
	GtkWidget *mw;
	GtkWidget *vbox;
	GtkPaned *hpane;
	GtkWidget *search_label;
	GtkWidget *right_scrolled_window;
	GtkWidget *left_scrolled_window;
	
	BonoboWindow *win;
	BonoboUIContainer *container;
	BonoboUIComponent *ui_component;
	Bonobo_UIContainer corba_container;
	
	mw = bonobo_window_new ("Galeon Bookmarks Editor", "Bookmarks Editor");
	gb_editor_set_main_widget (e, mw);

	g_object_weak_ref (G_OBJECT (mw), (GWeakNotify) g_object_unref, e);

	/* makes sure the tree view has been created */
	gb_editor_get_tree_view (e);
	
	gb_editor_set_search_widgets (e, gtk_entry_new (), gtk_toggle_button_new_with_mnemonic (_("O_ptions...")));
	p->search_hbox = gtk_hbox_new (FALSE, 6);
	search_label = gtk_label_new_with_mnemonic (_("Fin_d:"));
	gtk_box_pack_start (GTK_BOX (p->search_hbox), search_label, FALSE, TRUE, 0);
	gtk_box_pack_start (GTK_BOX (p->search_hbox), p->search_text_entry, TRUE, TRUE, 0);
	gtk_box_pack_start (GTK_BOX (p->search_hbox), p->search_options_button, FALSE, TRUE, 0);
	gtk_label_set_mnemonic_widget (GTK_LABEL (search_label), p->search_text_entry);
	p->search_placeholder_left = gtk_vbox_new (FALSE, 0);
	p->search_placeholder_right = gtk_vbox_new (FALSE, 0);

	contents = gtk_vpaned_new ();
	hpane = GTK_PANED (gtk_hpaned_new ());

	p->hpane = GTK_WIDGET (hpane);

	vbox = gtk_vbox_new (FALSE, 6);
	gtk_box_pack_start (GTK_BOX (p->search_placeholder_left), p->search_hbox, FALSE, TRUE, 0);
	gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (hpane), TRUE, TRUE, 0);

	gtk_paned_pack1 (GTK_PANED (contents), vbox, TRUE, TRUE);

	left_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (left_scrolled_window), 
					GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
	gtk_container_add (GTK_CONTAINER (left_scrolled_window), GTK_WIDGET (p->left_tree_view));

	p->left_box = gtk_vbox_new (FALSE, 0);
	gtk_box_pack_start (GTK_BOX (p->left_box), p->search_placeholder_left, FALSE, TRUE, 0);
	gtk_box_pack_start (GTK_BOX (p->left_box), left_scrolled_window, TRUE, TRUE, 0);
	gtk_paned_pack1 (hpane, p->left_box, TRUE, TRUE);
	g_object_ref (p->left_box);

	right_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (right_scrolled_window), 
					GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
	gtk_container_add (GTK_CONTAINER (right_scrolled_window), GTK_WIDGET (p->right_tree_view));

	p->right_box = gtk_vbox_new (FALSE, 0);
	gtk_box_pack_start (GTK_BOX (p->right_box), p->search_placeholder_right, FALSE, TRUE, 0);
	gtk_box_pack_start (GTK_BOX (p->right_box), right_scrolled_window, TRUE, TRUE, 0);
	gtk_paned_pack2 (hpane, p->right_box, TRUE, TRUE);
	g_object_ref (p->right_box);
	
	p->edit_pane = g_object_ref (gb_single_editor_small_get_widget (p->small_editor));
	gtk_paned_pack2 (GTK_PANED (contents), p->edit_pane, FALSE, FALSE);

	gtk_widget_show_all (contents);

	hpaned_position_middle_hack (GTK_PANED (p->hpane));
	
	win = BONOBO_WINDOW (p->main_widget);
	bonobo_window_set_contents (win, contents);
	container = bonobo_window_get_ui_container (win);
        bonobo_ui_engine_config_set_path (bonobo_window_get_ui_engine (win), 
					  "/galeon/bookmarksEditor/UIConfig/kvps");
        corba_container = BONOBO_OBJREF (container);
	ui_component = bonobo_ui_component_new_default ();
	bonobo_ui_component_set_container (ui_component, corba_container, NULL);
	bonobo_ui_util_set_ui (ui_component, DATADIR, 
			       "galeon-bookmarks-editor-ui.xml", 
			       "galeon-bookmarks", NULL);
	bonobo_ui_component_add_verb_list_with_data (ui_component, bookmarks_editor_verbs, e);

	bonobo_ui_component_add_listener(ui_component, SPLIT_VIEW_ID, 
					 (BonoboUIListenerFn) gb_editor_bonobo_split_view_changed_cb, 
					 e);
	bonobo_ui_component_add_listener(ui_component, EDIT_PANE_ID, 
					 (BonoboUIListenerFn) gb_editor_bonobo_edit_pane_changed_cb, 
					 e);

	/* load default status */
	{
		gboolean edit_pane = eel_gconf_get_boolean (CONF_BOOKMARKS_EDITOR_EDIT_PANE);
		gboolean split_view = eel_gconf_get_boolean (CONF_BOOKMARKS_EDITOR_SPLIT_VIEW);
		bonobo_ui_component_set_prop (ui_component, SPLIT_VIEW_PATH, "state", split_view ? "1" : "0", NULL);
		bonobo_ui_component_set_prop (ui_component, EDIT_PANE_PATH, "state", edit_pane ? "1" : "0", NULL);
	}

	/* sync ui with editor state */
	gb_editor_bonobo_cmd_edit_pane (ui_component, e, "EditPane");
	gb_editor_bonobo_cmd_split_view (ui_component, e, "SplitView");
	
	/* window size saving crack */
	g_signal_connect (p->main_widget, "configure_event", 
			  G_CALLBACK (gb_editor_window_configure_event_cb), e);
	
	gul_state_monitor_window (p->main_widget, "Bookmarks",
			          STATE_BOOKMARKS_WIDTH_DEFAULT,
				  STATE_BOOKMARKS_HEIGHT_DEFAULT);

	/* keyboard accelerator handling crack */
	g_signal_connect (p->main_widget, "key-press-event",
			  G_CALLBACK (gb_editor_key_press_event_cb), NULL);
}

GbEditor *
gb_editor_new (GbTreeModel *model)
{
	GbEditor *ret = g_object_new (GB_TYPE_EDITOR, NULL);
	gb_editor_set_model (ret, model);
	return ret;
}

GbEditor *
gb_editor_new_for_set (GbBookmarkSet *set)
{
	GbTreeModel *tm;
	GbEditor *e;
	
	g_return_val_if_fail (GB_IS_BOOKMARK_SET (set), NULL);
	g_return_val_if_fail (GB_IS_FOLDER (set->root), NULL);
	
	tm = gb_tree_model_new_for_set (set);
	e = gb_editor_new (tm);
	g_object_unref (tm);
	
	return e;
}

void
gb_editor_set_model (GbEditor *e, GbTreeModel *m)
{
	GbEditorPrivate *p = e->priv;
	
	gb_editor_ensure_init_widgets (e);

	g_return_if_fail (GB_IS_TREE_MODEL (m));
	g_return_if_fail (GB_IS_TREE_VIEW (p->left_tree_view));
	
	if (p->left_tree_model)
	{
		g_object_unref (G_OBJECT (p->left_tree_model));
	}
	if (p->set)
	{
		g_object_unref (G_OBJECT (p->set));
	}
	p->left_tree_model = m;
	g_object_ref (G_OBJECT (m));
	p->set = gb_tree_model_get_set (m);
	if (p->set)
	{
		g_object_ref (G_OBJECT (p->set));
	}
	
	gb_tree_view_set_model (p->left_tree_view, p->left_tree_model);

	gb_editor_set_show_right_tree_view (e, p->show_right_tree_view);
	gb_editor_set_show_edit_pane (e, p->show_edit_pane);
}

void
gb_editor_set_show_right_tree_view (GbEditor *e, gboolean value)
{
	GbEditorPrivate *p = e->priv;

	gb_editor_search_finish (e);

	p->show_right_tree_view = value;

	if (p->show_right_tree_view)
	{
		if (p->left_tree_model)
		{
			gb_tree_model_set_only_folders (p->left_tree_model, TRUE);
		}
		gtk_widget_show (p->right_box);
		gb_tree_view_set_location_visible (p->left_tree_view, FALSE);

		if (p->search_hbox && p->search_placeholder_right)
		{
			g_object_ref (p->search_hbox);
			if (p->search_hbox->parent)
			{
				gtk_container_remove (GTK_CONTAINER (p->search_hbox->parent), p->search_hbox);
			}
			gtk_box_pack_start (GTK_BOX (p->search_placeholder_right), p->search_hbox, FALSE, TRUE, 0);
			g_object_unref (p->search_hbox);
		}
	}
	else
	{
		if (p->left_tree_model)
		{
			gb_tree_model_set_only_folders (p->left_tree_model, FALSE);
		}
		if (p->right_box)
		{
			gtk_widget_hide (p->right_box);
		}
		gb_tree_view_set_location_visible (p->left_tree_view, TRUE);

		if (p->search_hbox && p->search_placeholder_left)
		{
			g_object_ref (p->search_hbox);
			if (p->search_hbox->parent)
			{
				gtk_container_remove (GTK_CONTAINER (p->search_hbox->parent), p->search_hbox);
			}
			gtk_box_pack_start (GTK_BOX (p->search_placeholder_left), p->search_hbox, FALSE, TRUE, 0);
			g_object_unref (p->search_hbox);
		}
	}

	gb_editor_selection_changed_cb (NULL, e);
	if (p->show_right_tree_view)
	{
		gb_editor_right_selection_changed_cb (NULL, e);
	}
}

void
gb_editor_set_show_edit_pane (GbEditor *e, gboolean value)
{
	GbEditorPrivate *p = e->priv;

	p->show_edit_pane = value;

	if (p->show_edit_pane)
	{
		gtk_widget_show (p->edit_pane);
		gb_editor_selection_changed_cb (NULL, e);
		gb_editor_right_selection_changed_cb (NULL, e);
	}
	else
	{
		if (p->edit_pane)
		{
			gtk_widget_hide (p->edit_pane);
		}
	}
}

void
gb_editor_set_location_source (GbEditor *e, GbLocationSource *s)
{
	GbEditorPrivate *p = e->priv;
	
	if (p->location_source)
	{
		g_object_remove_weak_pointer (G_OBJECT (p->location_source),
					      (gpointer *) &p->location_source);
	}
	
	p->location_source = s;
	
	if (p->location_source)
	{
		g_object_add_weak_pointer (G_OBJECT (p->location_source), 
					   (gpointer *) &p->location_source);
	}
	
	if (p->left_tree_view && GB_IS_TREE_VIEW (p->left_tree_view))
	{
		gb_tree_view_set_location_source (p->left_tree_view, s);
	}

	if (p->right_tree_view && GB_IS_TREE_VIEW (p->right_tree_view))
	{
		gb_tree_view_set_location_source (p->right_tree_view, s);
	}
}

static gboolean
gb_editor_compare_list_of_bookmarks (const GSList *l1, const GSList *l2)
{
	while (l1 && l2)
	{
		if (l1->data != l2->data) 
		{
			return FALSE;
		}
		l1 = l1->next;
		l2 = l2->next;
	}
	return !l1 && !l2;
}

static void
gb_editor_selection_changed_cb (GtkTreeSelection *treeselection, GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	GSList *selected = gb_tree_view_get_selected_list_prepared (p->left_tree_view);

	p->block_update++;
	
	gb_editor_show_data (e);
	
	if (selected && p->show_right_tree_view)
	{
		const GSList *previous_roots = 
			p->right_tree_model 
			&& gtk_tree_view_get_model (GTK_TREE_VIEW (p->right_tree_view)) 
					== GTK_TREE_MODEL (p->right_tree_model)
				? gb_tree_model_get_roots (p->right_tree_model) 
				: NULL;
		GSList *new_roots = g_slist_copy (selected);
		GSList *sli;

		if (p->search_text_entry)
		{
			gtk_entry_set_text (GTK_ENTRY (p->search_text_entry), "");
		}
		
		for (sli = new_roots; sli; sli = sli->next)
		{
			sli->data = gb_bookmark_real_bookmark (sli->data);
		}

		if (!gb_editor_compare_list_of_bookmarks (previous_roots, new_roots))
		{		
			if (p->right_tree_model) g_object_unref (p->right_tree_model);
			
			p->right_tree_model = gb_tree_model_new (new_roots);
			gb_tree_model_set_hide_roots (p->right_tree_model, TRUE);
			gb_tree_model_set_only_folders (p->right_tree_model, FALSE);
			gb_tree_view_set_model (p->right_tree_view, p->right_tree_model);
			gb_editor_right_selection_changed_cb (NULL, e);
		}
		g_slist_free (new_roots);
	}
	else if (p->show_right_tree_view)
	{
		gb_tree_view_set_model (p->right_tree_view, NULL);
		gb_editor_right_selection_changed_cb (NULL, e);
	}
	
	if (!p->show_right_tree_view && p->show_edit_pane && selected && !selected->next)
	{
		gb_single_editor_set_bookmark (GB_SINGLE_EDITOR (p->small_editor), selected->data);
	}
	else if (!p->show_right_tree_view && p->show_edit_pane)
	{
		gb_single_editor_set_bookmark (GB_SINGLE_EDITOR (p->small_editor), NULL);
	}

	g_slist_free (selected);

	p->block_update--;
	
}

static void
gb_editor_right_selection_changed_cb (GtkTreeSelection *treeselection, GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	GSList *selected = gb_tree_view_get_selected_list_prepared (p->right_tree_view);

	p->block_update++;
	
	gb_editor_show_data (e);
	
	if (p->show_right_tree_view && p->show_edit_pane && selected && !selected->next)
	{
		gb_single_editor_set_bookmark (GB_SINGLE_EDITOR (p->small_editor), selected->data);
	}
	else if (p->show_right_tree_view && p->show_edit_pane)
	{
		gb_single_editor_set_bookmark (GB_SINGLE_EDITOR (p->small_editor), NULL);
	}

	g_slist_free (selected);

	p->block_update--;
	
}

static void
gb_editor_show_data (GbEditor *e)
{
#if 0
	GbEditorPrivate *p = e->priv;
	const GSList *selected = gb_tree_view_get_selected_list (p->left_tree_view);
	p->block_update++;
	if (selected && !selected->next)
		/* there's one and only one item selected */
	{
		/* this does not do anything now. Previously, it displayed all the info
		   about the selected bookmark */
		
		/* probably I should update the UI depending of the
		 * type of the selected bookmark */
	}
	p->block_update--;
#endif
}


GtkWidget *
gb_editor_get_main_widget (GbEditor *editor)
{
	GbEditorPrivate *p = editor->priv;
	return p->main_widget;
}

void
gb_editor_select (GbEditor *e, GbBookmark *b)
{
	GbEditorPrivate *p = e->priv;
	g_return_if_fail (GB_IS_TREE_VIEW (p->left_tree_view));
	
	if (p->show_right_tree_view)
	{
		GbBookmark *parent = GB_BOOKMARK (b->parent);
		if (parent)
		{
			gb_tree_view_ensure_selected (p->left_tree_view, parent);
		}
		gb_tree_view_select (p->right_tree_view, b);
	}
	else
	{
		gb_tree_view_select (p->left_tree_view, b);
	}
}

static gboolean
gb_editor_window_configure_event_cb (GtkWidget *widget,
				     GdkEventConfigure *event,
				     GbEditor *e)
{
	GbEditorPrivate *p = e->priv;

	/* the check is to avoid resizing the pane when the user has set an explicit width */
	/* the first time the window is shown, the widht will be 0,
	 * because I have called the function before the widget were shown */

	if (gtk_paned_get_position (GTK_PANED (p->hpane)) < 2)
	{
		hpaned_position_middle_hack (GTK_PANED (p->hpane));
	}

	return FALSE;
}

static void
gb_editor_bookmark_activated_cb (GObject *sender,
				 GbBookmarkEventActivated *ev,
				 GbEditor *e)
{
	if (ev->flags & GB_BAF_EDITOR)
	{
		gb_editor_select (e, ev->bookmark);
	}
	else
	{
		g_signal_emit_by_name (e, "bookmark-activated", ev);
	}
}

static void 
gb_editor_add_new (GbEditor *e, GbBookmark *new_bookmark)
{
	GSList *l = g_slist_prepend (NULL, new_bookmark);
	gb_editor_add_several (e, l);
	g_slist_free (l);
}

static const GSList *
gb_editor_get_selected_current_pane (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	if (p->show_right_tree_view)
	{
		return gb_tree_view_get_selected_list (p->right_tree_view);
	}
	else
	{
		return gb_tree_view_get_selected_list (p->left_tree_view);
	}
}

static GSList *
gb_editor_get_selected_current_pane_prepared (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	if (p->show_right_tree_view)
	{
		return gb_tree_view_get_selected_list_prepared (p->right_tree_view);
	}
	else
	{
		return gb_tree_view_get_selected_list_prepared (p->left_tree_view);
	}
}

static const GSList *
gb_editor_get_selected_current_or_left_pane (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	const GSList *current = gb_editor_get_selected_current_pane (e);
	if (current)
	{
		return current;
	}
	else
	{
		return gb_tree_view_get_selected_list (p->left_tree_view);
	}
}

static GSList *
gb_editor_get_selected_current_or_left_pane_prepared (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	GSList *current = gb_editor_get_selected_current_pane_prepared (e);
	if (current)
	{
		return current;
	}
	else
	{
		return gb_tree_view_get_selected_list_prepared (p->left_tree_view);
	}
}

static void 
gb_editor_add_several (GbEditor *e, GSList *l)
{
	GbEditorPrivate *p = e->priv;
	GbFolder *parent = NULL;
	GbBookmark *next = NULL;
	gint index;
	GSList *li;
	const GSList *selected = gb_editor_get_selected_current_or_left_pane (e);

	if (selected && !selected->next)
		/* there's one and only one item selected */
	{
		GbBookmark *s = selected->data;
		if (GB_IS_FOLDER (s))
		{
			parent = GB_FOLDER (s);
		} 
		else
		{
			next = s;
			parent = s->parent;
		}
	}
	
	if (parent == NULL)
	{
		GbBookmark *fr = gb_tree_model_get_first_root (p->left_tree_model);
		if (GB_IS_FOLDER (fr))
		{
			parent = GB_FOLDER (fr);
		}
		else
		{
			parent = fr->parent;
			if (!parent)
			{
				g_warning ("Could not find a parent to add the new bookmark!\n");
				return;
			}
		}
		next = NULL;
	}
	
	if (next != NULL)
	{
		index = gb_folder_get_child_index (parent, next);
	}
	else
	{
		index = 0;
	}
	
	for (li = l; li; li = li->next)
	{
		gb_folder_add_child (parent, li->data, index++);
		gb_bookmark_set_time_added_now (li->data);
	}
	
	if (l && !l->next)
	{
		gb_editor_select (e, l->data);
	}
	else if (l)
	{
		/* TODO: select all of them? */
	}
}

static void
gb_editor_bonobo_cmd_add_site (BonoboUIComponent *uic, GbEditor *e, const gchar* verbname)
{
	gb_editor_cmd_add_site (e);
}

void 
gb_editor_cmd_add_site (GbEditor *e)
{
	/* see also bookmarks-context-menu.c */
	GbSite *new = gb_site_new (gb_tree_model_get_set (e->priv->left_tree_model),
				   _("New Site"), "http://");
	gb_editor_add_new (e, GB_BOOKMARK (new));
	g_object_unref (G_OBJECT (new));
}

static void
gb_editor_bonobo_cmd_add_smart_site (BonoboUIComponent *uic, GbEditor *e, const gchar* verbname)
{
	gb_editor_cmd_add_smart_site (e);
}

void 
gb_editor_cmd_add_smart_site (GbEditor *e)
{
	/* see also bookmarks-context-menu.c */
	GbSmartSite *new = gb_smart_site_new (gb_tree_model_get_set (e->priv->left_tree_model),
					      _("New Smart Site"), "http://", "http://%s");
	gb_editor_add_new (e, GB_BOOKMARK (new));
	g_object_unref (G_OBJECT (new));
}

static void
gb_editor_bonobo_cmd_add_folder (BonoboUIComponent *uic, GbEditor *e, const gchar* verbname)
{
	gb_editor_cmd_add_folder (e);
}

void
gb_editor_cmd_add_folder (GbEditor *e)
{
	GbFolder *new = gb_folder_new (gb_tree_model_get_set (e->priv->left_tree_model),
				       _("New folder"));
	gb_editor_add_new (e, GB_BOOKMARK (new));
	g_object_unref (G_OBJECT (new));
}

static void
gb_editor_bonobo_cmd_add_separator (BonoboUIComponent *uic, GbEditor *e, const gchar* verbname)
{
	gb_editor_cmd_add_separator (e);
}

void
gb_editor_cmd_add_separator (GbEditor *e)
{
	GbSeparator *new = gb_separator_new (gb_tree_model_get_set (e->priv->left_tree_model));
	gb_editor_add_new (e, GB_BOOKMARK (new));
	g_object_unref (G_OBJECT (new));
}

static void
gb_editor_bonobo_cmd_add_alias (BonoboUIComponent *uic, GbEditor *e, const gchar* verbname)
{
	gb_editor_cmd_add_alias (e);
}

void
gb_editor_cmd_add_alias (GbEditor *e)
{
	GSList *sel = gb_editor_get_selected_current_or_left_pane_prepared (e);
	GSList *seli;
	for (seli = sel; seli; seli = seli->next)
	{
		GbBookmark *b = seli->data;
		GbAliasPlaceholder *ap = gb_alias_placeholder_new (b->set, b->id);
		GbBookmark *new = gb_bookmark_alias_create (seli->data, ap);
		gb_editor_add_new (e, GB_BOOKMARK (new));
		g_object_unref (new);
		g_object_unref (ap);
	}
	g_slist_free (sel);
}

static void
gb_editor_bonobo_cmd_add_autobookmarks (BonoboUIComponent *uic, GbEditor *e, const gchar* verbname)
{
	gb_editor_cmd_add_autobookmarks (e);
}

void
gb_editor_cmd_add_autobookmarks (GbEditor *e)
{
	GbAutoFolder *new = gb_auto_folder_new (gb_tree_model_get_set (e->priv->left_tree_model), 
						_("New Autobookmarks Folder"));
	gb_editor_add_new (e, GB_BOOKMARK (new));
	g_object_unref (G_OBJECT (new));
}

static void
gb_editor_bonobo_cmd_edit_remove (BonoboUIComponent *uic, GbEditor *e, const gchar* verbname)
{
	GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (e->priv->main_widget));
	if (GTK_IS_EDITABLE(widget))
	{
		gtk_editable_delete_selection (GTK_EDITABLE(widget));
	}
	else
	{
		gb_editor_cmd_edit_remove (e);
	}
}

void
gb_editor_cmd_edit_remove (GbEditor *e)
{
	GSList *sel = gb_editor_get_selected_current_pane_prepared (e);
	GSList *seli;
	for (seli = sel; seli; seli = seli->next)
	{
		gb_bookmark_unparent_safe (seli->data);
	}
	g_slist_free (sel);
}

static void
gb_editor_bonobo_cmd_file_open (BonoboUIComponent *uic, GbEditor *e, const gchar *verbname)
{
	gb_editor_cmd_file_open (e);
}

void
gb_editor_cmd_file_open (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	gchar *dir = eel_gconf_get_string (CONF_STATE_OPEN_DIR);
	/* GbBookmarkSet *currentset = p->set; */
	char *file;
	
	file = bonobo_file_selector_open 
		(GTK_IS_WINDOW (p->main_widget) ? GTK_WINDOW (p->main_widget) : NULL,
		 FALSE, _("Select the bookmarks file to open"),
		 "XBEL files: application/xbel"
		 "|Mozilla bookmarks files:application/mozilla-bookmarks,text/html"
		 "|Netscape bookmarks files:application/netscape-bookmarks,text/html"
		 "|Epiphany RDF bookmarks files:application/xml,text/xml",
		 dir);
	g_free (dir);
	
	if (file)
	{
		GbIO *io = gb_io_object_for_file (file);
		GbBookmarkSet *newset = gb_io_load_from_file (io, file);
		GbEditor *e;
		if (newset)
		{
			e = gb_editor_new_for_set (newset);
			g_object_unref (G_OBJECT (newset));
		}
		else
		{
			/* FIXME: show an error message */
			NOT_IMPLEMENTED;
		}
		
		g_free (file);
	}
}


static void
gb_editor_bonobo_cmd_file_close (BonoboUIComponent *uic, GbEditor *e,
				 const gchar *verbname)
{
	gb_editor_cmd_file_close (e);
}

void
gb_editor_cmd_file_close (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	gtk_widget_destroy (p->main_widget);
}

static void
gb_editor_bonobo_cmd_edit_properties (BonoboUIComponent *uic, GbEditor *e, const gchar *verbname)
{
	gb_editor_cmd_edit_properties (e);
}

void
gb_editor_cmd_edit_properties (GbEditor *e)
{
	const GSList *sel = gb_editor_get_selected_current_or_left_pane (e);
	while (sel)
	{
		if (!GB_IS_SEPARATOR (sel->data))
		{
			GbSingleEditor *se = gb_single_editor_new ();
			gb_single_editor_set_bookmark (se, sel->data);
			gb_single_editor_show (se);
		}
		sel = sel->next;
	}
}

static void
gb_editor_bonobo_cmd_edit_cut (BonoboUIComponent *uic, GbEditor *e, const gchar *verbname)
{
	GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (e->priv->main_widget));
	if (GTK_IS_EDITABLE(widget))
	{
		gtk_editable_cut_clipboard (GTK_EDITABLE(widget));
	}
	else
	{
		gb_editor_cmd_edit_cut (e);
	}
}

void
gb_editor_cmd_edit_cut (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	GSList *sel = gb_editor_get_selected_current_pane_prepared (e);
	GSList *seli;
	gb_clipboard_clear (p->clipboard);
	for (seli = sel; seli; seli = seli->next)
	{
		gb_clipboard_add (p->clipboard, seli->data);
	}
	for (seli = sel; seli; seli = seli->next)
	{
		gb_bookmark_unparent_safe (seli->data);
	}
	g_slist_free (sel);
}

static void
gb_editor_bonobo_cmd_edit_copy (BonoboUIComponent *uic, GbEditor *e, const gchar *verbname)
{
	GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (e->priv->main_widget));
	if (GTK_IS_EDITABLE(widget))
	{
		gtk_editable_copy_clipboard (GTK_EDITABLE(widget));
	}
	else
	{
		gb_editor_cmd_edit_copy (e);
	}
}

void
gb_editor_cmd_edit_copy (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	GSList *sel = gb_editor_get_selected_current_or_left_pane_prepared (e);
	GSList *seli;
	gb_clipboard_clear (p->clipboard);
	for (seli = sel; seli; seli = seli->next)
	{
		gb_clipboard_add (p->clipboard, seli->data);
	}
	g_slist_free (sel);
}

static void
gb_editor_bonobo_cmd_edit_paste (BonoboUIComponent *uic, GbEditor *e, const gchar *verbname)
{
	GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (e->priv->main_widget));
	if (GTK_IS_EDITABLE(widget))
	{
		gtk_editable_paste_clipboard (GTK_EDITABLE(widget));
	}
	else
	{
		gb_editor_cmd_edit_paste (e);
	}
}

void
gb_editor_cmd_edit_paste (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	if (gb_clipboard_can_paste (p->clipboard))
	{
		GbBookmarkSet *s = gb_clipboard_paste (p->clipboard);
		GSList *l;
		if (!s) return;
		g_return_if_fail (GB_IS_BOOKMARK_SET (s) && GB_IS_FOLDER (s->root));
		l = gb_folder_list_children (s->root);
		gb_editor_add_several (e, l);
		g_slist_free (l);
		g_object_unref (s);
	}
}

static void
gb_editor_bonobo_cmd_edit_set_as_default_folder (BonoboUIComponent *uic, GbEditor *e,
						 const gchar *verbname)
{
	gb_editor_cmd_edit_set_as_default_folder (e);
}

void
gb_editor_cmd_edit_set_as_default_folder (GbEditor *e)
{
	const GSList *selected = gb_editor_get_selected_current_or_left_pane (e);
	if (selected && !selected->next && GB_IS_FOLDER (selected->data))
	{
		GbFolder *f = selected->data;
		gb_bookmark_set_set_default_folder (GB_BOOKMARK (f)->set, f);
	}
}

static void
gb_editor_bonobo_cmd_import_mozilla (BonoboUIComponent *uic, GbEditor *e,
				     const gchar *verbname)
{
	gb_editor_cmd_import_mozilla (e);
}

void
gb_editor_cmd_import_mozilla (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	GbImportDruid *d = GB_IMPORT_DRUID (gb_import_druid_mozilla_new ());
	gb_import_druid_set_dest_bookmark_set (d, p->set);
	gb_import_druid_show (d);
}

static void
gb_editor_bonobo_cmd_import_netscape (BonoboUIComponent *uic, GbEditor *e,
				      const gchar *verbname)
{
	gb_editor_cmd_import_netscape (e);
}

void
gb_editor_cmd_import_netscape (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	GbImportDruid *d = GB_IMPORT_DRUID (gb_import_druid_netscape_new ());
	gb_import_druid_set_dest_bookmark_set (d, p->set);
	gb_import_druid_show (d);
}

static void
gb_editor_bonobo_cmd_import_konqueror (BonoboUIComponent *uic, GbEditor *e,
				       const gchar *verbname)
{
	gb_editor_cmd_import_konqueror (e);
}

void
gb_editor_cmd_import_konqueror (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	GbImportDruid *d = GB_IMPORT_DRUID (gb_import_druid_konqueror_new ());
	gb_import_druid_set_dest_bookmark_set (d, p->set);
	gb_import_druid_show (d);
}

static void
gb_editor_bonobo_cmd_import_epiphany (BonoboUIComponent *uic, GbEditor *e,
				      const gchar *verbname)
{
	gb_editor_cmd_import_epiphany (e);
}

void
gb_editor_cmd_import_epiphany (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	GbImportDruid *d = GB_IMPORT_DRUID (gb_import_druid_epiphany_new ());
	gb_import_druid_set_dest_bookmark_set (d, p->set);
	gb_import_druid_show (d);
}

static void
gb_editor_bonobo_cmd_sort_one_level (BonoboUIComponent *uic, GbEditor *e,
				     const gchar *verbname)
{
	gb_editor_cmd_sort (e, FALSE, FALSE);
}

static void
gb_editor_bonobo_cmd_sort_recursively (BonoboUIComponent *uic, GbEditor *e,
				       const gchar *verbname)
{
	gb_editor_cmd_sort (e, FALSE, TRUE);
}

static void
gb_editor_bonobo_cmd_sort_one_level_folders_first (BonoboUIComponent *uic, GbEditor *e,
						   const gchar *verbname)
{
	gb_editor_cmd_sort (e, TRUE, FALSE);
}

static void
gb_editor_bonobo_cmd_sort_recursively_folders_first (BonoboUIComponent *uic, GbEditor *e,
						     const gchar *verbname)
{
	gb_editor_cmd_sort (e, TRUE, TRUE);
}

void
gb_editor_cmd_sort (GbEditor *e, gboolean folders_first, 
		    gboolean recursive)
{
	GSList *sel = gb_editor_get_selected_current_or_left_pane_prepared (e);
	GSList *seli;
	for (seli = sel; seli; seli = seli->next)
	{
		GbFolder *f;
		g_assert (GB_IS_BOOKMARK (seli->data));
		f = GB_IS_FOLDER (seli->data) ? seli->data : GB_BOOKMARK (seli->data)->parent;
		if (f) 
		{
			gb_folder_sort (f, folders_first, recursive);
		}
	}
	g_slist_free (sel);
}

static void
gb_editor_bonobo_cmd_edit_goto (BonoboUIComponent *uic, GbEditor *e,
				const gchar *verbname)
{
	gb_editor_cmd_edit_goto (e);
}

void
gb_editor_cmd_edit_goto (GbEditor *e)
{
	const GSList *selected = gb_editor_get_selected_current_or_left_pane (e);

	if (!selected) return;

	if (!selected->next)
	{
		GbBookmark *b = selected->data;
		const gchar *url = GB_IS_SITE (b) ? GB_SITE (b)->url : NULL;
		gb_activated_activate (e, b, url, GB_BAF_DEFAULT);
	}
	else while (selected)
	{
		GbBookmark *b = selected->data;
		const gchar *url = GB_IS_SITE (b) ? GB_SITE (b)->url : NULL;
		gb_activated_activate (e, b, url, GB_BAF_NEW_TAB_OR_WINDOW);
		selected = selected->next;
	}
}

static void
gb_editor_bonobo_cmd_export_mozilla (BonoboUIComponent *uic, GbEditor *e,
				     const gchar *verbname)
{
	gb_editor_cmd_export_mozilla (e);
}

void
gb_editor_cmd_export_mozilla (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	GbExportDruid *d = GB_EXPORT_DRUID (gb_export_druid_mozilla_new ());
	gb_export_druid_set_bookmark_set (d, p->set);
	gb_export_druid_show (d);
}

static void
gb_editor_bonobo_cmd_export_netscape (BonoboUIComponent *uic, GbEditor *e,
				      const gchar *verbname)
{
	gb_editor_cmd_export_netscape (e);
}

void
gb_editor_cmd_export_netscape (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	GbExportDruid *d = GB_EXPORT_DRUID (gb_export_druid_netscape_new ());
	gb_export_druid_set_bookmark_set (d, p->set);
	gb_export_druid_show (d);
}

static void
gb_editor_bonobo_cmd_export_konqueror (BonoboUIComponent *uic, GbEditor *e,
				       const gchar *verbname)
{
	gb_editor_cmd_export_konqueror (e);
}

void
gb_editor_cmd_export_konqueror (GbEditor *e)
{
	GbEditorPrivate *p = e->priv;
	GbExportDruid *d = GB_EXPORT_DRUID (gb_export_druid_konqueror_new ());
	gb_export_druid_set_bookmark_set (d, p->set);
	gb_export_druid_show (d);
}

static void
gb_editor_bonobo_split_view_changed_cb (BonoboUIComponent *component,
					const char *path,
					Bonobo_UIComponent_EventType type,
					const char *state,
					GbEditor *e)
{
	gb_editor_bonobo_cmd_split_view (component, e, "SplitView");
}

static void
gb_editor_bonobo_cmd_split_view (BonoboUIComponent *uic, GbEditor *e,
				 const gchar *verbname)
{
	gchar *value = bonobo_ui_component_get_prop (uic, SPLIT_VIEW_PATH, "state", NULL);
	gb_editor_cmd_split_view (e, atoi (value));
	g_free (value);
}

void
gb_editor_cmd_split_view (GbEditor *e, gboolean split)
{
	gb_editor_set_show_right_tree_view (e, split);

	eel_gconf_set_boolean (CONF_BOOKMARKS_EDITOR_SPLIT_VIEW, split);
}

static void
gb_editor_bonobo_edit_pane_changed_cb (BonoboUIComponent *component,
				       const char *path,
				       Bonobo_UIComponent_EventType type,
				       const char *state,
				       GbEditor *e)
{
	gb_editor_bonobo_cmd_edit_pane (component, e, "EditPane");
}

static void
gb_editor_bonobo_cmd_edit_pane (BonoboUIComponent *uic, GbEditor *e,
				const gchar *verbname)
{
	gchar *value = bonobo_ui_component_get_prop (uic, EDIT_PANE_PATH, "state", NULL);
	gb_editor_cmd_edit_pane (e, atoi (value));
	g_free (value);

}

void
gb_editor_cmd_edit_pane (GbEditor *e, gboolean pane)
{
	gb_editor_set_show_edit_pane (e, pane);

	eel_gconf_set_boolean (CONF_BOOKMARKS_EDITOR_EDIT_PANE, pane);
}


/* searching */

static gboolean
gb_editor_filter_search_in_text (const gchar *text, GbEditorPrivate *p)
{
	const gchar *whole = p->search_match_case ? p->search_text : p->search_casefold_text;
	gchar **words = p->search_match_case ? p->search_text_split : p->search_casefold_text_split;
	gchar *str = p->search_match_case ? (gchar *) text : g_utf8_casefold (text, -1);
	int i;
	gboolean ret = FALSE;
	
	switch (p->search_match_type)
	{
	case MATCH_TYPE_AND:
		ret = TRUE;
		for (i = 0; words[i]; ++i)
		{
			ret = ret && strstr (str, words[i]);
		}
		break;
	case MATCH_TYPE_OR:
		ret = FALSE;
		for (i = 0; words[i]; ++i)
		{
			ret = ret || strstr (str, words[i]);
		}
		break;
	case MATCH_TYPE_EXACT:
		ret = strstr (str, whole) != NULL;
		break;
	}

	if (!p->search_match_case) 
	{
		g_free (str);
	}
	return ret;
}

static gboolean
gb_editor_filter_func (GbBookmark *b, GbEditorPrivate *p)
{
#define gb_editor_filter_func_search(x) \
	if (gb_editor_filter_search_in_text ((x), p)) \
	{ \
		return TRUE; \
	} \

	if (!p->search_include_folders && GB_IS_FOLDER (b))
	{
		return FALSE;
	}
	else if (GB_IS_SITE (b))
	{
		if (!p->search_include_sites)
		{
			return FALSE;
		}
		else if (p->search_look_in_location)
		{
			gb_editor_filter_func_search (GB_SITE (b)->url);

			if (GB_IS_SMART_SITE (b))
			{
				gb_editor_filter_func_search (GB_SMART_SITE (b)->smarturl);
			}
		}
	}


	if (p->search_look_in_name)
	{
		gb_editor_filter_func_search (b->name);
	}

	if (p->search_look_in_notes && b->notes[0])
	{
		gb_editor_filter_func_search (b->notes);
	}

#undef gb_editor_filter_func_search

	return FALSE;
}

static gint 
gb_editor_sort_bookmark_by_name (gconstpointer a, gconstpointer b)
{
	const GbBookmark *ba = a;
	const GbBookmark *bb = b;
	return g_utf8_collate (ba->name, bb->name);
}

static void
gb_editor_search_do (GbEditor *f)
{
	GbEditorPrivate *p = f->priv;
	const GSList *l = gb_bookmark_set_get_all_noalias (p->set);
	GSList *filtered;
	GbTreeModel *tm;
	GbTreeView *tv = p->show_right_tree_view ? p->right_tree_view : p->left_tree_view;
	
	g_slist_foreach (p->old_left_selection, (GFunc) g_object_unref, NULL);
	g_slist_free (p->old_left_selection);
	p->old_left_selection = g_slist_copy ((GSList *) gb_tree_view_get_selected_list (p->left_tree_view));
	g_slist_foreach (p->old_left_selection, (GFunc) g_object_ref, NULL);

	gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (p->left_tree_view)));
	gb_tree_view_set_autoexpand_roots (p->left_tree_view, FALSE);

	filtered = gul_slist_filter (l, (GulFilterFunc) gb_editor_filter_func, p);
	filtered = g_slist_sort (filtered, gb_editor_sort_bookmark_by_name);

	if (filtered)
	{
		tm = gb_tree_model_new (filtered);
		gb_tree_view_set_model (tv, tm);
		g_object_unref (tm);
		g_slist_free (filtered);
	}
	else
	{
		gb_tree_view_set_model (tv, NULL);
	}
}

static gboolean
gb_editor_search_timeout_cb (gpointer data)
{
	GbEditor *f = data;
	GbEditorPrivate *p = f->priv;
	LOG ("gb_editor_search_timeout_cb");

	p->search_timeout = 0;

	if (p->search_text[0] == '\0')
	{
		gb_editor_search_finish (f);
	}
	else
	{
		gb_editor_search_do (f);
	}

	return FALSE;
}

static void
gb_editor_search_start_timeout (GbEditor *f)
{
	GbEditorPrivate *p = f->priv;

	if (p->search_timeout)
	{
		g_source_remove (p->search_timeout);
	}
	
	p->search_timeout = g_timeout_add (SEARCH_TIMEOUT, 
					   gb_editor_search_timeout_cb, f);
}

static void
gb_editor_search_stop_timeout (GbEditor *f)
{
	GbEditorPrivate *p = f->priv;

	if (p->search_timeout)
	{
		g_source_remove (p->search_timeout);
	}
	
	p->search_timeout = 0;
}

