/* * 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; using Dee; namespace Unity { namespace Internal { internal class GLibCancellable : Unity.Cancellable { private GLib.Cancellable canc = new GLib.Cancellable (); public override void cancel () { canc.cancel (); } public override bool is_cancelled () { return canc.is_cancelled (); } public override GLib.Cancellable? get_gcancellable () { return canc; } } } /* namespace Unity.Internal */ /** * Internal transitioning class, note that it will disappear from the public * API as soon as possible and therefore shouldn't be used. */ public class DeprecatedScopeSearch : ScopeSearchBase { public string channel_id { get; construct; } public string search_string { get { return search_context.search_query; } } public SearchType search_type { get { return search_context.search_type; } } public HashTable hints { get; construct; } public Dee.SerializableModel results_model { get; construct; } public unowned DeprecatedScopeBase owner { get; construct; } public signal void finished (); private HashTable? _reply_hints = null; internal DeprecatedScopeSearch (DeprecatedScope owner, string channel_id, HashTable hints, Dee.SerializableModel results_model) { Object (owner:owner, channel_id:channel_id, hints:hints, results_model:results_model); } public void set_reply_hint (string key, Variant variant) { if (_reply_hints == null) { _reply_hints = new HashTable (str_hash, str_equal); } _reply_hints.insert (key, variant); } internal HashTable? get_reply_hints () { return _reply_hints; } public unowned Filter? get_filter (string filter_id) { return this.search_context.filter_state.get_filter_by_id (filter_id); } public bool equals (DeprecatedScopeSearch other) { if (other == null || search_string != other.search_string) return false; return true; } protected override void run () { var ml = new MainLoop (); run_async (() => { ml.quit (); }); ml.run (); } private async void real_async_run () { bool waiting = false; bool search_finished = false; // emit search_changed and wait for finished signal ulong finished_sig_id = 0; finished_sig_id = finished.connect (() => { search_finished = true; if (waiting) real_async_run.callback (); }); if (finished_sig_id == 0) { critical ("Unexpected error ocurred"); return; } // we can't resume this method as soon as the cancellable is cancelled, // cause the search might be still running and adding results to the result // set backed by a single Dee model which is shared among multiple searches var depr_scope = owner as DeprecatedScope; if (depr_scope != null) { var canc = search_context.cancellable.get_gcancellable (); depr_scope.search_changed (this, search_type, canc); waiting = true; if (!search_finished) yield; } else { warning ("Unable to perform search, expected DeprecatedScope"); } // NOTE: perhaps add a timeout and log a warning if the search takes too // long? SignalHandler.disconnect (this, finished_sig_id); } protected override void run_async (ScopeSearchBaseCallback cb) { // emit search_changed and wait for finished signal real_async_run.begin ((obj, res) => { real_async_run.end (res); cb (this); }); } } public class AggregatedScopeSearch : DeprecatedScopeSearch { public AggregatedScopeSearch (AggregatorScope owner, string channel_id, HashTable hints, Dee.SerializableModel results_model) { Object (owner:owner, channel_id:channel_id, hints:hints, results_model:results_model); } public signal void transaction_complete (string origin_scope_id); public signal void category_order_changed (uint32[] category_indices); public async HashTable search_scope (string scope_id, string search_string, SearchType search_type, HashTable? hints) throws Error { if (search_context.cancellable.is_cancelled ()) { throw new IOError.CANCELLED ("Cancelled"); } var agg_scope = owner as AggregatorScope; var canc = search_context.cancellable.get_gcancellable (); Unity.Trace.tracepoint ("subsearch:start::scope=%s;target=%s;query=%s", agg_scope.id, scope_id, search_string); var res = yield agg_scope.search_scope (this, scope_id, search_string, search_type, hints, canc); Unity.Trace.tracepoint ("subsearch:end::scope=%s;target=%s;query=%s", agg_scope.id, scope_id, search_string); return res; } public async void push_results (string scope_id, Dee.SerializableModel results_model, string[] category_ids) { if (search_context.cancellable.is_cancelled ()) return; var agg_scope = owner as AggregatorScope; var canc = search_context.cancellable.get_gcancellable (); yield agg_scope.push_results (channel_id, search_string, scope_id, results_model, category_ids, canc); } public void push_filter_settings (FilterSet filters) { if (search_context.cancellable.is_cancelled ()) return; var agg_scope = owner as AggregatorScope; agg_scope.push_filter_settings (channel_id, filters); } protected override void run () { var ml = new MainLoop (); run_async (() => { ml.quit (); }); ml.run (); } private async void real_async_run () { var agg_scope = owner as AggregatorScope; yield agg_scope.search (this); } protected override void run_async (ScopeSearchBaseCallback cb) { // emit search_changed and wait for finished signal real_async_run.begin ((obj, res) => { real_async_run.end (res); cb (this); }); } } } /* namespace */