File 35.patch of Package gnome-documents

From bdac6006aebf40cc3d7105357ba3c813415cbe97 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Sun, 17 Jan 2021 16:21:26 +0100
Subject: [PATCH 1/8] search: Don't inspect Tracker settings

In a sandboxed environment it's no possible (or shouldn't be!) to
inspect tracker settings. This is just used to include results from
custom folders in addition to Documents/Downloads/Desktop folders,
however these are not accessible within the sandbox anymore.

Drop this code, and stick to the given XDG folders, if support for
custom folders is desirable, should go through the
org.freedesktop.Tracker3.Miner.Files.Index interface.
---
 src/search.js | 36 +-----------------------------------
 1 file changed, 1 insertion(+), 35 deletions(-)

diff --git a/src/search.js b/src/search.js
index df5907c5..738ca336 100644
--- a/src/search.js
+++ b/src/search.js
@@ -279,9 +279,6 @@ var SearchSourceStock = {
     LOCAL: 'local'
 };
 
-const TRACKER_SCHEMA = 'org.freedesktop.Tracker.Miner.Files';
-const TRACKER_KEY_RECURSIVE_DIRECTORIES = 'index-recursive-directories';
-
 const Source = class Source {
     constructor(params) {
         this.id = null;
@@ -310,35 +307,6 @@ const Source = class Source {
             return [];
     }
 
-    _getTrackerLocations() {
-        let settings = new Gio.Settings({ schema_id: TRACKER_SCHEMA });
-        let locations = settings.get_strv(TRACKER_KEY_RECURSIVE_DIRECTORIES);
-        let files = [];
-
-        locations.forEach((location) => {
-            // ignore special XDG placeholders, since we handle those internally
-            if (location[0] == '&' || location[0] == '$')
-                return;
-
-            let trackerFile = Gio.file_new_for_commandline_arg(location);
-
-            // also ignore XDG locations if they are present with their full path
-            for (let idx = 0; idx < GLib.UserDirectory.N_DIRECTORIES; idx++) {
-                let path = GLib.get_user_special_dir(idx);
-                if (!path)
-                    continue;
-
-                let file = Gio.file_new_for_path(path);
-                if (trackerFile.equal(file))
-                    return;
-            }
-
-            files.push(trackerFile);
-        });
-
-        return files;
-    }
-
     _getBuiltinLocations() {
         let files = [];
         let xdgDirs = [GLib.UserDirectory.DIRECTORY_DESKTOP,
@@ -356,9 +324,7 @@ const Source = class Source {
 
     _buildFilterLocal() {
         let locations = this._getBuiltinLocations();
-        locations = locations.concat(
-            this._getTrackerLocations(),
-            this._getGettingStartedLocations());
+        locations = locations.concat(this._getGettingStartedLocations());
 
         let filters = [];
         locations.forEach((location) => {
-- 
GitLab


From b1a5f853bb625621e5ddfc49c68841f2f19778ea Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Sun, 17 Jan 2021 16:26:05 +0100
Subject: [PATCH 2/8] application: Drop unused import

This library does not exist anymore in Tracker3, and is besides unused
here.
---
 src/application.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/application.js b/src/application.js
index eadcd43f..86bb1eff 100644
--- a/src/application.js
+++ b/src/application.js
@@ -30,7 +30,6 @@ const Gtk = imports.gi.Gtk;
 const GLib = imports.gi.GLib;
 const GObject = imports.gi.GObject;
 const Tracker = imports.gi.Tracker;
-const TrackerControl = imports.gi.TrackerControl;
 
 const ChangeMonitor = imports.changeMonitor;
 const Format = imports.format;
-- 
GitLab


From 68cd88e403322495e9f0de3ac9960a92e7c255f4 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Sun, 17 Jan 2021 16:41:57 +0100
Subject: [PATCH 3/8] notification: Delete indexing notification

This relies on libtracker-control, which is no longer a thing. It
might make sense to track indexing state, but that goes together
with requests to index specific locations.
---
 src/notifications.js | 159 -------------------------------------------
 1 file changed, 159 deletions(-)

diff --git a/src/notifications.js b/src/notifications.js
index 4629b832..7d77f40b 100644
--- a/src/notifications.js
+++ b/src/notifications.js
@@ -23,7 +23,6 @@ const Gd = imports.gi.Gd;
 const Gettext = imports.gettext;
 const GObject = imports.gi.GObject;
 const Gtk = imports.gi.Gtk;
-const TrackerControl = imports.gi.TrackerControl;
 const _ = imports.gettext.gettext;
 
 const Application = imports.application;
@@ -155,161 +154,6 @@ var PrintNotification = class PrintNotification {
     }
 }
 
-const REMOTE_MINER_TIMEOUT = 10; // seconds
-const TRACKER_MINER_FILES_NAME = 'org.freedesktop.Tracker1.Miner.Files';
-
-const IndexingNotification = class IndexingNotification {
-    constructor() {
-        this._closed = false;
-        this._timeoutId = 0;
-
-        try {
-            this._manager = TrackerControl.MinerManager.new_full(false);
-            this._manager.connect('miner-progress', this._checkNotification.bind(this));
-        } catch(e) {
-            logError(e, 'Unable to create a TrackerMinerManager, indexing progress ' +
-                     'notification won\'t work');
-            return;
-        }
-
-        Application.application.connect('miners-changed', this._checkNotification.bind(this));
-        Application.modeController.connect('window-mode-changed', this._checkNotification.bind(this));
-    }
-
-    _checkNotification() {
-        if (Application.modeController.getWindowMode() == WindowMode.WindowMode.PREVIEW_EV) {
-            this._destroy(false);
-            return;
-        }
-
-        let isIndexingLocal = false;
-        let isIndexingRemote = false;
-
-        if (this._manager) {
-            let running = this._manager.get_running();
-            if (running.indexOf(TRACKER_MINER_FILES_NAME) != -1) {
-                let [res, status, progress, time] = this._manager.get_status(TRACKER_MINER_FILES_NAME);
-
-                if (progress < 1)
-                    isIndexingLocal = true;
-            }
-        }
-
-        if (Application.application.minersRunning.length > 0)
-            isIndexingRemote = true;
-
-        if (isIndexingLocal) {
-            this._display(_("Your documents are being indexed"),
-                          _("Some documents might not be available during this process"));
-        } else if (isIndexingRemote) {
-            this._removeTimeout();
-            this._timeoutId = Mainloop.timeout_add_seconds(REMOTE_MINER_TIMEOUT, this._onTimeoutExpired.bind(this));
-        } else {
-            this._destroy(false);
-        }
-    }
-
-    _onTimeoutExpired() {
-        this._timeoutId = 0;
-
-        let primary = null;
-        let miner = null;
-
-        if (Application.application.minersRunning.length == 1) {
-            miner = Application.application.minersRunning[0];
-        }
-
-        if (miner && miner.DisplayName) {
-            // Translators: %s refers to an online account provider, e.g.
-            // "Google", or "Windows Live".
-            primary = _("Fetching documents from %s").format(miner.DisplayName);
-        } else {
-            primary = _("Fetching documents from online accounts");
-        }
-
-        this._display(primary, null);
-
-        return false;
-    }
-
-    _removeTimeout() {
-        if (this._timeoutId != 0) {
-            Mainloop.source_remove(this._timeoutId);
-            this._timeoutId = 0;
-        }
-    }
-
-    _buildWidget() {
-        this.widget = new Gtk.Grid({ orientation: Gtk.Orientation.HORIZONTAL,
-                                     column_spacing: 12 });
-
-        let spinner = new Gtk.Spinner({ width_request: 16,
-                                        height_request: 16 });
-        spinner.start();
-        this.widget.add(spinner);
-
-        let labels = new Gtk.Grid({ orientation: Gtk.Orientation.VERTICAL,
-                                    row_spacing: 3 });
-        this.widget.add(labels);
-
-        this._primaryLabel = new Gtk.Label({ halign: Gtk.Align.START });
-        labels.add(this._primaryLabel);
-
-        this._secondaryLabel = new Gtk.Label({ halign: Gtk.Align.START });
-        this._secondaryLabel.get_style_context().add_class('dim-label');
-        labels.add(this._secondaryLabel);
-
-        let close = new Gtk.Button({ image: new Gtk.Image({ icon_name: 'window-close-symbolic',
-                                                            pixel_size: 16,
-                                                            margin_top: 2,
-                                                            margin_bottom: 2 }),
-                                     valign: Gtk.Align.CENTER,
-                                     focus_on_click: false,
-                                     relief: Gtk.ReliefStyle.NONE });
-        close.connect('clicked', () => {
-            this._destroy(true);
-        });
-        this.widget.add(close);
-
-        Application.notificationManager.addNotification(this);
-    }
-
-    _update(primaryText, secondaryText) {
-        this._primaryLabel.label = primaryText;
-        this._secondaryLabel.label = secondaryText;
-
-        if (secondaryText) {
-            this._primaryLabel.vexpand = false;
-            this._secondaryLabel.show();
-        } else {
-            this._primaryLabel.vexpand = true;
-            this._secondaryLabel.hide();
-        }
-    }
-
-    _display(primaryText, secondaryText) {
-        if (this._closed) {
-            return;
-        }
-
-        if (!this.widget)
-            this._buildWidget();
-
-        this._update(primaryText, secondaryText);
-    }
-
-    _destroy(closed) {
-        this._removeTimeout();
-
-        if (this.widget) {
-            this.widget.destroy();
-            this.widget = null;
-        }
-
-        this._closed = closed;
-    }
-}
-
 var NotificationManager = GObject.registerClass(class NotificationManager extends Gtk.Revealer {
     _init() {
         super._init({ halign: Gtk.Align.CENTER,
@@ -323,9 +167,6 @@ var NotificationManager = GObject.registerClass(class NotificationManager extend
                                     row_spacing: 6 });
 
         frame.add(this._grid);
-
-        // add indexing monitor notification
-        this._indexingNotification = new IndexingNotification();
     }
 
     addNotification(notification) {
-- 
GitLab


From 6b49c764004369f579549438d1a58bd0e5e6767f Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Sun, 17 Jan 2021 16:54:46 +0100
Subject: [PATCH 4/8] application: Use
 org.freedesktop.Tracker3.Miner.Files.Control for index control

This new request allows prioritising graphs on index folders, so request
the tracker:Documents graph on the Documents folder here.
---
 src/application.js | 44 +++++++++++++++++++++-----------------------
 1 file changed, 21 insertions(+), 23 deletions(-)

diff --git a/src/application.js b/src/application.js
index 86bb1eff..d1a1d454 100644
--- a/src/application.js
+++ b/src/application.js
@@ -71,20 +71,21 @@ var trackerCollectionsController = null;
 var trackerDocumentsController = null;
 var trackerSearchController = null;
 
-const TrackerExtractPriorityIface = '<node> \
-<interface name="org.freedesktop.Tracker1.Extract.Priority"> \
-    <method name="ClearRdfTypes" /> \
-    <method name="SetRdfTypes"> \
-        <arg name="rdf_types" type="as" /> \
+const TrackerMinerFilesIndexIface = '<node> \
+<interface name="org.freedesktop.Tracker3.Miner.Files.Index"> \
+    <method name="IndexLocation"> \
+        <arg name="file_uri" type="s" /> \
+        <arg name="graphs" type="as" /> \
+        <arg name="flags" type="as" /> \
     </method> \
 </interface> \
 </node>';
 
-var TrackerExtractPriorityProxy = Gio.DBusProxy.makeProxyWrapper(TrackerExtractPriorityIface);
-function TrackerExtractPriority() {
-    return new TrackerExtractPriorityProxy(Gio.DBus.session,
-                                           'org.freedesktop.Tracker1.Miner.Extract',
-                                           '/org/freedesktop/Tracker1/Extract/Priority');
+var TrackerMinerFilesControlProxy = Gio.DBusProxy.makeProxyWrapper(TrackerMinerFilesIndexIface);
+function TrackerMinerFilesControl() {
+    return new TrackerMinerFilesControlProxy(Gio.DBus.session,
+                                             'org.freedesktop.Tracker3.Miner.Files.Control',
+                                             '/org/freedesktop/Tracker3/Miner/Files/Index');
 }
 
 const MINER_REFRESH_TIMEOUT = 60; /* seconds */
@@ -99,6 +100,7 @@ var Application = GObject.registerClass({
         this._activationTimestamp = Gdk.CURRENT_TIME;
         this._extractPriority = null;
         this._searchProvider = null;
+	this._minerControl = null;
 
         let appid;
         GLib.set_application_name(_("Documents"));
@@ -115,8 +117,6 @@ var Application = GObject.registerClass({
     }
 
     _initGettingStarted() {
-        let manager = TrackerControl.MinerManager.new_full(false);
-
         let languages = GLib.get_language_names();
         let files = languages.map(
             function(language) {
@@ -138,7 +138,7 @@ var Application = GObject.registerClass({
             this.gettingStartedLocation = files[i].get_parent();
 
             try {
-                manager.index_file(files[i], null);
+                this._minerControl.IndexLocationRemote(files[i].get_path(), ['tracker:Documents'], []);
             } catch (e) {
                 logError(e, 'Error indexing the getting started PDF');
             }
@@ -388,19 +388,20 @@ var Application = GObject.registerClass({
         if (this._mainWindow)
             return;
 
+        try {
+            this._minerControl = TrackerMinerFilesControl();
+            this._minerControl.IndexLocationRemote(GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOCUMENTS),
+                                                   ['tracker:Documents'], []);
+        } catch (e) {
+            logError(e, 'Unable to connect to the tracker extractor');
+        }
+
         this._initGettingStarted();
 
         notificationManager = new Notifications.NotificationManager();
         this._mainWindow = new MainWindow.MainWindow(this);
         this._mainWindow.connect('destroy', this._onWindowDestroy.bind(this));
 
-        try {
-            this._extractPriority = TrackerExtractPriority();
-            this._extractPriority.SetRdfTypesRemote(['nfo:Document']);
-        } catch (e) {
-            logError(e, 'Unable to connect to the tracker extractor');
-        }
-
         // start miners
         this._startMiners();
     }
@@ -475,9 +476,6 @@ var Application = GObject.registerClass({
 
         // stop miners
         this._stopMiners();
-
-        if (this._extractPriority)
-            this._extractPriority.ClearRdfTypesRemote();
     }
 
     _onWindowDestroy(window) {
-- 
GitLab


From 1a7724a9b1bc3add322958c7392957b3760b7591 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Sun, 17 Jan 2021 17:02:04 +0100
Subject: [PATCH 5/8] changeMonitor: Rewrite to use TrackerNotifier

The GraphUpdated DBus signal became superseded by TrackerNotifier
in 2.x, and completely removed on 3.x. Use TrackerNotifier here
for event tracking.
---
 src/changeMonitor.js | 182 +++++++++----------------------------------
 1 file changed, 36 insertions(+), 146 deletions(-)

diff --git a/src/changeMonitor.js b/src/changeMonitor.js
index 5308b042..0172cd65 100644
--- a/src/changeMonitor.js
+++ b/src/changeMonitor.js
@@ -20,167 +20,57 @@
  */
 
 const Gio = imports.gi.Gio;
+const Lang = imports.lang;
 const Mainloop = imports.mainloop;
 const Signals = imports.signals;
+const Tracker = imports.gi.Tracker;
 
 const Application = imports.application;
 
-const TrackerResourcesServiceIface = '<node> \
-<interface name="org.freedesktop.Tracker1.Resources"> \
-    <signal name="GraphUpdated"> \
-        <arg name="className" type="s" /> \
-        <arg name="deleteEvents" type="a(iiii)" /> \
-        <arg name="insertEvents" type="a(iiii)" /> \
-    </signal> \
-</interface> \
-</node>';
-
-var TrackerResourcesServiceProxy = Gio.DBusProxy.makeProxyWrapper(TrackerResourcesServiceIface);
-function TrackerResourcesService() {
-    return new TrackerResourcesServiceProxy(Gio.DBus.session,
-                                            'org.freedesktop.Tracker1',
-                                            '/org/freedesktop/Tracker1/Resources');
-}
-
 var ChangeEventType = {
     CHANGED: 0,
     CREATED: 1,
     DELETED: 2
 };
 
-const _RDF_TYPE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
-
-const ChangeEvent = class ChangeEvent {
-    constructor(urnId, predicateId, isDelete) {
-        this.urnId = urnId;
-        this.predicateId = predicateId;
-
-        if (isDelete)
-            this.type = ChangeEventType.DELETED;
-        else
-            this.type = ChangeEventType.CREATED;
-    }
+const ChangeEvent = new Lang.Class({
+    Name: 'ChangeEvent',
 
-    setResolvedValues(urn, predicate) {
+    _init: function(type, urn) {
         this.urn = urn;
-        this.predicate = predicate;
 
-        if (predicate != _RDF_TYPE)
+        if (type == Tracker.NotifierEventType.CREATE)
+            this.type = ChangeEventType.CREATED;
+        else if (type == Tracker.NotifierEventType.DELETE)
+            this.type = ChangeEventType.DELETED;
+        else if (type == Tracker.NotifierEventType.UPDATE)
             this.type = ChangeEventType.CHANGED;
     }
-
-    merge(event) {
-        // deletions or creations override the current type
-        if (event.type == ChangeEventType.DELETED ||
-            event.type == ChangeEventType.CREATED) {
-            this.type = event.type;
-        }
-    }
-}
-
-const CHANGE_MONITOR_TIMEOUT = 500; // msecs
-const CHANGE_MONITOR_MAX_ITEMS = 500; // items
-
-var TrackerChangeMonitor = class TrackerChangeMonitor {
-    constructor() {
-        this._pendingChanges = {};
-        this._unresolvedIds = {};
-
-        this._pendingEvents = [];
-        this._pendingEventsId = 0;
-
-        this._resourceService = new TrackerResourcesService();
-        this._resourceService.connectSignal('GraphUpdated', this._onGraphUpdated.bind(this));
-    }
-
-    _onGraphUpdated(proxy, senderName, [className, deleteEvents, insertEvents]) {
-        deleteEvents.forEach((event) => {
-            this._addPendingEvent(event, true);
-        });
-
-        insertEvents.forEach((event) => {
-            this._addPendingEvent(event, false);
-        });
-    }
-
-    _addPendingEvent(event, isDelete) {
-        if (this._pendingEventsId != 0)
-            Mainloop.source_remove(this._pendingEventsId);
-
-        this._unresolvedIds[event[1]] = event[1];
-        this._unresolvedIds[event[2]] = event[2];
-        this._pendingEvents.push(new ChangeEvent(event[1], event[2], isDelete));
-
-        if (this._pendingEvents.length >= CHANGE_MONITOR_MAX_ITEMS)
-            this._processEvents();
-        else
-            this._pendingEventsId =
-                Mainloop.timeout_add(CHANGE_MONITOR_TIMEOUT, this._processEvents.bind(this));
-    }
-
-    _processEvents() {
-        let events = this._pendingEvents;
-        let idTable = this._unresolvedIds;
-
-        this._pendingEventsId = 0;
-        this._pendingEvents = [];
-        this._unresolvedIds = {};
-
-        let sparql = 'SELECT';
-        Object.keys(idTable).forEach((unresolvedId) => {
-            sparql += (' tracker:uri(%d)').format(unresolvedId);
-        });
-        sparql += ' {}';
-
-        // resolve all the unresolved IDs we got so far
-        Application.connectionQueue.add(sparql, null, (object, res) => {
-            let cursor = object.query_finish(res);
-
-            cursor.next_async(null, (object, res) => {
-                let valid = false;
-                try {
-                    valid = cursor.next_finish(res);
-                } catch(e) {
-                    logError(e, 'Unable to resolve item URNs for graph changes');
-                }
-
-                if (valid) {
-                    let idx = 0;
-                    Object.keys(idTable).forEach((unresolvedId) => {
-                        idTable[unresolvedId] = cursor.get_string(idx)[0];
-                        idx++;
-                    });
-
-                    this._sendEvents(events, idTable);
-                }
-
-                cursor.close();
-            });
-        });
-
-        return false;
-    }
-
-    _addEvent(event) {
-        let urn = event.urn;
-        let oldEvent = this._pendingChanges[urn];
-
-        if (oldEvent != null) {
-            oldEvent.merge(event);
-            this._pendingChanges[urn] = oldEvent;
-        } else {
-            this._pendingChanges[urn] = event;
-        }
-    }
-
-    _sendEvents(events, idTable) {
-        events.forEach((event) => {
-            event.setResolvedValues(idTable[event.urnId], idTable[event.predicateId]);
-            this._addEvent(event);
-        });
-
-        this.emit('changes-pending', this._pendingChanges);
-        this._pendingChanges = {};
+});
+
+var TrackerChangeMonitor = new Lang.Class({
+    Name: 'TrackerChangeMonitor',
+
+    _init: function() {
+        this._notifier = Application.connection.create_notifier();
+        this._notifier.signal_subscribe(Gio.DBus.session,
+                                        'org.freedesktop.Tracker3.Miner.Files',
+                                        null,
+                                        'http://tracker.api.gnome.org/ontology/v3/tracker#Documents');
+        this._notifier.connect('events', Lang.bind(this, this._onNotifierEvents));
+    },
+
+    _onNotifierEvents: function(notifier, service, graph, events) {
+        let pendingChanges = {};
+
+        events.forEach(Lang.bind(this,
+            function(event) {
+                let urn = event.get_urn();
+                let changeEvent = new ChangeEvent(event.get_event_type(), urn);
+                pendingChanges[urn] = changeEvent;
+            }));
+
+        this.emit('changes-pending', pendingChanges);
     }
-}
+});
 Signals.addSignalMethods(TrackerChangeMonitor.prototype);
-- 
GitLab


From 3aa5fbc61583cf55454859bcbb76b3570df0bcbc Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Sun, 17 Jan 2021 17:03:14 +0100
Subject: [PATCH 6/8] Port queries to Tracker3

Use new Tracker.SparqlConnection constructors, and rework the queries
so that it:

1) Observes the data layout in use in Tracker Miners 3.x
2) Uses a private database for the data considered writeable:
   - collections
   - titles
3) Queries g-o-m miners specifically, alongside local data

All queries happen on the local connection, optionally including data
from tracker-miner-fs and g-o-m miners via SERVICE{} clauses, this is
just not the case for collection queries, since collections are stored
in the private documents database.
---
 meson.build              |   4 +-
 src/application.js       |   8 ++-
 src/documents.js         |   2 +-
 src/main.js              |   3 +-
 src/query.js             | 136 ++++++++++++++++++++++++++++++++-------
 src/search.js            |   4 +-
 src/trackerController.js |   4 +-
 src/trackerUtils.js      |   2 +-
 8 files changed, 127 insertions(+), 36 deletions(-)

diff --git a/meson.build b/meson.build
index 7a6d1ad0..1f63b310 100644
--- a/meson.build
+++ b/meson.build
@@ -54,7 +54,6 @@ endforeach
 add_project_arguments('-DHAVE_CONFIG_H', language: 'c')
 
 evince_req_version = '>= 3.13.3'
-tracker_req_version = '>= 0.17.3'
 
 gjs_dep = dependency('gjs-1.0', version: '>= 1.48.0')
 gjs_console = gjs_dep.get_pkgconfig_variable('gjs_console')
@@ -68,8 +67,7 @@ documents_deps = [
   dependency('gobject-introspection-1.0', version: '>= 1.31.6'),
   dependency('gtk+-3.0', version: '>= 3.22.15'),
   dependency('libsoup-2.4', version: '>= 2.41.3'),
-  dependency('tracker-control-2.0', version: tracker_req_version),
-  dependency('tracker-sparql-2.0', version: tracker_req_version),
+  dependency('tracker-sparql-3.0'),
   dependency('webkit2gtk-4.0', version: '>= 2.6.0'),
   cc.find_library('m')
 ]
diff --git a/src/application.js b/src/application.js
index d1a1d454..73cd2da1 100644
--- a/src/application.js
+++ b/src/application.js
@@ -337,9 +337,13 @@ var Application = GObject.registerClass({
 
         // connect to tracker
         try {
-            connection = Tracker.SparqlConnection.get(null);
+            let cacheDir = GLib.build_filenamev([GLib.get_user_cache_dir(), 'org.gnome.Documents', 'db']);
+            let nepomuk = Tracker.sparql_get_ontology_nepomuk();
+            connection = Tracker.SparqlConnection.new(Tracker.SparqlConnectionFlags.NONE,
+                                                      Gio.File.new_for_path(cacheDir),
+                                                      nepomuk, null);
         } catch (e) {
-            logError(e, 'Unable to connect to the tracker database');
+            logError(e, 'Unable to set up the tracker database');
             return;
         }
 
diff --git a/src/documents.js b/src/documents.js
index 752b5714..d2ad55f9 100644
--- a/src/documents.js
+++ b/src/documents.js
@@ -776,7 +776,7 @@ const DocCommon = class DocCommon {
         let retval = '';
 
         if (this.collection)
-            retval = '{ ?urn nie:isPartOf <' + this.id + '> }';
+            retval = '{ ?urn nie:isLogicalPartOf <' + this.id + '> }';
 
         return retval;
     }
diff --git a/src/main.js b/src/main.js
index b4afb261..9094f889 100644
--- a/src/main.js
+++ b/src/main.js
@@ -33,8 +33,7 @@ pkg.require({ 'EvinceDocument': '3.0',
               'Goa': '1.0',
               'Gtk': '3.0',
               'GObject': '2.0',
-              'Tracker': '2.0',
-              'TrackerControl': '2.0',
+              'Tracker': '3.0',
               'WebKit2': '4.0' });
 
 const Application = imports.application;
diff --git a/src/query.js b/src/query.js
index 6ab1a462..4f5142ea 100644
--- a/src/query.js
+++ b/src/query.js
@@ -90,9 +90,6 @@ var QueryBuilder = class QueryBuilder {
             part += this._buildOptional();
 
             if ((flags & QueryFlags.UNFILTERED) == 0) {
-                if (global)
-                    part += this._context.documentManager.getWhere();
-
                 part += this._buildFilterString(currentType, flags, ftsQuery.length > 0);
             }
 
@@ -141,6 +138,18 @@ var QueryBuilder = class QueryBuilder {
     }
 
     _buildQueryInternal(global, flags, offsetController, sortBy) {
+        let selectClauses =
+            '    (COALESCE (nie:url(?urn), nie:isStoredAs(?urn)) AS ?uri) ' +
+            '    (COALESCE (nfo:fileName(?urn), tracker:string-from-filename(nie:isStoredAs(?urn))) AS ?filename) ' +
+            '    (nie:mimeType(?urn) AS ?mimetype) ' +
+            '    (nie:title(?urn) AS ?title) ' +
+            '    (tracker:coalesce(nco:fullname(?creator), nco:fullname(?publisher), \'\') AS ?author) ' +
+            '    (nie:contentLastModified(?urn) AS ?mtime) ' +
+            '    (nao:identifier(?urn) AS ?identifier) ' +
+            '    (rdf:type(?urn) AS ?type) ' +
+            '    (nie:dataSource(?urn) AS ?datasource ) ' +
+            '    (( EXISTS { ?urn nco:contributor ?contributor FILTER ( ?contributor != ?creator ) } ) AS ?shared) ' +
+            '    (nie:contentCreated(?urn) AS ?created) ';
         let whereSparql = this._buildWhere(global, flags);
         let tailSparql = '';
 
@@ -175,19 +184,61 @@ var QueryBuilder = class QueryBuilder {
         }
 
         let sparql =
-            'SELECT DISTINCT ?urn ' + // urn
-            'nie:url(?urn) ' + // uri
-            'nfo:fileName(?urn) AS ?filename ' + // filename
-            'nie:mimeType(?urn)' + // mimetype
-            'nie:title(?urn) AS ?title ' + // title
-            'tracker:coalesce(nco:fullname(?creator), nco:fullname(?publisher), \'\') AS ?author ' + // author
-            'tracker:coalesce(nfo:fileLastModified(?urn), nie:contentLastModified(?urn)) AS ?mtime ' + // mtime
-            'nao:identifier(?urn) ' + // identifier
-            'rdf:type(?urn) ' + // type
-            'nie:dataSource(?urn) ' + // resource URN
-            '( EXISTS { ?urn nco:contributor ?contributor FILTER ( ?contributor != ?creator ) } ) ' + // shared
-            'tracker:coalesce(nfo:fileCreated(?urn), nie:contentCreated(?urn)) ' + // date created
-            whereSparql + tailSparql;
+            'SELECT ?urn ' +
+            '  ?uri ' +
+            '  ?filename ' +
+            '  ?mimetype ' +
+            '  COALESCE (?localTitle, ?title, ?filename) AS ?t ' +
+            '  ?author ' +
+            '  ?mtime ' +
+            '  ?identifier ' +
+            '  ?type ' +
+            '  ?datasource ' +
+            '  ?shared ' +
+            '  ?created ' +
+            'WHERE { ';
+
+        // Collections queries are local
+        if (flags & QueryFlags.COLLECTIONS) {
+            sparql +=
+                'SELECT DISTINCT ?urn ' +
+                selectClauses +
+                whereSparql;
+        } else {
+	    let services = ['org.freedesktop.Tracker3.Miner.Files'];
+	    let serviceQueries = [];
+
+            if (this._context.sourceManager.hasProviderType('google'))
+		services.push('org.gnome.OnlineMiners.GData');
+            if (this._context.sourceManager.hasProviderType('owncloud'))
+		services.push('org.gnome.OnlineMiners.Owncloud');
+            if (this._context.sourceManager.hasProviderType('windows_live'))
+		services.push('org.gnome.OnlineMiners.Zpj');
+
+	    services.forEach((service) => {
+		let serviceQuery =
+		    '{' +
+                    '  SERVICE SILENT <dbus:' + service + '> {' +
+                    '    GRAPH tracker:Documents { ' +
+                    '      SELECT DISTINCT ?urn ' +
+                    selectClauses +
+                    whereSparql +
+                    '    }' +
+                    '  }' +
+		    '}';
+
+		serviceQueries.push(serviceQuery);
+	    });
+
+            sparql += serviceQueries.join(' UNION ');
+            sparql += 'OPTIONAL { ?urn nie:title ?localTitle } . ';
+
+            if (global && (flags & QueryFlags.UNFILTERED) == 0)
+                sparql += this._context.documentManager.getWhere();
+	}
+
+        sparql += '}';
+        sparql += tailSparql;
 
         return sparql;
     }
@@ -204,8 +255,39 @@ var QueryBuilder = class QueryBuilder {
     }
 
     buildCountQuery(flags) {
-        let sparql = 'SELECT DISTINCT COUNT(?urn) ' +
-            this._buildWhere(true, flags);
+        let sparql;
+        if (flags & QueryFlags.COLLECTIONS) {
+	    sparql = 'SELECT DISTINCT COUNT(?urn) AS ?c ' +
+		this._buildWhere(true, flags);
+	} else {
+	    let services = ['org.freedesktop.Tracker3.Miner.Files'];
+	    let countQueries = [];
+
+            if (this._context.sourceManager.hasProviderType('google'))
+		services.push('org.gnome.OnlineMiners.GData');
+            if (this._context.sourceManager.hasProviderType('owncloud'))
+		services.push('org.gnome.OnlineMiners.Owncloud');
+            if (this._context.sourceManager.hasProviderType('windows_live'))
+		services.push('org.gnome.OnlineMiners.Zpj');
+
+	    sparql = 'SELECT SUM(?c) {';
+
+	    services.forEach((service) => {
+		let countQuery =
+		    '{ ' +
+		    '  SERVICE SILENT <dbus:' + service + '> { ' +
+		    '    GRAPH tracker:Documents { ' +
+		    '      SELECT DISTINCT COUNT(?urn) AS ?c ' +
+		    this._buildWhere(true, flags) +
+		    '    }' +
+		    '  }' +
+		    '}';
+		countQueries.push(countQuery);
+	    });
+
+	    sparql += countQueries.join(' UNION ');
+	    sparql += '}';
+	}
 
         return this._createQuery(sparql);
     }
@@ -215,8 +297,8 @@ var QueryBuilder = class QueryBuilder {
         let sparql =
             ('SELECT ' +
              '?urn ' +
-             'tracker:coalesce(nfo:fileLastModified(?urn), nie:contentLastModified(?urn)) AS ?mtime ' +
-             'WHERE { ?urn nie:isPartOf ?collUrn } ' +
+             'nie:contentLastModified(?urn) AS ?mtime ' +
+             'WHERE { ?urn nie:isLogicalPartOf ?collUrn } ' +
              'ORDER BY DESC (?mtime)' +
              'LIMIT 4').replace(/\?collUrn/, '<' + resource + '>');
 
@@ -228,7 +310,7 @@ var QueryBuilder = class QueryBuilder {
         let sparql =
             ('SELECT ' +
              '?urn ' +
-             'WHERE { ?urn a nfo:DataContainer . ?docUrn nie:isPartOf ?urn }'
+             'WHERE { ?urn a nfo:DataContainer . ?docUrn nie:isLogicalPartOf ?urn }'
             ).replace(/\?docUrn/, '<' + resource + '>');
 
         return this._createQuery(sparql);
@@ -236,15 +318,21 @@ var QueryBuilder = class QueryBuilder {
 
     // adds or removes the given item to the given collection
     buildSetCollectionQuery(itemUrn, collectionUrn, setting) {
-        let sparql = ('%s { <%s> nie:isPartOf <%s> }'
-                     ).format((setting ? 'INSERT' : 'DELETE'), itemUrn, collectionUrn);
+        let sparql;
+        if (setting) {
+            sparql = ('INSERT DATA { <%s> a nie:InformationElement; nie:isLogicalPartOf <%s> }'
+                     ).format(itemUrn, collectionUrn);
+        } else {
+            sparql = ('DELETE DATA { <%s> nie:isLogicalPartOf <%s> }'
+                     ).format(itemUrn, collectionUrn);
+        }
         return this._createQuery(sparql);
     }
 
     // bumps the mtime to current time for the given resource
     buildUpdateMtimeQuery(resource) {
         let time = GdPrivate.iso8601_from_timestamp(GLib.get_real_time() / GLib.USEC_PER_SEC);
-        let sparql = ('INSERT OR REPLACE { <%s> nie:contentLastModified \"%s\" }'
+        let sparql = ('INSERT OR REPLACE { <%s> a nie:InformationElement; nie:contentLastModified \"%s\" }'
                      ).format(resource, time);
 
         return this._createQuery(sparql);
diff --git a/src/search.js b/src/search.js
index 738ca336..557c7a0a 100644
--- a/src/search.js
+++ b/src/search.js
@@ -19,6 +19,8 @@
  *
  */
 
+imports.gi.versions.Tracker = '3.0';
+
 const Application = imports.application;
 const Documents = imports.documents;
 const Manager = imports.manager;
@@ -328,7 +330,7 @@ const Source = class Source {
 
         let filters = [];
         locations.forEach((location) => {
-            filters.push('(fn:contains (nie:url(?urn), "%s"))'.format(location.get_uri()));
+            filters.push('(fn:contains (nie:isStoredAs(?urn), "%s"))'.format(location.get_uri()));
         });
 
         filters.push('(fn:starts-with (nao:identifier(?urn), "gd:collection:local:"))');
diff --git a/src/trackerController.js b/src/trackerController.js
index 23e1c137..169ddcb5 100644
--- a/src/trackerController.js
+++ b/src/trackerController.js
@@ -86,10 +86,10 @@ var TrackerConnectionQueue = class TrackerConnectionQueue {
             Application.connection.query_async(params.query, params.cancellable,
                                                this._queueCollector.bind(this, params));
         else if (params.queryType == QueryType.UPDATE)
-            Application.connection.update_async(params.query, GLib.PRIORITY_DEFAULT, params.cancellable,
+            Application.connection.update_async(params.query, params.cancellable,
                                                 this._queueCollector.bind(this, params));
         else if (params.queryType == QueryType.UPDATE_BLANK)
-            Application.connection.update_blank_async(params.query, GLib.PRIORITY_DEFAULT, params.cancellable,
+            Application.connection.update_blank_async(params.query, params.cancellable,
                                                       this._queueCollector.bind(this, params));
     }
 
diff --git a/src/trackerUtils.js b/src/trackerUtils.js
index 007568c1..1ed63f2e 100644
--- a/src/trackerUtils.js
+++ b/src/trackerUtils.js
@@ -22,7 +22,7 @@
 const Application = imports.application;
 
 function setEditedName(newTitle, docId, callback) {
-    let sparql = ('INSERT OR REPLACE { <%s> nie:title \"%s\" }'.format(docId, newTitle));
+    let sparql = ('INSERT OR REPLACE { <%s> a nie:InformationElement ; nie:title \"%s\" }'.format(docId, newTitle));
 
     Application.connectionQueue.update(sparql, null,
         function(object, res) {
-- 
GitLab


From ba601fd31c610af06b83c41fdb872e8f32398a11 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Fri, 22 Jan 2021 18:00:55 +0100
Subject: [PATCH 7/8] flatpak: Update reference to use Tracker3

Use the Tracker3 policy to specify the accessed graph, drop
the builtin tracker copy, and change tracker-miners build parameters
so we can run our own internal copy.

In code, first check whether there is access to the stock miner,
then attempt this internal miner. This is a fallback for systems that
do not have tracker3 installed.
---
 flatpak/org.gnome.Documents.json | 35 +++++++++-----------------------
 src/application.js               | 11 ++++++++++
 src/query.js                     |  4 ++--
 3 files changed, 23 insertions(+), 27 deletions(-)

diff --git a/flatpak/org.gnome.Documents.json b/flatpak/org.gnome.Documents.json
index 5c2e3116..325d1e73 100644
--- a/flatpak/org.gnome.Documents.json
+++ b/flatpak/org.gnome.Documents.json
@@ -17,9 +17,8 @@
         /* Needs to talk to the network: */
         "--share=network",
         "--talk-name=org.gnome.Mutter.DisplayConfig",
-        /* Tracker access */
-        "--talk-name=org.freedesktop.Tracker1",
-        "--talk-name=org.freedesktop.Tracker1.Miner.Extract",
+        /* Tracker3 graph access */
+        "--add-policy=Tracker3.dbus:org.freedesktop.Tracker3.Miner.Files=tracker:Documents",
         /* Needed for dconf to work */
         "--filesystem=xdg-run/dconf", "--filesystem=~/.config/dconf:ro",
         "--talk-name=ca.desrt.dconf", "--env=DCONF_USER_CONFIG_DIR=.config/dconf"
@@ -157,35 +156,21 @@
                 }
             ]
         },
-        {
-            "name": "tracker",
-            "buildsystem": "meson",
-            "cleanup": [ "/bin", "/etc", "/lib/systemd", "/libexec", "/share/dbus-1/services" ],
-            "config-opts": [ "--default-library=shared", "-Dbash-completion=no", "-Ddocs=false" ],
-            "sources": [
-                {
-                    "type": "git",
-                    "url": "https://gitlab.gnome.org/GNOME/tracker.git",
-                    "branch": "tracker-2.3"
-                }
-            ]
-        },
         {
             "name": "tracker-miners",
             "buildsystem": "meson",
-            "cleanup": [ "/bin", "/etc", "/lib/systemd", "/libexec" ],
-            "config-opts": [ "--default-library=shared",
-                             "-Dminer_apps=false",
+            "config-opts": [ "-Ddefault_index_single_directories=&DOWNLOADS",
+                             "-Ddefault_index_recursive_directories=&DOCUMENTS",
+                             "-Ddomain_prefix=org.gnome.Documents",
+                             "-Dman=false",
+                             "-Dminer_fs=true",
+                             "-Dminer_fs_cache_location=$XDG_CACHE_HOME/org.gnome.Documents/miner/files",
                              "-Dminer_rss=false",
-                             "-Dextract=false",
-                             "-Dgeneric_media_extractor=none",
-                             "-Dwriteback=false",
-                             "-Dminer_fs=true" ],
+                             "-Dsystemd_user_services=false" ],
             "sources": [
                 {
                     "type": "git",
-                    "url": "https://gitlab.gnome.org/GNOME/tracker-miners.git",
-                    "branch": "tracker-miners-2.3"
+                    "url": "https://gitlab.gnome.org/GNOME/tracker-miners.git"
                 }
             ]
         },
diff --git a/src/application.js b/src/application.js
index 73cd2da1..1fa75b79 100644
--- a/src/application.js
+++ b/src/application.js
@@ -70,6 +70,7 @@ var sourceManager = null;
 var trackerCollectionsController = null;
 var trackerDocumentsController = null;
 var trackerSearchController = null;
+var trackerMinerService = null;
 
 const TrackerMinerFilesIndexIface = '<node> \
 <interface name="org.freedesktop.Tracker3.Miner.Files.Index"> \
@@ -347,6 +348,16 @@ var Application = GObject.registerClass({
             return;
         }
 
+        // test access to global tracker daemon
+        try {
+            let busConn = Tracker.SparqlConnection.bus_new('org.freedesktop.Tracker3.Miner.Files',
+                                                           null, Gio.DBus.session);
+            trackerMinerService = 'org.freedesktop.Tracker3.Miner.Files';
+        } catch (e) {
+            // if the daemon is not available, run our own copy (for the sandboxed case)
+            trackerMinerService = this.get_application_id() + '.Tracker3.Miner.Files';
+        }
+
         try {
             goaClient = Goa.Client.new_sync(null);
         } catch (e) {
diff --git a/src/query.js b/src/query.js
index 4f5142ea..ef90754e 100644
--- a/src/query.js
+++ b/src/query.js
@@ -205,7 +205,7 @@ var QueryBuilder = class QueryBuilder {
                 selectClauses +
                 whereSparql;
         } else {
-	    let services = ['org.freedesktop.Tracker3.Miner.Files'];
+	    let services = [this._context.trackerMinerService];
 	    let serviceQueries = [];
 
             if (this._context.sourceManager.hasProviderType('google'))
@@ -260,7 +260,7 @@ var QueryBuilder = class QueryBuilder {
 	    sparql = 'SELECT DISTINCT COUNT(?urn) AS ?c ' +
 		this._buildWhere(true, flags);
 	} else {
-	    let services = ['org.freedesktop.Tracker3.Miner.Files'];
+	    let services = [this._context.trackerMinerService];
 	    let countQueries = [];
 
             if (this._context.sourceManager.hasProviderType('google'))
-- 
GitLab


From 557e0768ef0ff079267b4bd40df02a633caefc81 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Tue, 26 Jan 2021 16:48:29 +0100
Subject: [PATCH 8/8] flatpak: Update flatpak reference

Drop gspell, and update to meson build in evince. Just needed
for CI to pass, and build flatpaks.
---
 .gitlab-ci.yml                   |  1 -
 flatpak/org.gnome.Documents.json | 23 ++++++-----------------
 2 files changed, 6 insertions(+), 18 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e2d7ce78..774a9834 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -4,7 +4,6 @@ variables:
     GIT_SUBMODULE_STRATEGY: normal
 
 flatpak-documents:
-    image: 'registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.32'
     variables:
         BUNDLE: "gnome-documents-dev.flatpak"
         MANIFEST_PATH: "flatpak/org.gnome.Documents.json"
diff --git a/flatpak/org.gnome.Documents.json b/flatpak/org.gnome.Documents.json
index 325d1e73..309cf6cb 100644
--- a/flatpak/org.gnome.Documents.json
+++ b/flatpak/org.gnome.Documents.json
@@ -1,7 +1,7 @@
 {
     "app-id": "org.gnome.Documents",
     "runtime": "org.gnome.Platform",
-    "runtime-version": "3.32",
+    "runtime-version": "master",
     "sdk": "org.gnome.Sdk",
     "command": "gnome-documents",
     "tags": [ "nightly" ],
@@ -130,25 +130,14 @@
                 }
             ]
         },
-        {
-            "name": "gspell",
-            "cleanup": [
-                "/bin"
-            ],
-            "sources": [
-                {
-                    "type": "git",
-                    "url": "https://gitlab.gnome.org/GNOME/gspell.git"
-                }
-            ]
-        },
         {
             "name": "evince",
+            "buildsystem": "meson",
             "cleanup": [ "/share/GConf", "/share/help" ],
-            "config-opts": [ "--disable-nautilus", "--disable-viewer",
-                             "--disable-previewer", "--disable-dbus",
-                             "--disable-browser-plugin", "--enable-introspection",
-                             "--disable-comics" ],
+            "config-opts": [ "-Dnautilus=false", "-Dviewer=false",
+                             "-Dpreviewer=false", "-Ddbus=false",
+                             "-Dbrowser-plugin=false", "-Dintrospection=true",
+                             "-Dcomics=disabled" ],
             "sources": [
                 {
                     "type": "git",
-- 
GitLab
openSUSE Build Service is sponsored by