st-stream-view.c

来自「linux下网络收音机的源码」· C语言 代码 · 共 988 行 · 第 1/2 页

C
988
字号
/* * Copyright (c) 2003, 2004 Jean-Yves Lefort * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of Jean-Yves Lefort nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include <string.h>#include <glib/gi18n.h>#include <gdk/gdkkeysyms.h>#include "sg-util.h"#include "st-handler.h"#include "st-handler-field.h"#include "st-stream-api.h"#include "st-stream-view.h"#include "st-stream-menu-items.h"#include "st-stock.h"#include "st-shell.h"#include "st-stream-bag.h"#include "st-stream-store.h"#define N_VISIBLE_STOCK_COLUMNS		1/*** type definitions ********************************************************/enum {  SELECTION_CHANGED,  LAST_SIGNAL};enum {  PROP_0,  PROP_HANDLER};    struct _STStreamViewPrivate{  STHandler		*handler;  GtkWidget		*menu;  STStreamMenuItems	*menu_items;};  /*** variable declarations ***************************************************/static GObjectClass *parent_class = NULL;static unsigned int stream_view_signals[LAST_SIGNAL] = { 0 };/*** function declarations ***************************************************/static void st_stream_view_init		(STStreamView		*view);static void st_stream_view_class_init	(STStreamViewClass	*class);static void st_stream_view_finalize	(GObject		*object);static GObject *st_stream_view_constructor (GType type,					    unsigned int n_construct_properties,					    GObjectConstructParam *construct_params);static void st_stream_view_set_property (GObject	*object,					 unsigned int	prop_id,					 const GValue	*value,					 GParamSpec	*pspec);static gboolean st_stream_view_column_drop_cb (GtkTreeView *view,					       GtkTreeViewColumn *column,					       GtkTreeViewColumn *prev_column,					       GtkTreeViewColumn *next_column,					       gpointer data);static void st_stream_view_construct_columns		(STStreamView *view);static void st_stream_view_column_add_field	(GtkTreeViewColumn *column,						 STHandlerField    *field,						 int               column_id);static void st_stream_view_construct_column_menu  (STStreamView       *view,						   GtkTreeViewColumn  *column);static gboolean st_stream_view_column_popup_menu_h (GtkWidget *widget,						    gpointer user_data);static gboolean st_stream_view_column_button_press_event_h (GtkWidget *widget,							    GdkEventButton *button,							    gpointer user_data);static void st_stream_view_column_notify_visible_h	(GObject      *object,							 GParamSpec   *pspec,							 gpointer     data);static void st_stream_view_column_notify_width_h	(GObject      *object,							 GParamSpec   *pspec,							 gpointer     data);static void st_stream_view_column_hide_activate_h	(GtkMenuItem  *item,							 gpointer     data);static void st_stream_view_column_show_all_activate_h	(GtkMenuItem  *item,							 gpointer     data);static void st_stream_view_column_stream_columns_activate_h (GtkMenuItem *item,							     gpointer    data);static void st_stream_view_selection_changed_h	(GtkTreeSelection     *selection,						 gpointer	      user_data);static void st_stream_view_columns_changed_h	(GtkTreeView          *view,						 gpointer             user_data);static void st_stream_view_destroy_h		(GtkObject            *object,						 gpointer             user_data);static void	st_stream_view_order_columns       (STStreamView      *view);static gboolean	st_stream_view_get_first_selection (STStreamView      *view,						    GtkTreeIter       *iter);static gboolean	st_stream_view_model_iter_move     (GtkTreeModel      *model,						    GtkTreeIter       *iter,						    sGtkDirection     direction,						    gboolean          wrap_around,						    gboolean          *edge_hit);/*** implementation **********************************************************/GTypest_stream_view_get_type (void){  static GType stream_view_type = 0;    if (! stream_view_type)    {      static const GTypeInfo stream_view_info = {	sizeof(STStreamViewClass),	NULL,	NULL,	(GClassInitFunc) st_stream_view_class_init,	NULL,	NULL,	sizeof(STStreamView),	0,	(GInstanceInitFunc) st_stream_view_init,      };            stream_view_type = g_type_register_static(GTK_TYPE_TREE_VIEW,						"STStreamView",						&stream_view_info,						0);    }  return stream_view_type;}static voidst_stream_view_class_init (STStreamViewClass *class){  GObjectClass *object_class = G_OBJECT_CLASS(class);  parent_class = g_type_class_peek_parent(class);  g_type_class_add_private(class, sizeof(STStreamViewPrivate));  object_class->finalize = st_stream_view_finalize;  object_class->constructor = st_stream_view_constructor;  object_class->set_property = st_stream_view_set_property;  g_object_class_install_property(object_class,				  PROP_HANDLER,				  g_param_spec_pointer("handler",						       NULL,						       NULL,						       G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));  stream_view_signals[SELECTION_CHANGED] = g_signal_new("selection-changed",							ST_TYPE_STREAM_VIEW,							G_SIGNAL_RUN_LAST,							G_STRUCT_OFFSET(STStreamViewClass, selection_changed),							NULL,							NULL,							g_cclosure_marshal_VOID__VOID,							G_TYPE_NONE,							0);}static voidst_stream_view_init (STStreamView *view){  view->priv = G_TYPE_INSTANCE_GET_PRIVATE(view, ST_TYPE_STREAM_VIEW, STStreamViewPrivate);}static voidst_stream_view_finalize (GObject *object){  STStreamView *view = ST_STREAM_VIEW(object);  if (view->priv->menu)    gtk_widget_destroy(view->priv->menu);  if (view->priv->menu_items)    st_stream_menu_items_free(view->priv->menu_items);  parent_class->finalize(object);}static GObject *st_stream_view_constructor (GType type,			    unsigned int n_construct_properties,			    GObjectConstructParam *construct_params){  GObject *object;   STStreamView *view;  GtkTreeSelection *selection;  object = parent_class->constructor(type, n_construct_properties, construct_params);  view = ST_STREAM_VIEW(object);  gtk_tree_view_set_enable_search(GTK_TREE_VIEW(view), TRUE);  gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(view),				      st_stream_store_search_equal_func,				      NULL,				      NULL);  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));  gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);  g_signal_connect(selection,		   "changed",		   G_CALLBACK(st_stream_view_selection_changed_h),		   view);  st_stream_view_construct_columns(view);  st_stream_view_order_columns(view);  g_object_connect(view,		   "signal::columns-changed", st_stream_view_columns_changed_h, NULL,		   "signal::destroy", st_stream_view_destroy_h, NULL,		   NULL);  gtk_tree_view_set_column_drag_function(GTK_TREE_VIEW(view),					 st_stream_view_column_drop_cb,					 NULL,					 NULL);  return object;}static voidst_stream_view_set_property (GObject *object,			     unsigned int prop_id,			     const GValue *value,			     GParamSpec *pspec){  STStreamView *view = ST_STREAM_VIEW(object);  switch (prop_id)    {    case PROP_HANDLER:      view->priv->handler = g_value_get_pointer(value);      break;    default:      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);      break;    }}static gbooleanst_stream_view_column_drop_cb (GtkTreeView *view,			       GtkTreeViewColumn *column,			       GtkTreeViewColumn *prev_column,			       GtkTreeViewColumn *next_column,			       gpointer data){  STHandlerField *prev_field;  STHandlerField *next_field;  prev_field = prev_column ? st_stream_view_column_get_field(prev_column) : NULL;  next_field = next_column ? st_stream_view_column_get_field(next_column) : NULL;  /*   * Do not allow to move between two stock columns, or between a   * stock column and an edge (we recognize stock columns because they   * have no associated STHandlerField).   */  return prev_field || next_field;}static voidst_stream_view_construct_columns (STStreamView *view){  GSList *l;  int vi = ST_STREAM_STORE_N_STOCK_COLUMNS; /* visible iterator */  GtkCellRenderer *renderer;  GtkTreeViewColumn *column;  GSList *pending_fields = NULL;  g_return_if_fail(ST_IS_STREAM_VIEW(view));  renderer = gtk_cell_renderer_pixbuf_new();  column = gtk_tree_view_column_new_with_attributes(NULL, renderer,						    "stock-id", ST_STREAM_STORE_COLUMN_STOCK_ID,						    "pixbuf", ST_STREAM_STORE_COLUMN_PIXBUF,						    NULL);  gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);  SG_LIST_FOREACH(l, st_handler_get_fields(view->priv->handler))    {      STHandlerField *field = l->data;      if (ST_HANDLER_FIELD_IS_VISIBLE(field))	{	  if (ST_HANDLER_FIELD_HAS_DEDICATED_COLUMN(field))	    {	      GSList *m;	      int pi = vi - g_slist_length(pending_fields); /* pending iterator */	      int width;      	      column = gtk_tree_view_column_new();	      SG_LIST_FOREACH(m, pending_fields)		st_stream_view_column_add_field(column, m->data, pi++);	      g_slist_free(pending_fields);	      pending_fields = NULL;	      st_stream_view_column_add_field(column, field, vi);	      gtk_tree_view_column_set_title(column, st_handler_field_get_label(field));	      gtk_tree_view_column_set_visible(column, st_handler_field_get_user_visible(field));	      gtk_tree_view_column_set_sort_column_id(column, vi);	      gtk_tree_view_column_set_resizable(column, TRUE);	      gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);	      gtk_tree_view_column_set_reorderable(column, TRUE);	      g_object_set_data(G_OBJECT(column), "field", field);	      width = st_handler_field_get_width(field);	      /* width == 0 only if loaded from an old config file */	      gtk_tree_view_column_set_fixed_width(column, width > 0 ? width : ST_HANDLER_FIELD_DEFAULT_WIDTH);	      gtk_tree_view_append_column(GTK_TREE_VIEW(view), column);	      st_stream_view_construct_column_menu(view, column);	      g_object_connect(column,			       "signal::notify::visible", st_stream_view_column_notify_visible_h, NULL,			       "signal::notify::width", st_stream_view_column_notify_width_h, NULL,			       NULL);	    }	  else	    pending_fields = g_slist_append(pending_fields, field);	  vi++;	}    }  g_slist_free(pending_fields);  pending_fields = NULL;}static voidst_stream_view_column_add_field (GtkTreeViewColumn *column,				 STHandlerField *field,				 int column_id){  GType type;  GtkCellRenderer *renderer;  const char *property;  gboolean expand;  g_return_if_fail(GTK_IS_TREE_VIEW_COLUMN(column));  g_return_if_fail(field != NULL);  type = st_handler_field_get_type(field);  if (type == GDK_TYPE_PIXBUF)    {      renderer = gtk_cell_renderer_pixbuf_new();      property = "pixbuf";      expand = FALSE;    }  else    {      renderer = gtk_cell_renderer_text_new();      property = "text";      expand = TRUE;    }  gtk_tree_view_column_pack_start(column, renderer, expand);  gtk_tree_view_column_set_attributes(column, renderer, property, column_id, NULL);}static voidst_stream_view_construct_column_menu (STStreamView *view,				      GtkTreeViewColumn *column){  GtkWidget *menu;  GtkWidget *hide;  GtkWidget *show_all;  GtkWidget *separator;  GtkWidget *stream_columns;    g_return_if_fail(ST_IS_STREAM_VIEW(view));  g_return_if_fail(GTK_IS_TREE_VIEW_COLUMN(column));  g_return_if_fail(GTK_IS_WIDGET(column->button));  menu = gtk_menu_new();  hide = gtk_image_menu_item_new_from_stock(ST_STOCK_HIDE_THIS_COLUMN, NULL);  show_all = gtk_image_menu_item_new_from_stock(ST_STOCK_SHOW_ALL_COLUMNS, NULL);  separator = gtk_separator_menu_item_new();  stream_columns = gtk_image_menu_item_new_from_stock(ST_STOCK_STREAM_COLUMNS, NULL);  gtk_widget_show(hide);  gtk_widget_show(show_all);  gtk_widget_show(separator);  gtk_widget_show(stream_columns);    gtk_menu_shell_append(GTK_MENU_SHELL(menu), hide);  gtk_menu_shell_append(GTK_MENU_SHELL(menu), show_all);  gtk_menu_shell_append(GTK_MENU_SHELL(menu), separator);  gtk_menu_shell_append(GTK_MENU_SHELL(menu), stream_columns);  g_object_set_data_full(G_OBJECT(column), "menu", menu, (GDestroyNotify) gtk_widget_destroy);  g_signal_connect(hide,		   "activate",		   G_CALLBACK(st_stream_view_column_hide_activate_h),		   column);  g_signal_connect(show_all,		   "activate",		   G_CALLBACK(st_stream_view_column_show_all_activate_h),		   view);  g_signal_connect(stream_columns,		   "activate",		   G_CALLBACK(st_stream_view_column_stream_columns_activate_h),		   view);  g_object_connect(column->button,		   "signal::popup-menu", st_stream_view_column_popup_menu_h, column,		   "signal::button-press-event", st_stream_view_column_button_press_event_h, column,		   NULL);}static gbooleanst_stream_view_column_popup_menu_h (GtkWidget *widget, gpointer user_data){  GtkTreeViewColumn *column = user_data;  GtkMenu *menu = g_object_get_data(G_OBJECT(column), "menu");  gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time());    return TRUE;			/* a menu was activated */}static gbooleanst_stream_view_column_button_press_event_h (GtkWidget *widget,					    GdkEventButton *event,					    gpointer user_data){  if (event->button == 3 && event->type == GDK_BUTTON_PRESS)    {      GtkTreeViewColumn *column = user_data;      GtkMenu *menu = g_object_get_data(G_OBJECT(column), "menu");      /* workaround for http://bugzilla.gnome.org/show_bug.cgi?id=159640 */      column->maybe_reordered = FALSE;      gtk_menu_popup(menu,		     NULL,		     NULL,		     NULL,		     NULL,		     event->button,		     event->time);    }  return FALSE;			/* propagate event */}static voidst_stream_view_column_notify_visible_h (GObject *object,					GParamSpec *pspec,					gpointer data){  STHandlerField *field = st_stream_view_column_get_field(GTK_TREE_VIEW_COLUMN(object));

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?