summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Georg <mail@jensge.org>2016-09-05 22:27:52 +0200
committerJens Georg <mail@jensge.org>2016-12-17 10:45:51 +0100
commit630c5fe1cbbd9ceb3a2fe44bb654a64c8cbedb50 (patch)
tree423aa17cdcaa2ac071920c5296a40a6d9c6668fc
parentff2c72d71a31453ac6ea6933ed4de0f41b1361f5 (diff)
downloadgupnp-tools-wip/search.tar.gz
av-cp: Show DIDL in search dialogwip/search
-rw-r--r--configure.ac2
-rw-r--r--data/Makefile.am4
-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.ui20
-rw-r--r--po/POTFILES.in4
-rw-r--r--src/av-cp/playlist-treeview.c1
-rw-r--r--src/av-cp/search-dialog.c178
-rw-r--r--src/av-cp/server-device.c8
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 &lt;vdepizzol@gmail.com&gt;</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;