on 105cfb0 help sign in
unity8/plugins/Unity/scope.cpp
328 lines 11 kB history raw
1/*
2 * Copyright (C) 2011 Canonical, Ltd.
3 *
4 * Authors:
5 * Florian Boucault <florian.boucault@canonical.com>
6 * Michal Hruby <michal.hruby@canonical.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 3.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
21// Self
22#include "scope.h"
24// local
25#include "categories.h"
26#include "preview.h"
27#include "variantutils.h"
29// Qt
30#include <QUrl>
31#include <QDebug>
32#include <QtGui/QDesktopServices>
33#include <QQmlEngine>
35#include <UnityCore/Variant.h>
37#include <libintl.h>
38#include <glib.h>
40Scope::Scope(QObject *parent) : QObject(parent)
41 , m_formFactor("phone")
43 m_categories.reset(new Categories(this));
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();
86Categories* Scope::categories() const
88 return m_categories.get();
91QString Scope::searchQuery() const
93 return m_searchQuery;
96QString Scope::noResultsHint() const
98 return m_noResultsHint;
101QString Scope::formFactor() const
103 return m_formFactor;
106Filters* Scope::filters() const
108 return m_filters.get();
111void Scope::setSearchQuery(const QString& search_query)
113 /* Checking for m_searchQuery.isNull() which returns true only when the string
114 has never been set is necessary because when search_query is the empty
115 string ("") and m_searchQuery is the null string,
116 search_query != m_searchQuery is still true.
117 */
118 if (m_searchQuery.isNull() || search_query != m_searchQuery) {
119 m_searchQuery = search_query;
120 m_unityScope->Search(search_query.toStdString(), sigc::mem_fun(this, &Scope::searchFinished));
121 Q_EMIT searchQueryChanged();
122 }
125void Scope::setNoResultsHint(const QString& hint) {
126 if (hint != m_noResultsHint) {
127 m_noResultsHint = hint;
128 Q_EMIT noResultsHintChanged();
129 }
132void Scope::setFormFactor(const QString& form_factor) {
133 if (form_factor != m_formFactor) {
134 m_formFactor = form_factor;
135 if (m_unityScope) {
136 m_unityScope->form_factor = m_formFactor.toStdString();
137 synchronizeStates(); // will trigger a re-search
138 }
139 Q_EMIT formFactorChanged();
140 }
143unity::dash::LocalResult Scope::createLocalResult(const QVariant &uri, const QVariant &icon_hint,
144 const QVariant &category, const QVariant &result_type,
145 const QVariant &mimetype, const QVariant &title,
146 const QVariant &comment, const QVariant &dnd_uri,
147 const QVariant &metadata)
149 unity::dash::LocalResult res;
150 res.uri = uri.toString().toStdString();
151 res.icon_hint = icon_hint.toString().toStdString();
152 res.category_index = category.toUInt();
153 res.result_type = result_type.toUInt();
154 res.mimetype = mimetype.toString().toStdString();
155 res.name = title.toString().toStdString();
156 res.comment = comment.toString().toStdString();
157 res.dnd_uri = dnd_uri.toString().toStdString();
158 res.hints = convertToHintsMap(metadata);
160 return res;
163// FIXME: Change to use row index.
164void Scope::activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
165 const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
166 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
168 auto res = createLocalResult(uri, icon_hint, category, result_type, mimetype, title, comment, dnd_uri, metadata);
169 m_unityScope->Activate(res);
172// FIXME: Change to use row index.
173void Scope::preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
174 const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
175 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
177 auto res = createLocalResult(uri, icon_hint, category, result_type, mimetype, title, comment, dnd_uri, metadata);
178 m_previewCancellable.Renew();
179 m_unityScope->Preview(res, nullptr, m_previewCancellable);
182void Scope::cancelActivation()
184 m_previewCancellable.Cancel();
187void Scope::onActivated(unity::dash::LocalResult const& result, unity::dash::ScopeHandledType type, unity::glib::HintsMap const& hints)
189 // note: we will not get called on SHOW_PREVIEW, instead UnityCore will signal preview_ready.
190 switch (type)
191 {
192 case unity::dash::NOT_HANDLED:
193 fallbackActivate(QString::fromStdString(result.uri));
194 break;
195 case unity::dash::SHOW_DASH:
196 Q_EMIT showDash();
197 break;
198 case unity::dash::HIDE_DASH:
199 Q_EMIT hideDash();
200 break;
201 case unity::dash::GOTO_DASH_URI:
202 if (hints.find("goto-uri") != hints.end()) {
203 Q_EMIT gotoUri(QString::fromStdString(g_variant_get_string(hints.at("goto-uri"), nullptr)));
204 } else {
205 qWarning() << "Missing goto-uri hint for GOTO_DASH_URI activation reply";
206 }
207 break;
208 default:
209 qWarning() << "Unhandled activation response:" << type;
210 }
213void Scope::onPreviewReady(unity::dash::LocalResult const& /* result */, unity::dash::Preview::Ptr const& preview)
215 auto prv = Preview::newFromUnityPreview(preview);
216 // is this the best solution? QML may need to keep more than one preview instance around, so we can't own it.
217 // passing it by value is not possible.
218 QQmlEngine::setObjectOwnership(prv, QQmlEngine::JavaScriptOwnership);
219 Q_EMIT previewReady(prv);
222void Scope::fallbackActivate(const QString& uri)
224 /* Tries various methods to trigger a sensible action for the given 'uri'.
225 If it has no understanding of the given scheme it falls back on asking
226 Qt to open the uri.
227 */
228 QUrl url(uri);
229 if (url.scheme() == "file") {
230 /* Override the files place's default URI handler: we want the file
231 manager to handle opening folders, not the dash.
233 Ref: https://bugs.launchpad.net/upicek/+bug/689667
234 */
235 QDesktopServices::openUrl(url);
236 return;
237 }
238 if (url.scheme() == "application") {
239 // get the full path to the desktop file
240 QString path(url.path().isEmpty() ? url.authority() : url.path());
241 if (path.startsWith("/")) {
242 Q_EMIT activateApplication(path);
243 } else {
244 // TODO: use the new desktop file finder/parser when it's ready
245 gchar* full_path = nullptr;
246 GKeyFile* key_file = g_key_file_new();
247 QString apps_path = "applications/" + path;
248 if (g_key_file_load_from_data_dirs(key_file, apps_path.toLocal8Bit().constData(), &full_path,
249 G_KEY_FILE_NONE, nullptr)) {
250 path = full_path;
251 Q_EMIT activateApplication(path);
252 } else {
253 qWarning() << "Unable to activate " << path;
254 }
255 g_key_file_free(key_file);
256 g_free(full_path);
257 }
258 return;
259 }
261 qDebug() << "Trying to open" << uri;
263 /* Try our luck */
264 QDesktopServices::openUrl(uri); //url?
267void Scope::setUnityScope(const unity::dash::Scope::Ptr& scope)
269 m_unityScope = scope;
271 m_categories->setUnityScope(m_unityScope);
272 m_filters.reset(new Filters(m_unityScope->filters, this));
274 m_unityScope->form_factor = m_formFactor.toStdString();
275 /* Property change signals */
276 m_unityScope->id.changed.connect(sigc::mem_fun(this, &Scope::idChanged));
277 m_unityScope->name.changed.connect(sigc::mem_fun(this, &Scope::nameChanged));
278 m_unityScope->icon_hint.changed.connect(sigc::mem_fun(this, &Scope::iconHintChanged));
279 m_unityScope->description.changed.connect(sigc::mem_fun(this, &Scope::descriptionChanged));
280 m_unityScope->search_hint.changed.connect(sigc::mem_fun(this, &Scope::searchHintChanged));
281 m_unityScope->visible.changed.connect(sigc::mem_fun(this, &Scope::visibleChanged));
282 m_unityScope->shortcut.changed.connect(sigc::mem_fun(this, &Scope::shortcutChanged));
283 m_unityScope->connected.changed.connect(sigc::mem_fun(this, &Scope::connectedChanged));
284 /* Signals forwarding */
285 connect(this, SIGNAL(searchFinished(const std::string &, unity::glib::HintsMap const &, unity::glib::Error const &)), SLOT(onSearchFinished(const std::string &, unity::glib::HintsMap const &)));
287 /* FIXME: signal should be forwarded instead of calling the handler directly */
288 m_unityScope->activated.connect(sigc::mem_fun(this, &Scope::onActivated));
290 m_unityScope->preview_ready.connect(sigc::mem_fun(this, &Scope::onPreviewReady));
292 /* Synchronize local states with m_unityScope right now and whenever
293 m_unityScope becomes connected */
294 /* FIXME: should emit change notification signals for all properties */
295 connect(this, SIGNAL(connectedChanged(bool)), SLOT(synchronizeStates()));
296 synchronizeStates();
299unity::dash::Scope::Ptr Scope::unityScope() const
301 return m_unityScope;
304void Scope::synchronizeStates()
306 if (connected()) {
307 /* Forward local states to m_unityScope */
308 if (!m_searchQuery.isNull()) {
309 m_unityScope->Search(m_searchQuery.toStdString());
310 }
311 }
314void Scope::onSearchFinished(const std::string& /* query */, unity::glib::HintsMap const &hints)
316 QString hint;
318 if (!m_unityScope->results()->count()) {
319 unity::glib::HintsMap::const_iterator it = hints.find("no-results-hint");
320 if (it != hints.end()) {
321 hint = QString::fromStdString(it->second.GetString());
322 } else {
323 hint = QString::fromUtf8(dgettext("unity", "Sorry, there is nothing that matches your search."));
324 }
325 }
327 setNoResultsHint(hint);