on 39bacfa help sign in
unity8/plugins/Unity/scope.cpp
303 lines 10 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>
39Scope::Scope(QObject *parent) :
40 QObject(parent)
42 m_categories.reset(new Categories(this));
45QString Scope::id() const
47 return QString::fromStdString(m_unityScope->id());
50QString Scope::name() const
52 return QString::fromStdString(m_unityScope->name());
55QString Scope::iconHint() const
57 return QString::fromStdString(m_unityScope->icon_hint());
60QString Scope::description() const
62 return QString::fromStdString(m_unityScope->description());
65QString Scope::searchHint() const
67 return QString::fromStdString(m_unityScope->search_hint());
70bool Scope::visible() const
72 return m_unityScope->visible();
75QString Scope::shortcut() const
77 return QString::fromStdString(m_unityScope->shortcut());
80bool Scope::connected() const
82 return m_unityScope->connected();
85Categories* Scope::categories() const
87 return m_categories.get();
90QString Scope::searchQuery() const
92 return m_searchQuery;
95QString Scope::noResultsHint() const
97 return m_noResultsHint;
100QString Scope::formFactor() const
102 return m_formFactor;
105void Scope::setSearchQuery(const QString& search_query)
107 /* Checking for m_searchQuery.isNull() which returns true only when the string
108 has never been set is necessary because when search_query is the empty
109 string ("") and m_searchQuery is the null string,
110 search_query != m_searchQuery is still true.
111 */
112 if (m_searchQuery.isNull() || search_query != m_searchQuery) {
113 m_searchQuery = search_query;
114 m_unityScope->Search(search_query.toStdString(), sigc::mem_fun(this, &Scope::searchFinished));
115 Q_EMIT searchQueryChanged();
116 }
119void Scope::setNoResultsHint(const QString& hint) {
120 if (hint != m_noResultsHint) {
121 m_noResultsHint = hint;
122 Q_EMIT noResultsHintChanged();
123 }
126void Scope::setFormFactor(const QString& form_factor) {
127 if (form_factor != m_formFactor) {
128 m_formFactor = form_factor;
129 if (m_unityScope) {
130 m_unityScope->form_factor = m_formFactor.toStdString();
131 }
132 Q_EMIT formFactorChanged();
133 }
136unity::dash::LocalResult Scope::createLocalResult(const QVariant &uri, const QVariant &icon_hint,
137 const QVariant &category, const QVariant &result_type,
138 const QVariant &mimetype, const QVariant &title,
139 const QVariant &comment, const QVariant &dnd_uri,
140 const QVariant &metadata)
142 unity::dash::LocalResult res;
143 res.uri = uri.toString().toStdString();
144 res.icon_hint = icon_hint.toString().toStdString();
145 res.category_index = category.toUInt();
146 res.result_type = result_type.toUInt();
147 res.mimetype = mimetype.toString().toStdString();
148 res.name = title.toString().toStdString();
149 res.comment = comment.toString().toStdString();
150 res.dnd_uri = dnd_uri.toString().toStdString();
151 res.hints = convertToHintsMap(metadata);
153 return res;
156// FIXME: Change to use row index.
157void Scope::activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
158 const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
159 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
161 auto res = createLocalResult(uri, icon_hint, category, result_type, mimetype, title, comment, dnd_uri, metadata);
162 m_unityScope->Activate(res);
165// FIXME: Change to use row index.
166void Scope::preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
167 const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
168 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
170 auto res = createLocalResult(uri, icon_hint, category, result_type, mimetype, title, comment, dnd_uri, metadata);
171 m_unityScope->Preview(res);
174void Scope::onActivated(unity::dash::LocalResult const& result, unity::dash::ScopeHandledType type, unity::glib::HintsMap const& hints)
176 // note: we will not get called on SHOW_PREVIEW, instead UnityCore will signal preview_ready.
177 switch (type)
178 {
179 case unity::dash::NOT_HANDLED:
180 fallbackActivate(QString::fromStdString(result.uri));
181 break;
182 case unity::dash::SHOW_DASH:
183 Q_EMIT showDash();
184 break;
185 case unity::dash::HIDE_DASH:
186 Q_EMIT hideDash();
187 break;
188 case unity::dash::GOTO_DASH_URI:
189 if (hints.find("goto-uri") != hints.end()) {
190 Q_EMIT gotoUri(QString::fromStdString(g_variant_get_string(hints.at("goto-uri"), nullptr)));
191 } else {
192 qWarning() << "Missing goto-uri hint for GOTO_DASH_URI activation reply";
193 }
194 break;
195 default:
196 qWarning() << "Unhandled activation response:" << type;
197 }
200void Scope::onPreviewReady(unity::dash::LocalResult const& /* result */, unity::dash::Preview::Ptr const& preview)
202 auto prv = Preview::newFromUnityPreview(preview);
203 // is this the best solution? QML may need to keep more than one preview instance around, so we can't own it.
204 // passing it by value is not possible.
205 QQmlEngine::setObjectOwnership(prv, QQmlEngine::JavaScriptOwnership);
206 Q_EMIT previewReady(prv);
209void Scope::fallbackActivate(const QString& uri)
211 /* FIXME: stripping all content before the first column because for some
212 reason the scopes give uri with junk content at their beginning.
213 */
214 QString tweakedUri = uri;
215 int firstColumnAt = tweakedUri.indexOf(":");
216 tweakedUri.remove(0, firstColumnAt+1);
218 /* Tries various methods to trigger a sensible action for the given 'uri'.
219 If it has no understanding of the given scheme it falls back on asking
220 Qt to open the uri.
221 */
222 QUrl url(tweakedUri);
223 if (url.scheme() == "file") {
224 /* Override the files place's default URI handler: we want the file
225 manager to handle opening folders, not the dash.
227 Ref: https://bugs.launchpad.net/upicek/+bug/689667
228 */
229 QDesktopServices::openUrl(url);
230 return;
231 }
232 if (url.scheme() == "application") {
233 // TODO: implement application handling
234 return;
235 }
237 qDebug() << "Trying to open" << uri;
239 /* Try our luck */
240 QDesktopServices::openUrl(uri); //url?
243void Scope::setUnityScope(const unity::dash::Scope::Ptr& scope)
245 m_unityScope = scope;
247 m_categories->setUnityScope(m_unityScope);
249 m_unityScope->form_factor = m_formFactor.toStdString();
250 /* Property change signals */
251 m_unityScope->id.changed.connect(sigc::mem_fun(this, &Scope::idChanged));
252 m_unityScope->name.changed.connect(sigc::mem_fun(this, &Scope::nameChanged));
253 m_unityScope->icon_hint.changed.connect(sigc::mem_fun(this, &Scope::iconHintChanged));
254 m_unityScope->description.changed.connect(sigc::mem_fun(this, &Scope::descriptionChanged));
255 m_unityScope->search_hint.changed.connect(sigc::mem_fun(this, &Scope::searchHintChanged));
256 m_unityScope->visible.changed.connect(sigc::mem_fun(this, &Scope::visibleChanged));
257 m_unityScope->shortcut.changed.connect(sigc::mem_fun(this, &Scope::shortcutChanged));
258 m_unityScope->connected.changed.connect(sigc::mem_fun(this, &Scope::connectedChanged));
259 /* Signals forwarding */
260 connect(this, SIGNAL(searchFinished(const std::string &, unity::glib::HintsMap const &, unity::glib::Error const &)), SLOT(onSearchFinished(const std::string &, unity::glib::HintsMap const &)));
262 /* FIXME: signal should be forwarded instead of calling the handler directly */
263 m_unityScope->activated.connect(sigc::mem_fun(this, &Scope::onActivated));
265 m_unityScope->preview_ready.connect(sigc::mem_fun(this, &Scope::onPreviewReady));
267 /* Synchronize local states with m_unityScope right now and whenever
268 m_unityScope becomes connected */
269 /* FIXME: should emit change notification signals for all properties */
270 connect(this, SIGNAL(connectedChanged(bool)), SLOT(synchronizeStates()));
271 synchronizeStates();
274unity::dash::Scope::Ptr Scope::unityScope() const
276 return m_unityScope;
279void Scope::synchronizeStates()
281 if (connected()) {
282 /* Forward local states to m_unityScope */
283 if (!m_searchQuery.isNull()) {
284 m_unityScope->Search(m_searchQuery.toStdString());
285 }
286 }
289void Scope::onSearchFinished(const std::string& /* query */, unity::glib::HintsMap const &hints)
291 QString hint;
293 if (!m_unityScope->results()->count()) {
294 unity::glib::HintsMap::const_iterator it = hints.find("no-results-hint");
295 if (it != hints.end()) {
296 hint = QString::fromStdString(it->second.GetString());
297 } else {
298 hint = QString::fromUtf8(dgettext("unity", "Sorry, there is nothing that matches your search."));
299 }
300 }
302 setNoResultsHint(hint);