static void
action_set_func (GtkTreeViewColumn *tree_column,
		 GtkCellRenderer   *cell,
		 GtkTreeModel      *model,
		 GtkTreeIter       *iter,
		 gpointer           data)
{
	CsdWacomTabletButton *button;
	CsdWacomActionType type;

	gtk_tree_model_get (model, iter, MAPPING_BUTTON_COLUMN, &button, -1);

	if (button == NULL) {
		g_object_set (cell, "visible", FALSE, NULL);
		return;
	}

	if (button->type == WACOM_TABLET_BUTTON_TYPE_HARDCODED) {
		g_object_set (cell,
			      "visible", TRUE,
			      "editable", FALSE,
			      "style", PANGO_STYLE_NORMAL,
			      "text", _("Switch Modes"),
			      NULL);
		return;
	}

	if (button->type == WACOM_TABLET_BUTTON_TYPE_STRIP ||
	    button->type == WACOM_TABLET_BUTTON_TYPE_RING) {
		g_object_set (cell,
			      "visible", TRUE,
			      "editable", FALSE,
			      "style", PANGO_STYLE_NORMAL,
			      "text", WACOM_C(action_table[CSD_WACOM_ACTION_TYPE_CUSTOM].action_name),
			      NULL);
		return;
	}

	if (button->settings == NULL) {
		g_warning ("Button '%s' does not have an associated GSettings", button->id);
		return;
	}

	type = g_settings_get_enum (button->settings, ACTION_TYPE_KEY);
	if (action_type_is_valid (type) == FALSE)
		type = CSD_WACOM_ACTION_TYPE_NONE;

	g_object_set (cell,
		      "visible", TRUE,
		      "editable", TRUE,
		      "style", PANGO_STYLE_NORMAL,
		      "text",  WACOM_C(action_table[type].action_name),
		      NULL);
}
static void
combo_action_cell_changed (GtkCellRendererCombo *cell,
                           const gchar          *path_string,
                           GtkTreeIter          *new_iter,
                           CcWacomPage          *page)
{
	GtkTreeView          *tree_view;
	GtkTreePath          *path;
	GtkTreeModel         *model;
	CcWacomPagePrivate   *priv;
	CsdWacomActionType    type;
	GtkTreeIter           iter;
	CsdWacomTabletButton *button;

	priv = page->priv;
	tree_view = GTK_TREE_VIEW (MWID("shortcut_treeview"));
	model = gtk_tree_view_get_model (tree_view);
	path = gtk_tree_path_new_from_string (path_string);

	gtk_tree_model_get (GTK_TREE_MODEL (priv->action_store), new_iter, ACTION_TYPE_COLUMN, &type, -1);
	gtk_tree_model_get_iter (model, &iter, path);
	gtk_list_store_set (GTK_LIST_STORE (model), &iter, MAPPING_TYPE_COLUMN, WACOM_C(action_table[type].action_name), -1);
	gtk_tree_path_free (path);

	gtk_tree_model_get (model, &iter, MAPPING_BUTTON_COLUMN, &button, -1);
	if (button == NULL)
		return;
	if (button->settings == NULL)
		return;
	g_settings_set_enum (button->settings, ACTION_TYPE_KEY, type);

	gtk_widget_grab_focus (GTK_WIDGET (tree_view));
}
static void
add_button_to_store (GtkListStore         *model,
		     CsdWacomTabletButton *button,
		     GtkDirectionType      dir,
		     CsdWacomActionType    type)
{
	GtkTreeIter new_row;
	char *dir_name;

	if (dir == GTK_DIR_UP || dir == GTK_DIR_DOWN) {
		if (button->type == WACOM_TABLET_BUTTON_TYPE_RING) {
			dir_name = g_strdup_printf ("%s (%s)",
						    button->name,
						    dir == GTK_DIR_UP ? "↺" : "↻");
		} else {
			dir_name = g_strdup_printf ("%s (%s)",
						    button->name,
						    dir == GTK_DIR_UP ? C_("Wacom tablet button", "Up") : C_("Wacom tablet button", "Down"));
		}
	} else {
		dir_name = NULL;
	}

	if (action_type_is_valid (type) == FALSE)
		type = CSD_WACOM_ACTION_TYPE_NONE;

	gtk_list_store_append (model, &new_row);
	gtk_list_store_set (model, &new_row,
			    MAPPING_DESCRIPTION_COLUMN, dir_name ? dir_name : button->name,
			    MAPPING_TYPE_COLUMN, WACOM_C(action_table[type].action_name),
			    MAPPING_BUTTON_COLUMN, button,
			    MAPPING_BUTTON_DIRECTION, dir,
			    -1);
	g_free (dir_name);
}
static GtkWidget *
create_actions_combo (GsdWacomTabletButtonType type)
{
  GtkListStore    *model;
  GtkTreeIter      iter;
  GtkWidget       *combo;
  GtkCellRenderer *renderer;
  gint             i;

  model = gtk_list_store_new (ACTION_N_COLUMNS, G_TYPE_STRING, G_TYPE_INT);

  for (i = 0; i < G_N_ELEMENTS (action_table); i++)
    {
      if ((type == WACOM_TABLET_BUTTON_TYPE_STRIP ||
           type == WACOM_TABLET_BUTTON_TYPE_RING) &&
          action_table[i].action_type != GSD_WACOM_ACTION_TYPE_NONE &&
          action_table[i].action_type != GSD_WACOM_ACTION_TYPE_CUSTOM)
        continue;

      gtk_list_store_append (model, &iter);
      gtk_list_store_set (model, &iter,
                          ACTION_NAME_COLUMN, WACOM_C(action_table[i].action_name),
                          ACTION_TYPE_COLUMN, action_table[i].action_type, -1);
    }

  combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (model));

  renderer = gtk_cell_renderer_text_new ();
  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
                                  "text", ACTION_NAME_COLUMN, NULL);


  return combo;
}
static void
setup_mapping_treeview (CcWacomPage *page)
{
	CcWacomPagePrivate *priv;
	GtkTreeView *treeview;
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkListStore *model;
	GtkTreeIter iter;
	GList *list, *l;
	gint i;

	priv = page->priv;
	treeview = GTK_TREE_VIEW(MWID ("shortcut_treeview"));

	g_signal_connect (treeview, "button_press_event",
			  G_CALLBACK (start_editing_cb), page);
	g_signal_connect (treeview, "row-activated",
			  G_CALLBACK (start_editing_kb_cb), page);

	renderer = gtk_cell_renderer_text_new ();
	g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);

	column = gtk_tree_view_column_new_with_attributes (_("Button"),
							   renderer,
							   "text", MAPPING_DESCRIPTION_COLUMN,
							   NULL);
	gtk_tree_view_column_set_resizable (column, FALSE);
	gtk_tree_view_column_set_expand (column, TRUE);

	gtk_tree_view_append_column (treeview, column);
	gtk_tree_view_column_set_sort_column_id (column, MAPPING_DESCRIPTION_COLUMN);

	priv->action_store = gtk_list_store_new (ACTION_N_COLUMNS, G_TYPE_STRING, G_TYPE_INT);
	for (i = 0; i < G_N_ELEMENTS (action_table); i++) {
		/* Screen tablets cannot switch monitors (as the monitor is the tablet) */
		if (action_table[i].action_type == CSD_WACOM_ACTION_TYPE_SWITCH_MONITOR &&
		    csd_wacom_device_is_screen_tablet (priv->stylus))
			continue;

		/* Do not list on-screen help if libwacom do no provide a layout */
		if (action_table[i].action_type == CSD_WACOM_ACTION_TYPE_HELP &&
		    csd_wacom_device_get_layout_path (priv->stylus) == NULL)
			continue;

		gtk_list_store_append (priv->action_store, &iter);
		gtk_list_store_set (priv->action_store, &iter,
		                    ACTION_NAME_COLUMN, WACOM_C(action_table[i].action_name),
		                    ACTION_TYPE_COLUMN, action_table[i].action_type, -1);
	}
	renderer = gtk_cell_renderer_combo_new ();
	g_object_set (renderer,
                      "text-column", ACTION_NAME_COLUMN,
                      "has-entry", FALSE,
                      "model", priv->action_store,
                      "editable", TRUE,
                      NULL);
	g_signal_connect (renderer, "changed",
	                  G_CALLBACK (combo_action_cell_changed), page);

	column = gtk_tree_view_column_new_with_attributes (_("Type"),
							   renderer,
							   "text", MAPPING_TYPE_COLUMN,
							   NULL);
	gtk_tree_view_column_set_cell_data_func (column, renderer, action_set_func, NULL, NULL);
	gtk_tree_view_column_set_resizable (column, FALSE);
	gtk_tree_view_column_set_expand (column, FALSE);

	gtk_tree_view_append_column (treeview, column);

	renderer = (GtkCellRenderer *) g_object_new (GTK_TYPE_CELL_RENDERER_ACCEL,
						     "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
						     NULL);

	g_signal_connect (renderer, "accel_edited",
			  G_CALLBACK (accel_edited_callback),
			  page);
	g_signal_connect (renderer, "accel_cleared",
			  G_CALLBACK (accel_cleared_callback),
			  page);

	column = gtk_tree_view_column_new_with_attributes (_("Action"), renderer, NULL);
	gtk_tree_view_column_set_cell_data_func (column, renderer, accel_set_func, NULL, NULL);
	gtk_tree_view_column_set_resizable (column, FALSE);
	gtk_tree_view_column_set_expand (column, FALSE);

	gtk_tree_view_append_column (treeview, column);

	model = gtk_list_store_new (MAPPING_N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT);
	gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (model));

	/* Fill it up! */
	list = csd_wacom_device_get_buttons (priv->pad);
	for (l = list; l != NULL; l = l->next) {
		CsdWacomTabletButton *button = l->data;
		CsdWacomActionType type = CSD_WACOM_ACTION_TYPE_NONE;

		if (button->settings)
			type = g_settings_get_enum (button->settings, ACTION_TYPE_KEY);

		if (button->type == WACOM_TABLET_BUTTON_TYPE_STRIP ||
		    button->type == WACOM_TABLET_BUTTON_TYPE_RING) {
			add_button_to_store (model, button, GTK_DIR_UP, CSD_WACOM_ACTION_TYPE_CUSTOM);
			add_button_to_store (model, button, GTK_DIR_DOWN, CSD_WACOM_ACTION_TYPE_CUSTOM);
		} else {
			add_button_to_store (model, button, 0, type);
		}
	}
	g_list_free (list);
	g_object_unref (model);
}