diff options
author | Jens Georg <mail@jensge.org> | 2016-09-05 22:27:52 +0200 |
---|---|---|
committer | Jens Georg <mail@jensge.org> | 2016-12-17 10:45:51 +0100 |
commit | 630c5fe1cbbd9ceb3a2fe44bb654a64c8cbedb50 (patch) | |
tree | 423aa17cdcaa2ac071920c5296a40a6d9c6668fc | |
parent | ff2c72d71a31453ac6ea6933ed4de0f41b1361f5 (diff) | |
download | gupnp-tools-wip/search.tar.gz |
av-cp: Show DIDL in search dialogwip/search
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | data/Makefile.am | 4 | ||||
-rw-r--r-- | data/didl-lite-dialog.ui.in (renamed from data/didl-lite-dialog.ui) | 2 | ||||
-rw-r--r-- | data/gupnp-av-cp.ui (renamed from data/gupnp-av-cp.ui.in) | 70 | ||||
-rw-r--r-- | data/search-dialog.ui | 20 | ||||
-rw-r--r-- | po/POTFILES.in | 4 | ||||
-rw-r--r-- | src/av-cp/playlist-treeview.c | 1 | ||||
-rw-r--r-- | src/av-cp/search-dialog.c | 178 | ||||
-rw-r--r-- | src/av-cp/server-device.c | 8 |
9 files changed, 207 insertions, 82 deletions
diff --git a/configure.ac b/configure.ac index c863aaf..f67bd08 100644 --- a/configure.ac +++ b/configure.ac @@ -138,7 +138,7 @@ src/network-light/Makefile src/universal-cp/Makefile src/upload/Makefile data/Makefile -data/gupnp-av-cp.ui +data/didl-lite-dialog.ui data/pixmaps/Makefile data/xml/Makefile po/Makefile.in diff --git a/data/Makefile.am b/data/Makefile.am index dfe289d..53248a7 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -10,7 +10,7 @@ desktop_in_files = gupnp-universal-cp.desktop.in \ gupnp-network-light.desktop.in if BUILD_AV -dist_shared_DATA += gupnp-av-cp.ui search-dialog.ui +dist_shared_DATA += gupnp-av-cp.ui search-dialog.ui didl-lite-dialog.ui desktop_in_files += gupnp-av-cp.desktop.in endif @@ -25,7 +25,7 @@ desktop_in_in_files = $(desktop_in_files:.desktop.in=.desktop.in.in) $(AM_V_GEN) $(SED) -e 's|@VERSION[@]|$(VERSION)|g' \ -e 's|@PKGDATADIR[@]|$(PKGDATADIR)|g' $< > $@ -EXTRA_DIST = $(desktop_in_in_files) gupnp-av-cp.ui.in $(desktop_in_files) +EXTRA_DIST = $(desktop_in_in_files) didl-lite-dialog.ui.in $(desktop_in_files) CLEANFILES = $(desktop_DATA) diff --git a/data/didl-lite-dialog.ui b/data/didl-lite-dialog.ui.in index 3b50007..f17d643 100644 --- a/data/didl-lite-dialog.ui +++ b/data/didl-lite-dialog.ui.in @@ -50,7 +50,7 @@ <property name="visible">True</property> <property name="can_focus">True</property> <child> - <object class="GtkSourceView" id="didl_textview"> + <object class="@TEXT_VIEW@" id="didl_textview"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="editable">False</property> diff --git a/data/gupnp-av-cp.ui.in b/data/gupnp-av-cp.ui index 19a21c4..bfc90fb 100644 --- a/data/gupnp-av-cp.ui.in +++ b/data/gupnp-av-cp.ui @@ -722,76 +722,6 @@ Vinicius Depizzol <vdepizzol@gmail.com></property> <placeholder/> </child> </object> - <object class="GtkDialog" id="didl-dialog"> - <property name="width_request">640</property> - <property name="height_request">480</property> - <property name="can_focus">False</property> - <property name="border_width">5</property> - <property name="title" translatable="yes">GUPnP AV CP - Metadata View</property> - <property name="type_hint">normal</property> - <property name="transient_for">main-window</property> - <signal name="delete-event" handler="gtk_widget_hide_on_delete" swapped="no"/> - <child internal-child="vbox"> - <object class="GtkBox" id="dialog-vbox3"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="orientation">vertical</property> - <property name="spacing">6</property> - <child internal-child="action_area"> - <object class="GtkButtonBox" id="didl-action-area"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="layout_style">end</property> - <child> - <object class="GtkButton" id="didl-close-button"> - <property name="label">Close</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <signal name="clicked" handler="gtk_widget_hide" object="didl-dialog" swapped="yes"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack_type">end</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkScrolledWindow" id="didl-scrolledwindow"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <child> - <object class="@TEXT_VIEW@" id="didl-textview"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="editable">False</property> - <property name="wrap_mode">char</property> - </object> - </child> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - <action-widgets> - <action-widget response="0">didl-close-button</action-widget> - </action-widgets> - <child> - <placeholder/> - </child> - </object> <object class="GtkSizeGroup" id="playback-button-sizegroup"> <widgets> <widget name="play-button"/> diff --git a/data/search-dialog.ui b/data/search-dialog.ui index ae0bb87..5350726 100644 --- a/data/search-dialog.ui +++ b/data/search-dialog.ui @@ -2,6 +2,19 @@ <!-- Generated with glade 3.20.0 --> <interface> <requires lib="gtk+" version="3.20"/> + <object class="GtkMenu" id="popup-menu"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkMenuItem"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Show _DIDL…</property> + <property name="use_underline">True</property> + <signal name="activate" handler="search_dialog_on_didl_popup_activate" object="SearchDialog" swapped="yes"/> + </object> + </child> + </object> <object class="GtkListStore" id="search_dialog_liststore"> <columns> <!-- column-name icon --> @@ -10,6 +23,8 @@ <column type="gchararray"/> <!-- column-name didl-lite-object --> <column type="GObject"/> + <!-- column-name id --> + <column type="gchararray"/> </columns> </object> <template class="SearchDialog" parent="GtkDialog"> @@ -24,7 +39,7 @@ <object class="GtkBox"> <property name="can_focus">False</property> <property name="orientation">vertical</property> - <property name="spacing">2</property> + <property name="spacing">6</property> <child internal-child="action_area"> <object class="GtkButtonBox"> <property name="can_focus">False</property> @@ -78,11 +93,12 @@ <property name="can_focus">True</property> <property name="shadow_type">in</property> <child> - <object class="GtkTreeView" id="search-dialog-treeview"> + <object class="GtkTreeView" id="search_dialog_treeview"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="model">search_dialog_liststore</property> <property name="headers_visible">False</property> + <signal name="button-release-event" handler="search_dialog_on_listview_button_release" object="SearchDialog" swapped="no"/> <child internal-child="selection"> <object class="GtkTreeSelection"/> </child> diff --git a/po/POTFILES.in b/po/POTFILES.in index 120e1dd..b9c2d72 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,7 +1,9 @@ # List of source files containing translatable strings. # Please keep this file sorted alphabetically. data/gupnp-av-cp.desktop.in.in -data/gupnp-av-cp.ui.in +data/didl-lite-dialog.ui +data/search-dialog.ui +data/gupnp-av-cp.ui data/gupnp-network-light.desktop.in.in data/gupnp-network-light.ui data/gupnp-universal-cp.desktop.in.in diff --git a/src/av-cp/playlist-treeview.c b/src/av-cp/playlist-treeview.c index e6fc956..22d8549 100644 --- a/src/av-cp/playlist-treeview.c +++ b/src/av-cp/playlist-treeview.c @@ -373,6 +373,7 @@ setup_playlist_treeview (GtkBuilder *builder) popup = GTK_WIDGET (gtk_builder_get_object (builder, "playlist-popup")); g_assert (popup != NULL); + gtk_menu_attach_to_widget (GTK_MENU (popup), treeview, NULL); didl_dialog = GTK_WIDGET (av_cp_didl_dialog_new ()); expanded = FALSE; diff --git a/src/av-cp/search-dialog.c b/src/av-cp/search-dialog.c index fa8dab4..d9cc637 100644 --- a/src/av-cp/search-dialog.c +++ b/src/av-cp/search-dialog.c @@ -25,6 +25,7 @@ #include "search-dialog.h" #include "server-device.h" +#include "didl-dialog.h" #include "icons.h" /* DLNA recommends something between 10 and 30, let's just use 30 @@ -51,6 +52,7 @@ struct _SearchDialogClass { struct _SearchDialogPrivate { GtkListStore *search_dialog_liststore; GtkEntry *search_dialog_entry; + GtkTreeView *search_dialog_treeview; char *id; char *title; AVCPMediaServer *server; @@ -58,6 +60,7 @@ struct _SearchDialogPrivate { SearchTask *task; GUPnPSearchCriteriaParser *parser; GRegex *position_re; + GtkWidget *popup_menu; }; typedef struct _SearchDialogPrivate SearchDialogPrivate; @@ -66,6 +69,14 @@ G_DEFINE_TYPE_WITH_PRIVATE (SearchDialog, search_dialog, GTK_TYPE_DIALOG) void search_dialog_on_search_activate (SearchDialog *self, GtkEntry *entry); +gboolean +search_dialog_on_listview_button_release (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data); + +void +search_dialog_on_didl_popup_activate (SearchDialog *self, gpointer user_data); + static void search_dialog_finalize (GObject *object); @@ -320,7 +331,7 @@ search_task_on_didl_object_available (GUPnPDIDLLiteParser *parser, -1, 0, get_item_icon (object), 1, gupnp_didl_lite_object_get_title (object), - 2, g_object_ref (object), + 3, gupnp_didl_lite_object_get_id (object), -1); } @@ -338,6 +349,9 @@ search_dialog_class_init (SearchDialogClass *klass) gtk_widget_class_bind_template_child_private (widget_class, SearchDialog, search_dialog_entry); + gtk_widget_class_bind_template_child_private (widget_class, + SearchDialog, + search_dialog_treeview); object_class->finalize = search_dialog_finalize; object_class->dispose = search_dialog_dispose; @@ -347,11 +361,16 @@ static void search_dialog_init (SearchDialog *self) { SearchDialogPrivate *priv = NULL; + GtkBuilder *builder = gtk_builder_new (); gtk_widget_init_template (GTK_WIDGET (self)); priv = search_dialog_get_instance_private (self); priv->parser = gupnp_search_criteria_parser_new (); + + gtk_builder_add_from_resource (builder, DIALOG_RESOURCE_PATH, NULL); + gtk_builder_connect_signals (builder, self); + priv->popup_menu = GTK_WIDGET (gtk_builder_get_object (builder, "popup-menu")); } static void @@ -372,6 +391,7 @@ search_dialog_dispose (GObject *object) } g_clear_object (&priv->parser); + g_clear_object (&priv->popup_menu); if (parent_class->dispose != NULL) { parent_class->dispose (object); @@ -576,3 +596,159 @@ search_dialog_on_search_activate (SearchDialog *self, GtkEntry *entry) } } + +static void +do_popup_menu (GtkMenu *menu, GtkWidget *widget, GdkEventButton *event) +{ + int button = 0; + int event_time; + if (event) { + button = event->button; + event_time = event->time; + } else { + event_time = gtk_get_current_event_time (); + } + + gtk_menu_popup (menu, NULL, NULL, NULL, NULL, button, event_time); +} + +G_MODULE_EXPORT +gboolean +search_dialog_on_listview_button_release (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + SearchDialog *self = SEARCH_DIALOG (user_data); + SearchDialogPrivate *priv = search_dialog_get_instance_private (self); + GtkTreeSelection *selection = NULL; + GtkTreeModel *model = NULL; + GtkTreeIter iter; + GtkTreeView *treeview = priv->search_dialog_treeview; + + if (event->type != GDK_BUTTON_RELEASE || event->button != 3) { + return FALSE; + } + + selection = gtk_tree_view_get_selection (treeview); + g_assert (selection != NULL); + + /* Only show the popup menu when a row is selected */ + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { + return FALSE; + } + + do_popup_menu (GTK_MENU (priv->popup_menu), + GTK_WIDGET (treeview), + event); + + return TRUE; +} + +static void +on_object (GUPnPDIDLLiteParser *parser, + GUPnPDIDLLiteObject *object, + gpointer user_data) +{ + GUPnPDIDLLiteObject **result = (GUPnPDIDLLiteObject **)user_data; + if (*result == NULL) { + *result = object; + } +} + +static void +search_dialog_on_metadata_ready (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + SearchDialog *self = SEARCH_DIALOG (user_data); + SearchDialogPrivate *priv = search_dialog_get_instance_private (self); + AVCPMediaServer *server = AV_CP_MEDIA_SERVER (source); + GtkTreeView *treeview = priv->search_dialog_treeview; + GtkTreeModel *model = NULL; + GtkTreeSelection *selection = NULL; + char *xml; + GError *error = NULL; + GtkTreeIter iter; + + if (!av_cp_media_server_browse_metadata_finish (server, + res, + &xml, + &error)) { + // TODO: Show error + } else { + selection = gtk_tree_view_get_selection (treeview); + if (gtk_tree_selection_get_selected (selection, + &model, + &iter)) { + GUPnPDIDLLiteParser *parser = NULL; + GUPnPDIDLLiteObject *didl_object = NULL; + + parser = gupnp_didl_lite_parser_new (); + g_signal_connect (G_OBJECT (parser), + "object-available", + G_CALLBACK (on_object), + &didl_object); + gupnp_didl_lite_parser_parse_didl (parser, xml, NULL); + gtk_list_store_set (GTK_LIST_STORE (model), + &iter, + 2, didl_object, + -1); + g_object_unref (parser); + { + AVCPDidlDialog *dialog = av_cp_didl_dialog_new (); + + av_cp_didl_dialog_set_xml (dialog, xml); + gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (self)); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (GTK_WIDGET (dialog)); + g_free (xml); } + } + } +} + +G_MODULE_EXPORT +void +search_dialog_on_didl_popup_activate (SearchDialog *self, gpointer user_data) +{ + SearchDialogPrivate *priv = search_dialog_get_instance_private (self); + GtkTreeView *treeview = priv->search_dialog_treeview; + GtkTreeModel *model = NULL; + GUPnPDIDLLiteObject *didl_object = NULL; + GtkTreeSelection *selection = NULL; + GtkTreeIter iter; + char *id = NULL; + + selection = gtk_tree_view_get_selection (treeview); + + /* Only show the popup menu when a row is selected */ + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { + return; + } + + gtk_tree_model_get (model, + &iter, + 2, &didl_object, + 3, &id, + -1); + + if (didl_object != NULL) { + AVCPDidlDialog *dialog = av_cp_didl_dialog_new (); + char *xml = NULL; + + g_free (id); + xml = gupnp_didl_lite_object_get_xml_string (didl_object); + av_cp_didl_dialog_set_xml (dialog, xml); + gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (self)); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (GTK_WIDGET (dialog)); + g_free (xml); + g_object_unref (didl_object); + } else { + av_cp_media_server_browse_metadata_async (priv->server, + NULL, + search_dialog_on_metadata_ready, + id, + self); + g_free (id); + } +} diff --git a/src/av-cp/server-device.c b/src/av-cp/server-device.c index 3f6736d..09a0e4a 100644 --- a/src/av-cp/server-device.c +++ b/src/av-cp/server-device.c @@ -315,7 +315,7 @@ av_cp_media_server_introspect_finish (AVCPMediaServer *self) GList *l; for (l = self->priv->tasks; l != NULL; l = l->next) { - GTask *task = l->data; + GTask *task = (GTask *) l->data; if (self->priv->state == INITIALIZED) { g_task_return_boolean (task, TRUE); @@ -349,7 +349,7 @@ av_cp_media_server_get_content_directory (AVCPMediaServer *self) self->priv->content_directory = GUPNP_SERVICE_PROXY (info); } - return g_object_ref (self->priv->content_directory); + return GUPNP_SERVICE_PROXY (g_object_ref (self->priv->content_directory)); } typedef struct _BrowseReturn { @@ -448,7 +448,7 @@ av_cp_media_server_browse_finish (AVCPMediaServer *self, g_return_val_if_fail (g_task_is_valid (result, self), FALSE); - res = g_task_propagate_pointer (G_TASK (result), error); + res = (BrowseReturn *)g_task_propagate_pointer (G_TASK (result), error); if (res != NULL) { if (didl_xml != NULL) { *didl_xml = res->didl_xml; @@ -543,7 +543,7 @@ av_cp_media_server_browse_metadata_finish (AVCPMediaServer *self, g_return_val_if_fail (g_task_is_valid (result, self), FALSE); - res = g_task_propagate_pointer (G_TASK (result), error); + res = (char *)g_task_propagate_pointer (G_TASK (result), error); if (res != NULL) { if (didl_xml != NULL) { *didl_xml = res; |