2 * Copyright (C) 2009 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>.
3 * Copyright (C) 2009,2010 Nokia Corporation.
5 * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
6 * <zeeshan.ali@nokia.com>
8 * This file is part of Rygel.
10 * Rygel is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * Rygel is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
30 * Represents an external container.
32 public class Rygel.External.Container : Rygel.MediaContainer {
33 public MediaContainerProxy actual_container;
35 public string host_ip;
36 public string service_name;
38 private ItemFactory item_factory;
39 private ArrayList<Container> containers;
41 private bool searchable;
43 public Container (string id,
50 Container? parent = null) throws IOError {
51 base (id, parent, title, (int) child_count);
53 this.service_name = service_name;
54 this.host_ip = host_ip;
55 this.item_factory = new ItemFactory ();
56 this.containers = new ArrayList<Container> ();
58 // Create proxy to MediaContainer iface
59 this.actual_container = Bus.get_proxy_sync (BusType.SESSION,
63 this.update_container.begin (true);
66 public override async MediaObjects? get_children (uint offset,
68 Cancellable? cancellable)
72 foreach (var object_prop in MediaObjectProxy.PROPERTIES) {
73 filter += object_prop;
76 foreach (var item_prop in MediaItemProxy.PROPERTIES) {
80 var children_props = yield this.actual_container.list_children (
85 return yield this.create_media_objects (children_props, this);
88 public override async MediaObjects? search (SearchExpression? expression,
91 out uint total_matches,
92 Cancellable? cancellable)
94 if (expression == null || !this.searchable) {
95 // Either its wildcard or backend doesn't implement search :(
96 return yield base.search (expression,
103 string[] filter = {};
104 foreach (var object_prop in MediaObjectProxy.PROPERTIES) {
105 filter += object_prop;
108 foreach (var container_prop in MediaContainerProxy.PROPERTIES) {
109 filter += container_prop;
112 foreach (var item_prop in MediaItemProxy.PROPERTIES) {
116 var ext_expression = this.translate_expression (expression);
117 var result = yield this.actual_container.search_objects (
118 ext_expression.to_string (),
122 total_matches = result.length;
124 return yield this.create_media_objects (result);
127 public override async MediaObject? find_object (string id,
128 Cancellable? cancellable)
130 MediaObject media_object = null;
132 // Create proxy to MediaObject iface
133 MediaObjectProxy actual_object = Bus.get_proxy_sync (BusType.SESSION,
137 if (actual_object.object_type == "container") {
138 media_object = this.find_container_by_id (id);
140 if (media_object == null) {
141 // Not a child container, lets search in child containers then
142 foreach (var container in this.containers) {
143 media_object = yield container.find_object (id,
146 if (media_object != null) {
152 var parent_container = new DummyContainer
153 ((string) actual_object.parent,
158 Properties props_iface = Bus.get_proxy_sync (BusType.SESSION,
162 var props = yield props_iface.get_all (MediaItemProxy.IFACE);
165 media_object = yield this.item_factory.create (
167 actual_object.object_type,
168 actual_object.display_name,
178 private async MediaObjects create_media_objects (
179 HashTable<string,Variant>[] all_props,
180 MediaContainer? parent
181 = null) throws GLib.Error {
182 var media_objects = new MediaObjects ();
184 foreach (var props in all_props) {
185 var id = (string) props.lookup ("Path");
186 var type = (string) props.lookup ("Type");
188 MediaContainer parent_container;
189 if (parent != null) {
190 parent_container = parent;
192 var parent_id = (string) props.lookup ("Parent");
194 parent_container = new DummyContainer (parent_id,
200 MediaObject media_object = null;
201 if (type == "container") {
202 media_object = this.find_container_by_id (id);
205 if (media_object == null) {
206 var title = (string) props.lookup ("DisplayName");
208 if (type == "container") {
209 var child_count = (uint) props.lookup ("ChildCount");
211 media_object = new DummyContainer (id,
217 media_object = yield this.item_factory.create (
228 media_objects.add (media_object);
231 return media_objects;
234 private async void refresh_child_containers () throws GLib.Error {
235 string[] filter = {};
237 foreach (var object_prop in MediaObjectProxy.PROPERTIES) {
238 filter += object_prop;
241 foreach (var container_prop in MediaContainerProxy.PROPERTIES) {
242 filter += container_prop;
245 var children_props = yield this.actual_container.list_containers (
249 this.containers.clear ();
251 foreach (var props in children_props) {
252 var path = (string) props.lookup ("Path");
253 var title = (string) props.lookup ("DisplayName");
254 var child_count = (uint) props.lookup ("ChildCount");
255 var searchable = (bool) props.lookup ("Searchable");
257 var container = new Container (path,
265 this.containers.add (container);
269 private async void update_container (bool connect_signal = false) {
271 // Update our information about the container
272 yield this.refresh_child_containers ();
273 } catch (GLib.Error err) {
274 warning ("Failed to update information about container '%s': %s",
275 this.actual_container.get_object_path (),
279 // and signal the clients
282 if (connect_signal) {
283 this.actual_container.updated.connect (this.on_updated);
287 private void on_updated (MediaContainerProxy actual_container) {
288 this.update_container.begin ();
291 private MediaContainer find_container_by_id (string id) {
292 MediaContainer target = null;
294 foreach (var container in this.containers) {
295 if (container.id == id) {
305 private SearchExpression translate_expression (
306 SearchExpression upnp_expression) {
307 if (upnp_expression is RelationalExpression) {
308 var expression = upnp_expression as RelationalExpression;
309 var ext_expression = new RelationalExpression ();
310 ext_expression.op = expression.op;
311 ext_expression.operand1 = this.translate_property (
312 expression.operand1);
313 ext_expression.operand2 = expression.operand2;
315 return ext_expression;
317 var expression = upnp_expression as LogicalExpression;
318 var ext_expression = new LogicalExpression ();
320 ext_expression.op = expression.op;
321 ext_expression.operand1 = this.translate_expression (
322 expression.operand1);
323 ext_expression.operand2 = this.translate_expression (
324 expression.operand2);
326 return ext_expression;
330 public string translate_property (string property) {
337 return "DisplayName";