1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2011 Qball Cow <qball@sarine.nl>
3 * Project homepage: http://gmpc.wikia.com/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <gdk/gdkkeysyms.h>
29 #include <glib/gi18n.h>
30 #include "gmpc-mpddata-model.h"
31 #include "eggcolumnchooserdialog.h"
32 #include "gmpc-mpddata-model-playlist.h"
33 #include "gmpc-metaimage.h"
39 #define MOUSE_OFFSET 10
40 #define ENABLE_GRADIENT_LOOK 1
41 #define BACKGROUND_OPACITY 0.92
42 #define BOTTOM_GRADIENT_HEIGHT 30
48 extern GtkTargetEntry gmt_targetentries[];
53 GtkTargetEntry gmt_targetentries[] =
55 { (const gchar *)"GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP , DND_SONG}
57 static int col_ids[NUM_COLS] = {
58 MPDDATA_MODEL_COL_MARKUP,
59 MPDDATA_MODEL_COL_SONG_ARTIST, /* album name */
60 MPDDATA_MODEL_COL_SONG_ALBUM, /* album name */
61 MPDDATA_MODEL_COL_SONG_TITLE, /* song title */
62 MPDDATA_MODEL_COL_SONG_TITLEFILE, /* song title */
63 MPDDATA_MODEL_COL_SONG_GENRE, /* song genre */
64 MPDDATA_MODEL_COL_SONG_TRACK, /* song track */
65 MPDDATA_MODEL_COL_SONG_NAME, /* stream name */
66 MPDDATA_MODEL_COL_SONG_COMPOSER, /* composer name */
67 MPDDATA_MODEL_COL_SONG_PERFORMER, /* performer */
68 MPDDATA_MODEL_COL_SONG_DATE, /* date */
69 MPDDATA_MODEL_COL_SONG_LENGTH_FORMAT, /* length formatted */
70 MPDDATA_MODEL_COL_SONG_DISC, /* disc */
71 MPDDATA_MODEL_COL_SONG_COMMENT, /* comment */
72 MPDDATA_MODEL_COL_ICON_ID, /* icon id */
73 MPDDATA_MODEL_COL_SONG_POS,
74 MPDDATA_MODEL_COL_SONG_ALBUMARTIST,
75 MPDDATA_MODEL_COL_PATH_EXTENSION, /* Extension */
76 MPDDATA_MODEL_COL_PATH_DIRECTORY /* Directory */
78 static const gchar *col_names[NUM_COLS] = {
100 static gint col_enabled[NUM_COLS] = {
117 FALSE,//"AlbumArtist"
122 static gint col_position[NUM_COLS] = {
144 static GList *paste_queue = NULL;
145 #define LOG_DOMAIN "MpdData.TreeView"
148 class Gmpc:MpdData:Treeview from Gtk:Tree:View {
149 private gchar *name = {NULL} destroywith g_free;
150 private gboolean do_sort = {TRUE};
151 private GtkTreeViewColumn *columns[NUM_COLS];
153 private GtkWidget *tooltip_window = {NULL};
154 private GtkWidget *tw_image = {NULL};
155 private GtkWidget *tw_title = {NULL};
156 private GtkWidget *tw_artist = {NULL};
157 private GtkWidget *tw_album = {NULL};
158 private GtkWidget *tw_genre = {NULL};
159 private GtkWidget *tw_date = {NULL};
160 private GtkWidget *tw_length = {NULL};
161 private gchar *file = NULL;
163 private gboolean pressed = FALSE;
171 GtkWidget * new (const char *name (check null), gboolean sort, Gtk:Tree:Model *model (check type null))
173 Self *self = GET_NEW;
174 self->_priv->name = g_strdup(name);
175 self->_priv->do_sort = sort;
177 gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(self), TRUE);
178 gtk_tree_view_set_model(GTK_TREE_VIEW(self), model);
182 self_enable_tooltip(self);
183 g_signal_connect(G_OBJECT(self), "key-release-event", G_CALLBACK(self_paste_key_release_event), NULL);
187 gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(self), GDK_BUTTON1_MASK, gmt_targetentries, 1, GDK_ACTION_COPY);
188 return (GtkWidget *)self;
194 gchar *conf_size,*conf_opt = g_strdup_printf("%s-colpos", self->_priv->name);
195 GtkTreeViewColumn *col = NULL;
196 for(i = 0;i< NUM_COLS;i++)
198 int conf_pos = cfg_get_single_value_as_int_with_default(config, conf_opt,col_names[i], col_position[i]);
199 col = self_add_column(self,col_names[i],col_ids[i],conf_pos);
200 g_object_set_data(G_OBJECT(col), "id",GINT_TO_POINTER(i));
203 conf_opt = g_strdup_printf("%s-colshow", self->_priv->name);
204 conf_size = g_strdup_printf("%s-colsize", self->_priv->name);
205 for(i = 0;i< NUM_COLS;i++)
207 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(self->_priv->columns[i]), "id"));
208 int col_size= cfg_get_single_value_as_int_with_default(config, conf_size,col_names[id], 200);
209 int col_show= cfg_get_single_value_as_int_with_default(config, conf_opt,col_names[id], col_enabled[id]);
210 gtk_tree_view_column_set_visible(self->_priv->columns[i],col_show);
211 gtk_tree_view_append_column(GTK_TREE_VIEW(self), self->_priv->columns[i]);
212 /* don't set the icon column */
213 if(col_ids[id]!= MPDDATA_MODEL_COL_ICON_ID)
214 gtk_tree_view_column_set_fixed_width(self->_priv->columns[i], col_size);
216 g_signal_connect_swapped(G_OBJECT(self->_priv->columns[i]), "notify::width", G_CALLBACK(self_column_width), self);
218 /* set the last column small, to stop weird grows */
219 //for(i=NUM_COLS-1; i>=0 && !gtk_tree_view_column_get_visible(self->_priv->columns[i]);i--);
220 //gtk_tree_view_column_set_fixed_width(self->_priv->columns[i], 150);
226 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(self)), GTK_SELECTION_MULTIPLE);
227 gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(self), TRUE);
228 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(self), TRUE);
230 if(self->_priv->do_sort)
232 int sort_col = cfg_get_single_value_as_int_with_default(config, self->_priv->name, "sort-column",MPDDATA_MODEL_COL_SONG_TITLE);
233 int sort_order = cfg_get_single_value_as_int_with_default(config, self->_priv->name, "sort-order", GTK_SORT_ASCENDING);
234 if(((sort_col < MPDDATA_MODEL_N_COLUMNS && sort_col >= 0) || sort_col == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID )&& (sort_order == GTK_SORT_ASCENDING || sort_order == GTK_SORT_DESCENDING)) {
235 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(gtk_tree_view_get_model(GTK_TREE_VIEW(self))),sort_col, sort_order);
245 save_column_setup (self)
248 GList *iter,*cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(self));
249 gchar *conf_pos = NULL;
250 gchar *conf_show = NULL;
252 i = g_list_length(cols);
259 conf_pos = g_strdup_printf("%s-colpos", self->_priv->name);
260 conf_show = g_strdup_printf("%s-colshow", self->_priv->name);
261 // conf_size = g_strdup_printf("%s-colsize", self->_priv->name);
263 for(iter = cols; iter; iter = g_list_next(iter))
265 GtkTreeViewColumn *column = iter->data;
266 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "id"));
267 cfg_set_single_value_as_int(config, conf_pos, col_names[id], i);
268 cfg_set_single_value_as_int(config, conf_show, col_names[id], gtk_tree_view_column_get_visible(column));
269 /* only save width on > 0 columns */
270 //if(gtk_tree_view_column_get_width(column) > 0)
271 // cfg_set_single_value_as_int(config, conf_size, col_names[id], gtk_tree_view_column_get_width(column));
276 // q_free(conf_size);
279 if(self->_priv->do_sort)
282 GtkSortType sort_order;
283 gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(gtk_tree_view_get_model(GTK_TREE_VIEW(self))), &sort_col, &sort_order);
284 cfg_set_single_value_as_int(config, self->_priv->name, "sort-column",sort_col);
285 cfg_set_single_value_as_int(config, self->_priv->name, "sort-order", sort_order);
291 dispose (G:Object *obj)
293 Self *self = GMPC_MPDDATA_TREEVIEW(obj);
294 self_save_column_setup(self);
299 highlight_row (GtkTreeViewColumn *tree_column,
300 GtkCellRenderer *cell,
301 GtkTreeModel *tree_model,
306 if(GMPC_IS_MPDDATA_MODEL_PLAYLIST(tree_model) && gmpc_mpddata_model_playlist_is_current_song(tree_model, iter))
307 g_object_set(G_OBJECT(cell), "weight", 800,NULL);
309 g_object_set(G_OBJECT(cell), "weight", 400,NULL);
314 column_width(self, GParamSpec *argc, GtkTreeViewColumn *column)
316 if(self->_priv->pressed)
318 int width = gtk_tree_view_column_get_width(column);
319 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "id"));
320 gchar *conf_size = g_strdup_printf("%s-colsize", self->_priv->name);
321 int w = cfg_get_single_value_as_int(config, conf_size, col_names[id]);
324 cfg_set_single_value_as_int(config, conf_size, col_names[id],width);
332 add_column(self, const char *columnname, int valuerow, int position)
334 GtkCellRenderer *renderer;
335 GtkTreeViewColumn *column = NULL;
338 if(valuerow == MPDDATA_MODEL_COL_ICON_ID)
340 renderer = gtk_cell_renderer_pixbuf_new();
341 g_value_init(&value, G_TYPE_FLOAT);
342 g_value_set_float(&value, 0.0);
343 g_object_set_property(G_OBJECT(renderer), "xalign", &value);
345 column = gtk_tree_view_column_new ();
346 gtk_tree_view_column_pack_start (column, renderer, TRUE);
347 gtk_tree_view_column_set_attributes (column,renderer,"icon-name", MPDDATA_MODEL_COL_ICON_ID,NULL);
349 gtk_tree_view_column_set_resizable(column, FALSE);
350 gtk_tree_view_column_set_fixed_width(column, 20);
353 renderer = gtk_cell_renderer_text_new();
354 column = gtk_tree_view_column_new_with_attributes (_(columnname), renderer,
355 "text", valuerow,NULL);
356 g_value_init(&value, G_TYPE_INT);
357 g_value_set_int(&value, PANGO_ELLIPSIZE_END);
358 g_object_set_property(G_OBJECT(renderer), "ellipsize", &value);
359 gtk_tree_view_column_set_resizable(column, TRUE);
360 if(GMPC_IS_MPDDATA_MODEL_PLAYLIST(gtk_tree_view_get_model(GTK_TREE_VIEW(self))))
362 g_object_set(G_OBJECT(renderer), "weight-set", TRUE, NULL);
363 gtk_tree_view_column_set_cell_data_func (column,renderer,self_highlight_row, NULL, NULL);
367 gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_FIXED);
368 gtk_tree_view_column_set_reorderable(column, TRUE);
370 self->_priv->columns[position] = column;
372 if(self->_priv->do_sort)
374 gtk_tree_view_column_set_sort_column_id(column,valuerow);
375 gtk_tree_view_column_set_sort_indicator(column, TRUE);
381 * Opens a column editor
387 GtkWidget *dialog = egg_column_chooser_dialog_new(GTK_TREE_VIEW(self));
388 gtk_widget_show_all(dialog);
389 gtk_dialog_run(GTK_DIALOG(dialog));
390 self_save_column_setup(self);
395 finalize(G:Object *obj)
397 Self *self = SELF(obj);
398 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(obj));
401 gtk_tree_view_set_model(GTK_TREE_VIEW(obj),NULL);
402 g_object_unref(model);
404 if(self->_priv->tooltip_window)
406 gtk_widget_destroy(self->_priv->tooltip_window);
407 self->_priv->tooltip_window = NULL;
409 if(self->_priv->file)
411 g_free(self->_priv->file);
412 self->_priv->file = NULL;
420 private gboolean query_tooltip(self,
422 gboolean keyboard_tip,
426 GtkTreeView *treeview = GTK_TREE_VIEW(self);
427 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
429 GtkTreePath *path = NULL;
430 mpd_Song *song = NULL;
433 if(!cfg_get_single_value_as_int_with_default(config, "GmpcTreeView", "show-tooltip", TRUE))
435 if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW(treeview), &x, &y,
437 &model, &path, &iter))
441 gtk_tree_model_get(model, &iter,MPDDATA_MODEL_COL_MPDSONG, &song, -1);
445 /* makes it look a bit nicer */
446 if(self->_priv->file && song->file && strcmp(self->_priv->file, song->file))
449 g_free(self->_priv->file);self->_priv->file = NULL;
451 else if(!(self->_priv->file && song->file && strcmp(self->_priv->file, song->file) == 0))
455 gmpc_metaimage_update_cover_from_song(GMPC_METAIMAGE(self->_priv->tw_image), song);
456 if(self->_priv->file)
457 g_free(self->_priv->file);
458 self->_priv->file = NULL;
460 self->_priv->file = g_strdup(song->file);
462 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_TITLE, &temp, -1);
463 gtk_label_set_text(GTK_LABEL(self->_priv->tw_title), temp);
466 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_ARTIST,&temp, -1);
467 gtk_label_set_text(GTK_LABEL(self->_priv->tw_artist), temp);
470 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_ALBUM, &temp, -1);
471 gtk_label_set_text(GTK_LABEL(self->_priv->tw_album), temp);
474 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_GENRE, &temp, -1);
475 gtk_label_set_text(GTK_LABEL(self->_priv->tw_genre), temp);
478 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_DATE, &temp, -1);
479 gtk_label_set_text(GTK_LABEL(self->_priv->tw_date), temp);
482 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_LENGTH_FORMAT, &temp, -1);
483 gtk_label_set_text(GTK_LABEL(self->_priv->tw_length), temp);
490 gtk_tree_path_free(path);
497 tooltip_expose_event(GtkWidget *widget, GdkEventExpose *event,gpointer data)
501 int stripe_height = widget->allocation.height;// 128+8;
503 GtkStyle *style = gtk_widget_get_style(widget);
504 GdkColor *background_color = &style->base[GTK_STATE_NORMAL];
506 cairo_surface_t *surface;
508 GdkScreen *screen = gtk_window_get_screen(GTK_WINDOW(widget));
509 #ifdef ENABLE_GRADIENT_LOOK
510 cairo_pattern_t *gradient;
512 int gradient_y = widget->allocation.height - BOTTOM_GRADIENT_HEIGHT;
516 context = gdk_cairo_create(widget->window);
518 cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
519 surface = cairo_surface_create_similar(cairo_get_target(context),
520 CAIRO_CONTENT_COLOR_ALPHA,
521 widget->allocation.width,
522 widget->allocation.height);
523 cr = cairo_create(surface);
528 if (gdk_screen_is_composited(screen))
530 cairo_set_source_rgba(cr,
531 background_color->red / 65535.0,
532 background_color->green / 65535.0,
533 background_color->blue / 65535.0,
538 gdk_cairo_set_source_color(cr, background_color);
541 cairo_rectangle(cr, 0, 0,
542 widget->allocation.width,
543 widget->allocation.height);
546 #ifdef ENABLE_GRADIENT_LOOK
547 /* Add a very subtle gradient to the bottom of the notification */
548 gradient = cairo_pattern_create_linear(0, gradient_y, 0,
549 widget->allocation.height);
550 cairo_pattern_add_color_stop_rgba(gradient, 0, 0, 0, 0, 0);
551 cairo_pattern_add_color_stop_rgba(gradient, 1, 0, 0, 0, 0.15);
552 cairo_rectangle(cr, 0, gradient_y, widget->allocation.width,
553 BOTTOM_GRADIENT_HEIGHT);
554 cairo_set_source(cr, gradient);
556 cairo_pattern_destroy(gradient);
559 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
560 cairo_set_line_width(cr, 1.0);
561 cairo_rectangle(cr, 0.5, 0.5,widget->allocation.width - 0.5, widget->allocation.height - 0.5);
565 color = style->bg[GTK_STATE_SELECTED];
567 cairo_rectangle(cr, stripe_x, stripe_y, 160, stripe_height);
569 #ifdef ENABLE_GRADIENT_LOOK
570 r = color.red / 65535.0;
571 g = color.green / 65535.0;
572 b = color.blue / 65535.0;
574 gradient = cairo_pattern_create_linear(stripe_x, 0, 160, 0);
575 cairo_pattern_add_color_stop_rgba(gradient, 0, r, g, b, 1);
576 cairo_pattern_add_color_stop_rgba(gradient, 1, r, g, b, 0);
577 cairo_set_source(cr, gradient);
579 cairo_pattern_destroy(gradient);
581 gdk_cairo_set_source_color(cr, &color);
586 cairo_set_source_surface(context, surface, 0, 0);
587 cairo_paint(context);
588 cairo_surface_destroy(surface);
589 cairo_destroy(context);
591 return FALSE;//GTK_WIDGET_CLASS(parent_class)->expose_event(widget, event);
594 private void enable_tooltip(self)
596 gchar *markup = NULL;
598 GdkColormap *colormap;
599 GtkWidget *treeview = GTK_WIDGET(self);
600 GtkWidget *table = gtk_table_new(6,2, FALSE);
601 GtkWidget *vbox = gtk_hbox_new(FALSE, 0);
602 GtkWidget *label,*ali;
603 GtkSizeGroup *group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
604 self->_priv->tooltip_window = gtk_window_new(GTK_WINDOW_POPUP);
605 screen = gtk_window_get_screen(GTK_WINDOW(self->_priv->tooltip_window));
606 colormap = gdk_screen_get_rgba_colormap(screen);
608 if (colormap != NULL && gdk_screen_is_composited(screen))
610 gtk_widget_set_colormap(self->_priv->tooltip_window, colormap);
614 gtk_widget_set_size_request(GTK_WIDGET(self->_priv->tooltip_window), 3*128,-1);
616 gtk_widget_set_app_paintable(self->_priv->tooltip_window, TRUE);
617 g_signal_connect(G_OBJECT(self->_priv->tooltip_window), "expose-event", G_CALLBACK(self_tooltip_expose_event), self);
619 gtk_container_add(GTK_CONTAINER(self->_priv->tooltip_window), vbox);
620 self->_priv->tw_image = gmpc_metaimage_new(META_ALBUM_ART);
622 ali = gtk_alignment_new(0.0f, 0.0f, 0.0f, 0.0f);
623 gtk_alignment_set_padding(GTK_ALIGNMENT(ali), 4,4,4,4);
624 gtk_container_add(GTK_CONTAINER(ali), self->_priv->tw_image);
625 gmpc_metaimage_set_size(GMPC_METAIMAGE(self->_priv->tw_image), 128);
627 gtk_box_pack_start(GTK_BOX(vbox), ali, FALSE, FALSE, 0);
629 gtk_table_set_row_spacings(GTK_TABLE(table), 6);
630 gtk_table_set_col_spacings(GTK_TABLE(table), 6);
632 gtk_container_set_border_width(GTK_CONTAINER(vbox),1);
633 gtk_container_set_border_width(GTK_CONTAINER(table), 6);
635 label = gtk_label_new("");
636 gtk_size_group_add_widget(group, label);
637 markup = g_markup_printf_escaped("<b>%s:</b>", _("Title"));
638 gtk_label_set_markup(GTK_LABEL(label), markup);
640 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
641 gtk_table_attach(GTK_TABLE(table), label, 0,1,0,1,GTK_FILL, GTK_FILL,0,0);
642 self->_priv->tw_title = gtk_label_new("n/a");
643 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_title), 0.0,0.5);
644 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_title), PANGO_ELLIPSIZE_END);
645 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_title, 1,2,0,1,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
648 label = gtk_label_new("");
649 gtk_size_group_add_widget(group, label);
650 markup = g_markup_printf_escaped("<b>%s:</b>", _("Artist"));
651 gtk_label_set_markup(GTK_LABEL(label),markup);
653 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
654 gtk_table_attach(GTK_TABLE(table), label, 0,1,1,2,GTK_FILL, GTK_FILL,0,0);
655 self->_priv->tw_artist = gtk_label_new("n/a");
656 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_artist), 0.0,0.5);
657 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_artist),PANGO_ELLIPSIZE_END);
658 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_artist, 1,2,1,2,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
662 label = gtk_label_new("");
663 gtk_size_group_add_widget(group, label);
664 markup = g_markup_printf_escaped("<b>%s:</b>", _("Album"));
665 gtk_label_set_markup(GTK_LABEL(label),markup);
667 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
668 gtk_table_attach(GTK_TABLE(table), label, 0,1,2,3,GTK_FILL, GTK_FILL,0,0);
669 self->_priv->tw_album = gtk_label_new("n/a");
670 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_album), 0.0,0.5);
671 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_album),PANGO_ELLIPSIZE_END);
672 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_album, 1,2,2,3,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
674 label = gtk_label_new("");
675 gtk_size_group_add_widget(group, label);
676 markup = g_markup_printf_escaped("<b>%s:</b>", _("Genre"));
677 gtk_label_set_markup(GTK_LABEL(label), markup);
679 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
680 gtk_table_attach(GTK_TABLE(table), label, 0,1,3,4,GTK_FILL, GTK_FILL,0,0);
681 self->_priv->tw_genre = gtk_label_new("n/a");
682 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_genre), 0.0,0.5);
683 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_genre),PANGO_ELLIPSIZE_END);
684 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_genre, 1,2,3,4,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
686 label = gtk_label_new("");
687 gtk_size_group_add_widget(group, label);
688 markup = g_markup_printf_escaped("<b>%s:</b>", _("Date"));
689 gtk_label_set_markup(GTK_LABEL(label), markup);
691 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
692 gtk_table_attach(GTK_TABLE(table), label, 0,1,4,5,GTK_FILL, GTK_FILL,0,0);
693 self->_priv->tw_date = gtk_label_new("n/a");
694 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_date), 0.0,0.5);
695 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_date),PANGO_ELLIPSIZE_END);
696 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_date, 1,2,4,5,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
698 label = gtk_label_new("");
699 gtk_size_group_add_widget(group, label);
700 markup = g_markup_printf_escaped("<b>%s:</b>", _("Duration"));
701 gtk_label_set_markup(GTK_LABEL(label), markup);
703 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
704 gtk_table_attach(GTK_TABLE(table), label, 0,1,5,6,GTK_FILL, GTK_FILL,0,0);
705 self->_priv->tw_length = gtk_label_new("n/a");
706 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_length), 0.0,0.5);
707 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_length),PANGO_ELLIPSIZE_END);
708 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_length, 1,2,5,6,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
713 g_object_unref(group);
715 gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
719 g_signal_connect(G_OBJECT(treeview),
721 G_CALLBACK(self_query_tooltip),
723 gtk_widget_set_tooltip_window(treeview, GTK_WINDOW(self->_priv->tooltip_window));
724 gtk_widget_show_all(vbox);
732 * Right mouse click behaviour fix
735 gboolean click_fix (self, GdkEventButton *event)
737 GtkTreePath *path = NULL;
738 self->_priv->pressed = TRUE;
739 if(event->button == 3 && event->window != NULL && gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(self), event->x, event->y,&path,NULL,NULL,NULL))
741 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
742 if(gtk_tree_selection_path_is_selected(sel, path))
744 gtk_tree_path_free(path);
750 gtk_tree_path_free(path);
756 gboolean click_released (self, GdkEventButton *event)
758 self->_priv->pressed = FALSE;
763 enable_click_fix(self)
765 g_signal_connect(G_OBJECT(self), "button-press-event", G_CALLBACK(self_click_fix), NULL);
767 g_signal_connect(G_OBJECT(self), "button-release-event", G_CALLBACK(self_click_released), NULL);
772 signal last NONE (POINTER)
774 paste_before(self, GList *items)
778 signal last NONE (POINTER)
780 paste_after(self, const GList *items)
783 signal last NONE (NONE)
791 paste_key_release_event(self, GdkEventKey *event,gpointer data)
793 if(event->keyval == GDK_Menu) {
794 GdkEventButton bevent;
795 gboolean value = FALSE;
796 bevent.window = NULL;
798 bevent.time = event->time;
799 g_signal_emit_by_name(self, "button-press-event", &bevent, &value,NULL);
801 g_signal_emit_by_name(self, "button-release-event", &bevent, &value,NULL);
806 if (event->keyval == GDK_c && event->state&GDK_CONTROL_MASK)
808 self_paste_copy_songs(self, NULL);
813 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[PASTE_BEFORE_SIGNAL], 0, TRUE))
815 if (event->keyval == GDK_b && event->state&GDK_CONTROL_MASK)
817 self_paste_paste_before_songs(self, NULL);
823 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[PASTE_AFTER_SIGNAL], 0, TRUE))
825 if (event->keyval == GDK_v && event->state&GDK_CONTROL_MASK)
827 self_paste_paste_after_songs(self, NULL);
833 if (gtk_tree_selection_count_selected_rows (gtk_tree_view_get_selection(GTK_TREE_VIEW(self))) > 0)
835 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[CUT_SIGNAL], 0, TRUE))
837 if (event->keyval == GDK_x && event->state&GDK_CONTROL_MASK)
839 self_paste_cut_songs(self, NULL);
848 paste_cut_songs(self, GtkMenuItem *item)
850 self_paste_copy_songs(self, item);
855 paste_paste_after_songs(self, GtkMenuItem *menuitem)
857 self_paste_after(self, g_list_first(paste_queue));
859 g_list_foreach(paste_queue, (GFunc)g_free, NULL);
860 g_list_free(paste_queue);
867 paste_paste_before_songs(self, GtkMenuItem *menuitem)
869 self_paste_before(self, g_list_first(paste_queue));
871 g_list_foreach(paste_queue, (GFunc)g_free, NULL);
872 g_list_free(paste_queue);
879 paste_copy_songs(self, GtkMenuItem *menitem)
881 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(self));
882 /* free old entries */
883 g_list_foreach(paste_queue, (GFunc)g_free, NULL);
884 g_list_free(paste_queue);
886 /* check if where connected */
887 /* see if there is a row selected */
888 if (gtk_tree_selection_count_selected_rows (selection) > 0)
890 GList *list = NULL, *llist = NULL;
891 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self));
892 /* start a command list */
893 /* grab the selected songs */
894 list = gtk_tree_selection_get_selected_rows (selection, &model);
895 /* grab the last song that is selected */
896 llist = g_list_last (list);
897 /* remove every selected song one by one */
900 gtk_tree_model_get_iter (model, &iter,(GtkTreePath *) llist->data);
901 /* Trick that avoids roundtrip to mpd */
905 /* this one allready has the pos. */
906 gtk_tree_model_get (model, &iter,
907 MPDDATA_MODEL_ROW_TYPE,&type,
908 MPDDATA_MODEL_COL_PATH, &path,
910 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Copying song, into queue: %s\n", path);
911 if(type == MPD_DATA_TYPE_SONG) {
912 paste_queue = g_list_prepend(paste_queue, path);
913 } else if (type == MPD_DATA_TYPE_DIRECTORY) {
914 MpdData *data = mpd_database_get_directory_recursive(connection, path);
915 for(;data; data= mpd_data_get_next(data)){
916 if(data->type == MPD_DATA_TYPE_SONG) {
917 paste_queue = g_list_prepend(paste_queue, g_strdup(data->song->file));
921 } else if (type == MPD_DATA_TYPE_PLAYLIST) {
922 MpdData *data = mpd_database_get_playlist_content(connection, path);
923 for(;data; data= mpd_data_get_next(data)){
924 if(data->type == MPD_DATA_TYPE_SONG) {
925 paste_queue = g_list_prepend(paste_queue, g_strdup(data->song->file));
931 } while ((llist = g_list_previous (llist)));
933 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
936 paste_queue = g_list_reverse(paste_queue);
941 right_mouse_intergration(self, GtkMenu *menu)
945 GtkWidget *menu_item;
946 GtkTreeSelection *selection = NULL;
947 GtkWidget *submenu = gtk_menu_new();
948 for(i=0; i< num_plugins;i++)
950 if(gmpc_plugin_get_enabled(plugins[i]))
952 retv += gmpc_plugin_browser_song_list_option_menu(plugins[i],self, GTK_MENU(submenu));
955 /* If no submenu item was added, destroy the submenu */
956 if(!retv) gtk_widget_destroy(submenu);
958 GList *temp = gtk_container_get_children(GTK_CONTAINER(menu));
960 menu_item = gtk_separator_menu_item_new();
962 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
964 /* Add a tools menu item with the previously generated menu as submenu */
965 menu_item = gtk_menu_item_new_with_label(_("Tools"));
966 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
967 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
975 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
976 if(selection && gtk_tree_selection_count_selected_rows(selection))
978 GList *temp = gtk_container_get_children(GTK_CONTAINER(menu));
980 menu_item = gtk_separator_menu_item_new();
982 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
985 menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_COPY, NULL);
986 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
987 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_paste_copy_songs), self);
992 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[PASTE_BEFORE_SIGNAL], 0, TRUE))
994 menu_item = gtk_image_menu_item_new_with_label(_("Paste before"));
995 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
996 gtk_image_new_from_stock(GTK_STOCK_PASTE, GTK_ICON_SIZE_MENU));
997 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
998 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_paste_paste_before_songs), self);
1001 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[PASTE_AFTER_SIGNAL], 0, TRUE))
1003 menu_item = gtk_image_menu_item_new_with_label(_("Paste after"));
1004 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
1005 gtk_image_new_from_stock(GTK_STOCK_PASTE, GTK_ICON_SIZE_MENU));
1006 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1007 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_paste_paste_after_songs), self);
1012 if (gtk_tree_selection_count_selected_rows (gtk_tree_view_get_selection(GTK_TREE_VIEW(self))) > 0)
1014 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[CUT_SIGNAL], 0, TRUE))
1016 menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CUT,NULL);
1017 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
1018 gtk_image_new_from_stock(GTK_STOCK_PASTE, GTK_ICON_SIZE_MENU));
1019 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1020 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_paste_cut_songs), self);
1026 GList *temp = gtk_container_get_children(GTK_CONTAINER(menu));
1028 menu_item = gtk_separator_menu_item_new();
1029 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1035 menu_item = gtk_image_menu_item_new_with_label(_("Edit Columns"));
1036 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
1037 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_edit_columns), self);
1038 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1050 g_list_foreach(paste_queue, (GFunc)g_free, NULL);
1051 g_list_free(paste_queue);
1057 /* vim: set noexpandtab ts=4 sw=4 sts=4 tw=120: */