Landing GtkTreeModelFilter and the completion code. (Test program and

Fri Jul 11 14:32:43 2003  Kristian Rietveld  <kris@gtk.org>

	Landing GtkTreeModelFilter and the completion code. (Test program
	and documentation will follow next week).

	* gtk/gtkcellayout.[ch], gtk/gtkentrycompletion.[ch],
	gtk/gtktreemodelfilter.[ch], gtk/gtkentryprivate.h: new files.

	* gtkentry.[ch]: added gtk_entry_{get,set}_completion, wrote
	necessary code to hook up completion.

	* gtktreeviewcolumn.c: made GtkTreeViewColumn implement the new
	GtkCellLayout interface.

	* gtkmarshalers.list: added BOOLEAN:OBJECT,BOXED.

	* gtk/gtk.h, gtk/Makefile.am, po/POTFILES.in: all updated for the new
	source files.
This commit is contained in:
Kristian Rietveld 2003-07-11 12:51:24 +00:00 committed by Kristian Rietveld
parent 8aafd6bb16
commit edef7d00d9
14 changed files with 4727 additions and 113 deletions

View File

@ -102,6 +102,7 @@ gtk_public_h_sources = \
gtkbutton.h \
gtkcalendar.h \
gtkcelleditable.h \
gtkcelllayout.h \
gtkcellrenderer.h \
gtkcellrendererpixbuf.h \
gtkcellrenderertext.h \
@ -124,6 +125,7 @@ gtk_public_h_sources = \
gtkdrawingarea.h \
gtkeditable.h \
gtkentry.h \
gtkentrycompletion.h \
gtkenums.h \
gtkeventbox.h \
gtkexpander.h \
@ -221,6 +223,7 @@ gtk_public_h_sources = \
gtktreednd.h \
gtktreeitem.h \
gtktreemodel.h \
gtktreemodelfilter.h \
gtktreemodelsort.h \
gtktreeselection.h \
gtktreesortable.h \
@ -241,6 +244,7 @@ gtk_public_h_sources = \
# GTK+ header files that don't get installed
gtk_private_h_sources = \
gtkentryprivate.h \
gtkrbtree.h \
gtktextbtree.h \
gtktextchildprivate.h \
@ -277,6 +281,7 @@ gtk_c_sources = \
gtkbox.c \
gtkbutton.c \
gtkcalendar.c \
gtkcelllayout.c \
gtkcellrenderer.c \
gtkcelleditable.c \
gtkcellrenderertext.c \
@ -299,6 +304,7 @@ gtk_c_sources = \
gtkdrawingarea.c \
gtkeditable.c \
gtkentry.c \
gtkentrycompletion.c \
gtkeventbox.c \
gtkexpander.c \
gtkfilesel.c \
@ -403,6 +409,7 @@ gtk_c_sources = \
gtktreedatalist.c \
gtktreednd.c \
gtktreemodel.c \
gtktreemodelfilter.c \
gtktreemodelsort.c \
gtktreeselection.c \
gtktreesortable.c \

View File

@ -43,6 +43,7 @@
#include <gtk/gtkbox.h>
#include <gtk/gtkbutton.h>
#include <gtk/gtkcalendar.h>
#include <gtk/gtkcelllayout.h>
#include <gtk/gtkcellrenderer.h>
#include <gtk/gtkcellrendererpixbuf.h>
#include <gtk/gtkcellrenderertext.h>
@ -63,6 +64,7 @@
#include <gtk/gtkdrawingarea.h>
#include <gtk/gtkeditable.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkentrycompletion.h>
#include <gtk/gtkenums.h>
#include <gtk/gtkeventbox.h>
#include <gtk/gtkexpander.h>
@ -152,6 +154,7 @@
#include <gtk/gtktreednd.h>
#include <gtk/gtktreeitem.h>
#include <gtk/gtktreemodel.h>
#include <gtk/gtktreemodelfilter.h>
#include <gtk/gtktreemodelsort.h>
#include <gtk/gtktreeselection.h>
#include <gtk/gtktreestore.h>

168
gtk/gtkcelllayout.c Normal file
View File

@ -0,0 +1,168 @@
/* gtkcelllayout.c
* Copyright (C) 2003 Kristian Rietveld <kris@gtk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "gtkcelllayout.h"
GType
gtk_cell_layout_get_type (void)
{
static GType cell_layout_type = 0;
if (! cell_layout_type)
{
static const GTypeInfo cell_layout_info =
{
sizeof (GtkCellLayoutIface),
NULL,
NULL,
NULL,
NULL,
NULL,
0,
0,
NULL
};
cell_layout_type =
g_type_register_static (G_TYPE_INTERFACE, "GtkCellLayout",
&cell_layout_info, 0);
g_type_interface_add_prerequisite (cell_layout_type, G_TYPE_OBJECT);
}
return cell_layout_type;
}
void
gtk_cell_layout_pack_start (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
gboolean expand)
{
g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
(* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->pack_start) (cell_layout,
cell,
expand);
}
void
gtk_cell_layout_pack_end (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
gboolean expand)
{
g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
(* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->pack_end) (cell_layout,
cell,
expand);
}
void
gtk_cell_layout_clear (GtkCellLayout *cell_layout)
{
g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
(* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->clear) (cell_layout);
}
static void
gtk_cell_layout_set_attributesv (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
va_list args)
{
gchar *attribute;
gint column;
GtkCellLayoutIface *iface;
attribute = va_arg (args, gchar *);
iface = GTK_CELL_LAYOUT_GET_IFACE (cell_layout);
(* iface->clear_attributes) (cell_layout, cell);
while (attribute != NULL)
{
column = va_arg (args, gint);
(* iface->add_attribute) (cell_layout, cell, attribute, column);
attribute = va_arg (args, gchar *);
}
}
void
gtk_cell_layout_set_attributes (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
...)
{
va_list args;
g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
va_start (args, cell);
gtk_cell_layout_set_attributesv (cell_layout, cell, args);
va_end (args);
}
void
gtk_cell_layout_add_attribute (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
const gchar *attribute,
gint column)
{
g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
g_return_if_fail (attribute != NULL);
g_return_if_fail (column >= 0);
(* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->add_attribute) (cell_layout,
cell,
attribute,
column);
}
void
gtk_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
GtkCellLayoutDataFunc func,
gpointer func_data,
GDestroyNotify destroy)
{
g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
(* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->set_cell_data_func) (cell_layout,
cell,
func,
func_data,
destroy);
}
void
gtk_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
GtkCellRenderer *cell)
{
g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
(* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->clear_attributes) (cell_layout,
cell);
}

96
gtk/gtkcelllayout.h Normal file
View File

@ -0,0 +1,96 @@
/* gtkcelllayout.h
* Copyright (C) 2003 Kristian Rietveld <kris@gtk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GTK_CELL_LAYOUT_H__
#define __GTK_CELL_LAYOUT_H__
#include <glib-object.h>
#include <gtk/gtkcellrenderer.h>
#include <gtk/gtktreeviewcolumn.h>
G_BEGIN_DECLS
#define GTK_TYPE_CELL_LAYOUT (gtk_cell_layout_get_type ())
#define GTK_CELL_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_CELL_LAYOUT, GtkCellLayout))
#define GTK_IS_CELL_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_CELL_LAYOUT))
#define GTK_CELL_LAYOUT_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GTK_TYPE_CELL_LAYOUT, GtkCellLayoutIface))
typedef struct _GtkCellLayout GtkCellLayout; /* dummy typedef */
typedef struct _GtkCellLayoutIface GtkCellLayoutIface;
/* keep in sync with GtkTreeCellDataFunc */
typedef void (* GtkCellLayoutDataFunc) (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer data);
struct _GtkCellLayoutIface
{
GTypeInterface g_iface;
/* Virtual Table */
void (* pack_start) (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
gboolean expand);
void (* pack_end) (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
gboolean expand);
void (* clear) (GtkCellLayout *cell_layout);
void (* add_attribute) (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
const gchar *attribute,
gint column);
void (* set_cell_data_func) (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
GtkCellLayoutDataFunc func,
gpointer func_data,
GDestroyNotify destroy);
void (* clear_attributes) (GtkCellLayout *cell_layout,
GtkCellRenderer *cell);
};
GType gtk_cell_layout_get_type (void);
void gtk_cell_layout_pack_start (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
gboolean expand);
void gtk_cell_layout_pack_end (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
gboolean expand);
void gtk_cell_layout_clear (GtkCellLayout *cell_layout);
void gtk_cell_layout_set_attributes (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
...);
void gtk_cell_layout_add_attribute (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
const gchar *attribute,
gint column);
void gtk_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
GtkCellLayoutDataFunc func,
gpointer func_data,
GDestroyNotify destroy);
void gtk_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
GtkCellRenderer *cell);
G_END_DECLS
#endif /* __GTK_CELL_LAYOUT_H__ */

View File

@ -47,10 +47,17 @@
#include "gtkstock.h"
#include "gtktextutil.h"
#include "gtkwindow.h"
#include "gtktreeview.h"
#include "gtktreeselection.h"
#include "gtkentryprivate.h"
#include "gtkcelllayout.h"
#define GTK_ENTRY_COMPLETION_KEY "gtk-entry-completion-key"
#define MIN_ENTRY_WIDTH 150
#define DRAW_TIMEOUT 20
#define INNER_BORDER 2
#define COMPLETION_TIMEOUT 300
/* Initial size of buffer, in bytes */
#define MIN_SIZE 16
@ -936,6 +943,8 @@ gtk_entry_finalize (GObject *object)
{
GtkEntry *entry = GTK_ENTRY (object);
gtk_entry_set_completion (entry, NULL);
if (entry->cached_layout)
g_object_unref (entry->cached_layout);
@ -1664,6 +1673,7 @@ gtk_entry_focus_out (GtkWidget *widget,
GdkEventFocus *event)
{
GtkEntry *entry = GTK_ENTRY (widget);
GtkEntryCompletion *completion;
gtk_widget_queue_draw (widget);
@ -1675,6 +1685,10 @@ gtk_entry_focus_out (GtkWidget *widget,
g_signal_handlers_disconnect_by_func (gdk_keymap_get_for_display (gtk_widget_get_display (widget)),
gtk_entry_keymap_direction_changed,
entry);
completion = gtk_entry_get_completion (entry);
if (completion)
_gtk_entry_completion_popdown (completion);
return FALSE;
}
@ -4451,3 +4465,245 @@ gtk_entry_pend_cursor_blink (GtkEntry *entry)
show_cursor (entry);
}
}
/* completion */
static gint
gtk_entry_completion_timeout (gpointer data)
{
GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
GDK_THREADS_ENTER ();
completion->priv->completion_timeout = 0;
if (strlen (gtk_entry_get_text (GTK_ENTRY (completion->priv->entry))) >= completion->priv->minimum_key_length)
{
gint matches;
gint actions;
GtkTreeSelection *s;
gtk_entry_completion_complete (completion);
matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
s = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view));
gtk_tree_selection_unselect_all (s);
actions = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
if (matches > 0 || actions > 0)
_gtk_entry_completion_popup (completion);
}
GDK_THREADS_LEAVE ();
return FALSE;
}
static gboolean
gtk_entry_completion_key_press (GtkWidget *widget,
GdkEventKey *event,
gpointer user_data)
{
gint matches, actions = 0;
GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
if (!GTK_WIDGET_MAPPED (completion->priv->popup_window))
return FALSE;
matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
if (completion->priv->actions)
actions = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
if (event->keyval == GDK_Up || event->keyval == GDK_Down)
{
GtkTreePath *path = NULL;
if (event->keyval == GDK_Up)
{
completion->priv->current_selected--;
if (completion->priv->current_selected < 0)
completion->priv->current_selected = 0;
}
else
{
completion->priv->current_selected++;
if (completion->priv->current_selected >= matches + actions)
completion->priv->current_selected = 0;
}
if (completion->priv->current_selected < matches)
{
gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view)));
path = gtk_tree_path_new_from_indices (completion->priv->current_selected, -1);
gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->tree_view),
path, NULL, FALSE);
}
else if (completion->priv->current_selected - matches >= 0)
{
gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
path = gtk_tree_path_new_from_indices (completion->priv->current_selected - matches, -1);
gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->action_view),
path, NULL, FALSE);
}
gtk_tree_path_free (path);
return TRUE;
}
else if (event->keyval == GDK_ISO_Enter ||
event->keyval == GDK_Return ||
event->keyval == GDK_Escape)
{
_gtk_entry_completion_popdown (completion);
if (event->keyval == GDK_Escape)
return TRUE;
if (completion->priv->current_selected < matches)
{
GtkTreeIter iter;
GtkTreeModel *model = NULL;
GtkTreeSelection *sel;
gboolean entry_set;
sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view));
gtk_tree_selection_get_selected (sel, &model, &iter);
g_signal_emit_by_name (completion, "match_selected",
model, &iter, &entry_set);
if (!entry_set)
{
gchar *str = NULL;
gtk_tree_model_get (model, &iter,
completion->priv->text_column, &str,
-1);
g_signal_handler_block (widget, completion->priv->changed_id);
gtk_entry_set_text (GTK_ENTRY (widget), str);
g_signal_handler_unblock (widget, completion->priv->changed_id);
/* move the cursor to the end */
gtk_editable_set_position (GTK_EDITABLE (widget), -1);
g_free (str);
}
return TRUE;
}
else if (completion->priv->current_selected - matches >= 0)
{
GtkTreePath *path;
path = gtk_tree_path_new_from_indices (completion->priv->current_selected - matches, -1);
g_signal_emit_by_name (completion, "action_activated",
gtk_tree_path_get_indices (path)[0]);
gtk_tree_path_free (path);
}
}
return FALSE;
}
static void
gtk_entry_completion_changed (GtkWidget *entry,
gpointer user_data)
{
GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
if (GTK_WIDGET_MAPPED (completion->priv->popup_window))
_gtk_entry_completion_popdown (completion);
/* (re)install completion timeout */
if (completion->priv->completion_timeout)
g_source_remove (completion->priv->completion_timeout);
if (!gtk_entry_get_text (GTK_ENTRY (entry)))
return;
/* no need to normalize for this test */
if (! strcmp ("", gtk_entry_get_text (GTK_ENTRY (entry))))
return;
completion->priv->completion_timeout =
g_timeout_add (COMPLETION_TIMEOUT,
gtk_entry_completion_timeout,
completion);
}
void
gtk_entry_set_completion (GtkEntry *entry,
GtkEntryCompletion *completion)
{
GtkEntryCompletion *old;
g_return_if_fail (GTK_IS_ENTRY (entry));
g_return_if_fail (!completion || GTK_IS_ENTRY_COMPLETION (completion));
old = gtk_entry_get_completion (entry);
if (old)
{
if (old->priv->completion_timeout)
{
g_source_remove (old->priv->completion_timeout);
old->priv->completion_timeout = 0;
}
if (GTK_WIDGET_MAPPED (old->priv->popup_window))
_gtk_entry_completion_popdown (old);
gtk_cell_layout_clear (GTK_CELL_LAYOUT (old));
old->priv->text_column = -1;
if (g_signal_handler_is_connected (entry, old->priv->changed_id))
g_signal_handler_disconnect (entry, old->priv->changed_id);
if (g_signal_handler_is_connected (entry, old->priv->key_press_id))
g_signal_handler_disconnect (entry, old->priv->key_press_id);
old->priv->entry = NULL;
g_object_unref (old);
}
if (!completion)
{
g_object_set_data (G_OBJECT (entry), GTK_ENTRY_COMPLETION_KEY, NULL);
return;
}
/* hook into the entry */
g_object_ref (completion);
completion->priv->changed_id =
g_signal_connect (entry, "changed",
G_CALLBACK (gtk_entry_completion_changed), completion);
completion->priv->key_press_id =
g_signal_connect (entry, "key_press_event",
G_CALLBACK (gtk_entry_completion_key_press), completion);
completion->priv->entry = GTK_WIDGET (entry);
g_object_set_data (G_OBJECT (entry), GTK_ENTRY_COMPLETION_KEY, completion);
}
GtkEntryCompletion *
gtk_entry_get_completion (GtkEntry *entry)
{
GtkEntryCompletion *completion;
g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
completion = GTK_ENTRY_COMPLETION (g_object_get_data (G_OBJECT (entry),
GTK_ENTRY_COMPLETION_KEY));
return completion;
}

View File

@ -32,6 +32,7 @@
#include <gtk/gtkeditable.h>
#include <gtk/gtkimcontext.h>
#include <gtk/gtkmenu.h>
#include <gtk/gtkentrycompletion.h>
#include <pango/pango.h>
#ifdef __cplusplus
@ -182,6 +183,10 @@ void gtk_entry_get_layout_offsets (GtkEntry *entry,
gint *x,
gint *y);
void gtk_entry_set_completion (GtkEntry *entry,
GtkEntryCompletion *completion);
GtkEntryCompletion *gtk_entry_get_completion (GtkEntry *entry);
/* Deprecated compatibility functions
*/

956
gtk/gtkentrycompletion.c Normal file
View File

@ -0,0 +1,956 @@
/* gtkentrycompletion.c
* Copyright (C) 2003 Kristian Rietveld <kris@gtk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "gtkentrycompletion.h"
#include "gtkentryprivate.h"
#include "gtkcelllayout.h"
#include <gtk/gtkintl.h>
#include <gtk/gtkcellrenderertext.h>
#include <gtk/gtktreeselection.h>
#include <gtk/gtktreeview.h>
#include <gtk/gtkscrolledwindow.h>
#include <gtk/gtkvbox.h>
#include <gtk/gtkwindow.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkmain.h>
#include <gtk/gtksignal.h>
#include <gtk/gtkmarshalers.h>
#include <string.h>
/* signals */
enum
{
MATCH_SELECTED,
ACTION_ACTIVATED,
LAST_SIGNAL
};
/* properties */
enum
{
PROP_0,
PROP_MODEL,
PROP_MINIMUM_KEY_LENGTH
};
static void gtk_entry_completion_class_init (GtkEntryCompletionClass *klass);
static void gtk_entry_completion_cell_layout_init (GtkCellLayoutIface *iface);
static void gtk_entry_completion_init (GtkEntryCompletion *completion);
static void gtk_entry_completion_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gtk_entry_completion_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void gtk_entry_completion_finalize (GObject *object);
static void gtk_entry_completion_pack_start (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
gboolean expand);
static void gtk_entry_completion_pack_end (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
gboolean expand);
static void gtk_entry_completion_clear (GtkCellLayout *cell_layout);
static void gtk_entry_completion_add_attribute (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
const char *attribute,
gint column);
static void gtk_entry_completion_set_cell_data_func (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
GtkCellLayoutDataFunc func,
gpointer func_data,
GDestroyNotify destroy);
static void gtk_entry_completion_clear_attributes (GtkCellLayout *cell_layout,
GtkCellRenderer *cell);
static gboolean gtk_entry_completion_visible_func (GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data);
static gboolean gtk_entry_completion_popup_key_press (GtkWidget *widget,
GdkEventKey *event,
gpointer user_data);
static gboolean gtk_entry_completion_popup_button_press (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data);
static gboolean gtk_entry_completion_list_button_press (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data);
static gboolean gtk_entry_completion_action_button_press (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data);
static void gtk_entry_completion_insert_action (GtkEntryCompletion *completion,
gint index,
gchar *string,
gboolean markup);
static void gtk_entry_completion_action_data_func (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data);
static guint entry_completion_signals[LAST_SIGNAL] = { 0 };
GType
gtk_entry_completion_get_type (void)
{
static GType entry_completion_type = 0;
if (!entry_completion_type)
{
static const GTypeInfo entry_completion_info =
{
sizeof (GtkEntryCompletionClass),
NULL,
NULL,
(GClassInitFunc) gtk_entry_completion_class_init,
NULL,
NULL,
sizeof (GtkEntryCompletion),
0,
(GInstanceInitFunc) gtk_entry_completion_init
};
static const GInterfaceInfo cell_layout_info =
{
(GInterfaceInitFunc) gtk_entry_completion_cell_layout_init,
NULL,
NULL
};
entry_completion_type =
g_type_register_static (G_TYPE_OBJECT, "GtkEntryCompletion",
&entry_completion_info, 0);
g_type_add_interface_static (entry_completion_type,
GTK_TYPE_CELL_LAYOUT,
&cell_layout_info);
}
return entry_completion_type;
}
static void
gtk_entry_completion_class_init (GtkEntryCompletionClass *klass)
{
GObjectClass *object_class;
object_class = (GObjectClass *)klass;
object_class->set_property = gtk_entry_completion_set_property;
object_class->get_property = gtk_entry_completion_get_property;
object_class->finalize = gtk_entry_completion_finalize;
entry_completion_signals[MATCH_SELECTED] =
g_signal_new ("match_selected",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkEntryCompletionClass, match_selected),
_gtk_boolean_handled_accumulator, NULL,
_gtk_marshal_BOOLEAN__OBJECT_BOXED,
G_TYPE_BOOLEAN, 2,
GTK_TYPE_TREE_MODEL,
GTK_TYPE_TREE_ITER);
entry_completion_signals[ACTION_ACTIVATED] =
g_signal_new ("action_activated",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkEntryCompletionClass, action_activated),
NULL, NULL,
_gtk_marshal_NONE__INT,
G_TYPE_NONE, 1,
G_TYPE_INT);
g_object_class_install_property (object_class,
PROP_MODEL,
g_param_spec_object ("model",
_("Completion Model"),
_("The model to find matches in"),
GTK_TYPE_TREE_MODEL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_MINIMUM_KEY_LENGTH,
g_param_spec_int ("minimum_key_length",
_("Minimum Key Length"),
_("Minimum length of the search key in order to look up matches"),
-1,
G_MAXINT,
1,
G_PARAM_READWRITE));
g_type_class_add_private (object_class, sizeof (GtkEntryCompletionPrivate));
}
static void
gtk_entry_completion_cell_layout_init (GtkCellLayoutIface *iface)
{
iface->pack_start = gtk_entry_completion_pack_start;
iface->pack_end = gtk_entry_completion_pack_end;
iface->clear = gtk_entry_completion_clear;
iface->add_attribute = gtk_entry_completion_add_attribute;
iface->set_cell_data_func = gtk_entry_completion_set_cell_data_func;
iface->clear_attributes = gtk_entry_completion_clear_attributes;
}
static void
gtk_entry_completion_init (GtkEntryCompletion *completion)
{
GtkCellRenderer *cell;
GtkTreeSelection *sel;
GtkEntryCompletionPrivate *priv;
/* yes, also priv, need to keep the code readable */
priv = completion->priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (completion);
priv->minimum_key_length = 1;
priv->text_column = -1;
/* completions */
priv->filter_model = NULL;
priv->tree_view = gtk_tree_view_new ();
g_signal_connect (priv->tree_view, "button_press_event",
G_CALLBACK (gtk_entry_completion_list_button_press),
completion);
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE);
sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view));
gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
gtk_tree_selection_unselect_all (sel);
priv->column = gtk_tree_view_column_new ();
gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), priv->column);
priv->scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window),
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scrolled_window),
GTK_SHADOW_ETCHED_IN);
/* actions */
priv->actions = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
priv->action_view =
gtk_tree_view_new_with_model (GTK_TREE_MODEL (priv->actions));
g_signal_connect (priv->action_view, "button_press_event",
G_CALLBACK (gtk_entry_completion_action_button_press),
completion);
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->action_view), FALSE);
sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->action_view));
gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
gtk_tree_selection_unselect_all (sel);
cell = gtk_cell_renderer_text_new ();
g_object_set (cell, "cell_background_gdk",
&priv->tree_view->style->bg[GTK_STATE_NORMAL],
NULL);
gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (priv->action_view),
0, "",
cell,
gtk_entry_completion_action_data_func,
NULL,
NULL);
/* pack it all */
priv->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
gtk_window_set_resizable (GTK_WINDOW (priv->popup_window), FALSE);
g_signal_connect (priv->popup_window, "key_press_event",
G_CALLBACK (gtk_entry_completion_popup_key_press),
completion);
g_signal_connect (priv->popup_window, "button_press_event",
G_CALLBACK (gtk_entry_completion_popup_button_press),
completion);
priv->vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (priv->popup_window), priv->vbox);
gtk_container_add (GTK_CONTAINER (priv->scrolled_window), priv->tree_view);
gtk_box_pack_start (GTK_BOX (priv->vbox), priv->scrolled_window,
TRUE, TRUE, 0);
/* we don't want to see the action treeview when no actions have
* been inserted, so we pack the action treeview after the first
* action has been added
*/
}
static void
gtk_entry_completion_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (object);
switch (prop_id)
{
case PROP_MODEL:
gtk_entry_completion_set_model (completion,
g_value_get_object (value));
break;
case PROP_MINIMUM_KEY_LENGTH:
gtk_entry_completion_set_minimum_key_length (completion,
g_value_get_int (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_entry_completion_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (object);
switch (prop_id)
{
case PROP_MODEL:
g_value_set_object (value,
gtk_entry_completion_get_model (completion));
break;
case PROP_MINIMUM_KEY_LENGTH:
g_value_set_int (value, gtk_entry_completion_get_minimum_key_length (completion));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_entry_completion_finalize (GObject *object)
{
GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (object);
if (completion->priv->tree_view)
gtk_widget_destroy (completion->priv->tree_view);
if (completion->priv->entry)
gtk_entry_set_completion (GTK_ENTRY (completion->priv->entry), NULL);
if (completion->priv->actions)
g_object_unref (completion->priv->actions);
if (completion->priv->case_normalized_key)
g_free (completion->priv->case_normalized_key);
if (completion->priv->popup_window)
gtk_widget_destroy (completion->priv->popup_window);
}
/* implement cell layout interface */
static void
gtk_entry_completion_pack_start (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
gboolean expand)
{
GtkEntryCompletionPrivate *priv;
g_return_if_fail (GTK_IS_ENTRY_COMPLETION (cell_layout));
priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (cell_layout);
gtk_tree_view_column_pack_start (priv->column, cell, expand);
}
static void
gtk_entry_completion_pack_end (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
gboolean expand)
{
GtkEntryCompletionPrivate *priv;
g_return_if_fail (GTK_IS_ENTRY_COMPLETION (cell_layout));
priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (cell_layout);
gtk_tree_view_column_pack_end (priv->column, cell, expand);
}
static void
gtk_entry_completion_clear (GtkCellLayout *cell_layout)
{
GtkEntryCompletionPrivate *priv;
g_return_if_fail (GTK_IS_ENTRY_COMPLETION (cell_layout));
priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (cell_layout);
gtk_tree_view_column_clear (priv->column);
}
static void
gtk_entry_completion_add_attribute (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
const gchar *attribute,
gint column)
{
GtkEntryCompletionPrivate *priv;
g_return_if_fail (GTK_IS_ENTRY_COMPLETION (cell_layout));
priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (cell_layout);
gtk_tree_view_column_add_attribute (priv->column, cell, attribute, column);
}
static void
gtk_entry_completion_set_cell_data_func (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
GtkCellLayoutDataFunc func,
gpointer func_data,
GDestroyNotify destroy)
{
GtkEntryCompletionPrivate *priv;
g_return_if_fail (GTK_IS_ENTRY_COMPLETION (cell_layout));
priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (cell_layout);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (priv->column),
cell, func, func_data, destroy);
}
static void
gtk_entry_completion_clear_attributes (GtkCellLayout *cell_layout,
GtkCellRenderer *cell)
{
GtkEntryCompletionPrivate *priv;
g_return_if_fail (GTK_IS_ENTRY_COMPLETION (cell_layout));
priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (cell_layout);
gtk_tree_view_column_clear_attributes (priv->column, cell);
}
/* all those callbacks */
static gboolean
gtk_entry_completion_default_completion_func (GtkEntryCompletion *completion,
const gchar *key,
GtkTreeIter *iter,
gpointer user_data)
{
gchar *item = NULL;
gchar *normalized_string;
gchar *case_normalized_string;
gboolean ret = FALSE;
GtkTreeModel *model;
model = gtk_tree_model_filter_get_model (completion->priv->filter_model);
gtk_tree_model_get (model, iter,
completion->priv->text_column, &item,
-1);
normalized_string = g_utf8_normalize (item, -1, G_NORMALIZE_ALL);
case_normalized_string = g_utf8_casefold (normalized_string, -1);
if (!strncmp (key, case_normalized_string, strlen (key)))
ret = TRUE;
g_free (item);
g_free (normalized_string);
g_free (case_normalized_string);
return ret;
}
static gboolean
gtk_entry_completion_visible_func (GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
gboolean ret = FALSE;
GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
if (!completion->priv->case_normalized_key)
return ret;
if (completion->priv->text_column >= 0)
ret = gtk_entry_completion_default_completion_func (completion,
completion->priv->case_normalized_key,
iter,
NULL);
else if (completion->priv->match_func)
ret = (* completion->priv->match_func) (completion,
completion->priv->case_normalized_key,
iter,
completion->priv->match_data);
return ret;
}
static gboolean
gtk_entry_completion_popup_key_press (GtkWidget *widget,
GdkEventKey *event,
gpointer user_data)
{
GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
if (!GTK_WIDGET_MAPPED (completion->priv->popup_window))
return FALSE;
/* propagate event to the entry */
gtk_widget_event (completion->priv->entry, (GdkEvent *)event);
return TRUE;
}
static gboolean
gtk_entry_completion_popup_button_press (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
if (!GTK_WIDGET_MAPPED (completion->priv->popup_window))
return FALSE;
/* if we come here, it's usually time to popdown */
_gtk_entry_completion_popdown (completion);
return TRUE;
}
static gboolean
gtk_entry_completion_list_button_press (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
GtkTreePath *path = NULL;
if (!GTK_WIDGET_MAPPED (completion->priv->popup_window))
return FALSE;
if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
event->x, event->y,
&path, NULL, NULL, NULL))
{
gboolean entry_set;
GtkTreeIter iter;
gtk_tree_model_get_iter (GTK_TREE_MODEL (completion->priv->filter_model),
&iter, path);
gtk_tree_path_free (path);
g_signal_emit (completion, entry_completion_signals[MATCH_SELECTED],
0, GTK_TREE_MODEL (completion->priv->filter_model),
&iter, &entry_set);
if (!entry_set)
{
gchar *str = NULL;
gtk_tree_model_get (GTK_TREE_MODEL (completion->priv->filter_model),
&iter,
completion->priv->text_column, &str,
-1);
g_signal_handler_block (completion->priv->entry,
completion->priv->changed_id);
gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), str);
g_signal_handler_unblock (completion->priv->entry,
completion->priv->changed_id);
/* move cursor to the end */
gtk_editable_set_position (GTK_EDITABLE (completion->priv->entry),
-1);
g_free (str);
}
_gtk_entry_completion_popdown (completion);
return TRUE;
}
return FALSE;
}
static gboolean
gtk_entry_completion_action_button_press (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
GtkTreePath *path = NULL;
if (!GTK_WIDGET_MAPPED (completion->priv->popup_window))
return FALSE;
if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
event->x, event->y,
&path, NULL, NULL, NULL))
{
g_signal_emit (completion, entry_completion_signals[ACTION_ACTIVATED],
0, gtk_tree_path_get_indices (path)[0]);
gtk_tree_path_free (path);
_gtk_entry_completion_popdown (completion);
return TRUE;
}
return FALSE;
}
static void
gtk_entry_completion_action_data_func (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
gchar *string = NULL;
gboolean markup;
gtk_tree_model_get (model, iter,
0, &string,
1, &markup,
-1);
if (!string)
return;
if (markup)
g_object_set (G_OBJECT (cell),
"text", NULL,
"markup", string,
NULL);
else
g_object_set (G_OBJECT (cell),
"markup", NULL,
"text", string,
NULL);
}
/* public API */
GtkEntryCompletion *
gtk_entry_completion_new (void)
{
GtkEntryCompletion *completion;
completion = g_object_new (GTK_TYPE_ENTRY_COMPLETION, NULL);
return completion;
}
GtkWidget *
gtk_entry_completion_get_entry (GtkEntryCompletion *completion)
{
g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), NULL);
return completion->priv->entry;
}
void
gtk_entry_completion_set_model (GtkEntryCompletion *completion,
GtkTreeModel *model)
{
g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
g_return_if_fail (GTK_IS_TREE_MODEL (model));
/* code will unref the old filter model (if any) */
completion->priv->filter_model =
GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
gtk_tree_model_filter_set_visible_func (completion->priv->filter_model,
gtk_entry_completion_visible_func,
completion,
NULL);
gtk_tree_view_set_model (GTK_TREE_VIEW (completion->priv->tree_view),
GTK_TREE_MODEL (completion->priv->filter_model));
g_object_unref (G_OBJECT (completion->priv->filter_model));
}
GtkTreeModel *
gtk_entry_completion_get_model (GtkEntryCompletion *completion)
{
g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), NULL);
return gtk_tree_model_filter_get_model (completion->priv->filter_model);
}
void
gtk_entry_completion_set_match_func (GtkEntryCompletion *completion,
GtkEntryCompletionMatchFunc func,
gpointer func_data,
GDestroyNotify func_notify)
{
g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
if (completion->priv->match_notify)
(* completion->priv->match_notify) (completion->priv->match_data);
completion->priv->match_func = func;
completion->priv->match_data = func_data;
completion->priv->match_notify = func_notify;
}
void
gtk_entry_completion_set_minimum_key_length (GtkEntryCompletion *completion,
gint length)
{
g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
g_return_if_fail (length >= 1);
completion->priv->minimum_key_length = length;
}
gint
gtk_entry_completion_get_minimum_key_length (GtkEntryCompletion *completion)
{
g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), 0);
return completion->priv->minimum_key_length;
}
void
gtk_entry_completion_complete (GtkEntryCompletion *completion)
{
gchar *tmp;
g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
g_return_if_fail (completion->priv->filter_model != NULL);
if (completion->priv->case_normalized_key)
g_free (completion->priv->case_normalized_key);
tmp = g_utf8_normalize (gtk_entry_get_text (GTK_ENTRY (completion->priv->entry)),
-1, G_NORMALIZE_ALL);
completion->priv->case_normalized_key = g_utf8_casefold (tmp, -1);
g_free (tmp);
gtk_tree_model_filter_refilter (completion->priv->filter_model);
}
static void
gtk_entry_completion_insert_action (GtkEntryCompletion *completion,
gint index,
gchar *string,
gboolean markup)
{
GtkTreeIter iter;
gtk_list_store_insert (completion->priv->actions, &iter, index);
gtk_list_store_set (completion->priv->actions, &iter,
0, string,
1, markup,
-1);
if (!completion->priv->action_view->parent)
{
GtkTreePath *path = gtk_tree_path_new_from_indices (0, -1);
gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->action_view),
path, NULL, FALSE);
gtk_tree_path_free (path);
gtk_box_pack_start (GTK_BOX (completion->priv->vbox),
completion->priv->action_view, FALSE, FALSE, 0);
gtk_widget_show (completion->priv->action_view);
}
}
void
gtk_entry_completion_insert_action_text (GtkEntryCompletion *completion,
gint index,
gchar *text)
{
g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
g_return_if_fail (text != NULL);
gtk_entry_completion_insert_action (completion, index, text, FALSE);
}
void
gtk_entry_completion_insert_action_markup (GtkEntryCompletion *completion,
gint index,
gchar *markup)
{
g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
g_return_if_fail (markup != NULL);
gtk_entry_completion_insert_action (completion, index, markup, TRUE);
}
void
gtk_entry_completion_delete_action (GtkEntryCompletion *completion,
gint index)
{
GtkTreeIter iter;
g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
g_return_if_fail (index >= 0);
gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (completion->priv->actions),
&iter, NULL, index);
gtk_list_store_remove (completion->priv->actions, &iter);
}
void
gtk_entry_completion_set_text_column (GtkEntryCompletion *completion,
gint column)
{
GtkCellRenderer *cell;
g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
g_return_if_fail (column >= 0);
completion->priv->text_column = column;
cell = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion),
cell, TRUE);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (completion),
cell,
"text", column);
}
/* private */
/* lame copy from gtkentry.c */
static void
get_borders (GtkEntry *entry,
gint *xborder,
gint *yborder)
{
GtkWidget *widget = GTK_WIDGET (entry);
gint focus_width;
gboolean interior_focus;
gtk_widget_style_get (widget,
"interior-focus", &interior_focus,
"focus-line-width", &focus_width,
NULL);
if (entry->has_frame)
{
*xborder = widget->style->xthickness;
*yborder = widget->style->ythickness;
}
else
{
*xborder = 0;
*yborder = 0;
}
if (!interior_focus)
{
*xborder += focus_width;
*yborder += focus_width;
}
}
/* this function is a bit nasty */
void
_gtk_entry_completion_popup (GtkEntryCompletion *completion)
{
gint x, y, x_border, y_border;
gint items;
gint height;
GtkTreePath *path;
if (GTK_WIDGET_MAPPED (completion->priv->popup_window))
return;
gtk_widget_show_all (completion->priv->vbox);
gdk_window_get_origin (completion->priv->entry->window, &x, &y);
get_borders (GTK_ENTRY (completion->priv->entry), &x_border, &y_border);
items = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
items = MIN (items, 15);
gtk_tree_view_column_cell_get_size (completion->priv->column, NULL,
NULL, NULL, NULL, &height);
gtk_widget_set_size_request (completion->priv->tree_view,
completion->priv->entry->allocation.width - 2 * x_border,
items * height);
if (items <= 0)
gtk_widget_hide (completion->priv->scrolled_window);
/* default on the first match */
path = gtk_tree_path_new_from_indices (0, -1);
gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->tree_view), path,
NULL, FALSE);
completion->priv->current_selected = 0;
gtk_tree_path_free (path);
items = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
if (items)
{
gtk_tree_view_column_cell_get_size (gtk_tree_view_get_column (GTK_TREE_VIEW (completion->priv->action_view), 0),
NULL, NULL, NULL, NULL,
&height);
gtk_widget_set_size_request (completion->priv->action_view,
completion->priv->entry->allocation.width - 2 * x_border,
items * height);
}
x += x_border;
y += 2 * y_border;
gtk_window_move (GTK_WINDOW (completion->priv->popup_window), x, y + height);
gtk_widget_show (completion->priv->popup_window);
gtk_grab_add (completion->priv->popup_window);
gdk_pointer_grab (completion->priv->popup_window->window, TRUE,
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK,
NULL, NULL, GDK_CURRENT_TIME);
}
void
_gtk_entry_completion_popdown (GtkEntryCompletion *completion)
{
gdk_pointer_ungrab (GDK_CURRENT_TIME);
gtk_grab_remove (completion->priv->popup_window);
gtk_widget_hide (completion->priv->popup_window);
}

103
gtk/gtkentrycompletion.h Normal file
View File

@ -0,0 +1,103 @@
/* gtkentrycompletion.h
* Copyright (C) 2003 Kristian Rietveld <kris@gtk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GTK_ENTRY_COMPLETION_H__
#define __GTK_ENTRY_COMPLETION_H__
#include <glib-object.h>
#include <gtk/gtktreemodel.h>
#include <gtk/gtkliststore.h>
#include <gtk/gtktreeviewcolumn.h>
#include <gtk/gtktreemodelfilter.h>
G_BEGIN_DECLS
#define GTK_TYPE_ENTRY_COMPLETION (gtk_entry_completion_get_type ())
#define GTK_ENTRY_COMPLETION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ENTRY_COMPLETION, GtkEntryCompletion))
#define GTK_ENTRY_COMPLETION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_ENTRY_COMPLETION, GtkEntryCompletionClass))
#define GTK_IS_ENTRY_COMPLETION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ENTRY_COMPLETION))
#define GTK_IS_ENTRY_COMPLETION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_ENTRY_COMPLETION))
#define GTK_ENTRY_COMPLETION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_ENTRY_COMPLETION, GtkEntryCompletionClass))
#define GTK_ENTRY_COMPLETION_GET_PRIVATE(obj)(G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ENTRY_COMPLETION, GtkEntryCompletionPrivate))
typedef struct _GtkEntryCompletion GtkEntryCompletion;
typedef struct _GtkEntryCompletionClass GtkEntryCompletionClass;
typedef struct _GtkEntryCompletionPrivate GtkEntryCompletionPrivate;
typedef gboolean (* GtkEntryCompletionMatchFunc) (GtkEntryCompletion *completion,
const gchar *key,
GtkTreeIter *iter,
gpointer user_data);
struct _GtkEntryCompletion
{
GObject parent_instance;
/*< private >*/
GtkEntryCompletionPrivate *priv;
};
struct _GtkEntryCompletionClass
{
GObjectClass parent_class;
gboolean (* match_selected) (GtkEntryCompletion *completion,
GtkTreeModel *model,
GtkTreeIter *iter);
void (* action_activated) (GtkEntryCompletion *completion,
gint index);
};
/* core */
GType gtk_entry_completion_get_type (void);
GtkEntryCompletion *gtk_entry_completion_new (void);
GtkWidget *gtk_entry_completion_get_entry (GtkEntryCompletion *entry);
void gtk_entry_completion_set_model (GtkEntryCompletion *completion,
GtkTreeModel *model);
GtkTreeModel *gtk_entry_completion_get_model (GtkEntryCompletion *completion);
void gtk_entry_completion_set_match_func (GtkEntryCompletion *completion,
GtkEntryCompletionMatchFunc func,
gpointer func_data,
GDestroyNotify func_notify);
void gtk_entry_completion_set_minimum_key_length (GtkEntryCompletion *completion,
gint length);
gint gtk_entry_completion_get_minimum_key_length (GtkEntryCompletion *completion);
void gtk_entry_completion_complete (GtkEntryCompletion *completion);
void gtk_entry_completion_insert_action_text (GtkEntryCompletion *completion,
gint index,
gchar *text);
void gtk_entry_completion_insert_action_markup (GtkEntryCompletion *completion,
gint index,
gchar *markup);
void gtk_entry_completion_delete_action (GtkEntryCompletion *completion,
gint index);
/* convenience */
void gtk_entry_completion_set_text_column (GtkEntryCompletion *completion,
gint column);
G_END_DECLS
#endif /* __GTK_ENTRY_COMPLETION_H__ */

65
gtk/gtkentryprivate.h Normal file
View File

@ -0,0 +1,65 @@
/* gtkentryprivate.h
* Copyright (C) 2003 Kristian Rietveld <kris@gtk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GTK_ENTRY_PRIVATE_H__
#define __GTK_ENTRY_PRIVATE_H__
#include <gtk/gtktreeviewcolumn.h>
#include <gtk/gtktreemodelfilter.h>
#include <gtk/gtkliststore.h>
#include <gtk/gtkentrycompletion.h>
G_BEGIN_DECLS
struct _GtkEntryCompletionPrivate
{
GtkWidget *entry;
GtkWidget *tree_view;
GtkTreeViewColumn *column;
GtkTreeModelFilter *filter_model;
GtkListStore *actions;
GtkEntryCompletionMatchFunc match_func;
gpointer match_data;
GDestroyNotify match_notify;
gint minimum_key_length;
gint text_column;
gint current_selected;
gchar *case_normalized_key;
/* only used by GtkEntry when attached: */
GtkWidget *popup_window;
GtkWidget *vbox;
GtkWidget *scrolled_window;
GtkWidget *action_view;
gulong completion_timeout;
gulong changed_id;
gulong key_press_id;
};
void _gtk_entry_completion_popup (GtkEntryCompletion *completion);
void _gtk_entry_completion_popdown (GtkEntryCompletion *completion);
G_END_DECLS
#endif /* __GTK_ENTRY_PRIVATE_H__ */

View File

@ -28,6 +28,7 @@ BOOLEAN:ENUM,INT
BOOLEAN:OBJECT,UINT,FLAGS
BOOLEAN:OBJECT,INT,INT,UINT
BOOLEAN:OBJECT,STRING,STRING,BOXED
BOOLEAN:OBJECT,BOXED
BOOLEAN:OBJECT,BOXED,BOXED
BOOLEAN:OBJECT,STRING,STRING
BOOLEAN:INT,INT

2746
gtk/gtktreemodelfilter.c Normal file

File diff suppressed because it is too large Load Diff

99
gtk/gtktreemodelfilter.h Normal file
View File

@ -0,0 +1,99 @@
/* gtktreemodelfilter.h
* Copyright (C) 2000,2001 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
* Copyright (C) 2001-2003 Kristian Rietveld <kris@gtk.org>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GTK_TREE_MODEL_FILTER_H__
#define __GTK_TREE_MODEL_FILTER_H__
#include <gtk/gtktreemodel.h>
G_BEGIN_DECLS
#define GTK_TYPE_TREE_MODEL_FILTER (gtk_tree_model_filter_get_type ())
#define GTK_TREE_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_TREE_MODEL_FILTER, GtkTreeModelFilter))
#define GTK_TREE_MODEL_FILTER_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), GTK_TYPE_TREE_MODEL_FILTER, GtkTreeModelFilterClass))
#define GTK_IS_TREE_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_TREE_MODEL_FILTER))
#define GTK_IS_TREE_MODEL_FILTER_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), GTK_TYPE_TREE_MODEL_FILTER))
#define GTK_TREE_MODEL_FILTER_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_TREE_MODEL_FILTER, GtkTreeModelFilterClass))
#define GTK_TREE_MODEL_FILTER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_TREE_MODEL_FILTER, GtkTreeModelFilterPrivate))
typedef gboolean (* GtkTreeModelFilterVisibleFunc) (GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data);
typedef void (* GtkTreeModelFilterModifyFunc) (GtkTreeModel *model,
GtkTreeIter *iter,
GValue *value,
gint column,
gpointer data);
typedef struct _GtkTreeModelFilter GtkTreeModelFilter;
typedef struct _GtkTreeModelFilterClass GtkTreeModelFilterClass;
typedef struct _GtkTreeModelFilterPrivate GtkTreeModelFilterPrivate;
struct _GtkTreeModelFilter
{
GObject parent;
/*< private >*/
GtkTreeModelFilterPrivate *priv;
};
struct _GtkTreeModelFilterClass
{
GObjectClass parent_class;
};
/* base */
GType gtk_tree_model_filter_get_type (void);
GtkTreeModel *gtk_tree_model_filter_new (GtkTreeModel *child_model,
GtkTreePath *root);
void gtk_tree_model_filter_set_visible_func (GtkTreeModelFilter *filter,
GtkTreeModelFilterVisibleFunc func,
gpointer data,
GtkDestroyNotify destroy);
void gtk_tree_model_filter_set_modify_func (GtkTreeModelFilter *filter,
gint n_columns,
GType *types,
GtkTreeModelFilterModifyFunc func,
gpointer data,
GtkDestroyNotify destroy);
void gtk_tree_model_filter_set_visible_column (GtkTreeModelFilter *filter,
gint column);
GtkTreeModel *gtk_tree_model_filter_get_model (GtkTreeModelFilter *filter);
/* conversion */
void gtk_tree_model_filter_convert_child_iter_to_iter (GtkTreeModelFilter *filter,
GtkTreeIter *filter_iter,
GtkTreeIter *child_iter);
void gtk_tree_model_filter_convert_iter_to_child_iter (GtkTreeModelFilter *filter,
GtkTreeIter *child_iter,
GtkTreeIter *filter_iter);
GtkTreePath *gtk_tree_model_filter_convert_child_path_to_path (GtkTreeModelFilter *filter,
GtkTreePath *child_path);
GtkTreePath *gtk_tree_model_filter_convert_path_to_child_path (GtkTreeModelFilter *path,
GtkTreePath *filter_path);
/* extras */
void gtk_tree_model_filter_refilter (GtkTreeModelFilter *filter);
void gtk_tree_model_filter_clear_cache (GtkTreeModelFilter *filter);
G_END_DECLS
#endif /* __GTK_TREE_MODEL_FILTER_H__ */

View File

@ -21,6 +21,7 @@
#include "gtktreeviewcolumn.h"
#include "gtktreeview.h"
#include "gtktreeprivate.h"
#include "gtkcelllayout.h"
#include "gtkbutton.h"
#include "gtkalignment.h"
#include "gtklabel.h"
@ -74,6 +75,7 @@ struct _GtkTreeViewColumnCellInfo
/* Type methods */
static void gtk_tree_view_column_init (GtkTreeViewColumn *tree_column);
static void gtk_tree_view_column_class_init (GtkTreeViewColumnClass *klass);
static void gtk_tree_view_column_cell_layout_init (GtkCellLayoutIface *iface);
/* GObject methods */
static void gtk_tree_view_column_set_property (GObject *object,
@ -86,6 +88,26 @@ static void gtk_tree_view_column_get_property (GObject
GParamSpec *pspec);
static void gtk_tree_view_column_finalize (GObject *object);
/* GtkCellLayout implementation */
static void gtk_tree_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
gboolean expand);
static void gtk_tree_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
gboolean expand);
static void gtk_tree_view_column_cell_layout_clear (GtkCellLayout *cell_layout);
static void gtk_tree_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
const gchar *attribute,
gint column);
static void gtk_tree_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
GtkCellLayoutDataFunc func,
gpointer func_data,
GDestroyNotify destroy);
static void gtk_tree_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
GtkCellRenderer *cell);
/* Button handling code */
static void gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column);
static void gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column);
@ -145,12 +167,23 @@ gtk_tree_view_column_get_type (void)
NULL, /* class_data */
sizeof (GtkTreeViewColumn),
0,
(GInstanceInitFunc) gtk_tree_view_column_init,
(GInstanceInitFunc) gtk_tree_view_column_init
};
static const GInterfaceInfo cell_layout_info =
{
(GInterfaceInitFunc) gtk_tree_view_column_cell_layout_init,
NULL,
NULL
};
tree_column_type =
g_type_register_static (GTK_TYPE_OBJECT, "GtkTreeViewColumn",
&tree_column_info, 0);
g_type_add_interface_static (tree_column_type,
GTK_TYPE_CELL_LAYOUT,
&cell_layout_info);
}
return tree_column_type;
@ -314,6 +347,17 @@ gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class)
}
static void
gtk_tree_view_column_cell_layout_init (GtkCellLayoutIface *iface)
{
iface->pack_start = gtk_tree_view_column_cell_layout_pack_start;
iface->pack_end = gtk_tree_view_column_cell_layout_pack_end;
iface->clear = gtk_tree_view_column_cell_layout_clear;
iface->add_attribute = gtk_tree_view_column_cell_layout_add_attribute;
iface->set_cell_data_func = gtk_tree_view_column_cell_layout_set_cell_data_func;
iface->clear_attributes = gtk_tree_view_column_cell_layout_clear_attributes;
}
static void
gtk_tree_view_column_init (GtkTreeViewColumn *tree_column)
{
@ -552,6 +596,169 @@ gtk_tree_view_column_get_property (GObject *object,
}
}
/* Implementation of GtkCellLayout interface
*/
static void
gtk_tree_view_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
gboolean expand)
{
GtkTreeViewColumn *column;
GtkTreeViewColumnCellInfo *cell_info;
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (cell_layout));
column = GTK_TREE_VIEW_COLUMN (cell_layout);
g_return_if_fail (! gtk_tree_view_column_get_cell_info (column, cell));
g_object_ref (cell);
gtk_object_sink (GTK_OBJECT (cell));
cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1);
cell_info->cell = cell;
cell_info->expand = expand ? TRUE : FALSE;
cell_info->pack = GTK_PACK_START;
cell_info->has_focus = 0;
cell_info->attributes = NULL;
column->cell_list = g_list_append (column->cell_list, cell_info);
}
static void
gtk_tree_view_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
gboolean expand)
{
GtkTreeViewColumn *column;
GtkTreeViewColumnCellInfo *cell_info;
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (cell_layout));
column = GTK_TREE_VIEW_COLUMN (cell_layout);
g_return_if_fail (! gtk_tree_view_column_get_cell_info (column, cell));
g_object_ref (cell);
gtk_object_sink (GTK_OBJECT (cell));
cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1);
cell_info->cell = cell;
cell_info->expand = expand ? TRUE : FALSE;
cell_info->pack = GTK_PACK_END;
cell_info->has_focus = 0;
cell_info->attributes = NULL;
column->cell_list = g_list_append (column->cell_list, cell_info);
}
static void
gtk_tree_view_column_cell_layout_clear (GtkCellLayout *cell_layout)
{
GList *list;
GtkTreeViewColumn *column;
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (cell_layout));
column = GTK_TREE_VIEW_COLUMN (cell_layout);
for (list = column->cell_list; list; list = list->next)
{
GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;
gtk_tree_view_column_clear_attributes (column, info->cell);
g_object_unref (info->cell);
g_free (info);
}
g_list_free (column->cell_list);
column->cell_list = NULL;
}
static void
gtk_tree_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
const gchar *attribute,
gint column)
{
GtkTreeViewColumn *tree_column;
GtkTreeViewColumnCellInfo *info;
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (cell_layout));
tree_column = GTK_TREE_VIEW_COLUMN (cell_layout);
info = gtk_tree_view_column_get_cell_info (tree_column, cell);
g_return_if_fail (info != NULL);
info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
if (tree_column->tree_view)
_gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
}
static void
gtk_tree_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
GtkCellLayoutDataFunc func,
gpointer func_data,
GDestroyNotify destroy)
{
GtkTreeViewColumn *column;
GtkTreeViewColumnCellInfo *info;
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (cell_layout));
column = GTK_TREE_VIEW_COLUMN (cell_layout);
info = gtk_tree_view_column_get_cell_info (column, cell);
g_return_if_fail (info != NULL);
if (info->destroy)
{
GDestroyNotify d = info->destroy;
info->destroy = NULL;
d (info->func_data);
}
info->func = (GtkTreeCellDataFunc)func;
info->func_data = func_data;
info->destroy = destroy;
if (column->tree_view)
_gtk_tree_view_column_cell_set_dirty (column, TRUE);
}
static void
gtk_tree_view_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
GtkCellRenderer *cell_renderer)
{
GtkTreeViewColumn *column;
GtkTreeViewColumnCellInfo *info;
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (cell_layout));
column = GTK_TREE_VIEW_COLUMN (cell_layout);
info = gtk_tree_view_column_get_cell_info (column, cell_renderer);
gtk_tree_view_column_clear_attributes_by_info (column, info);
}
static void
gtk_tree_view_column_clear_attributes_by_info (GtkTreeViewColumn *tree_column,
GtkTreeViewColumnCellInfo *info)
{
GSList *list;
list = info->attributes;
while (list && list->next)
{
g_free (list->data);
list = list->next->next;
}
g_slist_free (info->attributes);
info->attributes = NULL;
if (tree_column->tree_view)
_gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
}
/* Helper functions
*/
@ -1246,23 +1453,7 @@ gtk_tree_view_column_pack_start (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
gboolean expand)
{
GtkTreeViewColumnCellInfo *cell_info;
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
g_return_if_fail (! gtk_tree_view_column_get_cell_info (tree_column, cell));
g_object_ref (cell);
gtk_object_sink (GTK_OBJECT (cell));
cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1);
cell_info->cell = cell;
cell_info->expand = expand ? TRUE : FALSE;
cell_info->pack = GTK_PACK_START;
cell_info->has_focus = 0;
cell_info->attributes = NULL;
tree_column->cell_list = g_list_append (tree_column->cell_list, cell_info);
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (tree_column), cell, expand);
}
/**
@ -1280,26 +1471,9 @@ gtk_tree_view_column_pack_end (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
gboolean expand)
{
GtkTreeViewColumnCellInfo *cell_info;
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
g_return_if_fail (! gtk_tree_view_column_get_cell_info (tree_column, cell));
g_object_ref (cell);
gtk_object_sink (GTK_OBJECT (cell));
cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1);
cell_info->cell = cell;
cell_info->expand = expand ? TRUE : FALSE;
cell_info->pack = GTK_PACK_END;
cell_info->has_focus = 0;
cell_info->attributes = NULL;
tree_column->cell_list = g_list_append (tree_column->cell_list, cell_info);
gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (tree_column), cell, expand);
}
/**
* gtk_tree_view_column_clear:
* @tree_column: A #GtkTreeViewColumn
@ -1309,20 +1483,7 @@ gtk_tree_view_column_pack_end (GtkTreeViewColumn *tree_column,
void
gtk_tree_view_column_clear (GtkTreeViewColumn *tree_column)
{
GList *list;
g_return_if_fail (tree_column != NULL);
for (list = tree_column->cell_list; list; list = list->next)
{
GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;
gtk_tree_view_column_clear_attributes (tree_column, info->cell);
g_object_unref (info->cell);
g_free (info);
}
g_list_free (tree_column->cell_list);
tree_column->cell_list = NULL;
gtk_cell_layout_clear (GTK_CELL_LAYOUT (tree_column));
}
/**
@ -1371,18 +1532,8 @@ gtk_tree_view_column_add_attribute (GtkTreeViewColumn *tree_column,
const gchar *attribute,
gint column)
{
GtkTreeViewColumnCellInfo *info;
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
g_return_if_fail (info != NULL);
info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
if (tree_column->tree_view)
_gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (tree_column),
cell_renderer, attribute, column);
}
static void
@ -1454,28 +1605,10 @@ gtk_tree_view_column_set_cell_data_func (GtkTreeViewColumn *tree_column,
gpointer func_data,
GtkDestroyNotify destroy)
{
GtkTreeViewColumnCellInfo *info;
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
g_return_if_fail (info != NULL);
if (info->destroy)
{
GtkDestroyNotify d = info->destroy;
info->destroy = NULL;
d (info->func_data);
}
info->func = func;
info->func_data = func_data;
info->destroy = destroy;
if (tree_column->tree_view)
_gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (tree_column),
cell_renderer,
(GtkCellLayoutDataFunc)func,
func_data, destroy);
}
@ -1491,37 +1624,10 @@ void
gtk_tree_view_column_clear_attributes (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell_renderer)
{
GtkTreeViewColumnCellInfo *info;
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
gtk_tree_view_column_clear_attributes_by_info (tree_column, info);
gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (tree_column),
cell_renderer);
}
static void
gtk_tree_view_column_clear_attributes_by_info (GtkTreeViewColumn *tree_column,
GtkTreeViewColumnCellInfo *info)
{
GSList *list;
list = info->attributes;
while (list && list->next)
{
g_free (list->data);
list = list->next->next;
}
g_slist_free (info->attributes);
info->attributes = NULL;
if (tree_column->tree_view)
_gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
}
/**
* gtk_tree_view_column_set_spacing:
* @tree_column: A #GtkTreeViewColumn.

View File

@ -28,6 +28,7 @@ gtk/gtkbbox.c
gtk/gtkbox.c
gtk/gtkbutton.c
gtk/gtkcalendar.c
gtk/gtkcelllayout.c
gtk/gtkcellrenderer.c
gtk/gtkcellrendererpixbuf.c
gtk/gtkcellrenderertext.c
@ -41,6 +42,7 @@ gtk/gtkcontainer.c
gtk/gtkcurve.c
gtk/gtkdialog.c
gtk/gtkentry.c
gtk/gtkentrycompletion.c
gtk/gtkfilesel.c
gtk/gtkfixed.c
gtk/gtkfontsel.c
@ -89,6 +91,7 @@ gtk/gtkthemes.c
gtk/gtktipsquery.c
gtk/gtktogglebutton.c
gtk/gtktoolbar.c
gtk/gtktreemodelfilter.c
gtk/gtktreemodelsort.c
gtk/gtktreeview.c
gtk/gtktreeviewcolumn.c