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 + -
显示快捷键?