on 2be4be1 help sign in
unity8/plugins/Unity/scope.cpp
335 lines 12 kB history raw
1/*
2 * Copyright (C) 2011 Canonical, Ltd.
3 *
4 * Authors:
5 * Florian Boucault <florian.boucault@canonical.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 3.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
20// Self
21#include "scope.h"
23// local
24#include "categories.h"
25#include "preview.h"
26#include "variantutils.h"
28// Qt
29#include <QUrl>
30#include <QDebug>
31#include <QtGui/QDesktopServices>
33#include <UnityCore/Variant.h>
35#include <libintl.h>
37Scope::Scope(QObject *parent) :
38 QObject(parent)
40 m_results = new DeeListModel(this);
41 m_categories = new Categories(this);
43 m_categories->setResultModel(m_results);
46QString Scope::id() const
48 return QString::fromStdString(m_unityScope->id());
51QString Scope::name() const
53 return QString::fromStdString(m_unityScope->name());
56QString Scope::iconHint() const
58 return QString::fromStdString(m_unityScope->icon_hint());
61QString Scope::description() const
63 return QString::fromStdString(m_unityScope->description());
66QString Scope::searchHint() const
68 return QString::fromStdString(m_unityScope->search_hint());
71bool Scope::visible() const
73 return m_unityScope->visible();
76QString Scope::shortcut() const
78 return QString::fromStdString(m_unityScope->shortcut());
81bool Scope::connected() const
83 return m_unityScope->connected();
86DeeListModel* Scope::results() const
88 return m_results;
91Categories* Scope::categories() const
93 return m_categories;
96QString Scope::searchQuery() const
98 return m_searchQuery;
101QString Scope::noResultsHint() const
103 return m_noResultsHint;
106void Scope::setSearchQuery(const QString& search_query)
108 /* Checking for m_searchQuery.isNull() which returns true only when the string
109 has never been set is necessary because when search_query is the empty
110 string ("") and m_searchQuery is the null string,
111 search_query != m_searchQuery is still true.
112 */
113 if (m_searchQuery.isNull() || search_query != m_searchQuery) {
114 m_searchQuery = search_query;
115 m_unityScope->Search(search_query.toStdString(), sigc::mem_fun(this, &Scope::searchFinished));
116 Q_EMIT searchQueryChanged();
117 }
120void Scope::setNoResultsHint(const QString& hint) {
121 if (hint != m_noResultsHint) {
122 m_noResultsHint = hint;
123 Q_EMIT noResultsHintChanged();
124 }
128unity::dash::LocalResult Scope::createLocalResult(const QVariant &uri, const QVariant &icon_hint,
129 const QVariant &category, const QVariant &result_type,
130 const QVariant &mimetype, const QVariant &title,
131 const QVariant &comment, const QVariant &dnd_uri,
132 const QVariant &metadata)
134 unity::dash::LocalResult res;
135 res.uri = uri.toString().toStdString();
136 res.icon_hint = icon_hint.toString().toStdString();
137 res.category_index = category.toUInt();
138 res.result_type = result_type.toUInt();
139 res.mimetype = mimetype.toString().toStdString();
140 res.name = title.toString().toStdString();
141 res.comment = comment.toString().toStdString();
142 res.dnd_uri = dnd_uri.toString().toStdString();
143 res.hints = convertToHintsMap(metadata);
145 return res;
148void Scope::activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
149 const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
150 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
152 auto res = createLocalResult(uri, icon_hint, category, result_type, mimetype, title, comment, dnd_uri, metadata);
153 m_unityScope->Activate(res);
156void Scope::preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
157 const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
158 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
160 auto res = createLocalResult(uri, icon_hint, category, result_type, mimetype, title, comment, dnd_uri, metadata);
161 m_unityScope->Preview(res);
164void Scope::onActivated(unity::dash::LocalResult const& result, unity::dash::ScopeHandledType type, unity::glib::HintsMap const& hints)
166 // note: we will not get called on SHOW_PREVIEW, instead UnityCore will signal preview_ready.
167 switch (type)
168 {
169 case unity::dash::NOT_HANDLED:
170 fallbackActivate(QString::fromStdString(result.uri));
171 break;
172 case unity::dash::SHOW_DASH:
173 Q_EMIT showDash();
174 break;
175 case unity::dash::HIDE_DASH:
176 Q_EMIT hideDash();
177 break;
178 case unity::dash::GOTO_DASH_URI:
179 if (hints.find("goto-uri") != hints.end()) {
180 Q_EMIT gotoUri(QString::fromStdString(g_variant_get_string(hints.at("goto-uri"), nullptr)));
181 } else {
182 qWarning() << "Missing goto-uri hint for GOTO_DASH_URI activation reply";
183 }
184 break;
185 default:
186 qWarning() << "Unhandled activation response:" << type;
187 }
190void Scope::onPreviewReady(unity::dash::LocalResult const& /* result */, unity::dash::Preview::Ptr const& preview)
192 auto prv = Preview::newFromUnityPreview(preview);
193 Q_EMIT previewReady(*prv);
196void Scope::fallbackActivate(const QString& uri)
198 /* FIXME: stripping all content before the first column because for some
199 reason the scopes give uri with junk content at their beginning.
200 */
201 QString tweakedUri = uri;
202 int firstColumnAt = tweakedUri.indexOf(":");
203 tweakedUri.remove(0, firstColumnAt+1);
205 /* Tries various methods to trigger a sensible action for the given 'uri'.
206 If it has no understanding of the given scheme it falls back on asking
207 Qt to open the uri.
208 */
209 QUrl url(tweakedUri);
210 if (url.scheme() == "file") {
211 /* Override the files place's default URI handler: we want the file
212 manager to handle opening folders, not the dash.
214 Ref: https://bugs.launchpad.net/upicek/+bug/689667
215 */
216 QDesktopServices::openUrl(url);
217 return;
218 }
219 if (url.scheme() == "application") {
220 // TODO: implement application handling
221 return;
222 }
224 qDebug() << "Trying to open" << uri;
226 /* Try our luck */
227 QDesktopServices::openUrl(uri); //url?
230void Scope::setUnityScope(const unity::dash::Scope::Ptr& scope)
232 m_unityScope = scope;
234 if (QString::fromStdString(m_unityScope->results()->swarm_name) == QString(":local")) {
235 m_results->setModel(m_unityScope->results()->model());
236 } else {
237 m_results->setName(QString::fromStdString(m_unityScope->results()->swarm_name));
238 }
240 if (QString::fromStdString(m_unityScope->categories()->swarm_name) == QString(":local")) {
241 m_categories->setModel(m_unityScope->categories()->model());
242 } else {
243 m_categories->setName(QString::fromStdString(m_unityScope->categories()->swarm_name));
244 }
246 /* Property change signals */
247 m_unityScope->id.changed.connect(sigc::mem_fun(this, &Scope::idChanged));
248 m_unityScope->name.changed.connect(sigc::mem_fun(this, &Scope::nameChanged));
249 m_unityScope->icon_hint.changed.connect(sigc::mem_fun(this, &Scope::iconHintChanged));
250 m_unityScope->description.changed.connect(sigc::mem_fun(this, &Scope::descriptionChanged));
251 m_unityScope->search_hint.changed.connect(sigc::mem_fun(this, &Scope::searchHintChanged));
252 m_unityScope->visible.changed.connect(sigc::mem_fun(this, &Scope::visibleChanged));
253 m_unityScope->shortcut.changed.connect(sigc::mem_fun(this, &Scope::shortcutChanged));
254 m_unityScope->connected.changed.connect(sigc::mem_fun(this, &Scope::connectedChanged));
255 m_unityScope->results.changed.connect(sigc::mem_fun(this, &Scope::onResultsChanged));
256 m_unityScope->results()->swarm_name.changed.connect(sigc::mem_fun(this, &Scope::onResultsSwarmNameChanged));
257 m_unityScope->results()->model.changed.connect(sigc::mem_fun(this, &Scope::onResultsModelChanged));
258 m_unityScope->categories()->model.changed.connect(sigc::mem_fun(this, &Scope::onCategoriesModelChanged));
259 m_unityScope->categories.changed.connect(sigc::mem_fun(this, &Scope::onCategoriesChanged));
260 m_unityScope->categories()->swarm_name.changed.connect(sigc::mem_fun(this, &Scope::onCategoriesSwarmNameChanged));
261 /* Signals forwarding */
262 connect(this, SIGNAL(searchFinished(const std::string &, unity::glib::HintsMap const &, unity::glib::Error const &)), SLOT(onSearchFinished(const std::string &, unity::glib::HintsMap const &)));
264 /* FIXME: signal should be forwarded instead of calling the handler directly */
265 m_unityScope->activated.connect(sigc::mem_fun(this, &Scope::onActivated));
267 m_unityScope->preview_ready.connect(sigc::mem_fun(this, &Scope::onPreviewReady));
269 /* Synchronize local states with m_unityScope right now and whenever
270 m_unityScope becomes connected */
271 /* FIXME: should emit change notification signals for all properties */
272 connect(this, SIGNAL(connectedChanged(bool)), SLOT(synchronizeStates()));
273 synchronizeStates();
276unity::dash::Scope::Ptr Scope::unityScope() const
278 return m_unityScope;
281void Scope::synchronizeStates()
283 if (connected()) {
284 /* Forward local states to m_unityScope */
285 if (!m_searchQuery.isNull()) {
286 m_unityScope->Search(m_searchQuery.toStdString());
287 }
288 }
291void Scope::onResultsSwarmNameChanged(const std::string& /* swarm_name */)
293 m_results->setName(QString::fromStdString(m_unityScope->results()->swarm_name));
296void Scope::onResultsChanged(const unity::dash::Results::Ptr& /* results */)
298 m_results->setName(QString::fromStdString(m_unityScope->results()->swarm_name));
301void Scope::onResultsModelChanged(unity::glib::Object<DeeModel> /* model */)
303 m_results->setModel(m_unityScope->results()->model());
306void Scope::onCategoriesSwarmNameChanged(const std::string& /* swarm_name */)
308 m_categories->setName(QString::fromStdString(m_unityScope->categories()->swarm_name));
311void Scope::onCategoriesChanged(const unity::dash::Categories::Ptr& /* categories */)
313 m_categories->setName(QString::fromStdString(m_unityScope->categories()->swarm_name));
316void Scope::onCategoriesModelChanged(unity::glib::Object<DeeModel> model)
318 m_categories->setModel(model);
321void Scope::onSearchFinished(const std::string& /* query */, unity::glib::HintsMap const &hints)
323 QString hint;
325 if (!m_unityScope->results()->count()) {
326 unity::glib::HintsMap::const_iterator it = hints.find("no-results-hint");
327 if (it != hints.end()) {
328 hint = QString::fromStdString(it->second.GetString());
329 } else {
330 hint = QString::fromUtf8(dgettext("unity", "Sorry, there is nothing that matches your search."));
331 }
332 }
334 setNoResultsHint(hint);