Commit 630c5fe1 authored by Jens Georg's avatar Jens Georg

av-cp: Show DIDL in search dialog

parent ff2c72d7
......@@ -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
......
......@@ -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)
......
......@@ -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>
......
......@@ -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"/>
......
......@@ -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>
......
# 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
......
......@@ -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;
......
......@@ -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);
}
}
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment