[gnome-documents/wip/split-view: 12/14] Rework the guts of the query engine to accomodate multiple views



commit 6a9f10e35420534c4e44fe7a60a3e8ea73b6f3d9
Author: Debarshi Ray <debarshir gnome org>
Date:   Fri Oct 17 13:52:47 2014 +0200

    Rework the guts of the query engine to accomodate multiple views
    
    The objective is to have separate views for documents, collections and
    search results. The first two views will always show only documents and
    collections arranged in reverse chronological order. Whenever search
    constraints are applied the results are supposed to show up in the
    search view.
    
    Each view will have its separate TrackerController and OffsetController
    implementations to decide when to refresh its contents and what the
    current offsets are. The OffsetController is no longer a part of the
    search context because the different views need to use their own
    implementations. The search provider does not have a way to change the
    offsets, so it can just use the initial value of [0, 50).
    
    New flags corresponding to each of the views have been added to
    QueryFlags. These are passed around to the classes that play a part in
    constructing the queries.
    
    The meaning of the NONE and UNFILTERED flags have also changed.
    Earlier, UNFILTERED was used to completely turn off search categories,
    search matches, search types and collections, while NONE had them
    enabled. Now, NONE will disable the search type WHERE clauses but keep
    everything else enabled so that it can be used to create queries for
    browsing the contents of a collection.
    
    Since the getFilter method of the various BaseManager classes are now
    affected by their roles in the individual views, it no longer makes
    sense to have a generic implementation in the parent. Instead,
    getAllFilter has been made public so that the children can use it to
    construct their query snippets.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=686461

 src/application.js         |   17 +++++++--
 src/manager.js             |   14 ++------
 src/query.js               |   47 ++++++++++++++++--------
 src/search.js              |   86 +++++++++++++++++++++++++++++++++++++++-----
 src/shellSearchProvider.js |    3 +-
 src/trackerController.js   |   68 ++++++++++++++++++++++++++++++++---
 6 files changed, 188 insertions(+), 47 deletions(-)
---
diff --git a/src/application.js b/src/application.js
index 03cba8b..609e73f 100644
--- a/src/application.js
+++ b/src/application.js
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012 Red Hat, Inc.
+ * Copyright (c) 2011, 2012, 2014 Red Hat, Inc.
  *
  * Gnome Documents is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by the
@@ -77,7 +77,9 @@ let cssProvider = null;
 let documentManager = null;
 let modeController = null;
 let notificationManager = null;
-let offsetController = null;
+let offsetCollectionsController = null;
+let offsetDocumentsController = null;
+let offsetSearchController = null;
 let queryBuilder = null;
 let searchCategoryManager = null;
 let searchController = null;
@@ -85,7 +87,9 @@ let searchMatchManager = null;
 let searchTypeManager = null;
 let selectionController = null;
 let sourceManager = null;
-let trackerController = null;
+let trackerCollectionsController = null;
+let trackerDocumentsController = null;
+let trackerSearchController = null;
 
 const TrackerExtractPriorityIface = '<node> \
 <interface name="org.freedesktop.Tracker1.Extract.Priority"> \
@@ -445,7 +449,12 @@ const Application = new Lang.Class({
         Search.initSearch(imports.shellSearchProvider);
 
         modeController = new WindowMode.ModeController();
-        trackerController = new TrackerController.TrackerOverviewController();
+        offsetCollectionsController = new Search.OffsetCollectionsController();
+        offsetDocumentsController = new Search.OffsetDocumentsController();
+        offsetSearchController = new Search.OffsetSearchController();
+        trackerCollectionsController = new TrackerController.TrackerCollectionsController();
+        trackerDocumentsController = new TrackerController.TrackerDocumentsController();
+        trackerSearchController = new TrackerController.TrackerSearchController();
         selectionController = new Selections.SelectionController();
 
         this._actionEntries = [
diff --git a/src/manager.js b/src/manager.js
index 03bbe84..9dac51b 100644
--- a/src/manager.js
+++ b/src/manager.js
@@ -124,16 +124,8 @@ const BaseManager = new Lang.Class({
         this.emit('clear');
     },
 
-    getFilter: function() {
-        let item = this.getActiveItem();
-        let retval = '';
-
-        if (item.id == 'all')
-            retval = this._getAllFilter();
-        else if (item && item.getFilter)
-            retval = item.getFilter();
-
-        return retval;
+    getFilter: function(flags) {
+        log('Error: BaseManager implementations must override getFilter');
     },
 
     getWhere: function() {
@@ -151,7 +143,7 @@ const BaseManager = new Lang.Class({
             func(this._items[idx]);
     },
 
-    _getAllFilter: function() {
+    getAllFilter: function() {
         let filters = [];
 
         this.forEachItem(function(item) {
diff --git a/src/query.js b/src/query.js
index 61e7f28..48b89f7 100644
--- a/src/query.js
+++ b/src/query.js
@@ -23,6 +23,7 @@ const GdPrivate = imports.gi.GdPrivate;
 const Gio = imports.gi.Gio;
 const GLib = imports.gi.GLib;
 const Lang = imports.lang;
+const Search = imports.search;
 
 const QueryColumns = {
     URN: 0,
@@ -41,7 +42,10 @@ const QueryColumns = {
 
 const QueryFlags = {
     NONE: 0,
-    UNFILTERED: 1 << 0
+    UNFILTERED: 1 << 0,
+    COLLECTIONS: 1 << 1,
+    DOCUMENTS: 1 << 2,
+    SEARCH: 1 << 3
 };
 
 const LOCAL_COLLECTIONS_IDENTIFIER = 'gd:collection:local:';
@@ -58,12 +62,12 @@ const QueryBuilder = new Lang.Class({
                  activeSource: this._context.sourceManager.getActiveItem() };
     },
 
-    _buildFilterString: function(currentType) {
+    _buildFilterString: function(currentType, flags) {
         let filters = [];
 
-        filters.push(this._context.searchMatchManager.getFilter());
-        filters.push(this._context.sourceManager.getFilter());
-        filters.push(this._context.searchCategoryManager.getFilter());
+        filters.push(this._context.searchMatchManager.getFilter(flags));
+        filters.push(this._context.sourceManager.getFilter(flags));
+        filters.push(this._context.searchCategoryManager.getFilter(flags));
 
         if (currentType) {
             filters.push(currentType.getFilter());
@@ -85,10 +89,14 @@ const QueryBuilder = new Lang.Class({
         let whereParts = [];
         let searchTypes = [];
 
-        if (flags & QueryFlags.UNFILTERED)
-            searchTypes = this._context.searchTypeManager.getAllTypes();
-        else
+        if (flags & QueryFlags.COLLECTIONS)
+            searchTypes = [this._context.searchTypeManager.getItemById(Search.SearchTypeStock.COLLECTIONS)];
+        else if (flags & QueryFlags.DOCUMENTS)
+            searchTypes = this._context.searchTypeManager.getDocumentTypes();
+        else if (flags & QueryFlags.SEARCH)
             searchTypes = this._context.searchTypeManager.getCurrentTypes();
+        else
+            searchTypes = this._context.searchTypeManager.getAllTypes();
 
         // build an array of WHERE clauses; each clause maps to one
         // type of resource we're looking for.
@@ -101,7 +109,7 @@ const QueryBuilder = new Lang.Class({
                         part += this._context.searchCategoryManager.getWhere() +
                                 this._context.documentManager.getWhere();
 
-                    part += this._buildFilterString(currentType);
+                    part += this._buildFilterString(currentType, flags);
                 }
 
                 part += ' }';
@@ -115,16 +123,23 @@ const QueryBuilder = new Lang.Class({
         return whereSparql;
     },
 
-    _buildQueryInternal: function(global, flags) {
+    _buildQueryInternal: function(global, flags, offsetController) {
         let whereSparql = this._buildWhere(global, flags);
         let tailSparql = '';
 
         // order results by mtime
         if (global) {
+            let offset = 0;
+            let step = Search.OFFSET_STEP;
+
+            if (offsetController) {
+                offset = offsetController.getOffset();
+                step = offsetController.getOffsetStep();
+            }
+
             tailSparql +=
                 'ORDER BY DESC (?mtime)' +
-                ('LIMIT %d OFFSET %d').format(this._context.offsetController.getOffsetStep(),
-                                              this._context.offsetController.getOffset());
+                ('LIMIT %d OFFSET %d').format(step, offset);
         }
 
         let sparql =
@@ -152,13 +167,13 @@ const QueryBuilder = new Lang.Class({
         return this._createQuery(sparql);
     },
 
-    buildGlobalQuery: function() {
-        return this._createQuery(this._buildQueryInternal(true, QueryFlags.NONE));
+    buildGlobalQuery: function(flags, offsetController) {
+        return this._createQuery(this._buildQueryInternal(true, flags, offsetController));
     },
 
-    buildCountQuery: function() {
+    buildCountQuery: function(flags) {
         let sparql = 'SELECT DISTINCT COUNT(?urn) ' +
-            this._buildWhere(true, QueryFlags.NONE);
+            this._buildWhere(true, flags);
 
         return this._createQuery(sparql);
     },
diff --git a/src/search.js b/src/search.js
index b46138d..12d88dc 100644
--- a/src/search.js
+++ b/src/search.js
@@ -40,7 +40,6 @@ function initSearch(context) {
     context.searchMatchManager = new SearchMatchManager(context);
     context.searchTypeManager = new SearchTypeManager(context);
     context.searchController = new SearchController(context);
-    context.offsetController = new OffsetOverviewController(context);
     context.queryBuilder = new Query.QueryBuilder(context);
 };
 
@@ -137,6 +136,12 @@ const SearchCategoryManager = new Lang.Class({
         // this._categories[category.id] = category;
 
         this.setActiveItem(recent);
+    },
+
+    getFilter: function(flags) {
+        // Since we don't expose the SearchCategoryManager in the UI,
+        // this is a placeholder for the moment.
+        return '(true)';
     }
 });
 
@@ -285,7 +290,10 @@ const SearchMatchManager = new Lang.Class({
         this.setActiveItemById(SearchMatchStock.ALL);
     },
 
-    getFilter: function() {
+    getFilter: function(flags) {
+        if ((flags & Query.QueryFlags.SEARCH) == 0)
+            return '(true)';
+
         let terms = this.context.searchController.getTerms();
         let filters = [];
 
@@ -293,7 +301,16 @@ const SearchMatchManager = new Lang.Class({
             this.forEachItem(function(item) {
                 item.setFilterTerm(terms[i]);
             });
-            filters.push(this.parent());
+
+            let filter;
+            let item = this.getActiveItem();
+
+            if (item.id == SearchMatchStock.ALL)
+                filter = this.getAllFilter();
+            else
+                filter = item.getFilter();
+
+            filters.push(filter);
         }
         return filters.length ? '( ' + filters.join(' && ') + ')' : '';
     }
@@ -467,6 +484,24 @@ const SourceManager = new Lang.Class({
         this.processNewItems(newItems);
     },
 
+    getFilter: function(flags) {
+        let item;
+
+        if (flags & Query.QueryFlags.SEARCH)
+            item = this.getActiveItem();
+        else
+            item = this.getItemById(SearchSourceStock.ALL);
+
+        let filter;
+
+        if (item.id == SearchSourceStock.ALL)
+            filter = this.getAllFilter();
+        else
+            filter = item.getFilter();
+
+        return filter;
+    }
+
     getFilterNotLocal: function() {
         let sources = this.getItems();
         let filters = [];
@@ -515,7 +550,7 @@ const SourceManager = new Lang.Class({
     }
 });
 
-const _OFFSET_STEP = 50;
+const OFFSET_STEP = 50;
 
 const OffsetController = new Lang.Class({
     Name: 'OffsetController',
@@ -587,16 +622,49 @@ const OffsetController = new Lang.Class({
 });
 Signals.addSignalMethods(OffsetController.prototype);
 
-const OffsetOverviewController = new Lang.Class({
-    Name: 'OffsetOverviewController',
+const OffsetCollectionsController = new Lang.Class({
+    Name: 'OffsetCollectionsController',
     Extends: OffsetController,
 
-    _init: function(context) {
+    _init: function() {
+        this.parent();
+    },
+
+    getQuery: function() {
+        let activeCollection = Application.documentManager.getActiveCollection();
+        let flags;
+
+        if (activeCollection)
+            flags = Query.QueryFlags.NONE;
+        else
+            flags = Query.QueryFlags.COLLECTIONS;
+
+        return Application.queryBuilder.buildCountQuery(flags);
+    }
+});
+
+const OffsetDocumentsController = new Lang.Class({
+    Name: 'OffsetDocumentsController',
+    Extends: OffsetController,
+
+    _init: function() {
+        this.parent();
+    },
+
+    getQuery: function() {
+        return Application.queryBuilder.buildCountQuery(Query.QueryFlags.DOCUMENTS);
+    }
+});
+
+const OffsetSearchController = new Lang.Class({
+    Name: 'OffsetSearchController',
+    Extends: OffsetController,
+
+    _init: function() {
         this.parent();
-        this._context = context;
     },
 
     getQuery: function() {
-        return this._context.queryBuilder.buildCountQuery();
+        return Application.queryBuilder.buildCountQuery(Query.QueryFlags.SEARCH);
     }
 });
diff --git a/src/shellSearchProvider.js b/src/shellSearchProvider.js
index 2711714..6f77a24 100644
--- a/src/shellSearchProvider.js
+++ b/src/shellSearchProvider.js
@@ -39,7 +39,6 @@ const TrackerUtils = imports.trackerUtils;
 const Utils = imports.utils;
 
 let documentManager = null;
-let offsetController = null;
 let queryBuilder = null;
 let searchCategoryManager = null;
 let searchMatchManager = null;
@@ -319,7 +318,7 @@ const FetchIdsJob = new Lang.Class({
         this._cancellable = cancellable;
         searchController.setString(this._terms.join(' '));
 
-        let query = queryBuilder.buildGlobalQuery();
+        let query = queryBuilder.buildGlobalQuery(Query.QueryFlags.SEARCH, null);
         Application.connectionQueue.add(query.sparql, this._cancellable, Lang.bind(this,
             function(object, res) {
                 let cursor = null;
diff --git a/src/trackerController.js b/src/trackerController.js
index 1173b15..7633195 100644
--- a/src/trackerController.js
+++ b/src/trackerController.js
@@ -281,15 +281,72 @@ const TrackerController = new Lang.Class({
 });
 Signals.addSignalMethods(TrackerController.prototype);
 
-const TrackerOverviewController = new Lang.Class({
-    Name: 'TrackerOverviewController',
+const TrackerCollectionsController = new Lang.Class({
+    Name: 'TrackerCollectionsController',
+    Extends: TrackerController,
+
+    _init: function() {
+        this.parent(WindowMode.WindowMode.COLLECTIONS);
+
+        Application.documentManager.connect('active-collection-changed', Lang.bind(this,
+            function() {
+                let windowMode = Application.modeController.getWindowMode();
+                if (windowMode == WindowMode.WindowMode.COLLECTIONS)
+                    this.refreshForObject();
+            }));
+    },
+
+    getOffsetController: function() {
+        return Application.offsetCollectionsController;
+    },
+
+    getQuery: function() {
+        let flags;
+        let activeCollection = Application.documentManager.getActiveCollection();
+
+        if (activeCollection)
+            flags = Query.QueryFlags.NONE;
+        else
+            flags = Query.QueryFlags.COLLECTIONS;
+
+        return Application.queryBuilder.buildGlobalQuery(flags,
+                                                         Application.offsetCollectionsController);
+    },
+});
+
+const TrackerDocumentsController = new Lang.Class({
+    Name: 'TrackerDocumentsController',
+    Extends: TrackerController,
+
+    _init: function() {
+        this.parent(WindowMode.WindowMode.DOCUMENTS);
+    },
+
+    getOffsetController: function() {
+        return Application.offsetDocumentsController;
+    },
+
+    getQuery: function() {
+        return Application.queryBuilder.buildGlobalQuery(Query.QueryFlags.DOCUMENTS,
+                                                         Application.offsetDocumentsController);
+    },
+});
+
+const TrackerSearchController = new Lang.Class({
+    Name: 'TrackerSearchController',
     Extends: TrackerController,
 
     _init: function() {
         this.parent(WindowMode.WindowMode.OVERVIEW);
 
+        Application.documentManager.connect('active-collection-changed', Lang.bind(this,
+            function() {
+                let windowMode = Application.modeController.getWindowMode();
+                if (windowMode == WindowMode.WindowMode.SEARCH)
+                    this.refreshForObject();
+            }));
+
         Application.sourceManager.connect('active-changed', Lang.bind(this, this.refreshForObject));
-        Application.documentManager.connect('active-collection-changed', Lang.bind(this, 
this.refreshForObject));
         Application.searchController.connect('search-string-changed', Lang.bind(this, 
this.refreshForObject));
         Application.searchCategoryManager.connect('active-changed', Lang.bind(this, this.refreshForObject));
         Application.searchTypeManager.connect('active-changed', Lang.bind(this, this.refreshForObject));
@@ -305,10 +362,11 @@ const TrackerOverviewController = new Lang.Class({
     },
 
     getOffsetController: function() {
-        return Application.offsetController;
+        return Application.offsetSearchController;
     },
 
     getQuery: function() {
-        return Application.queryBuilder.buildGlobalQuery();
+        return Application.queryBuilder.buildGlobalQuery(Query.QueryFlags.SEARCH,
+                                                         Application.offsetSearchController);
     },
 });


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]