1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
3 * Project homepage: http://gmpclient.org/
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 { (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 */
77 MPDDATA_MODEL_COL_SONG_PRIORITY,
79 static const gchar *col_names[NUM_COLS] = {
102 static gint col_enabled[NUM_COLS] = {
119 FALSE,//"AlbumArtist"
125 static gint col_position[NUM_COLS] = {
148 static GList *paste_queue = NULL;
149 #define LOG_DOMAIN "MpdData.TreeView"
152 class Gmpc:MpdData:Treeview from Gtk:Tree:View {
153 private gchar *name = {NULL} destroywith g_free;
154 private gboolean do_sort = {TRUE};
155 private GtkTreeViewColumn *columns[NUM_COLS];
157 private GtkWidget *tooltip_window = {NULL};
158 private GtkWidget *tw_image = {NULL};
159 private GtkWidget *tw_title = {NULL};
160 private GtkWidget *tw_artist = {NULL};
161 private GtkWidget *tw_album = {NULL};
162 private GtkWidget *tw_genre = {NULL};
163 private GtkWidget *tw_date = {NULL};
164 private GtkWidget *tw_length = {NULL};
165 private gchar *file = NULL;
167 private gboolean pressed = FALSE;
175 GtkWidget * new (const char *name (check null), gboolean sort, Gtk:Tree:Model *model (check type null))
177 Self *self = GET_NEW;
178 self->_priv->name = g_strdup(name);
179 self->_priv->do_sort = sort;
181 gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(self), TRUE);
182 gtk_tree_view_set_model(GTK_TREE_VIEW(self), model);
186 self_enable_tooltip(self);
187 g_signal_connect(G_OBJECT(self), "key-release-event", G_CALLBACK(self_paste_key_release_event), NULL);
191 gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(self), GDK_BUTTON1_MASK, gmt_targetentries, 1, GDK_ACTION_COPY);
192 return (GtkWidget *)self;
198 gchar *conf_size,*conf_opt = g_strdup_printf("%s-colpos", self->_priv->name);
199 GtkTreeViewColumn *col = NULL;
200 for(i = 0;i< NUM_COLS;i++)
202 int conf_pos = cfg_get_single_value_as_int_with_default(config, conf_opt,col_names[i], col_position[i]);
203 col = self_add_column(self,col_names[i],col_ids[i],conf_pos);
204 g_object_set_data(G_OBJECT(col), "id",GINT_TO_POINTER(i));
207 conf_opt = g_strdup_printf("%s-colshow", self->_priv->name);
208 conf_size = g_strdup_printf("%s-colsize", self->_priv->name);
209 for(i = 0;i< NUM_COLS;i++)
211 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(self->_priv->columns[i]), "id"));
212 int col_size= cfg_get_single_value_as_int_with_default(config, conf_size,col_names[id], 200);
213 int col_show= cfg_get_single_value_as_int_with_default(config, conf_opt,col_names[id], col_enabled[id]);
214 gtk_tree_view_column_set_visible(self->_priv->columns[i],col_show);
215 gtk_tree_view_append_column(GTK_TREE_VIEW(self), self->_priv->columns[i]);
216 /* don't set the icon column */
217 if(col_ids[id]!= MPDDATA_MODEL_COL_ICON_ID)
218 gtk_tree_view_column_set_fixed_width(self->_priv->columns[i], col_size);
220 g_signal_connect_swapped(G_OBJECT(self->_priv->columns[i]), "notify::width", G_CALLBACK(self_column_width), self);
222 /* set the last column small, to stop weird grows */
223 //for(i=NUM_COLS-1; i>=0 && !gtk_tree_view_column_get_visible(self->_priv->columns[i]);i--);
224 //gtk_tree_view_column_set_fixed_width(self->_priv->columns[i], 150);
230 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(self)), GTK_SELECTION_MULTIPLE);
231 gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(self), TRUE);
232 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(self), TRUE);
234 if(self->_priv->do_sort)
236 int sort_col = cfg_get_single_value_as_int_with_default(config, self->_priv->name, "sort-column",MPDDATA_MODEL_COL_SONG_TITLE);
237 int sort_order = cfg_get_single_value_as_int_with_default(config, self->_priv->name, "sort-order", GTK_SORT_ASCENDING);
238 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)) {
239 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(gtk_tree_view_get_model(GTK_TREE_VIEW(self))),sort_col, sort_order);
249 save_column_setup (self)
252 GList *iter,*cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(self));
253 gchar *conf_pos = NULL;
254 gchar *conf_show = NULL;
256 i = g_list_length(cols);
263 conf_pos = g_strdup_printf("%s-colpos", self->_priv->name);
264 conf_show = g_strdup_printf("%s-colshow", self->_priv->name);
265 // conf_size = g_strdup_printf("%s-colsize", self->_priv->name);
267 for(iter = cols; iter; iter = g_list_next(iter))
269 GtkTreeViewColumn *column = iter->data;
270 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "id"));
271 cfg_set_single_value_as_int(config, conf_pos, col_names[id], i);
272 cfg_set_single_value_as_int(config, conf_show, col_names[id], gtk_tree_view_column_get_visible(column));
273 /* only save width on > 0 columns */
274 //if(gtk_tree_view_column_get_width(column) > 0)
275 // cfg_set_single_value_as_int(config, conf_size, col_names[id], gtk_tree_view_column_get_width(column));
280 // q_free(conf_size);
283 if(self->_priv->do_sort)
286 GtkSortType sort_order;
287 gtk_tree_sortable_get_sort_column_id(GTK_TREE_SORTABLE(gtk_tree_view_get_model(GTK_TREE_VIEW(self))), &sort_col, &sort_order);
288 cfg_set_single_value_as_int(config, self->_priv->name, "sort-column",sort_col);
289 cfg_set_single_value_as_int(config, self->_priv->name, "sort-order", sort_order);
295 dispose (G:Object *obj)
297 Self *self = GMPC_MPDDATA_TREEVIEW(obj);
298 self_save_column_setup(self);
303 highlight_row (GtkTreeViewColumn *tree_column,
304 GtkCellRenderer *cell,
305 GtkTreeModel *tree_model,
310 if(GMPC_IS_MPDDATA_MODEL_PLAYLIST(tree_model) && gmpc_mpddata_model_playlist_is_current_song(tree_model, iter))
311 g_object_set(G_OBJECT(cell), "weight", 800,NULL);
313 g_object_set(G_OBJECT(cell), "weight", 400,NULL);
318 column_width(self, GParamSpec *argc, GtkTreeViewColumn *column)
320 if(self->_priv->pressed)
322 int width = gtk_tree_view_column_get_width(column);
323 int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "id"));
324 gchar *conf_size = g_strdup_printf("%s-colsize", self->_priv->name);
325 int w = cfg_get_single_value_as_int(config, conf_size, col_names[id]);
328 cfg_set_single_value_as_int(config, conf_size, col_names[id],width);
336 add_column(self, const char *columnname, int valuerow, int position)
338 GtkCellRenderer *renderer;
339 GtkTreeViewColumn *column = NULL;
342 if(valuerow == MPDDATA_MODEL_COL_ICON_ID)
344 renderer = gtk_cell_renderer_pixbuf_new();
345 g_value_init(&value, G_TYPE_FLOAT);
346 g_value_set_float(&value, 0.0);
347 g_object_set_property(G_OBJECT(renderer), "xalign", &value);
349 column = gtk_tree_view_column_new ();
350 gtk_tree_view_column_pack_start (column, renderer, TRUE);
351 gtk_tree_view_column_set_attributes (column,renderer,"icon-name", MPDDATA_MODEL_COL_ICON_ID,NULL);
353 gtk_tree_view_column_set_resizable(column, FALSE);
354 gtk_tree_view_column_set_fixed_width(column, 20);
357 renderer = gtk_cell_renderer_text_new();
358 column = gtk_tree_view_column_new_with_attributes (_(columnname), renderer,
359 "text", valuerow,NULL);
360 g_value_init(&value, G_TYPE_INT);
361 g_value_set_int(&value, PANGO_ELLIPSIZE_END);
362 g_object_set_property(G_OBJECT(renderer), "ellipsize", &value);
363 gtk_tree_view_column_set_resizable(column, TRUE);
364 if(GMPC_IS_MPDDATA_MODEL_PLAYLIST(gtk_tree_view_get_model(GTK_TREE_VIEW(self))))
366 g_object_set(G_OBJECT(renderer), "weight-set", TRUE, NULL);
367 gtk_tree_view_column_set_cell_data_func (column,renderer,self_highlight_row, NULL, NULL);
371 gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_FIXED);
372 gtk_tree_view_column_set_reorderable(column, TRUE);
374 self->_priv->columns[position] = column;
376 if(self->_priv->do_sort)
378 gtk_tree_view_column_set_sort_column_id(column,valuerow);
379 gtk_tree_view_column_set_sort_indicator(column, TRUE);
385 * Opens a column editor
391 GtkWidget *dialog = egg_column_chooser_dialog_new(GTK_TREE_VIEW(self));
392 gtk_widget_show_all(dialog);
393 gtk_dialog_run(GTK_DIALOG(dialog));
394 self_save_column_setup(self);
399 finalize(G:Object *obj)
401 Self *self = SELF(obj);
402 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(obj));
405 gtk_tree_view_set_model(GTK_TREE_VIEW(obj),NULL);
406 g_object_unref(model);
408 if(self->_priv->tooltip_window)
410 gtk_widget_destroy(self->_priv->tooltip_window);
411 self->_priv->tooltip_window = NULL;
413 if(self->_priv->file)
415 g_free(self->_priv->file);
416 self->_priv->file = NULL;
424 private gboolean query_tooltip(self,
426 gboolean keyboard_tip,
430 GtkTreeView *treeview = GTK_TREE_VIEW(self);
431 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
433 GtkTreePath *path = NULL;
434 mpd_Song *song = NULL;
437 if(!cfg_get_single_value_as_int_with_default(config, "GmpcTreeView", "show-tooltip", TRUE))
439 if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW(treeview), &x, &y,
441 &model, &path, &iter))
445 gtk_tree_model_get(model, &iter,MPDDATA_MODEL_COL_MPDSONG, &song, -1);
449 /* makes it look a bit nicer */
450 if(self->_priv->file && song->file && strcmp(self->_priv->file, song->file))
453 g_free(self->_priv->file);self->_priv->file = NULL;
455 else if(!(self->_priv->file && song->file && strcmp(self->_priv->file, song->file) == 0))
459 gmpc_metaimage_update_cover_from_song(GMPC_METAIMAGE(self->_priv->tw_image), song);
460 if(self->_priv->file)
461 g_free(self->_priv->file);
462 self->_priv->file = NULL;
464 self->_priv->file = g_strdup(song->file);
466 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_TITLE, &temp, -1);
467 gtk_label_set_text(GTK_LABEL(self->_priv->tw_title), temp);
470 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_ARTIST,&temp, -1);
471 gtk_label_set_text(GTK_LABEL(self->_priv->tw_artist), temp);
474 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_ALBUM, &temp, -1);
475 gtk_label_set_text(GTK_LABEL(self->_priv->tw_album), temp);
478 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_GENRE, &temp, -1);
479 gtk_label_set_text(GTK_LABEL(self->_priv->tw_genre), temp);
482 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_DATE, &temp, -1);
483 gtk_label_set_text(GTK_LABEL(self->_priv->tw_date), temp);
486 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_LENGTH_FORMAT, &temp, -1);
487 gtk_label_set_text(GTK_LABEL(self->_priv->tw_length), temp);
494 gtk_tree_path_free(path);
501 tooltip_draw (GtkWidget *widget, cairo_t *context,gpointer data)
505 GtkAllocation allocation;
507 GtkStyle *style = gtk_widget_get_style(widget);
508 GdkColor *background_color = &style->base[GTK_STATE_NORMAL];
509 cairo_surface_t *surface;
511 GdkScreen *screen = gtk_window_get_screen(GTK_WINDOW(widget));
512 gtk_widget_get_allocation(widget, &allocation);
513 int stripe_height = allocation.height;// 128+8;
514 #ifdef ENABLE_GRADIENT_LOOK
515 cairo_pattern_t *gradient;
517 int gradient_y = allocation.height - BOTTOM_GRADIENT_HEIGHT;
522 cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
523 surface = cairo_surface_create_similar(cairo_get_target(context),
524 CAIRO_CONTENT_COLOR_ALPHA,
527 cr = cairo_create(surface);
532 if (gdk_screen_is_composited(screen))
534 cairo_set_source_rgba(cr,
535 background_color->red / 65535.0,
536 background_color->green / 65535.0,
537 background_color->blue / 65535.0,
542 gdk_cairo_set_source_color(cr, background_color);
545 cairo_rectangle(cr, 0, 0,
550 #ifdef ENABLE_GRADIENT_LOOK
551 /* Add a very subtle gradient to the bottom of the notification */
552 gradient = cairo_pattern_create_linear(0, gradient_y, 0,
554 cairo_pattern_add_color_stop_rgba(gradient, 0, 0, 0, 0, 0);
555 cairo_pattern_add_color_stop_rgba(gradient, 1, 0, 0, 0, 0.15);
556 cairo_rectangle(cr, 0, gradient_y, allocation.width,
557 BOTTOM_GRADIENT_HEIGHT);
558 cairo_set_source(cr, gradient);
560 cairo_pattern_destroy(gradient);
563 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
564 cairo_set_line_width(cr, 1.0);
565 cairo_rectangle(cr, 0.5, 0.5,allocation.width - 0.5, allocation.height - 0.5);
569 color = style->bg[GTK_STATE_SELECTED];
571 cairo_rectangle(cr, stripe_x, stripe_y, 160, stripe_height);
573 #ifdef ENABLE_GRADIENT_LOOK
574 r = color.red / 65535.0;
575 g = color.green / 65535.0;
576 b = color.blue / 65535.0;
578 gradient = cairo_pattern_create_linear(stripe_x, 0, 160, 0);
579 cairo_pattern_add_color_stop_rgba(gradient, 0, r, g, b, 1);
580 cairo_pattern_add_color_stop_rgba(gradient, 1, r, g, b, 0);
581 cairo_set_source(cr, gradient);
583 cairo_pattern_destroy(gradient);
585 gdk_cairo_set_source_color(cr, &color);
590 cairo_set_source_surface(context, surface, 0, 0);
591 cairo_paint(context);
592 cairo_surface_destroy(surface);
594 return FALSE;//GTK_WIDGET_CLASS(parent_class)->expose_event(widget, event);
597 private void enable_tooltip(self)
599 gchar *markup = NULL;
601 // GdkColormap *colormap;
602 GtkWidget *treeview = GTK_WIDGET(self);
603 GtkWidget *table = gtk_table_new(6,2, FALSE);
604 GtkWidget *vbox = gtk_hbox_new(FALSE, 0);
605 GtkWidget *label,*ali;
606 GtkSizeGroup *group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
607 self->_priv->tooltip_window = gtk_window_new(GTK_WINDOW_POPUP);
608 screen = gtk_window_get_screen(GTK_WINDOW(self->_priv->tooltip_window));
610 //colormap = gdk_screen_get_rgba_colormap(screen);
612 if (colormap != NULL && gdk_screen_is_composited(screen))
614 gtk_widget_set_colormap(self->_priv->tooltip_window, colormap);
618 gtk_widget_set_size_request(GTK_WIDGET(self->_priv->tooltip_window), 3*128,-1);
620 gtk_widget_set_app_paintable(self->_priv->tooltip_window, TRUE);
621 g_signal_connect(G_OBJECT(self->_priv->tooltip_window), "draw", G_CALLBACK(self_tooltip_draw), self);
623 gtk_container_add(GTK_CONTAINER(self->_priv->tooltip_window), vbox);
624 self->_priv->tw_image = gmpc_metaimage_new(META_ALBUM_ART);
626 ali = gtk_alignment_new(0.0f, 0.0f, 0.0f, 0.0f);
627 gtk_alignment_set_padding(GTK_ALIGNMENT(ali), 4,4,4,4);
628 gtk_container_add(GTK_CONTAINER(ali), self->_priv->tw_image);
629 gmpc_metaimage_set_size(GMPC_METAIMAGE(self->_priv->tw_image), 128);
631 gtk_box_pack_start(GTK_BOX(vbox), ali, FALSE, FALSE, 0);
633 gtk_table_set_row_spacings(GTK_TABLE(table), 6);
634 gtk_table_set_col_spacings(GTK_TABLE(table), 6);
636 gtk_container_set_border_width(GTK_CONTAINER(vbox),1);
637 gtk_container_set_border_width(GTK_CONTAINER(table), 6);
639 label = gtk_label_new("");
640 gtk_size_group_add_widget(group, label);
641 markup = g_markup_printf_escaped("<b>%s:</b>", _("Title"));
642 gtk_label_set_markup(GTK_LABEL(label), markup);
644 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
645 gtk_table_attach(GTK_TABLE(table), label, 0,1,0,1,GTK_FILL, GTK_FILL,0,0);
646 self->_priv->tw_title = gtk_label_new("n/a");
647 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_title), 0.0,0.5);
648 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_title), PANGO_ELLIPSIZE_END);
649 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_title, 1,2,0,1,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
652 label = gtk_label_new("");
653 gtk_size_group_add_widget(group, label);
654 markup = g_markup_printf_escaped("<b>%s:</b>", _("Artist"));
655 gtk_label_set_markup(GTK_LABEL(label),markup);
657 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
658 gtk_table_attach(GTK_TABLE(table), label, 0,1,1,2,GTK_FILL, GTK_FILL,0,0);
659 self->_priv->tw_artist = gtk_label_new("n/a");
660 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_artist), 0.0,0.5);
661 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_artist),PANGO_ELLIPSIZE_END);
662 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_artist, 1,2,1,2,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
666 label = gtk_label_new("");
667 gtk_size_group_add_widget(group, label);
668 markup = g_markup_printf_escaped("<b>%s:</b>", _("Album"));
669 gtk_label_set_markup(GTK_LABEL(label),markup);
671 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
672 gtk_table_attach(GTK_TABLE(table), label, 0,1,2,3,GTK_FILL, GTK_FILL,0,0);
673 self->_priv->tw_album = gtk_label_new("n/a");
674 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_album), 0.0,0.5);
675 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_album),PANGO_ELLIPSIZE_END);
676 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_album, 1,2,2,3,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
678 label = gtk_label_new("");
679 gtk_size_group_add_widget(group, label);
680 markup = g_markup_printf_escaped("<b>%s:</b>", _("Genre"));
681 gtk_label_set_markup(GTK_LABEL(label), markup);
683 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
684 gtk_table_attach(GTK_TABLE(table), label, 0,1,3,4,GTK_FILL, GTK_FILL,0,0);
685 self->_priv->tw_genre = gtk_label_new("n/a");
686 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_genre), 0.0,0.5);
687 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_genre),PANGO_ELLIPSIZE_END);
688 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_genre, 1,2,3,4,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
690 label = gtk_label_new("");
691 gtk_size_group_add_widget(group, label);
692 markup = g_markup_printf_escaped("<b>%s:</b>", _("Date"));
693 gtk_label_set_markup(GTK_LABEL(label), markup);
695 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
696 gtk_table_attach(GTK_TABLE(table), label, 0,1,4,5,GTK_FILL, GTK_FILL,0,0);
697 self->_priv->tw_date = gtk_label_new("n/a");
698 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_date), 0.0,0.5);
699 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_date),PANGO_ELLIPSIZE_END);
700 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_date, 1,2,4,5,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
702 label = gtk_label_new("");
703 gtk_size_group_add_widget(group, label);
704 markup = g_markup_printf_escaped("<b>%s:</b>", _("Duration"));
705 gtk_label_set_markup(GTK_LABEL(label), markup);
707 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
708 gtk_table_attach(GTK_TABLE(table), label, 0,1,5,6,GTK_FILL, GTK_FILL,0,0);
709 self->_priv->tw_length = gtk_label_new("n/a");
710 gtk_misc_set_alignment(GTK_MISC(self->_priv->tw_length), 0.0,0.5);
711 gtk_label_set_ellipsize(GTK_LABEL(self->_priv->tw_length),PANGO_ELLIPSIZE_END);
712 gtk_table_attach(GTK_TABLE(table), self->_priv->tw_length, 1,2,5,6,GTK_EXPAND|GTK_FILL, GTK_FILL,0,0);
717 g_object_unref(group);
719 gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
723 g_signal_connect(G_OBJECT(treeview),
725 G_CALLBACK(self_query_tooltip),
727 gtk_widget_set_tooltip_window(treeview, GTK_WINDOW(self->_priv->tooltip_window));
728 gtk_widget_show_all(vbox);
736 * Right mouse click behaviour fix
739 gboolean click_fix (self, GdkEventButton *event)
741 GtkTreePath *path = NULL;
742 self->_priv->pressed = TRUE;
743 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))
745 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
746 if(gtk_tree_selection_path_is_selected(sel, path))
748 gtk_tree_path_free(path);
754 gtk_tree_path_free(path);
760 gboolean click_released (self, GdkEventButton *event)
762 self->_priv->pressed = FALSE;
767 enable_click_fix(self)
769 g_signal_connect(G_OBJECT(self), "button-press-event", G_CALLBACK(self_click_fix), NULL);
771 g_signal_connect(G_OBJECT(self), "button-release-event", G_CALLBACK(self_click_released), NULL);
776 signal last NONE (POINTER)
778 paste_before(self, GList *items)
782 signal last NONE (POINTER)
784 paste_after(self, const GList *items)
787 signal last NONE (NONE)
793 private void insert_selected_rows(self,gboolean replace)
795 GtkTreeModel *model = NULL;
796 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
797 GList *iter, *list = gtk_tree_selection_get_selected_rows(selection, &model);
799 for(iter = g_list_first(list); iter != NULL; iter = g_list_next(iter))
804 GtkTreePath *path = iter->data;
805 gtk_tree_model_get_iter(model, &titer, path);
806 gtk_tree_model_get(model, &titer, MPDDATA_MODEL_COL_PATH, &name, MPDDATA_MODEL_ROW_TYPE, &type, -1);
807 if (type == MPD_DATA_TYPE_SONG || type == MPD_DATA_TYPE_DIRECTORY) {
808 /* add them to the add list */
809 mpd_playlist_queue_add(connection, name);
811 } else if (type == MPD_DATA_TYPE_PLAYLIST) {
812 mpd_playlist_queue_load(connection, name);
816 if(replace && added > 0) {
817 mpd_playlist_clear(connection);
819 mpd_playlist_queue_commit(connection);
820 if(replace && added > 0) {
821 mpd_player_play(connection);
823 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
827 * This will add selected songs. (only songs)
828 * with priority. If song has an song-id, it only changes priority.
830 public void insert_selected_rows_with_priority(self)
832 GtkTreeModel *model = NULL;
833 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
834 GList *iter, *list = gtk_tree_selection_get_selected_rows(selection, &model);
836 int sel_rows = gtk_tree_selection_count_selected_rows(selection);
839 if(sel_rows >= 254) {
840 playlist3_show_error_message(_("You can only queue 254 songs at the time."),
844 for(iter = g_list_first(list); iter != NULL; iter = g_list_next(iter))
850 GtkTreePath *path = iter->data;
851 gtk_tree_model_get_iter(model, &titer, path);
852 gtk_tree_model_get(model, &titer,
853 MPDDATA_MODEL_COL_PATH, &name,
854 MPDDATA_MODEL_COL_SONG_ID, &id,
855 MPDDATA_MODEL_ROW_TYPE, &type, -1);
856 if (type == MPD_DATA_TYPE_SONG ) {
857 /* add them to the add list */
859 id = mpd_playlist_add_get_id(connection, name);
862 mpd_playlist_set_priority(connection, id, priority--);
867 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
873 paste_key_release_event(self, GdkEventKey *event,gpointer data)
875 if(event->keyval == GDK_KEY_q && (event->state&GDK_MOD1_MASK) > 0) {
876 if(mpd_check_connected(connection) &&
877 mpd_server_check_command_allowed(connection, "prioid") ==
878 MPD_SERVER_COMMAND_ALLOWED)
880 self_insert_selected_rows_with_priority(self);
884 else if(event->keyval == GDK_KEY_Insert || event->keyval == GDK_KEY_KP_Insert) {
885 if(mpd_check_connected(connection))
887 self_insert_selected_rows(self,((event->state & GDK_CONTROL_MASK) > 0));
892 if(event->keyval == GDK_KEY_Menu) {
893 GdkEventButton bevent;
894 gboolean value = FALSE;
895 bevent.window = NULL;
897 bevent.time = event->time;
898 g_signal_emit_by_name(self, "button-press-event", &bevent, &value,NULL);
900 g_signal_emit_by_name(self, "button-release-event", &bevent, &value,NULL);
905 if (event->keyval == GDK_KEY_c && event->state&GDK_CONTROL_MASK)
907 self_paste_copy_songs(self, NULL);
912 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[PASTE_BEFORE_SIGNAL], 0, TRUE))
914 if (event->keyval == GDK_KEY_b && event->state&GDK_CONTROL_MASK)
916 self_paste_paste_before_songs(self, NULL);
922 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[PASTE_AFTER_SIGNAL], 0, TRUE))
924 if (event->keyval == GDK_KEY_v && event->state&GDK_CONTROL_MASK)
926 self_paste_paste_after_songs(self, NULL);
932 if (gtk_tree_selection_count_selected_rows (gtk_tree_view_get_selection(GTK_TREE_VIEW(self))) > 0)
934 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[CUT_SIGNAL], 0, TRUE))
936 if (event->keyval == GDK_KEY_x && event->state&GDK_CONTROL_MASK)
938 self_paste_cut_songs(self, NULL);
947 paste_cut_songs(self, GtkMenuItem *item)
949 self_paste_copy_songs(self, item);
954 paste_paste_after_songs(self, GtkMenuItem *menuitem)
956 self_paste_after(self, g_list_first(paste_queue));
958 g_list_foreach(paste_queue, (GFunc)g_free, NULL);
959 g_list_free(paste_queue);
966 paste_paste_before_songs(self, GtkMenuItem *menuitem)
968 self_paste_before(self, g_list_first(paste_queue));
970 g_list_foreach(paste_queue, (GFunc)g_free, NULL);
971 g_list_free(paste_queue);
978 paste_copy_songs(self, GtkMenuItem *menitem)
980 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(self));
981 /* free old entries */
982 g_list_foreach(paste_queue, (GFunc)g_free, NULL);
983 g_list_free(paste_queue);
985 /* check if where connected */
986 /* see if there is a row selected */
987 if (gtk_tree_selection_count_selected_rows (selection) > 0)
989 GList *list = NULL, *llist = NULL;
990 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(self));
991 /* start a command list */
992 /* grab the selected songs */
993 list = gtk_tree_selection_get_selected_rows (selection, &model);
994 /* grab the last song that is selected */
995 llist = g_list_last (list);
996 /* remove every selected song one by one */
999 gtk_tree_model_get_iter (model, &iter,(GtkTreePath *) llist->data);
1000 /* Trick that avoids roundtrip to mpd */
1004 /* this one allready has the pos. */
1005 gtk_tree_model_get (model, &iter,
1006 MPDDATA_MODEL_ROW_TYPE,&type,
1007 MPDDATA_MODEL_COL_PATH, &path,
1009 g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Copying song, into queue: %s\n", path);
1010 if(type == MPD_DATA_TYPE_SONG) {
1011 paste_queue = g_list_prepend(paste_queue, path);
1012 } else if (type == MPD_DATA_TYPE_DIRECTORY) {
1013 MpdData *data = mpd_database_get_directory_recursive(connection, path);
1014 for(;data; data= mpd_data_get_next(data)){
1015 if(data->type == MPD_DATA_TYPE_SONG) {
1016 paste_queue = g_list_prepend(paste_queue, g_strdup(data->song->file));
1020 } else if (type == MPD_DATA_TYPE_PLAYLIST) {
1021 MpdData *data = mpd_database_get_playlist_content(connection, path);
1022 for(;data; data= mpd_data_get_next(data)){
1023 if(data->type == MPD_DATA_TYPE_SONG) {
1024 paste_queue = g_list_prepend(paste_queue, g_strdup(data->song->file));
1030 } while ((llist = g_list_previous (llist)));
1032 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
1035 paste_queue = g_list_reverse(paste_queue);
1040 right_mouse_intergration(self, GtkMenu *menu)
1044 GtkWidget *menu_item;
1045 GtkTreeSelection *selection = NULL;
1046 GtkWidget *submenu = gtk_menu_new();
1047 for(i=0; i< num_plugins;i++)
1049 if(gmpc_plugin_get_enabled(plugins[i]))
1051 retv += gmpc_plugin_browser_song_list_option_menu(plugins[i],self, GTK_MENU(submenu));
1054 /* If no submenu item was added, destroy the submenu */
1055 if(!retv) gtk_widget_destroy(submenu);
1057 GList *temp = gtk_container_get_children(GTK_CONTAINER(menu));
1059 menu_item = gtk_separator_menu_item_new();
1061 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1063 /* Add a tools menu item with the previously generated menu as submenu */
1064 menu_item = gtk_menu_item_new_with_label(_("Tools"));
1065 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
1066 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1074 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
1075 if(selection && gtk_tree_selection_count_selected_rows(selection))
1077 GList *temp = gtk_container_get_children(GTK_CONTAINER(menu));
1079 menu_item = gtk_separator_menu_item_new();
1081 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1084 menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_COPY, NULL);
1085 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1086 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_paste_copy_songs), self);
1091 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[PASTE_BEFORE_SIGNAL], 0, TRUE))
1093 menu_item = gtk_image_menu_item_new_with_label(_("Paste before"));
1094 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
1095 gtk_image_new_from_stock(GTK_STOCK_PASTE, GTK_ICON_SIZE_MENU));
1096 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1097 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_paste_paste_before_songs), self);
1100 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[PASTE_AFTER_SIGNAL], 0, TRUE))
1102 menu_item = gtk_image_menu_item_new_with_label(_("Paste after"));
1103 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
1104 gtk_image_new_from_stock(GTK_STOCK_PASTE, GTK_ICON_SIZE_MENU));
1105 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1106 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_paste_paste_after_songs), self);
1111 if (gtk_tree_selection_count_selected_rows (gtk_tree_view_get_selection(GTK_TREE_VIEW(self))) > 0)
1113 if(g_signal_has_handler_pending(G_OBJECT(self), object_signals[CUT_SIGNAL], 0, TRUE))
1115 menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CUT,NULL);
1116 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item),
1117 gtk_image_new_from_stock(GTK_STOCK_PASTE, GTK_ICON_SIZE_MENU));
1118 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1119 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_paste_cut_songs), self);
1125 GList *temp = gtk_container_get_children(GTK_CONTAINER(menu));
1127 menu_item = gtk_separator_menu_item_new();
1128 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1134 menu_item = gtk_image_menu_item_new_with_label(_("Edit Columns"));
1135 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menu_item), gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
1136 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(self_edit_columns), self);
1137 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1149 g_list_foreach(paste_queue, (GFunc)g_free, NULL);
1150 g_list_free(paste_queue);
1156 /* vim: set noexpandtab ts=4 sw=4 sts=4 tw=120: */