Fiddle with it to speed up.
[gmpc-albumview.git] / src / plugin.c
blob6c05cf437f4e0dfc1ce8b30edb041d9459d9411c
1 #include <config.h>
2 #include <glib.h>
3 #include <glib/gi18n-lib.h>
4 #include <gtk/gtk.h>
5 #include <gdk/gdkkeysyms.h>
6 #include <gmpc/plugin.h>
7 #include <gmpc/playlist3-messages.h>
8 #include <gmpc/gmpc-metaimage.h>
9 #include <gmpc/misc.h>
10 #include <libmpd/libmpd-internal.h>
11 #include <math.h>
12 #include "exo-wrap-table.h"
13 #include "plugin.h"
15 #define ALBUM_SIZE 200
16 static GtkWidget * create_button(AlbumViewPlugin *self, MpdData_real *complete_list_iter);
18 const GType albumview_plugin_get_type(void);
19 #define ALBUM_VIEW_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), albumview_plugin_get_type(), AlbumViewPlugin))
20 #define AV_LOG_DOMAIN "AlbumViewPlugin"
22 typedef struct _AlbumViewPluginPrivate {
23 int supported_columns;
24 int supported_rows;
25 GtkWidget *filter_entry;
26 GtkWidget *progress_bar;
27 GtkWidget *item_table;
28 GtkWidget *albumview_box;
29 GtkWidget *albumview_main_box;
30 GtkWidget *event_bg;
31 int max_entries;
32 int current_entry;
34 MpdData *complete_list;
35 guint update_timeout;
36 /* temp */
37 MpdData *data;
38 GList *current_item;
39 GtkTreeRowReference *albumview_ref;
40 }_AlbumViewPluginPrivate;
44 static gchar * albumview_format_time(unsigned long seconds);
45 static void albumview_browser_save_myself(GmpcPluginBase *plug);
46 static void filter_list(GtkEntry *entry, gpointer data);
47 void update_view(AlbumViewPlugin *self);
48 static void load_list(AlbumViewPlugin *self);
50 void size_changed(GtkWidget *widget, GtkAllocation *alloc, gpointer user_data)
52 AlbumViewPlugin *self = ALBUM_VIEW_PLUGIN(user_data);
53 int columns = (alloc->width-10)/(ALBUM_SIZE);
54 int rows = (alloc->height-10)/(ALBUM_SIZE+40);
56 if(columns != self->priv->supported_columns || rows != self->priv->supported_rows)
58 self->priv->supported_columns = (columns)?columns:1;
59 self->priv->supported_rows = (rows)?rows:1;
60 if(self->priv->filter_entry && GTK_WIDGET_IS_SENSITIVE(self->priv->filter_entry))
62 update_view(self);
67 /**
68 * Get/Set enable
71 static int albumview_get_enabled(GmpcPluginBase *plug)
73 return cfg_get_single_value_as_int_with_default(config, "albumview", "enable", TRUE);
76 void albumview_set_enabled(GmpcPluginBase *plug, int enabled)
78 AlbumViewPlugin *self = ALBUM_VIEW_PLUGIN(plug);
79 cfg_set_single_value_as_int(config, "albumview", "enable", enabled);
80 if(enabled)
82 if(self->priv->albumview_ref == NULL)
84 albumview_add(GMPC_PLUGIN_BROWSER_IFACE(plug), GTK_WIDGET(playlist3_get_category_tree_view()));
87 else
89 GtkTreePath *path = gtk_tree_row_reference_get_path(self->priv->albumview_ref);
90 GtkTreeModel *model = gtk_tree_row_reference_get_model(self->priv->albumview_ref);
91 if (path){
92 GtkTreeIter iter;
93 if (gtk_tree_model_get_iter(model, &iter, path)){
94 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
96 gtk_tree_path_free(path);
97 gtk_tree_row_reference_free(self->priv->albumview_ref);
98 self->priv->albumview_ref = NULL;
104 * Playlist browser functions
106 static void albumview_add(GmpcPluginBrowserIface *plug, GtkWidget *category_tree)
108 AlbumViewPlugin *self = ALBUM_VIEW_PLUGIN(plug);
109 GtkTreePath *path;
110 GtkTreeModel *model = GTK_TREE_MODEL(playlist3_get_category_tree_store());
111 GtkTreeIter iter;
112 gint pos;
114 * don't do anything if we are disabled
116 if(!cfg_get_single_value_as_int_with_default(config, "albumview", "enable", TRUE)) return;
117 /**
118 * Add ourslef to the list
120 pos = cfg_get_single_value_as_int_with_default(config, "albumview","position",2);
121 playlist3_insert_browser(&iter, pos);
122 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
123 PL3_CAT_TYPE, GMPC_PLUGIN_BASE(plug)->id,
124 PL3_CAT_TITLE,"Album View",
125 PL3_CAT_ICON_ID, "albumview",
126 -1);
127 /**
128 * remove odl reference if exists
130 if (self->priv->albumview_ref) {
131 gtk_tree_row_reference_free(self->priv->albumview_ref);
132 self->priv->albumview_ref = NULL;
135 * create reference to ourself in the list
137 path = gtk_tree_model_get_path(GTK_TREE_MODEL(model), &iter);
138 if (path) {
139 self->priv->albumview_ref = gtk_tree_row_reference_new(model, path);
140 gtk_tree_path_free(path);
143 static void albumview_browser_save_myself(GmpcPluginBase *plug)
145 AlbumViewPlugin *self = ALBUM_VIEW_PLUGIN(plug);
146 if(self->priv->albumview_ref)
148 GtkTreePath *path = gtk_tree_row_reference_get_path(self->priv->albumview_ref);
149 if(path)
151 gint *indices = gtk_tree_path_get_indices(path);
152 g_log(AV_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Saving myself to position: %i", indices[0]);
153 cfg_set_single_value_as_int(config, "albumview","position",indices[0]);
154 gtk_tree_path_free(path);
160 static gboolean albumview_button_press_event(GtkWidget *event_box, GdkEventButton *event, gpointer data)
162 AlbumViewPlugin *self = ALBUM_VIEW_PLUGIN(data);
163 if(self->priv->current_item == NULL) return FALSE;
164 gtk_widget_grab_focus(self->priv->event_bg);
166 static gboolean albumview_focus(GtkWidget *wid,GdkEventFocus *event, gpointer data)
168 AlbumViewPlugin *self = ALBUM_VIEW_PLUGIN(data);
169 g_log(AV_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "focus in");
170 gtk_widget_queue_draw(self->priv->event_bg);
171 return TRUE;
173 static gboolean albumview_focus_out(GtkWidget *wid,GdkEventFocus *event, gpointer data)
175 AlbumViewPlugin *self = ALBUM_VIEW_PLUGIN(data);
176 g_log(AV_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "focus out");
178 gtk_widget_queue_draw(self->priv->event_bg);
179 return TRUE;
181 static gboolean albumview_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data)
183 int width = widget->allocation.width;
184 int height = widget->allocation.height;
185 AlbumViewPlugin *self = ALBUM_VIEW_PLUGIN(data);
187 gtk_paint_flat_box(widget->style,
188 widget->window,
189 GTK_STATE_NORMAL,
190 GTK_SHADOW_NONE,
191 NULL,
192 widget,
193 "entry_bg",
194 0,0,width,height);
195 if(gtk_widget_is_focus(widget))
197 gtk_paint_focus(widget->style, widget->window,
198 GTK_STATE_NORMAL,
199 NULL,
200 widget,
201 "entry_bg",
202 0,0,width,height);
204 return FALSE;
206 #if GTK_CHECK_VERSION(2,16,0)
207 static void mod_fill_clear_search_entry(GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEvent *event, gpointer user_data)
209 if(icon_pos == GTK_ENTRY_ICON_SECONDARY){
210 gtk_entry_set_text(GTK_ENTRY(entry), "");
213 #endif
214 static void albumview_init(AlbumViewPlugin *self)
216 /** Get an allready exposed widgets to grab theme colors from. */
217 GtkWidget *colw = (GtkWidget *)playlist3_get_category_tree_view();
218 GtkWidget *label = NULL;
219 GtkWidget *event = gtk_scrolled_window_new(NULL, NULL);
220 GtkWidget *hbox = NULL; int i = 0;
221 self->priv->event_bg = gtk_event_box_new();
222 self->priv->albumview_main_box = gtk_vbox_new(FALSE, 6);
224 GtkWidget *iv = self->priv->albumview_box = gtk_vbox_new(FALSE, 6);
225 g_signal_connect(G_OBJECT(event), "size-allocate", G_CALLBACK(size_changed), self);
227 self->priv->filter_entry = gtk_entry_new();
229 #if GTK_CHECK_VERSION(2,16,0)
230 gtk_entry_set_icon_from_stock(GTK_ENTRY(self->priv->filter_entry), GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR);
231 g_signal_connect(GTK_ENTRY(self->priv->filter_entry), "icon-press", G_CALLBACK(mod_fill_clear_search_entry), NULL);
232 #endif
233 g_signal_connect(G_OBJECT(self->priv->filter_entry),"changed", G_CALLBACK(filter_list), self);
236 hbox = gtk_hbox_new(FALSE, 6);
237 gtk_box_pack_start(GTK_BOX(hbox),gtk_label_new(("Filter")), FALSE, FALSE, 0);
238 gtk_box_pack_start(GTK_BOX(hbox),self->priv->filter_entry, TRUE, TRUE, 0);
240 gtk_box_pack_end(GTK_BOX(self->priv->albumview_main_box), hbox, FALSE, FALSE, 0);
242 hbox = gtk_hbox_new(FALSE, 6);
243 gtk_box_pack_start(GTK_BOX(self->priv->albumview_main_box),hbox, TRUE, TRUE, 0);
244 gtk_box_pack_start(GTK_BOX(hbox),event, TRUE, TRUE, 0);
245 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(event), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
246 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(event), GTK_SHADOW_ETCHED_IN);
247 /* setup bg */
248 /* TODO draw focus */
249 // gtk_widget_modify_bg(self->priv->event_bg, GTK_STATE_NORMAL,&(self->priv->albumview_main_box->style->white));
250 gtk_widget_set_app_paintable(self->priv->event_bg, TRUE);
251 g_signal_connect(G_OBJECT(self->priv->event_bg), "expose-event", G_CALLBACK(albumview_expose_event), self);
252 gtk_event_box_set_visible_window(GTK_EVENT_BOX(self->priv->event_bg), TRUE);
254 g_object_set(self->priv->event_bg, "can-focus", TRUE,NULL);
255 GTK_WIDGET_SET_FLAGS(self->priv->event_bg, GTK_HAS_FOCUS);
256 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(event), self->priv->event_bg);
257 gtk_container_add(GTK_CONTAINER(self->priv->event_bg), iv);
258 gtk_widget_add_events(self->priv->event_bg, GDK_SCROLL_MASK|GDK_BUTTON_PRESS_MASK|GDK_FOCUS_CHANGE_MASK);
259 g_signal_connect_object(G_OBJECT(self->priv->event_bg), "focus-in-event", G_CALLBACK(albumview_focus), self,0);
260 g_signal_connect_object(G_OBJECT(self->priv->event_bg), "focus-out-event", G_CALLBACK(albumview_focus_out), self, 0);
261 g_signal_connect_object(G_OBJECT(self->priv->event_bg), "button-press-event", G_CALLBACK(albumview_button_press_event), self,0);
263 gtk_widget_show_all(self->priv->albumview_main_box);
266 /* maintain my own reference to the widget, so it won't get destroyed removing
267 * from view
269 g_object_ref_sink(self->priv->albumview_main_box);
273 static void albumview_selected(GmpcPluginBrowserIface *plug, GtkWidget *container)
275 AlbumViewPlugin *self = ALBUM_VIEW_PLUGIN(plug);
276 if(self->priv->albumview_main_box== NULL) {
277 albumview_init((AlbumViewPlugin *)plug);
278 albumview_connection_changed(gmpcconn, connection,1,self);
280 gtk_container_add(GTK_CONTAINER(container), self->priv->albumview_main_box);
281 gtk_widget_show(self->priv->albumview_main_box);
282 gtk_widget_show(container);
283 gtk_widget_grab_focus(self->priv->event_bg);
286 static void albumview_unselected(GmpcPluginBrowserIface *plug,GtkWidget *container)
288 AlbumViewPlugin *self = ALBUM_VIEW_PLUGIN(plug);
289 gtk_container_remove(GTK_CONTAINER(container), self->priv->albumview_main_box);
292 static void status_changed(GmpcConnection *gmpcconnn,MpdObj *mi, ChangedStatusType type, AlbumViewPlugin *self)
294 if((type&MPD_CST_DATABASE) > 0)
297 if(self->priv->albumview_main_box)
298 load_list(self);
302 void albumview_plugin_init(AlbumViewPlugin *self)
304 gchar *path;
305 const gchar * const *paths = g_get_system_data_dirs();
306 int i;
308 /* First try the compile time path */
309 path = g_build_filename(PIXMAP_DATA_DIR, NULL);
310 if(path){
311 if(!g_file_test(path, G_FILE_TEST_EXISTS|G_FILE_TEST_IS_DIR))
313 g_free(path);
314 path = NULL;
318 for(i=0; path == NULL && paths && paths[i]; i++) {
319 path = g_build_filename(paths[i], "gmpc-albumview", "icons", NULL);
320 if(!g_file_test(path, G_FILE_TEST_EXISTS|G_FILE_TEST_IS_DIR))
322 g_free(path);
323 path = NULL;
326 if(path) {
327 gtk_icon_theme_append_search_path(gtk_icon_theme_get_default (),path);
329 g_signal_connect_object(G_OBJECT(gmpcconn), "status-changed", G_CALLBACK(status_changed), self, 0);
331 g_free(path);
332 path = NULL;
334 #define TIMER_SUB(start,stop,diff) diff.tv_usec = stop.tv_usec - start.tv_usec;\
335 diff.tv_sec = stop.tv_sec - start.tv_sec;\
336 if(diff.tv_usec < 0) {\
337 diff.tv_sec -= 1; \
338 diff.tv_usec += G_USEC_PER_SEC; \
340 static gint __add_sort(gpointer aa, gpointer bb, gpointer data)
342 MpdData_real *a = *(MpdData_real **)aa;
343 MpdData_real *b = *(MpdData_real **)bb;
344 if(!a || !b) return 0;
345 if(a->type == MPD_DATA_TYPE_SONG && b->type == MPD_DATA_TYPE_SONG)
347 if(a->song->artist && b->song->artist)
349 int val;
351 gchar *sa,*sb;
352 sa = g_utf8_strdown(a->song->artist, -1);
353 sb = g_utf8_strdown(b->song->artist, -1);
354 val = g_utf8_collate(sa,sb);
355 g_free(sa);
356 g_free(sb);
357 }/* else {
358 val = (a == NULL)?((b==NULL)?0:-1):1;
360 if(val != 0)
361 return val;
362 if (a->song->album && b->song->album)
364 gchar *sa,*sb;
365 sa = g_utf8_strdown(a->song->album, -1);
366 sb = g_utf8_strdown(b->song->album, -1);
367 val = g_utf8_collate(sa,sb);
368 g_free(sa);
369 g_free(sb);
372 return val;
375 return -1;
378 static gboolean update_progressbar(AlbumViewPlugin *self)
380 gchar *temp = g_strdup_printf("%i of %i albums loaded", self->priv->current_entry, self->priv->max_entries);
381 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(self->priv->progress_bar), self->priv->current_entry/(double)self->priv->max_entries);
382 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(self->priv->progress_bar), temp);
383 g_free(temp);
384 return FALSE;
387 static void load_list_itterate(MpdObj *mi, AlbumViewPlugin *self)
390 MpdData *data2 = NULL;
391 self->priv->current_entry++;
392 if(self->priv->max_entries>0 && self->priv->current_entry%25 == 0){
393 g_idle_add((GSourceFunc)update_progressbar, self);
395 if(self->priv->data)
397 mpd_database_search_field_start(mi, MPD_TAG_ITEM_ARTIST);
398 mpd_database_search_add_constraint(mi, MPD_TAG_ITEM_ALBUM, (self->priv->data)->tag);
399 data2 = mpd_database_search_commit(mi);
400 if(data2)
402 mpd_Song *song = mpd_newSong();
403 song->album = g_strdup((self->priv->data)->tag);
404 song->artist = g_strdup(data2->tag);
405 if(!mpd_data_is_last(data2))
407 /* test if server supports album artist */
408 if(mpd_server_tag_supported(mi, MPD_TAG_ITEM_ALBUM_ARTIST))
410 mpd_database_search_field_start(mi, MPD_TAG_ITEM_ALBUM_ARTIST);
411 mpd_database_search_add_constraint(mi, MPD_TAG_ITEM_ALBUM, (self->priv->data)->tag);
412 MpdData *data3 = mpd_database_search_commit(mi);
413 if(mpd_data_is_last(data3)){
414 if(strlen(data3->tag) > 0)
416 song->albumartist = g_strdup(data3->tag);
417 if(song->artist) g_free(song->artist);
418 song->artist = g_strdup(data3->tag);
421 else{
422 mpd_freeSong(song);
423 song = NULL;
425 mpd_data_free(data3);
427 else {
428 mpd_freeSong(song);
429 song = NULL;
432 mpd_data_free(data2);
433 if(song){
434 self->priv->complete_list = mpd_new_data_struct_append(self->priv->complete_list);
435 self->priv->complete_list->song = song;
436 self->priv->complete_list->type = MPD_DATA_TYPE_SONG;
437 self->priv->complete_list->userdata = create_button(self, (MpdData_real *)self->priv->complete_list);
438 self->priv->complete_list->freefunc = (void *)gtk_widget_destroy;
439 song = NULL;
443 (self->priv->data) = mpd_data_get_next((self->priv->data));
446 while(self->priv->data != NULL);
447 self->priv->complete_list = (MpdData *)misc_sort_mpddata(mpd_data_get_first(self->priv->complete_list), (GCompareDataFunc)__add_sort, NULL);
450 void update_finished(MpdData *data, AlbumViewPlugin *self)
452 if(self->priv->data == NULL){
453 int items = 0;
454 MpdData_real *iter;
455 g_log(AV_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,"update view\n");
456 gtk_widget_destroy(self->priv->progress_bar);
457 self->priv->progress_bar = NULL;
458 for(iter = (MpdData_real*)self->priv->complete_list; iter; iter = iter->next) items++;
460 gtk_widget_set_sensitive(self->priv->filter_entry, TRUE);
461 filter_list(GTK_ENTRY(self->priv->filter_entry), self);
463 gtk_widget_grab_focus(self->priv->event_bg);
464 // return FALSE;
467 // g_idle_add((GSourceFunc)load_list_itterate, self);
468 // return FALSE;
471 static void load_list(AlbumViewPlugin *self)
473 if(self->priv->complete_list)mpd_data_free(self->priv->complete_list);
474 self->priv->complete_list = NULL;
475 if(self->priv->current_item) g_list_free(self->priv->current_item);
476 self->priv->current_item = NULL;
479 self->priv->progress_bar = gtk_progress_bar_new();
480 gtk_box_pack_start(GTK_BOX(self->priv->albumview_box), self->priv->progress_bar, FALSE, FALSE, 0);
481 gtk_widget_show(self->priv->progress_bar);
482 mpd_database_search_field_start(connection, MPD_TAG_ITEM_ALBUM);
483 MpdData *iter,*data = mpd_database_search_commit(connection);
484 self->priv->max_entries= 0;
485 self->priv->current_entry = 0;
486 gtk_widget_set_sensitive(self->priv->filter_entry, FALSE);
487 for(iter = data; iter; iter = mpd_data_get_next_real(iter, FALSE)) self->priv->max_entries++;
488 self->priv->data= data;
489 mpd_async_request(update_finished, self, load_list_itterate, self);
491 void albumview_connection_changed(GmpcConnection *conn, MpdObj *mi, int connect,void *usedata)
493 AlbumViewPlugin *self = ALBUM_VIEW_PLUGIN(usedata);
495 if(connect && self->priv->albumview_main_box)
497 load_list(self);
499 else if(self->priv->albumview_main_box){
500 mpd_data_free(self->priv->complete_list);
501 self->priv->complete_list = NULL;
502 if(self->priv->item_table)
503 gtk_widget_hide(self->priv->item_table);
506 static void album_add(GtkWidget *button, mpd_Song *song)
508 mpd_database_search_start(connection,TRUE);
510 mpd_database_search_add_constraint(connection, MPD_TAG_ITEM_ALBUM, song->album);
511 if(song->albumartist && strlen(song->albumartist) >0){
512 mpd_database_search_add_constraint(connection, MPD_TAG_ITEM_ALBUM_ARTIST, song->albumartist);
513 }else{
514 mpd_database_search_add_constraint(connection, MPD_TAG_ITEM_ARTIST, song->artist);
516 MpdData *data = mpd_database_search_commit(connection);
517 /* Sort it before adding */
518 data = misc_sort_mpddata_by_album_disc_track(data);
519 for(;data;data = mpd_data_get_next(data)){
520 mpd_playlist_queue_add(connection, data->song->file);
522 mpd_playlist_queue_commit(connection);
524 static void album_view(GtkWidget *button ,mpd_Song *song)
526 if (song && song->artist && song->album) {
527 info2_activate();
528 info2_fill_album_view(song->artist, song->album);
532 static void album_replace(GtkWidget *button, mpd_Song *song)
534 mpd_playlist_clear(connection);
535 album_add(button, song);
536 mpd_player_play(connection);
538 static gboolean album_button_press(GtkWidget *image, GtkMenu *menu, mpd_Song *song)
540 GtkWidget *item;
542 item = gtk_image_menu_item_new_with_label("Album information");
543 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
544 gtk_image_new_from_stock(GTK_STOCK_INFO, GTK_ICON_SIZE_MENU));
545 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
546 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(album_view), song);
548 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ADD,NULL);
549 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
550 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(album_add), song);
552 /* replace the replace widget */
553 item = gtk_image_menu_item_new_with_label("Replace");
554 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
555 gtk_image_new_from_stock(GTK_STOCK_REDO, GTK_ICON_SIZE_MENU));
556 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
557 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(album_replace), song);
559 item = gtk_separator_menu_item_new();
560 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
562 gtk_widget_show(item);
564 return TRUE;
566 static GtkWidget * create_button(AlbumViewPlugin *self, MpdData_real *complete_list_iter)
568 GtkWidget *item;
569 GtkWidget *vbox;
570 GtkWidget *label = NULL;
571 gchar *temp = NULL;
572 /* Wrap it in a vbox */
573 vbox = gtk_vbox_new(FALSE, 3);
574 gtk_widget_set_size_request(vbox, ALBUM_SIZE,ALBUM_SIZE+20);
576 item = gmpc_metaimage_new_size(META_ALBUM_ART,ALBUM_SIZE-20);
577 gmpc_metaimage_set_scale_up(GMPC_METAIMAGE(item), TRUE);
578 gtk_widget_set_has_tooltip(GTK_WIDGET(item), FALSE);
579 gmpc_metaimage_set_squared(GMPC_METAIMAGE(item), TRUE);
581 gmpc_metaimage_update_cover_from_song_delayed(GMPC_METAIMAGE(item), complete_list_iter->song);
583 gtk_box_pack_start(GTK_BOX(vbox), item, TRUE, TRUE, 0);
584 /* Set artist name */
585 if(complete_list_iter->song->albumartist){
586 GtkWidget *label = gtk_label_new(complete_list_iter->song->albumartist);
587 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_MIDDLE);
588 gtk_box_pack_end(GTK_BOX(vbox), label, FALSE, FALSE, 0);
589 }else{
590 GtkWidget *label = gtk_label_new(complete_list_iter->song->artist);
591 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_MIDDLE);
592 gtk_box_pack_end(GTK_BOX(vbox), label, FALSE, FALSE, 0);
595 /* Set album name */
596 label = gtk_label_new("");
597 temp = g_markup_printf_escaped("<b>%s</b>", complete_list_iter->song->album);
598 gtk_label_set_markup(GTK_LABEL(label), temp);
599 g_free(temp);
600 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_MIDDLE);
601 gtk_box_pack_end(GTK_BOX(vbox), label, FALSE, FALSE, 0);
604 /* Attach it to the song */
605 g_object_add_weak_pointer(G_OBJECT(vbox),&(complete_list_iter->userdata));
606 complete_list_iter->userdata = vbox;//g_object_ref_sink(vbox);
607 complete_list_iter->freefunc = (void *)gtk_widget_destroy;
608 g_object_set_data(G_OBJECT(vbox), "item", item);
609 g_signal_connect(G_OBJECT(item), "menu_populate_client", G_CALLBACK(album_button_press), complete_list_iter->song);
611 g_signal_connect(item, "button-press-event",
612 G_CALLBACK(album_button_press), complete_list_iter->song);
614 return g_object_ref_sink(vbox);
617 static void filter_list(GtkEntry *entry, gpointer data)
619 AlbumViewPlugin *self = ALBUM_VIEW_PLUGIN(data);
620 GRegex *regex = NULL;
621 int items = 0;
622 GList *list = NULL;
623 const gchar *search_query = gtk_entry_get_text(GTK_ENTRY(self->priv->filter_entry));
624 MpdData_real *complete_list_iter = NULL;
625 if(search_query[0] != '\0')
627 gchar *str = g_strdup(search_query);
628 gchar **test = g_strsplit(g_strstrip(str), " ", -1);
629 int i=0;
630 GString *s = g_string_new("((?:");
631 GError *error = NULL;
632 g_free(str);
633 for(i=0;test && test[i];i++){
634 gchar *temp = g_regex_escape_string(test[i], -1);
635 s = g_string_append(s, ".*");
636 s= g_string_append(s, temp);
637 s = g_string_append(s, ".*");
638 if(test[i+1] != NULL)
639 s = g_string_append(s, "|");
640 g_free(temp);
642 g_string_append_printf(s,"){%i})",i);
643 g_log(AV_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,"regex: %s\n", s->str);
644 regex = g_regex_new(s->str, G_REGEX_CASELESS|G_REGEX_EXTENDED, 0,&error);;
645 if(regex)
647 g_string_free(s, TRUE);
648 for(complete_list_iter = (MpdData_real *) mpd_data_get_first(self->priv->complete_list);
649 complete_list_iter;
650 complete_list_iter = (MpdData_real *)mpd_data_get_next_real((MpdData *)complete_list_iter, FALSE))
652 if(g_regex_match(regex,complete_list_iter->song->album,0,NULL)||
653 g_regex_match(regex,complete_list_iter->song->artist,0,NULL)||
654 (complete_list_iter->song->albumartist && g_regex_match(regex,complete_list_iter->song->albumartist,0,NULL))){
655 items++;
656 list = g_list_append(list, complete_list_iter);
660 if(error) {
661 g_log(AV_LOG_DOMAIN, G_LOG_LEVEL_WARNING," error creating regex: %s\n", error->message);
662 g_error_free(error);
664 g_regex_unref(regex);
666 if(self->priv->current_item) g_list_free(self->priv->current_item);
667 self->priv->current_item = g_list_first(list);
668 update_view(self);
671 static gboolean update_view_real(AlbumViewPlugin *self)
673 MpdData *complete_list_iter;
674 const char *search_query = gtk_entry_get_text(GTK_ENTRY(self->priv->filter_entry));
675 int i=0;
676 int j=0;
677 gchar *artist= NULL;
678 int items =0;
679 MpdData *data = NULL;
680 GList *entries = NULL;
681 GList *list = (self->priv->item_table)?gtk_container_get_children(GTK_CONTAINER(self->priv->item_table)):NULL;
682 GList *iter;
683 GRegex *regex = NULL;
685 g_log(AV_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,"search query: %s\n", search_query);
687 if(self->priv->item_table)
688 gtk_widget_hide(self->priv->item_table);
689 for(iter = g_list_first(list); iter; iter = iter->next){
690 GtkWidget *widget = iter->data;
691 gtk_container_remove(GTK_CONTAINER(self->priv->item_table), widget);
693 g_list_free(list);
694 list = NULL;
698 gtk_widget_show(self->priv->albumview_box);
699 if(self->priv->current_item == NULL){
700 int items =0;
701 for(complete_list_iter = mpd_data_get_first(self->priv->complete_list);
702 complete_list_iter;
703 complete_list_iter = mpd_data_get_next_real(complete_list_iter, FALSE))
705 items++;
706 self->priv->current_item = g_list_append(self->priv->current_item, complete_list_iter);
708 self->priv->current_item = g_list_first(self->priv->current_item);
711 int rows = self->priv->supported_rows;
713 * Create holding table if it does not exist
715 if(!self->priv->item_table){
716 GtkWidget *ali = gtk_alignment_new(0.0, 0.5, 0,0);
717 self->priv->item_table = exo_wrap_table_new(TRUE);//gtk_table_new(rows, supported_columns, TRUE);
718 gtk_container_add(GTK_CONTAINER(ali), self->priv->item_table);
719 gtk_box_pack_start(GTK_BOX(self->priv->albumview_box), ali, FALSE, FALSE, 0);
722 /* I know how large it is going to be.. so lets set the size */
723 gtk_widget_set_size_request(self->priv->item_table, self->priv->supported_columns*(ALBUM_SIZE)+6,-1);// (rows)*(self->priv->album_size+40));
725 * Add albums
728 if(self->priv->current_item)//(iter = g_list_first(list)))
730 GList *iter = g_list_first(self->priv->current_item);
731 int v_items = 0;
734 complete_list_iter = iter->data;
735 if(complete_list_iter->song/* && (complete_list_iter->song->artist)[0] != '\0'*/)
737 GtkWidget *vbox = complete_list_iter->userdata;
738 GtkWidget *item;
739 int a,b;
740 if(vbox == NULL){
741 complete_list_iter->userdata = vbox = create_button(self, (MpdData_real *)complete_list_iter);
743 else{
744 item = g_object_get_data(G_OBJECT(vbox), "item");
746 entries = g_list_prepend(entries, vbox);
747 j++;
749 v_items++;
750 }while(iter = iter->next);//v_items < (rows*self->priv->supported_columns)&& (iter = iter->next));
752 /* remove list */
753 if(list) g_list_free(list);
754 list = NULL;
756 for(iter = entries = g_list_reverse(entries); iter; iter = g_list_next(iter)){
757 gtk_container_add(GTK_CONTAINER(self->priv->item_table), iter->data);
759 if(entries) g_list_free(entries);
761 gtk_widget_show_all(self->priv->albumview_box);
763 * Remove the timeout
765 if(self->priv->update_timeout)
766 g_source_remove(self->priv->update_timeout);
767 self->priv->update_timeout = 0;
768 return FALSE;
772 void update_view(AlbumViewPlugin *self)
774 if(self->priv->update_timeout != 0) {
775 g_source_remove(self->priv->update_timeout);
777 self->priv->update_timeout = g_timeout_add(10, (GSourceFunc)update_view_real,self);
781 * Gobject plugin
783 static void albumview_plugin_class_init (AlbumViewPluginClass *klass);
785 static int *albumview_plugin_get_version(GmpcPluginBase *plug, int *length)
787 static int version[3] = {PLUGIN_MAJOR_VERSION,PLUGIN_MINOR_VERSION,PLUGIN_MICRO_VERSION};
788 if(length) *length = 3;
789 return (int *)version;
792 static const char *albumview_plugin_get_name(GmpcPluginBase *plug)
794 return ("Album View");
796 static GObject *albumview_plugin_constructor(GType type, guint n_construct_properties, GObjectConstructParam * construct_properties) {
797 AlbumViewPluginClass * klass;
798 AlbumViewPlugin *self;
799 GObjectClass * parent_class;
800 klass = (g_type_class_peek (albumview_plugin_get_type()));
801 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
802 self = (AlbumViewPlugin *) parent_class->constructor (type, n_construct_properties, construct_properties);
804 g_log(AV_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Constructing plugin");
806 /* setup private structure */
807 self->priv = g_malloc0(sizeof(AlbumViewPluginPrivate));
808 /* set defaults */
809 self->priv->supported_rows = 1;
810 self->priv->supported_columns = 1;
811 self->priv->data = NULL;
812 self->priv->filter_entry = NULL;
813 self->priv->progress_bar = NULL;
814 self->priv->max_entries = 0;
815 self->priv->current_entry = 0;
816 self->priv->current_item = NULL;
817 self->priv->update_timeout = 0;
818 self->priv->complete_list = NULL;
819 self->priv->item_table = NULL;
820 self->priv->albumview_ref = NULL;
821 self->priv->albumview_box = NULL;
823 /* Watch status changed signals */
824 g_signal_connect_object(G_OBJECT(gmpcconn), "connection-changed", G_CALLBACK(albumview_connection_changed), self, 0);
826 /* Setup textdomain */
827 bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
828 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
830 GMPC_PLUGIN_BASE(self)->translation_domain = GETTEXT_PACKAGE;
831 GMPC_PLUGIN_BASE(self)->plugin_type = GMPC_PLUGIN_NO_GUI;
833 albumview_plugin_init(self);
835 return G_OBJECT(self);
837 static void albumview_plugin_finalize(GObject *obj) {
838 AlbumViewPlugin *self = (AlbumViewPlugin *)obj;
839 AlbumViewPluginClass * klass = (g_type_class_peek (play_queue_plugin_get_type()));
840 gpointer parent_class = g_type_class_peek_parent (klass);
842 g_log(AV_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Destroying plugin");
844 if(self->priv){
845 if(self->priv->current_item) g_list_free(self->priv->current_item);
846 self->priv->current_item = NULL;
847 if(self->priv->complete_list) mpd_data_free(self->priv->complete_list);
848 self->priv->complete_list = NULL;
850 g_free(self->priv);
851 self->priv = NULL;
853 if(parent_class)
854 G_OBJECT_CLASS(parent_class)->finalize(obj);
858 static void albumview_plugin_class_init (AlbumViewPluginClass *klass)
860 G_OBJECT_CLASS(klass)->finalize = albumview_plugin_finalize;
861 G_OBJECT_CLASS(klass)->constructor = albumview_plugin_constructor;
862 /* Connect plugin functions */
863 GMPC_PLUGIN_BASE_CLASS(klass)->get_version = albumview_plugin_get_version;
864 GMPC_PLUGIN_BASE_CLASS(klass)->get_name = albumview_plugin_get_name;
866 GMPC_PLUGIN_BASE_CLASS(klass)->get_enabled = albumview_get_enabled;
867 GMPC_PLUGIN_BASE_CLASS(klass)->set_enabled = albumview_set_enabled;
869 GMPC_PLUGIN_BASE_CLASS(klass)->save_yourself = albumview_browser_save_myself;
872 static void albumview_plugin_browser_iface_init(GmpcPluginBrowserIfaceIface * iface) {
873 iface->browser_add = albumview_add;
874 iface->browser_selected = albumview_selected;
875 iface->browser_unselected = albumview_unselected;
878 const GType albumview_plugin_get_type(void) {
879 static GType albumview_plugin_type_id = 0;
880 if(albumview_plugin_type_id == 0) {
881 static const GTypeInfo info = {
882 .class_size = sizeof(AlbumViewPluginClass),
883 .class_init = (GClassInitFunc)albumview_plugin_class_init,
884 .instance_size = sizeof(AlbumViewPlugin),
885 .n_preallocs = 0
888 albumview_plugin_type_id = g_type_register_static(GMPC_PLUGIN_TYPE_BASE, "AlbumViewPlugin", &info, 0);
890 /** Browser interface */
891 static const GInterfaceInfo iface_info = { (GInterfaceInitFunc) albumview_plugin_browser_iface_init,
892 (GInterfaceFinalizeFunc) NULL, NULL};
893 g_type_add_interface_static (albumview_plugin_type_id, GMPC_PLUGIN_TYPE_BROWSER_IFACE, &iface_info);
895 return albumview_plugin_type_id;
898 G_MODULE_EXPORT GType plugin_get_type(void)
900 return albumview_plugin_get_type();