Back to index

unity  6.0.0
Lens.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003  * Copyright (C) 2011 Canonical Ltd
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 3 as
00007  * published by the Free Software Foundation.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  *
00017  * Authored by: Neil Jagdish Patel <neil.patel@canonical.com>
00018  */
00019 
00020 #include "Lens.h"
00021 
00022 #include <gio/gio.h>
00023 #include <glib.h>
00024 #include <NuxCore/Logger.h>
00025 
00026 #include "config.h"
00027 #include "GLibDBusProxy.h"
00028 #include "GLibWrapper.h"
00029 
00030 namespace unity
00031 {
00032 namespace dash
00033 {
00034 
00035 namespace
00036 {
00037 nux::logging::Logger logger("unity.dash.lens");
00038 }
00039 
00040 using std::string;
00041 
00042 class Lens::Impl
00043 {
00044 public:
00045   Impl(Lens* owner,
00046        string const& id,
00047        string const& dbus_name,
00048        string const& dbus_path,
00049        string const& name,
00050        string const& icon_hint,
00051        string const& description,
00052        string const& search_hint,
00053        bool visible,
00054        string const& shortcut,
00055        ModelType model_type);
00056 
00057   ~Impl();
00058 
00059   void OnProxyConnectionChanged();
00060   void OnProxyDisconnected();
00061 
00062   void ResultsModelUpdated(unsigned long long begin_seqnum, 
00063                            unsigned long long end_seqnum);
00064   void GlobalResultsModelUpdated(unsigned long long begin_seqnum,
00065                                  unsigned long long end_seqnum);
00066 
00067   unsigned long long ExtractModelSeqnum(GVariant *parameters);
00068 
00069   void OnSearchFinished(GVariant* parameters);
00070   void OnGlobalSearchFinished(GVariant* parameters);
00071   void OnChanged(GVariant* parameters);
00072   void UpdateProperties(bool search_in_global,
00073                         bool visible,
00074                         string const& search_hint,
00075                         string const& private_connection_name,
00076                         string const& results_model_name,
00077                         string const& global_results_model_name,
00078                         string const& categories_model_name,
00079                         string const& filters_model_name);
00080   void OnViewTypeChanged(ViewType view_type);
00081 
00082   void GlobalSearch(std::string const& search_string);
00083   void Search(std::string const& search_string);
00084   void Activate(std::string const& uri);
00085   void ActivationReply(GVariant* parameters);
00086   void Preview(std::string const& uri);
00087   void PreviewReply(GVariant* parameters);
00088 
00089   string const& id() const;
00090   string const& dbus_name() const;
00091   string const& dbus_path() const;
00092   string const& name() const;
00093   string const& icon_hint() const;
00094   string const& description() const;
00095   string const& search_hint() const;
00096   bool visible() const;
00097   bool search_in_global() const;
00098   bool set_search_in_global(bool val);
00099   string const& shortcut() const;
00100   Results::Ptr const& results() const;
00101   Results::Ptr const& global_results() const;
00102   Categories::Ptr const& categories() const;
00103   Filters::Ptr const& filters() const;
00104   bool connected() const;
00105 
00106   Lens* owner_;
00107 
00108   string id_;
00109   string dbus_name_;
00110   string dbus_path_;
00111   string name_;
00112   string icon_hint_;
00113   string description_;
00114   string search_hint_;
00115   bool visible_;
00116   bool search_in_global_;
00117   string shortcut_;
00118   Results::Ptr results_;
00119   Results::Ptr global_results_;
00120   Categories::Ptr categories_;
00121   Filters::Ptr filters_;
00122   bool connected_;
00123 
00124   string private_connection_name_;
00125 
00126   glib::DBusProxy* proxy_;
00127   glib::Object<GCancellable> search_cancellable_;
00128   glib::Object<GCancellable> global_search_cancellable_;
00129 
00130   GVariant *results_variant_;
00131   GVariant *global_results_variant_;
00132 };
00133 
00134 Lens::Impl::Impl(Lens* owner,
00135                  string const& id,
00136                  string const& dbus_name,
00137                  string const& dbus_path,
00138                  string const& name,
00139                  string const& icon_hint,
00140                  string const& description,
00141                  string const& search_hint,
00142                  bool visible,
00143                  string const& shortcut,
00144                  ModelType model_type)
00145   : owner_(owner)
00146   , id_(id)
00147   , dbus_name_(dbus_name)
00148   , dbus_path_(dbus_path)
00149   , name_(name)
00150   , icon_hint_(icon_hint)
00151   , description_(description)
00152   , search_hint_(search_hint)
00153   , visible_(visible)
00154   , search_in_global_(false)
00155   , shortcut_(shortcut)
00156   , results_(new Results(model_type))
00157   , global_results_(new Results(model_type))
00158   , categories_(new Categories(model_type))
00159   , filters_(new Filters(model_type))
00160   , connected_(false)
00161   , proxy_(NULL)
00162   , results_variant_(NULL)
00163   , global_results_variant_(NULL)
00164 {
00165   if (model_type == ModelType::REMOTE)
00166   {
00167     proxy_ = new glib::DBusProxy(dbus_name, dbus_path, "com.canonical.Unity.Lens");
00168     proxy_->connected.connect(sigc::mem_fun(this, &Lens::Impl::OnProxyConnectionChanged));
00169     proxy_->disconnected.connect(sigc::mem_fun(this, &Lens::Impl::OnProxyDisconnected));
00170     proxy_->Connect("Changed", sigc::mem_fun(this, &Lens::Impl::OnChanged));
00171   }
00172 
00173   /* Technically these signals will only be fired by remote models, but we
00174    * connect them no matter the ModelType. Dee may grow support in the future.
00175    */
00176   results_->end_transaction.connect(sigc::mem_fun(this, &Lens::Impl::ResultsModelUpdated));
00177   global_results_->end_transaction.connect(sigc::mem_fun(this, &Lens::Impl::GlobalResultsModelUpdated));
00178 
00179   owner_->id.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::id));
00180   owner_->dbus_name.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::dbus_name));
00181   owner_->dbus_path.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::dbus_path));
00182   owner_->name.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::name));
00183   owner_->icon_hint.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::icon_hint));
00184   owner_->description.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::description));
00185   owner_->search_hint.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::search_hint));
00186   owner_->visible.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::visible));
00187   owner_->search_in_global.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::search_in_global));
00188   owner_->search_in_global.SetSetterFunction(sigc::mem_fun(this, &Lens::Impl::set_search_in_global));
00189   owner_->shortcut.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::shortcut));
00190   owner_->results.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::results));
00191   owner_->global_results.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::global_results));
00192   owner_->categories.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::categories));
00193   owner_->filters.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::filters));
00194   owner_->connected.SetGetterFunction(sigc::mem_fun(this, &Lens::Impl::connected));
00195   owner_->view_type.changed.connect(sigc::mem_fun(this, &Lens::Impl::OnViewTypeChanged));
00196 }
00197 
00198 Lens::Impl::~Impl()
00199 {
00200   if (search_cancellable_)
00201   {
00202     g_cancellable_cancel (search_cancellable_);
00203   }
00204   if (global_search_cancellable_)
00205   {
00206     g_cancellable_cancel (global_search_cancellable_);
00207   }
00208 
00209   if (proxy_)
00210     delete proxy_;
00211 }
00212 
00213 void Lens::Impl::OnProxyConnectionChanged()
00214 {
00215   if (proxy_->IsConnected())
00216   {
00217     proxy_->Call("InfoRequest");
00218     ViewType current_view_type = owner_->view_type;
00219     proxy_->Call("SetViewType", g_variant_new("(u)", current_view_type));
00220   }
00221 }
00222 
00223 void Lens::Impl::OnProxyDisconnected()
00224 {
00225   connected_ = false;
00226   owner_->connected.EmitChanged(connected_);
00227 }
00228 
00229 void Lens::Impl::ResultsModelUpdated(unsigned long long begin_seqnum,
00230                                      unsigned long long end_seqnum)
00231 {
00232   if (results_variant_ != NULL &&
00233       end_seqnum >= ExtractModelSeqnum (results_variant_))
00234   {
00235     glib::Variant dict(results_variant_, glib::StealRef());
00236     Hints hints;
00237 
00238     dict.ASVToHints(hints);
00239 
00240     owner_->search_finished.emit(hints);
00241 
00242     results_variant_ = NULL;
00243   }
00244 }
00245 
00246 void Lens::Impl::GlobalResultsModelUpdated(unsigned long long begin_seqnum,
00247                                            unsigned long long end_seqnum)
00248 {
00249   if (global_results_variant_ != NULL &&
00250       end_seqnum >= ExtractModelSeqnum (global_results_variant_))
00251   {
00252     glib::Variant dict(global_results_variant_, glib::StealRef());
00253     Hints hints;
00254 
00255     dict.ASVToHints(hints);
00256 
00257     owner_->global_search_finished.emit(hints);
00258 
00259     global_results_variant_ = NULL;
00260   }
00261 }
00262 
00263 unsigned long long Lens::Impl::ExtractModelSeqnum(GVariant *parameters)
00264 {
00265   GVariant *dict;
00266   guint64 seqnum64;
00267   unsigned long long seqnum = 0;
00268 
00269   dict = g_variant_get_child_value (parameters, 0);
00270   if (dict)
00271   {
00272     if (g_variant_lookup (dict, "model-seqnum", "t", &seqnum64))
00273     {
00274       seqnum = static_cast<unsigned long long> (seqnum64);
00275     }
00276 
00277     g_variant_unref (dict);
00278   }
00279 
00280   return seqnum;
00281 }
00282 
00283 void Lens::Impl::OnSearchFinished(GVariant* parameters)
00284 {
00285   Hints hints;
00286   unsigned long long reply_seqnum;
00287 
00288   reply_seqnum = ExtractModelSeqnum (parameters);
00289   if (results_->seqnum < reply_seqnum)
00290   {
00291     // wait for the end-transaction signal
00292     if (results_variant_) g_variant_unref (results_variant_);
00293     results_variant_ = g_variant_ref (parameters);
00294 
00295     // ResultsModelUpdated will emit OnSearchFinished
00296     return;
00297   }
00298 
00299   glib::Variant dict (parameters);
00300   dict.ASVToHints(hints);
00301 
00302   owner_->search_finished.emit(hints);
00303 }
00304 
00305 void Lens::Impl::OnGlobalSearchFinished(GVariant* parameters)
00306 {
00307   Hints hints;
00308   unsigned long long reply_seqnum;
00309   
00310   reply_seqnum = ExtractModelSeqnum (parameters);
00311   if (global_results_->seqnum < reply_seqnum)
00312   {
00313     // wait for the end-transaction signal
00314     if (global_results_variant_) g_variant_unref (global_results_variant_);
00315     global_results_variant_ = g_variant_ref (parameters);
00316 
00317     // GlobalResultsModelUpdated will emit OnGlobalSearchFinished
00318     return;
00319   }
00320 
00321   glib::Variant dict (parameters);
00322   dict.ASVToHints(hints);
00323 
00324   owner_->global_search_finished.emit(hints);
00325 }
00326 
00327 void Lens::Impl::OnChanged(GVariant* parameters)
00328 {
00329   glib::String dbus_path;
00330   gboolean search_in_global = FALSE;
00331   gboolean visible = FALSE;
00332   glib::String search_hint;
00333   glib::String private_connection_name;
00334   glib::String results_model_name;
00335   glib::String global_results_model_name;
00336   glib::String categories_model_name;
00337   glib::String filters_model_name;
00338   GVariantIter* hints_iter = NULL;
00339 
00340   g_variant_get(parameters, "((sbbssssssa{sv}))",
00341                 &dbus_path,
00342                 &search_in_global,
00343                 &visible,
00344                 &search_hint,
00345                 &private_connection_name,
00346                 &results_model_name,
00347                 &global_results_model_name,
00348                 &categories_model_name,
00349                 &filters_model_name,
00350                 &hints_iter);
00351 
00352   LOG_DEBUG(logger) << "Lens info changed for " << name_ << "\n"
00353                     << "  Path: " << dbus_path << "\n"
00354                     << "  SearchInGlobal: " << search_in_global << "\n"
00355                     << "  Visible: " << visible << "\n"
00356                     << "  PrivateConnName: " << private_connection_name << "\n"
00357                     << "  Results: " << results_model_name << "\n"
00358                     << "  GlobalModel: " << global_results_model_name << "\n"
00359                     << "  Categories: " << categories_model_name << "\n"
00360                     << "  Filters: " << filters_model_name << "\n";
00361   if (dbus_path.Str() == dbus_path_)
00362   {
00363     /* FIXME: We ignore hints for now */
00364     UpdateProperties(search_in_global,
00365                      visible,
00366                      search_hint.Str(),
00367                      private_connection_name.Str(),
00368                      results_model_name.Str(),
00369                      global_results_model_name.Str(),
00370                      categories_model_name.Str(),
00371                      filters_model_name.Str());
00372   }
00373   else
00374   {
00375     LOG_WARNING(logger) << "Paths do not match " << dbus_path_ << " != " << dbus_path;
00376   }
00377 
00378   connected_ = true;
00379   owner_->connected.EmitChanged(connected_);
00380 
00381   g_variant_iter_free(hints_iter);
00382 }
00383 
00384 void Lens::Impl::UpdateProperties(bool search_in_global,
00385                                   bool visible,
00386                                   string const& search_hint,
00387                                   string const& private_connection_name,
00388                                   string const& results_model_name,
00389                                   string const& global_results_model_name,
00390                                   string const& categories_model_name,
00391                                   string const& filters_model_name)
00392 {
00393   // Diff the properties received from those we have
00394   if (search_hint_ != search_hint)
00395   {
00396     search_hint_ = search_hint;
00397     owner_->search_hint.EmitChanged(search_hint_);
00398   }
00399 
00400   if (search_in_global_ != search_in_global)
00401   {
00402     search_in_global_ = search_in_global;
00403     owner_->search_in_global.EmitChanged(search_in_global_);
00404   }
00405 
00406   if (visible_ != visible)
00407   {
00408     visible_ = visible;
00409     owner_->visible.EmitChanged(visible_);
00410   }
00411 
00412   if (private_connection_name_ != private_connection_name)
00413   {
00414     // FIXME: Update all the models as they are no longer valid when we use this
00415     private_connection_name_ = private_connection_name;
00416   }
00417   categories_->swarm_name = categories_model_name;
00418   filters_->swarm_name = filters_model_name;
00419   global_results_->swarm_name = global_results_model_name;
00420   results_->swarm_name = results_model_name;
00421 }
00422 
00423 void Lens::Impl::OnViewTypeChanged(ViewType view_type)
00424 {
00425   if (proxy_ && proxy_->IsConnected())
00426     proxy_->Call("SetViewType", g_variant_new("(u)", view_type));
00427 }
00428 
00429 void Lens::Impl::GlobalSearch(std::string const& search_string)
00430 {
00431   LOG_DEBUG(logger) << "Global Searching '" << id_ << "' for '" << search_string << "'";
00432 
00433   GVariantBuilder b;
00434   g_variant_builder_init(&b, G_VARIANT_TYPE("a{sv}"));
00435 
00436   if (global_search_cancellable_)
00437     g_cancellable_cancel (global_search_cancellable_);
00438   global_search_cancellable_ = g_cancellable_new ();
00439 
00440   if (global_results_variant_)
00441   {
00442     g_variant_unref (global_results_variant_);
00443     global_results_variant_ = NULL;
00444   }
00445 
00446   proxy_->Call("GlobalSearch",
00447               g_variant_new("(sa{sv})",
00448                             search_string.c_str(),
00449                             &b),
00450               sigc::mem_fun(this, &Lens::Impl::OnGlobalSearchFinished),
00451               global_search_cancellable_);
00452   g_variant_builder_clear(&b);
00453 }
00454 
00455 void Lens::Impl::Search(std::string const& search_string)
00456 {
00457   LOG_DEBUG(logger) << "Searching '" << id_ << "' for '" << search_string << "'";
00458 
00459   if (proxy_ == NULL)
00460   {
00461     LOG_DEBUG(logger) << "Skipping search. Proxy not initialized. ('" << id_ << "')";
00462     return;
00463   }
00464 
00465   GVariantBuilder b;
00466   g_variant_builder_init(&b, G_VARIANT_TYPE("a{sv}"));
00467 
00468   if (search_cancellable_) g_cancellable_cancel (search_cancellable_);
00469   search_cancellable_ = g_cancellable_new ();
00470 
00471   if (results_variant_)
00472   {
00473     g_variant_unref (results_variant_);
00474     results_variant_ = NULL;
00475   }
00476 
00477   proxy_->Call("Search",
00478                g_variant_new("(sa{sv})",
00479                              search_string.c_str(),
00480                              &b),
00481                sigc::mem_fun(this, &Lens::Impl::OnSearchFinished),
00482                search_cancellable_);
00483 
00484   g_variant_builder_clear(&b);
00485 }
00486 
00487 void Lens::Impl::Activate(std::string const& uri)
00488 {
00489   LOG_DEBUG(logger) << "Activating '" << uri << "' on  '" << id_ << "'";
00490 
00491   if (!proxy_->IsConnected())
00492     {
00493       LOG_DEBUG(logger) << "Skipping activation. Proxy not connected. ('" << id_ << "')";
00494       return;
00495     }
00496 
00497   proxy_->Call("Activate",
00498                g_variant_new("(su)", uri.c_str(), 0),
00499                sigc::mem_fun(this, &Lens::Impl::ActivationReply));
00500 }
00501 
00502 void Lens::Impl::ActivationReply(GVariant* parameters)
00503 {
00504   glib::String uri;
00505   guint32 handled;
00506   GVariant* hints_variant;
00507   Hints hints;
00508   
00509   g_variant_get(parameters, "((su@a{sv}))", &uri, &handled, &hints_variant);
00510 
00511   glib::Variant dict (hints_variant, glib::StealRef());
00512   dict.ASVToHints(hints);
00513 
00514   owner_->activated.emit(uri.Str(), static_cast<HandledType>(handled), hints);
00515 }
00516 
00517 void Lens::Impl::Preview(std::string const& uri)
00518 {
00519   LOG_DEBUG(logger) << "Previewing '" << uri << "' on  '" << id_ << "'";
00520 
00521   if (!proxy_->IsConnected())
00522     {
00523       LOG_DEBUG(logger) << "Skipping preview. Proxy not connected. ('" << id_ << "')";
00524       return;
00525     }
00526 
00527   proxy_->Call("Preview",
00528                g_variant_new("(s)", uri.c_str()),
00529                sigc::mem_fun(this, &Lens::Impl::PreviewReply));
00530 }
00531 
00532 void Lens::Impl::PreviewReply(GVariant* parameters)
00533 {
00534   glib::String uri;
00535   glib::String renderer_name;
00536   GVariant* hints_variant;
00537   Hints hints;
00538   
00539   g_variant_get(parameters, "((ss@a{sv}))", &uri, &renderer_name, &hints_variant);
00540 
00541   glib::Variant dict (hints_variant, glib::StealRef());
00542   dict.ASVToHints(hints);
00543 
00544   Preview::Ptr preview = Preview::PreviewForProperties(renderer_name.Str(), hints);
00545   owner_->preview_ready.emit(uri.Str(), preview);
00546 }
00547 string const& Lens::Impl::id() const
00548 {
00549   return id_;
00550 }
00551 
00552 string const& Lens::Impl::dbus_name() const
00553 {
00554   return dbus_name_;
00555 }
00556 
00557 string const& Lens::Impl::dbus_path() const
00558 {
00559   return dbus_path_;
00560 }
00561 
00562 string const& Lens::Impl::name() const
00563 {
00564   return name_;
00565 }
00566 
00567 string const& Lens::Impl::icon_hint() const
00568 {
00569   return icon_hint_;
00570 }
00571 
00572 string const& Lens::Impl::description() const
00573 {
00574   return description_;
00575 }
00576 
00577 string const& Lens::Impl::search_hint() const
00578 {
00579   return search_hint_;
00580 }
00581 
00582 bool Lens::Impl::visible() const
00583 {
00584   return visible_;
00585 }
00586 
00587 bool Lens::Impl::search_in_global() const
00588 {
00589   return search_in_global_;
00590 }
00591 
00592 bool Lens::Impl::set_search_in_global(bool val)
00593 {
00594   if (search_in_global_ != val)
00595   {
00596     search_in_global_ = val;
00597     owner_->search_in_global.EmitChanged(val);
00598   }
00599 
00600   return search_in_global_;
00601 }
00602 
00603 string const& Lens::Impl::shortcut() const
00604 {
00605   return shortcut_;
00606 }
00607 
00608 Results::Ptr const& Lens::Impl::results() const
00609 {
00610   return results_;
00611 }
00612 
00613 Results::Ptr const& Lens::Impl::global_results() const
00614 {
00615   return global_results_;
00616 }
00617 
00618 Categories::Ptr const& Lens::Impl::categories() const
00619 {
00620   return categories_;
00621 }
00622 
00623 Filters::Ptr const& Lens::Impl::filters() const
00624 {
00625   return filters_;
00626 }
00627 
00628 bool Lens::Impl::connected() const
00629 {
00630   return connected_;
00631 }
00632 
00633 Lens::Lens(string const& id_,
00634            string const& dbus_name_,
00635            string const& dbus_path_,
00636            string const& name_,
00637            string const& icon_hint_,
00638            string const& description_,
00639            string const& search_hint_,
00640            bool visible_,
00641            string const& shortcut_)
00642 
00643   : pimpl(new Impl(this,
00644                    id_,
00645                    dbus_name_,
00646                    dbus_path_,
00647                    name_,
00648                    icon_hint_,
00649                    description_,
00650                    search_hint_,
00651                    visible_,
00652                    shortcut_,
00653                    ModelType::REMOTE))
00654 {}
00655 
00656 Lens::Lens(string const& id_,
00657             string const& dbus_name_,
00658             string const& dbus_path_,
00659             string const& name_,
00660             string const& icon_hint_,
00661             string const& description_,
00662             string const& search_hint_,
00663             bool visible_,
00664             string const& shortcut_,
00665             ModelType model_type)
00666 
00667   : pimpl(new Impl(this,
00668                    id_,
00669                    dbus_name_,
00670                    dbus_path_,
00671                    name_,
00672                    icon_hint_,
00673                    description_,
00674                    search_hint_,
00675                    visible_,
00676                    shortcut_,
00677                    model_type))
00678 {}
00679 
00680 Lens::~Lens()
00681 {
00682   delete pimpl;
00683 }
00684 
00685 void Lens::GlobalSearch(std::string const& search_string)
00686 {
00687   pimpl->GlobalSearch(search_string);
00688 }
00689 
00690 void Lens::Search(std::string const& search_string)
00691 {
00692   pimpl->Search(search_string);
00693 }
00694 
00695 void Lens::Activate(std::string const& uri)
00696 {
00697   pimpl->Activate(uri);
00698 }
00699 
00700 void Lens::Preview(std::string const& uri)
00701 {
00702   pimpl->Preview(uri);
00703 }
00704 
00705 }
00706 }