/* * Copyright (C) 2011 Canonical, Ltd. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License * version 3.0 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3.0 for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . * * Authored by Neil Jagdish Patel * */ using GLib; namespace Unity { /* * Previews */ public abstract class Preview : AbstractPreview, Dee.Serializable { public string title { get { return _raw.title; } set { _raw.title = value; } } public string subtitle { get { return _raw.subtitle; } set { _raw.subtitle = value; } } public string description_markup { get { return _raw.description; } set { _raw.description = value; } } /** * Source for the image. * * URI to the source which can be used to generate a thumbnail. (for example * a .pdf file, .webm etc). If a thumbnail in appropriate resolution * is already available use the "image" property instead. */ public string image_source_uri { get { return _raw.image_source_uri; } set { _raw.image_source_uri = value; } } public Icon? image { get { return _raw.image; } set { _raw.image = value; } } private Protocol.Preview? _raw; internal unowned Protocol.Preview? get_raw () { return _raw; } construct { _raw = create_raw () as Protocol.Preview; warn_if_fail (_raw != null); } // as a virtual method this will get into our main .h file and we don't want // to add dep on the unity-protocol library, therefore it returns Object // instead of Protocol.Preview internal abstract Object create_raw (); private GenericArray _actions = new GenericArray (); public void add_action (PreviewAction action) { _actions.add (action); _raw.add_action_with_hints (action.id, action.display_name, action.icon_hint, action.layout_hint, action.get_hints_internal ()); } public void add_info (InfoHint info_hint) { // unlike Vala, C will likely pass floating ref var sunk = info_hint.ref_sink () as InfoHint; _raw.add_info_hint (sunk.id, sunk.display_name, sunk.icon_hint, sunk.data); } internal unowned GenericArray get_actions () { return _actions; } private Variant serialize () { return _raw.serialize (); } protected override uint8[] serialize_as (Unity.SerializationType serialize_type) { switch (serialize_type) { case SerializationType.BINARY: Variant serialized = this.serialize (); var result = new uint8[serialized.get_size ()]; serialized.store (result); return result; case SerializationType.JSON: return """{"error": "JSON serialization not supported"}""".data; } return {}; } } /* This is 1:1 copy of Protocol.LayoutHint, but we need to expose this * to our gir, we don't want to depend on UnityProtocol's gir */ public enum LayoutHint { NONE, LEFT, RIGHT, TOP, BOTTOM } public class PreviewAction : Object, Dee.Serializable // TODO: Implement GLib.Action { public string id { get; construct; } public string display_name { get; construct; } public string extra_text { get; set; } public Icon? icon_hint { get; construct; } public LayoutHint layout_hint { get; construct; } public HashTable? hints { get { return hints_; } } private HashTable hints_ = new HashTable (str_hash, str_equal); public PreviewAction (string id, string display_name, Icon? icon_hint) { Object (id: id, display_name: display_name, icon_hint: icon_hint); } public PreviewAction.with_layout_hint (string id, string display_name, Icon? icon_hint, LayoutHint layout) { Object (id: id, display_name: display_name, icon_hint: icon_hint, layout_hint: layout); } public PreviewAction.with_uri (string uri, string display_name, Icon? icon_hint) { Object (id: uri, display_name: display_name, icon_hint: icon_hint); hints["activation-uri"] = uri; } public signal ActivationResponse activated (string uri); private Variant serialize () { // FIXME: we should use PreviewActionRaw, but this is faster Variant tuple[5]; tuple[0] = id; tuple[1] = display_name; tuple[2] = new Variant.string (icon_hint != null ? icon_hint.to_string () : ""); tuple[3] = (uint) layout_hint; tuple[4] = get_hints_internal (); return new Variant.tuple (tuple); } internal unowned HashTable get_hints_internal () { if (extra_text != null && extra_text[0] != '\0') hints["extra-text"] = extra_text; return hints; } static construct { Dee.Serializable.register_parser (typeof (PreviewAction), new VariantType ("(sssua{sv})"), (data) => { unowned string icon_hint = data.get_child_value (2).get_string (); Icon? icon = null; if (icon_hint != null && icon_hint != "") { try { icon = Icon.new_for_string (icon_hint); } catch (Error err) { warning ("Failed to deserialize GIcon: %s", err.message); } } var result = new PreviewAction.with_layout_hint ( data.get_child_value (0).get_string (), data.get_child_value (1).get_string (), icon, (LayoutHint) data.get_child_value (3).get_uint32 ()); result.hints_ = (HashTable) data.get_child_value (4); return result; }); } } public class InfoHint : InitiallyUnowned { public string id { get; construct; } public string display_name { get; construct; } public Icon? icon_hint { get; construct; } public Variant data { get; construct; } public InfoHint (string id, string display_name, Icon? icon_hint, string data) { Object (id: id, display_name: display_name, icon_hint: icon_hint, data: new Variant.string (data)); } public InfoHint.with_variant (string id, string display_name, Icon? icon_hint, Variant data) { Object (id: id, display_name: display_name, icon_hint: icon_hint, data: data); } } public class GenericPreview : Preview { public GenericPreview (string title, string description, Icon? image) { Object (title: title, image: image, description_markup: description); } internal static GenericPreview empty () { var preview = new GenericPreview ("", "", null); preview.get_raw ().set_no_details (true); return preview; } internal override Object create_raw () { return new Protocol.GenericPreview (); } } public class ApplicationPreview : Preview { public Icon app_icon { get { return _raw.app_icon; } set { _raw.app_icon = value; } } public string license { get { return _raw.license; } set { _raw.license = value; } } public string copyright { get { return _raw.copyright; } set { _raw.copyright = value; } } public string last_update { get { return _raw.last_update; } set { _raw.last_update = value; } } public ApplicationPreview (string title, string subtitle, string description, Icon? icon, Icon? screenshot) { Object (title: title, subtitle: subtitle, image: screenshot, description_markup: description, app_icon: icon); } public void set_rating (float rating, uint num_ratings) { _raw.rating = rating; _raw.num_ratings = num_ratings; } private unowned Protocol.ApplicationPreview _raw; internal override Object create_raw () { var raw = new Protocol.ApplicationPreview (); _raw = raw; return _raw; } } public class MusicPreview : Preview { /* Keep in sync with Protocol.PlayState! */ public enum TrackState { STOPPED, PLAYING, PAUSED } private Dee.SerializableModel _track_data; public MusicPreview (string title, string subtitle, Icon? image) { Object (title: title, subtitle: subtitle, image: image); } private unowned Protocol.MusicPreview _raw; internal override Object create_raw () { var raw = new Protocol.MusicPreview (); _raw = raw; return _raw; } public void add_track (TrackMetadata track) { init_model (); _track_data.append (track.uri, track.track_no, track.title, track.length, TrackState.STOPPED, 0.0); } // use add_info to add total number of tracks and "tags" private enum TrackDataColumns { URI, TRACK_NO, TITLE, LENGTH, PLAY_STATE, PROGRESS } private void init_model () { if (_track_data == null) { _track_data = new Dee.SequenceModel (); _track_data.set_schema ("s", "i", "s", "u", "u", "d"); _track_data.set_column_names ("uri", "track-number", "title", "length", "play-state", "progress"); _raw.track_model = _track_data; } } } public class PaymentPreview : Preview { public enum Type { APPLICATION, MUSIC, ERROR } public string header { get { return _raw.header; } set { _raw.header = value;} } public string email { get { return _raw.email; } set { _raw.email = value; } } public string payment_method { get { return _raw.payment_method; } set { _raw.payment_method = value; } } public string purchase_prize { get { return _raw.purchase_prize; } set { _raw.purchase_prize = value; } } public string purchase_type { get { return _raw.purchase_type; } set { _raw.purchase_type = value; } } public Type preview_type { get { return (Type) _raw.preview_type; } set { _raw.preview_type = (Unity.Protocol.PreviewPaymentType) value; } } public PaymentPreview (string title, string subtitle, Icon? image) { Object (title: title, subtitle: subtitle, image: image); } public PaymentPreview.for_type (string title, string subtitle, Icon? image, Type type) { this (title, subtitle, image); preview_type = type; } public PaymentPreview.for_application (string title, string subtitle, Icon? image) { this.for_type (title, subtitle, image, Type.APPLICATION); } public PaymentPreview.for_music (string title, string subtitle, Icon? image) { this.for_type (title, subtitle, image, Type.MUSIC); } public PaymentPreview.for_error (string title, string subtitle, Icon? image) { this.for_type (title, subtitle, image, Type.ERROR); } static construct { // perform assertion so that we do not have bad castings if // someone forgot to keep the enums synced static_assert ((int) Protocol.PreviewPaymentType.APPLICATION == (int) Type.APPLICATION); static_assert ((int) Protocol.PreviewPaymentType.MUSIC == (int) Type.MUSIC); static_assert ((int) Protocol.PreviewPaymentType.ERROR == (int) Type.ERROR); } private unowned Protocol.PaymentPreview _raw; internal override Object create_raw () { var raw = new Protocol.PaymentPreview (); _raw = raw; return _raw; } } public class MoviePreview : Preview { public string year { get { return _raw.year; } set { _raw.year = value; } } public MoviePreview (string title, string subtitle, string description, Icon? image) { Object (title: title, subtitle: subtitle, description_markup: description, image: image); } public void set_rating (float rating, uint num_ratings) { _raw.rating = rating; _raw.num_ratings = num_ratings; } private unowned Protocol.MoviePreview _raw; internal override Object create_raw () { var raw = new Protocol.MoviePreview (); _raw = raw; return _raw; } } public class SocialPreview : Preview { public class Comment : InitiallyUnowned { public string id { get; construct; } public string name { get; construct; } public string text { get; construct; } public string time { get; construct; } public Comment (string id, string name, string text, string time) { Object (id: id, name: name, text: text, time: time); } } public Icon avatar { get { return _raw.avatar; } set { _raw.avatar = value; } } public string content { get { return _raw.description; } set { _raw.description = value; } } public string sender { get { return _raw.sender; } set { _raw.sender = value; } } public SocialPreview (string sender, string subtitle, string content, Icon? avatar) { Object (title: sender, subtitle: subtitle, content: content, avatar: avatar); } private unowned Protocol.SocialPreview _raw; internal override Object create_raw () { var raw = new Protocol.SocialPreview (); _raw = raw; return _raw; } public void add_comment (Comment comment) { // unlike Vala, C will likely pass floating ref var sunk = comment.ref_sink () as Comment; _raw.add_comment (sunk.id, sunk.name, sunk.text, sunk.time); } } } /* namespace */