/*
* gedit-encodings-combo-box.c
* This file is part of gedit
*
* Copyright (C) 2003-2005 - Paolo Maggi
*
* 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, see .
*/
#include "gedit-encodings-combo-box.h"
#include
#include "gedit-encoding-items.h"
#include "gedit-encodings-dialog.h"
struct _GeditEncodingsComboBox
{
GtkComboBox parent_instance;
GtkListStore *store;
glong changed_id;
guint activated_item;
guint save_mode : 1;
};
enum
{
COLUMN_NAME,
COLUMN_ENCODING,
COLUMN_CONFIGURE_ROW, /* TRUE for the "Add or Remove..." row. */
N_COLUMNS
};
enum
{
PROP_0,
PROP_SAVE_MODE,
LAST_PROP
};
static GParamSpec *properties[LAST_PROP];
G_DEFINE_TYPE (GeditEncodingsComboBox, gedit_encodings_combo_box, GTK_TYPE_COMBO_BOX)
static void update_menu (GeditEncodingsComboBox *combo_box);
static void
gedit_encodings_combo_box_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GeditEncodingsComboBox *combo;
combo = GEDIT_ENCODINGS_COMBO_BOX (object);
switch (prop_id)
{
case PROP_SAVE_MODE:
combo->save_mode = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gedit_encodings_combo_box_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GeditEncodingsComboBox *combo;
combo = GEDIT_ENCODINGS_COMBO_BOX (object);
switch (prop_id)
{
case PROP_SAVE_MODE:
g_value_set_boolean (value, combo->save_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gedit_encodings_combo_box_dispose (GObject *object)
{
GeditEncodingsComboBox *combo = GEDIT_ENCODINGS_COMBO_BOX (object);
g_clear_object (&combo->store);
G_OBJECT_CLASS (gedit_encodings_combo_box_parent_class)->dispose (object);
}
static void
gedit_encodings_combo_box_constructed (GObject *object)
{
GeditEncodingsComboBox *combo = GEDIT_ENCODINGS_COMBO_BOX (object);
GtkCellRenderer *text_renderer;
G_OBJECT_CLASS (gedit_encodings_combo_box_parent_class)->constructed (object);
/* Setup up the cells */
text_renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (combo),
text_renderer, TRUE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo),
text_renderer,
"text",
COLUMN_NAME,
NULL);
update_menu (combo);
}
static void
gedit_encodings_combo_box_class_init (GeditEncodingsComboBoxClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = gedit_encodings_combo_box_set_property;
object_class->get_property = gedit_encodings_combo_box_get_property;
object_class->dispose = gedit_encodings_combo_box_dispose;
object_class->constructed = gedit_encodings_combo_box_constructed;
/**
* GeditEncodingsComboBox:save-mode:
*
* Whether the combo box should be used for saving a content. If
* %FALSE, the combo box is used for loading a content (e.g. a file)
* and the row "Automatically Detected" is added.
*/
/* TODO It'd be clearer if "save-mode" is renamed as "mode" with an
* enum: loading, saving. Or something like that.
*/
properties[PROP_SAVE_MODE] =
g_param_spec_boolean ("save-mode",
"Save Mode",
"Save Mode",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, LAST_PROP, properties);
}
static void
dialog_response_cb (GtkDialog *dialog,
gint response_id,
GeditEncodingsComboBox *menu)
{
update_menu (menu);
gtk_widget_destroy (GTK_WIDGET (dialog));
}
static void
configure_encodings (GeditEncodingsComboBox *menu)
{
GtkWidget *dialog;
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (menu));
if (!gtk_widget_is_toplevel (toplevel))
{
toplevel = NULL;
}
g_signal_handler_block (menu, menu->changed_id);
gtk_combo_box_set_active (GTK_COMBO_BOX (menu),
menu->activated_item);
g_signal_handler_unblock (menu, menu->changed_id);
dialog = gedit_encodings_dialog_new ();
if (toplevel != NULL)
{
GtkWindowGroup *wg;
gtk_window_set_transient_for (GTK_WINDOW (dialog),
GTK_WINDOW (toplevel));
if (gtk_window_has_group (GTK_WINDOW (toplevel)))
{
wg = gtk_window_get_group (GTK_WINDOW (toplevel));
}
else
{
wg = gtk_window_group_new ();
gtk_window_group_add_window (wg, GTK_WINDOW (toplevel));
}
gtk_window_group_add_window (wg, GTK_WINDOW (dialog));
}
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
g_signal_connect_after (dialog,
"response",
G_CALLBACK (dialog_response_cb),
menu);
gtk_widget_show (dialog);
}
static void
changed_cb (GeditEncodingsComboBox *menu,
GtkTreeModel *model)
{
GtkTreeIter iter;
gboolean configure = FALSE;
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (menu), &iter))
{
gtk_tree_model_get (model, &iter,
COLUMN_CONFIGURE_ROW, &configure,
-1);
}
if (configure)
{
configure_encodings (menu);
}
else
{
menu->activated_item = gtk_combo_box_get_active (GTK_COMBO_BOX (menu));
}
}
static gboolean
separator_func (GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
gchar *str;
gboolean ret;
gtk_tree_model_get (model, iter, COLUMN_NAME, &str, -1);
ret = (str == NULL || str[0] == '\0');
g_free (str);
return ret;
}
static void
add_separator (GtkListStore *store)
{
GtkTreeIter iter;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COLUMN_NAME, "",
COLUMN_ENCODING, NULL,
COLUMN_CONFIGURE_ROW, FALSE,
-1);
}
static void
update_menu (GeditEncodingsComboBox *menu)
{
GtkListStore *store;
GtkTreeIter iter;
GSList *encodings;
store = menu->store;
/* Unset the previous model */
g_signal_handler_block (menu, menu->changed_id);
gtk_list_store_clear (store);
gtk_combo_box_set_model (GTK_COMBO_BOX (menu), NULL);
if (!menu->save_mode)
{
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COLUMN_NAME, _("Automatically Detected"),
COLUMN_ENCODING, NULL,
COLUMN_CONFIGURE_ROW, FALSE,
-1);
add_separator (store);
}
encodings = gedit_encoding_items_get ();
while (encodings)
{
GeditEncodingItem *item = encodings->data;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COLUMN_NAME, gedit_encoding_item_get_name (item),
COLUMN_ENCODING, gedit_encoding_item_get_encoding (item),
COLUMN_CONFIGURE_ROW, FALSE,
-1);
gedit_encoding_item_free (item);
encodings = g_slist_delete_link (encodings, encodings);
}
add_separator (store);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COLUMN_NAME, _("Add or Remove…"),
COLUMN_ENCODING, NULL,
COLUMN_CONFIGURE_ROW, TRUE,
-1);
/* set the model back */
gtk_combo_box_set_model (GTK_COMBO_BOX (menu),
GTK_TREE_MODEL (menu->store));
gtk_combo_box_set_active (GTK_COMBO_BOX (menu), 0);
g_signal_handler_unblock (menu, menu->changed_id);
}
static void
gedit_encodings_combo_box_init (GeditEncodingsComboBox *menu)
{
menu->store = gtk_list_store_new (N_COLUMNS,
G_TYPE_STRING,
G_TYPE_POINTER,
G_TYPE_BOOLEAN);
gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (menu),
separator_func, NULL,
NULL);
menu->changed_id = g_signal_connect (menu,
"changed",
G_CALLBACK (changed_cb),
menu->store);
}
/**
* gedit_encodings_combo_box_new:
* @save_mode: whether the combo box is used for saving a content.
*
* Creates a new encodings combo box object. If @save_mode is %FALSE, it means
* that the combo box is used for loading a content (e.g. a file), so the row
* "Automatically Detected" is added. For saving a content, the encoding must be
* provided.
*
* Returns: a new #GeditEncodingsComboBox object.
*/
GtkWidget *
gedit_encodings_combo_box_new (gboolean save_mode)
{
return g_object_new (GEDIT_TYPE_ENCODINGS_COMBO_BOX,
"save_mode", save_mode,
NULL);
}
/**
* gedit_encodings_combo_box_get_selected_encoding:
* @menu: a #GeditEncodingsComboBox.
*
* Returns: the selected #GtkSourceEncoding, or %NULL if the encoding should be
* auto-detected (only for loading mode, not for saving).
*/
const GtkSourceEncoding *
gedit_encodings_combo_box_get_selected_encoding (GeditEncodingsComboBox *menu)
{
GtkTreeIter iter;
g_return_val_if_fail (GEDIT_IS_ENCODINGS_COMBO_BOX (menu), NULL);
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (menu), &iter))
{
const GtkSourceEncoding *ret;
GtkTreeModel *model;
model = gtk_combo_box_get_model (GTK_COMBO_BOX (menu));
gtk_tree_model_get (model, &iter,
COLUMN_ENCODING, &ret,
-1);
return ret;
}
return NULL;
}
/**
* gedit_encodings_combo_box_set_selected_encoding:
* @menu: a #GeditEncodingsComboBox.
* @encoding: the #GtkSourceEncoding.
*
* Sets the selected encoding.
*/
void
gedit_encodings_combo_box_set_selected_encoding (GeditEncodingsComboBox *menu,
const GtkSourceEncoding *encoding)
{
GtkTreeIter iter;
GtkTreeModel *model;
gboolean b;
g_return_if_fail (GEDIT_IS_ENCODINGS_COMBO_BOX (menu));
model = gtk_combo_box_get_model (GTK_COMBO_BOX (menu));
b = gtk_tree_model_get_iter_first (model, &iter);
while (b)
{
const GtkSourceEncoding *enc;
gtk_tree_model_get (model, &iter,
COLUMN_ENCODING, &enc,
-1);
if (enc == encoding)
{
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (menu), &iter);
return;
}
b = gtk_tree_model_iter_next (model, &iter);
}
}
/* ex:set ts=8 noet: */