summary refs log blame commit diff stats
path: root/src/fe-gtk/editlist.c
blob: f7e22d52b61e2d439b120a294edddcaf2a0b6255 (plain) (tree)
4a6ceffb pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/* X-Chat
 * Copyright (C) 1998 Peter Zelezny.
 *
 * 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.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "fe-gtk.h"

#include "../common/hexchat.h"
#include "../common/ignore.h"
#include "../common/cfgfiles.h"
#include "../common/fe.h"
#include "gtkutil.h"
#include "maingui.h"

enum
{
	MASK_COLUMN,
	CHAN_COLUMN,
	PRIV_COLUMN,
	NOTICE_COLUMN,
	CTCP_COLUMN,
	DCC_COLUMN,
	INVITE_COLUMN,
	UNIGNORE_COLUMN,
	N_COLUMNS
};

static GtkWidget *ignorewin = 0;

static GtkWidget *num_ctcp;
static GtkWidget *num_priv;
static GtkWidget *num_chan;
static GtkWidget *num_noti;
static GtkWidget *num_invi;

static GtkTreeModel *
get_store (void)
{
	return gtk_tree_view_get_model (g_object_get_data (G_OBJECT (ignorewin), "view"));
}

static int
ignore_get_flags (GtkTreeModel *model, GtkTreeIter *iter)
{
	gboolean chan, priv, noti, ctcp, dcc, invi, unig;
	int flags = 0;

	gtk_tree_model_get (model, iter, 1, &chan, 2, &priv, 3, &noti,
	                    4, &ctcp, 5, &dcc, 6, &invi, 7, &unig, -1);
	if (chan)
		flags |= IG_CHAN;
	if (priv)
		flags |= IG_PRIV;
	if (noti)
		flags |= IG_NOTI;
	if (ctcp)
		flags |= IG_CTCP;
	if (dcc)
		flags |= IG_DCC;
	if (invi)
		flags |= IG_INVI;
	if (unig)
		flags |= IG_UNIG;
	return flags;
}

static void
mask_edited (GtkCellRendererText *render, gchar *path, gchar *new, gpointer dat)
{
	GtkListStore *store = GTK_LIST_STORE (get_store ());
	GtkTreeIter iter;
	char *old;
	int flags;

	gtkutil_treemodel_string_to_iter (GTK_TREE_MODEL (store), path, &iter);
	gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, 0, &old, -1);
	
	if (!strcmp (old, new))	/* no change */
		;
	else if (ignore_exists (new))	/* duplicate, ignore */
		fe_message (_("That mask already exists."), FE_MSG_ERROR);
	else
	{
		/* delete old mask, and add new one with original flags */
		ignore_del (old, NULL);
		flags = ignore_get_flags (GTK_TREE_MODEL (store), &iter);
		ignore_add (new, flags, TRUE);

		/* update tree */
		gtk_list_store_set (store, &iter, MASK_COLUMN, new, -1);
	}
	g_free (old);
	
}

static void
option_toggled (GtkCellRendererToggle *render, gchar *path, gpointer data)
{
	GtkListStore *store = GTK_LIST_STORE (get_store ());
	GtkTreeIter iter;
	int col_id = GPOINTER_TO_INT (data);
	gboolean active;
	char *mask;
	int flags;

	gtkutil_treemodel_string_to_iter (GTK_TREE_MODEL (store), path, &iter);

	/* update model */
	gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, col_id, &active, -1);
	gtk_list_store_set (store, &iter, col_id, !active, -1);

	/* update ignore list */
	gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, 0, &mask, -1);
	flags = ignore_get_flags (GTK_TREE_MODEL (store), &iter);
	if (ignore_add (mask, flags, TRUE) != 2)
		g_warning ("ignore treeview is out of sync!\n");
	
	g_free (mask);
}

static GtkWidget *
ignore_treeview_new (GtkWidget *box)
{
	GtkListStore *store;
	GtkWidget *view;
	GtkTreeViewColumn *col;
	GtkCellRenderer *render;
	int col_id;

	store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING,
	                            G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
	                            G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
	                            G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
	                            G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
	g_return_val_if_fail (store != NULL, NULL);

	view = gtkutil_treeview_new (box, GTK_TREE_MODEL (store),
	                             NULL,
	                             MASK_COLUMN, _("Mask"),
	                             CHAN_COLUMN, _("Channel"),
	                             PRIV_COLUMN, _("Private"),
	                             NOTICE_COLUMN, _("Notice"),
	                             CTCP_COLUMN, _("CTCP"),
	                             DCC_COLUMN, _("DCC"),
	                             INVITE_COLUMN, _("Invite"),
	                             UNIGNORE_COLUMN, _("Unignore"),
	                             -1);

	gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE);
	gtk_tree_view_column_set_expand (gtk_tree_view_get_column (GTK_TREE_VIEW (view), 0), TRUE);

	/* attach to signals and customise columns */
	for (col_id=0; (col = gtk_tree_view_get_column (GTK_TREE_VIEW (view), col_id));
	     col_id++)
	{
		GList *list = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (col));
		GList *tmp;

		for (tmp = list; tmp; tmp = tmp->next)
		{
			render = tmp->data;
			if (col_id > 0)	/* it's a toggle button column */
			{
				g_signal_connect (render, "toggled", G_CALLBACK (option_toggled),
				                  GINT_TO_POINTER (col_id));
			} else	/* mask column */
			{
				g_object_set (G_OBJECT (render), "editable", TRUE, NULL);
				g_signal_connect (render, "edited", G_CALLBACK (mask_edited), NULL);
				/* make this column sortable */
				gtk_tree_view_column_set_sort_column_id (col, col_id);
				gtk_tree_view_column_set_min_width (col, 272);
			}
			/* centre titles */
			gtk_tree_view_column_set_alignment (col, 0.5);
		}

		g_list_free (list);
	}
	
	gtk_widget_show (view);
	return view;
}

static void
ignore_delete_entry_clicked (GtkWidget * wid, struct session *sess)
{
	GtkTreeView *view = g_object_get_data (G_OBJECT (ignorewin), "view");
	GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
	GtkTreeIter iter;
	GtkTreePath *path;
	char *mask = NULL;

	if (gtkutil_treeview_get_selected (view, &iter, 0, &mask, -1))
	{
		/* delete this row, select next one */
		if (gtk_list_store_remove (store, &iter))
		{
			path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
			gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 1.0, 0.0);
			gtk_tree_view_set_cursor (view, path, NULL, FALSE);
			gtk_tree_path_free (path);
		}

		ignore_del (mask, NULL);
		g_free (mask);
	}
}

static void
ignore_store_new (int cancel, char *mask, gpointer data)
{
	GtkTreeView *view = g_object_get_data (G_OBJECT (ignorewin), "view");
	GtkListStore *store = GTK_LIST_STORE (get_store ());
	GtkTreeIter iter;
	GtkTreePath *path;
	int flags = IG_CHAN | IG_PRIV | IG_NOTI | IG_CTCP | IG_DCC | IG_INVI;

	if (cancel)
		return;
	/* check if it already exists */
	if (ignore_exists (mask))
	{
		fe_message (_("That mask already exists."), FE_MSG_ERROR);
		return;
	}

	ignore_add (mask, flags, TRUE);

	gtk_list_store_append (store, &iter);
	/* ignore everything by default */
	gtk_list_store_set (store, &iter, 0, mask, 1, TRUE, 2, TRUE, 3, TRUE,
	                    4, TRUE, 5, TRUE, 6, TRUE, 7, FALSE, -1);
	/* make sure the new row is visible and selected */
	path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
	gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 1.0, 0.0);
	gtk_tree_view_set_cursor (view, path, NULL, FALSE);
	gtk_tree_path_free (path);
}

static void
ignore_clear_cb (GtkDialog *dialog, gint response)
{
	GtkListStore *store = GTK_LIST_STORE (get_store ());
	GtkTreeIter iter;
	char *mask;

	gtk_widget_destroy (GTK_WIDGET (dialog));

	if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter) && response == GTK_RESPONSE_OK)
	{
		/* remove from ignore_list */
		do
		{
			mask = NULL;
			gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, MASK_COLUMN, &mask, -1);
			ignore_del (mask, NULL);
			g_free (mask);
		}
		while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));

		/* remove from GUI */
		gtk_list_store_clear (store);
	}
}

static void
ignore_clear_entry_clicked (GtkWidget * wid)
{
	GtkWidget *dialog;

	dialog = gtk_message_dialog_new (NULL, 0,
								GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL,
					_("Are you sure you want to remove all ignores?"));
	g_signal_connect (G_OBJECT (dialog), "response",
							G_CALLBACK (ignore_clear_cb), NULL);
	gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
	gtk_widget_show (dialog);
}

static void
ignore_new_entry_clicked (GtkWidget * wid, struct session *sess)
{
	fe_get_str (_("Enter mask to ignore:"), "nick!userid@host.com",
	            ignore_store_new, NULL);

}

static void
close_ignore_gui_callback ()
{
	ignore_save ();
	ignorewin = 0;
}

static GtkWidget *
ignore_stats_entry (GtkWidget * box, char *label, int value)
{
	GtkWidget *wid;
	char buf[16];

	sprintf (buf, "%d", value);
	gtkutil_label_new (label, box);
	wid = gtkutil_entry_new (16, box, 0, 0);
	gtk_widget_set_size_request (wid, 30, -1);
	gtk_editable_set_editable (GTK_EDITABLE (wid), FALSE);
	gtk_widget_set_sensitive (GTK_WIDGET (wid), FALSE);
	gtk_entry_set_text (GTK_ENTRY (wid), buf);

	return wid;
}

void
ignore_gui_open ()
{
	GtkWidget *vbox, *box, *stat_box, *frame;
	GtkWidget *view;
	GtkListStore *store;
	GtkTreeIter iter;
	GSList *temp = ignore_list;
	char *mask;
	gboolean private, chan, notice, ctcp, dcc, invite, unignore;

	if (ignorewin)
	{
		mg_bring_tofront (ignorewin);
		return;
	}

	ignorewin =
			  mg_create_generic_tab ("IgnoreList", _(DISPLAY_NAME": Ignore list"),
											FALSE, TRUE, close_ignore_gui_callback,
											NULL, pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/* X-Chat
 * Copyright (C) 1998 Peter Zelezny.
 *
 * 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.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <gdk/gdkkeysyms.h>

#ifdef WIN32
#include <io.h>
#else
#include <unistd.h>
#endif

#include "fe-gtk.h"

#include "../common/hexchat.h"
#include "../common/cfgfiles.h"
#include "../common/hexchatc.h"
#include "../common/fe.h"
#include "menu.h"
#include "gtkutil.h"
#include "maingui.h"
#include "editlist.h"

enum
{
	NAME_COLUMN,
	CMD_COLUMN,
	N_COLUMNS
};

static GtkWidget *editlist_win = NULL;
static GSList *editlist_list = NULL;

static GtkTreeModel *
get_store (void)
{
	return gtk_tree_view_get_model (g_object_get_data (G_OBJECT (editlist_win), "view"));
}

static void
editlist_save (GtkWidget *igad, gchar *file)
{
	GtkTreeModel *store = get_store ();
	GtkTreeIter iter;
	char buf[512];
	char *name, *cmd;
	int fh;

	fh = hexchat_open_file (file, O_TRUNC | O_WRONLY | O_CREAT, 0600, XOF_DOMODE);
	if (fh != -1)
	{
		if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
		{
			do
			{
				name = NULL;
				cmd = NULL;
				gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, NAME_COLUMN, &name, CMD_COLUMN, &cmd, -1);
				g_snprintf (buf, sizeof (buf), "NAME %s\nCMD %s\n\n", name, cmd);
				write (fh, buf, strlen (buf));
				g_free (name);
				g_free (cmd);
			} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
		}

		close (fh);
		gtk_widget_destroy (editlist_win);
		if (editlist_list == replace_list)
		{
			list_free (&replace_list);
			list_loadconf (file, &replace_list, 0);
		} else if (editlist_list == popup_list)
		{
			list_free (&popup_list);
			list_loadconf (file, &popup_list, 0);
		} else if (editlist_list == button_list)
		{
			GSList *list = sess_list;
			struct session *sess;
			list_free (&button_list);
			list_loadconf (file, &button_list, 0);
			while (list)
			{
				sess = (struct session *) list
pan> = list->next; } } else if (editlist_list == dlgbutton_list) { GSList *list = sess_list; struct session *sess; list_free (&dlgbutton_list); list_loadconf (file, &dlgbutton_list, 0); while (list) { sess = (struct session *) list->data; fe_dlgbuttons_update (sess); list = list->next; } } else if (editlist_list == ctcp_list) { list_free (&ctcp_list); list_loadconf (file, &ctcp_list, 0); } else if (editlist_list == command_list) { list_free (&command_list); list_loadconf (file, &command_list, 0); } else if (editlist_list == usermenu_list) { list_free (&usermenu_list); list_loadconf (file, &usermenu_list, 0); usermenu_update (); } else { list_free (&urlhandler_list); list_loadconf (file, &urlhandler_list, 0); } } } static void editlist_load (GtkListStore *store, GSList *list) { struct popup *pop; gchar *name, *cmd; GtkTreeIter iter; while (list) { pop = (struct popup *) list->data; name = pop->name; cmd = pop->cmd; gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, NAME_COLUMN, name, CMD_COLUMN, cmd, -1); list = list->next; } } static void editlist_delete (GtkWidget *wid, gpointer userdata) { GtkTreeView *view = g_object_get_data (G_OBJECT (editlist_win), "view"); GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (view)); GtkTreeIter iter; GtkTreePath *path; if (gtkutil_treeview_get_selected (view, &iter, -1)) { /* delete this row, select next one */ if (gtk_list_store_remove (store, &iter)) { path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter); gtk_tree_view_scroll_to_cell (view, path, NULL, TRUE, 1.0, 0.0); gtk_tree_view_set_cursor (view, path, NULL, FALSE); gtk_tree_path_free (path); } } } static void editlist_add (GtkWidget *wid, gpointer userdata) { GtkTreeView *view = g_object_get_data (G_OBJECT (editlist_win), "view"); GtkTreeViewColumn *col; GtkListStore *store = GTK_LIST_STORE (get_store ()); GtkTreeIter iter; GtkTreePath *path; gtk_list_store_append (store, &iter); /* make sure the new row is visible and selected */ path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter); col = gtk_tree_view_get_column (view, NAME_COLUMN); gtk_tree_view_scroll_to_cell (view, path, NULL, FALSE, 0.0, 0.0); gtk_tree_view_set_cursor (view, path, col, TRUE); gtk_tree_path_free (path); } static void editlist_close (GtkWidget *wid, gpointer userdata) { gtk_widget_destroy (editlist_win); editlist_win = NULL; } static void editlist_edited (GtkCellRendererText *render, gchar *pathstr, gchar *new_text, gpointer data) { GtkTreeModel *model = get_store (); GtkTreePath *path = gtk_tree_path_new_from_string (pathstr); GtkTreeIter iter; gint column = GPOINTER_TO_INT (data); gtk_tree_model_get_iter (model, &iter, path); gtk_list_store_set (GTK_LIST_STORE (model), &iter, column, new_text, -1); gtk_tree_path_free (path); } static gboolean editlist_keypress (GtkWidget *wid, GdkEventKey *evt, gpointer userdata) { GtkTreeView *view = g_object_get_data (G_OBJECT (editlist_win), "view"); GtkTreeModel *store; GtkTreeIter iter1, iter2; GtkTreeSelection *sel; GtkTreePath *path; gboolean handled = FALSE; int delta; if (evt->state & GDK_SHIFT_MASK) { if (evt->keyval == GDK_KEY_Up) { handled = TRUE; delta = -1; } else if (evt->keyval == GDK_KEY_Down) { handled = TRUE; delta = 1; } } if (handled) { sel = gtk_tree_view_get_selection (view); gtk_tree_selection_get_selected (sel, &store, &iter1); path = gtk_tree_model_get_path (store, &iter1); if (delta == 1) gtk_tree_path_next (path); else gtk_tree_path_prev (path); gtk_tree_model_get_iter (store, &iter2, path); gtk_tree_path_free (path); gtk_list_store_swap (GTK_LIST_STORE (store), &iter1, &iter2); } return handled; } static GtkWidget * editlist_treeview_new (GtkWidget *box, char *title1, char *title2) { GtkWidget *scroll; GtkListStore *store; GtkTreeViewColumn *col; GtkWidget *view; GtkCellRenderer *render; scroll = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN); store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING); g_return_val_if_fail (store != NULL, NULL); view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (view), TRUE); gtk_tree_view_set_enable_search (GTK_TREE_VIEW (view), FALSE); g_signal_connect (G_OBJECT (view), "key_press_event", G_CALLBACK (editlist_keypress), NULL); gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (view), TRUE); render = gtk_cell_renderer_text_new (); g_object_set (render, "editable", TRUE, NULL); g_signal_connect (G_OBJECT (render), "edited", G_CALLBACK (editlist_edited), GINT_TO_POINTER(NAME_COLUMN)); gtk_tree_view_insert_column_with_attributes ( GTK_TREE_VIEW (view), NAME_COLUMN, title1, render, "text", NAME_COLUMN, NULL); render = gtk_cell_renderer_text_new (); g_object_set (render, "editable", TRUE, NULL); g_signal_connect (G_OBJECT (render), "edited", G_CALLBACK (editlist_edited), GINT_TO_POINTER(CMD_COLUMN)); gtk_tree_view_insert_column_with_attributes ( GTK_TREE_VIEW (view), CMD_COLUMN, title2, render, "text", CMD_COLUMN, NULL); col = gtk_tree_view_get_column (GTK_TREE_VIEW (view), NAME_COLUMN); gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_AUTOSIZE); gtk_tree_view_column_set_resizable (col, TRUE); gtk_tree_view_column_set_min_width (col, 100); col = gtk_tree_view_get_column (GTK_TREE_VIEW (view), CMD_COLUMN); gtk_container_add (GTK_CONTAINER (scroll), view); gtk_container_add (GTK_CONTAINER (box), scroll); gtk_widget_show_all (box); return view; } void editlist_gui_open (char *title1, char *title2, GSList *list, char *title, char *wmclass, char *file, char *help) { GtkWidget *vbox, *box; GtkWidget *view; GtkListStore *store; if (editlist_win) { mg_bring_tofront (editlist_win); return; } editlist_win = mg_create_generic_tab (wmclass, title, TRUE, FALSE, editlist_close, NULL, 450, 250, &vbox, 0); editlist_list = list; view = editlist_treeview_new (vbox, title1, title2); g_object_set_data (G_OBJECT (editlist_win), "view", view); if (help) gtk_widget_set_tooltip_text (view, help); box = gtk_hbutton_box_new (); gtk_button_box_set_layout (GTK_BUTTON_BOX (box), GTK_BUTTONBOX_SPREAD); gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 2); gtk_container_set_border_width (GTK_CONTAINER (box), 5); gtk_widget_show (box); gtkutil_button (box, GTK_STOCK_NEW, 0, editlist_add, NULL, _("Add")); gtkutil_button (box, GTK_STOCK_DELETE, 0, editlist_delete, NULL, _("Delete")); gtkutil_button (box, GTK_STOCK_CANCEL, 0, editlist_close, NULL, _("Cancel")); gtkutil_button (box, GTK_STOCK_SAVE, 0, editlist_save, file, _("Save")); store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view))); editlist_load (store, list); gtk_widget_show (editlist_win); }