103
100
scope.queue_search_changed (SearchType.GLOBAL);
106
/* Listen for filter changes */
107
scope.filters_changed.connect (() => {
108
scope.queue_search_changed (SearchType.DEFAULT);
111
scope.generate_search_key.connect ((lens_search) => {
112
return lens_search.search_string.strip ();
115
/* Listen for changes to the lens entry search */
116
scope.search_changed.connect ((lens_search, search_type, cancellable) =>
103
scope.generate_search_key.connect ((search) => {
104
return search.search_string.strip ();
107
/* Listen for changes to the search */
108
scope.search_changed.connect ((search, search_type, cancellable) =>
118
dispatch_search.begin (lens_search, search_type, cancellable);
110
dispatch_search.begin (search, search_type, cancellable);
124
private async void dispatch_search (LensSearch lens_search,
116
private async void dispatch_search (DeprecatedScopeSearch scope_search,
125
117
SearchType search_type,
126
Cancellable cancellable)
118
GLib.Cancellable cancellable)
128
120
if (search_type == SearchType.GLOBAL)
130
yield update_global_search_async (lens_search, cancellable);
122
yield update_global_search_async (scope_search, cancellable);
134
yield update_search_async (lens_search, cancellable);
126
yield update_search_async (scope_search, cancellable);
137
129
// make sure we don't forget to emit finished (if we didn't get cancelled)
138
130
if (!cancellable.is_cancelled ())
140
if (lens_search.results_model.get_n_rows () == 0)
132
if (scope_search.results_model.get_n_rows () == 0)
142
lens_search.set_reply_hint ("no-results-hint",
134
scope_search.set_reply_hint ("no-results-hint",
143
135
_("Sorry, there are no files or folders that match your search."));
146
lens_search.finished ();
139
scope_search.finished ();
150
142
private void populate_filters ()
152
var filters = new GLib.List<Unity.Filter> ();
144
var filters = new Unity.FilterSet ();
154
146
/* Last modified */
1184
1175
scope.queue_search_changed (SearchType.DEFAULT);
1185
1176
scope.queue_search_changed (SearchType.GLOBAL);
1189
private const string ATTRS_TYPE_HIDDEN = FileAttribute.STANDARD_TYPE +
1190
"," + FileAttribute.STANDARD_IS_HIDDEN;
1191
private const string ATTRS_TYPE_SIZE_HIDDEN = FileAttribute.STANDARD_TYPE +
1192
"," + FileAttribute.STANDARD_SIZE +
1193
"," + FileAttribute.STANDARD_IS_HIDDEN;
1196
public enum ResultFlags
1204
/* Appends a set of Zeitgeist.Events to our Dee.Model assuming that
1205
* these events are already sorted with descending timestamps */
1206
public void append_events_sorted (string search_string,
1207
Zeitgeist.ResultSet? events,
1209
int64 min_size, int64 max_size,
1211
Gee.Set<string>? excluded_uris = null,
1212
int category_override = -1)
1214
if (events == null) return;
1216
Set<string>? extracted_directories = null;
1218
if (ResultFlags.EXTRACT_ORIGINS in flags)
1220
var folded_search = search_string.casefold ();
1221
var origins = new HashSet<string> ();
1222
// loop through all found events, take a look at origin field, add it
1223
// to result set if it matches our search
1224
// NOTE: using separate zg query with MOST_RECENT_ORIGINS grouping
1225
// is more likely to find relevant directories, but is much slower
1226
// than this kind of "approximation"
1179
private const string ATTRS_TYPE_HIDDEN = FileAttribute.STANDARD_TYPE +
1180
"," + FileAttribute.STANDARD_IS_HIDDEN;
1181
private const string ATTRS_TYPE_SIZE_HIDDEN = FileAttribute.STANDARD_TYPE +
1182
"," + FileAttribute.STANDARD_SIZE +
1183
"," + FileAttribute.STANDARD_IS_HIDDEN;
1186
public enum ResultFlags
1194
/* Appends a set of Zeitgeist.Events to our Dee.Model assuming that
1195
* these events are already sorted with descending timestamps */
1196
public void append_events_sorted (string search_string,
1197
Zeitgeist.ResultSet? events,
1199
int64 min_size, int64 max_size,
1201
Gee.Set<string>? excluded_uris = null,
1202
int category_override = -1)
1204
if (events == null) return;
1206
Set<string>? extracted_directories = null;
1208
if (ResultFlags.EXTRACT_ORIGINS in flags)
1210
var folded_search = search_string.casefold ();
1211
var origins = new HashSet<string> ();
1212
// loop through all found events, take a look at origin field, add it
1213
// to result set if it matches our search
1214
// NOTE: using separate zg query with MOST_RECENT_ORIGINS grouping
1215
// is more likely to find relevant directories, but is much slower
1216
// than this kind of "approximation"
1217
foreach (var ev in events)
1219
if (ev.num_subjects () > 0)
1221
string origin = ev.get_subject (0).get_origin ();
1222
if (origin == null || origin == "") continue;
1223
var f = File.new_for_uri (origin);
1224
origin = f.get_uri ();
1225
if (excluded_uris != null && origin in excluded_uris) continue;
1226
if (!(origin in origins) && f.is_native () && f.query_exists ())
1228
string? path = f.get_path ();
1229
if (path != null && path.contains ("/."))
1232
var display_name = Path.get_basename (f.get_parse_name ());
1233
if (display_name.casefold ().has_prefix (folded_search))
1235
string mimetype = "inode/directory";
1236
string icon = Utils.get_icon_for_uri (origin, mimetype);
1237
if (category_override >= 0)
1238
category_id = category_override;
1240
category_id = Categories.FOLDERS;
1241
results.append (origin, icon, category_id, ResultType.PERSONAL,
1242
mimetype, display_name, "", origin, empty_asv);
1246
if (extracted_directories == null)
1248
extracted_directories = new HashSet<string> ();
1250
extracted_directories.add (origin);
1252
origins.add (origin);
1256
// we need this because of way ResultSet works with foreach
1257
if (events.size () > 0) events.seek (0);
1227
1259
foreach (var ev in events)
1229
1261
if (ev.num_subjects () > 0)
1231
string origin = ev.get_subject (0).get_origin ();
1232
if (origin == null || origin == "") continue;
1233
var f = File.new_for_uri (origin);
1234
origin = f.get_uri ();
1235
if (excluded_uris != null && origin in excluded_uris) continue;
1236
if (!(origin in origins) && f.is_native () && f.query_exists ())
1238
string? path = f.get_path ();
1239
if (path != null && path.contains ("/."))
1242
var display_name = Path.get_basename (f.get_parse_name ());
1243
if (display_name.casefold ().has_prefix (folded_search))
1245
string mimetype = "inode/directory";
1246
string icon = Utils.get_icon_for_uri (origin, mimetype);
1247
if (category_override >= 0)
1248
category_id = category_override;
1250
category_id = Categories.FOLDERS;
1251
results.append (origin, icon, category_id, mimetype,
1252
display_name, "", origin);
1256
if (extracted_directories == null)
1263
// FIXME: We only use the first subject...
1264
Zeitgeist.Subject su = ev.get_subject (0);
1267
string display_name;
1270
if (ResultFlags.USE_ORIGIN in flags)
1272
uri = su.get_origin ();
1274
mimetype = "inode/directory";
1278
uri = su.get_current_uri ();
1279
display_name = su.get_text ();
1280
mimetype = su.get_mimetype ();
1281
mimetype = su.get_mimetype () != null ?
1282
su.get_mimetype () : "application/octet-stream";
1284
if (uri == null) continue;
1285
File file = File.new_for_uri (uri);
1286
if (excluded_uris != null && file.get_uri () in excluded_uris) continue;
1288
if (display_name == null || display_name == "")
1290
display_name = Path.get_basename (file.get_parse_name ());
1293
bool check_size = min_size > 0 || max_size < int64.MAX;
1294
/* Don't check existence on non-native files as http:// and
1295
* friends are *very* expensive to query */
1296
FileType file_type = FileType.UNKNOWN;
1297
if (file.is_native ())
1299
// hidden files should be ignored
1302
FileInfo info = file.query_info (check_size ?
1303
ATTRS_TYPE_SIZE_HIDDEN : ATTRS_TYPE_HIDDEN, 0, null);
1304
string? path = file.get_path ();
1305
if (path != null && path.contains ("/."))
1308
(info.get_size () < min_size || info.get_size () > max_size))
1258
extracted_directories = new HashSet<string> ();
1260
extracted_directories.add (origin);
1312
file_type = info.get_file_type ();
1262
origins.add (origin);
1266
// we need this because of way ResultSet works with foreach
1267
if (events.size () > 0) events.seek (0);
1269
foreach (var ev in events)
1271
if (ev.num_subjects () > 0)
1273
// FIXME: We only use the first subject...
1274
Zeitgeist.Subject su = ev.get_subject (0);
1277
string display_name;
1280
if (ResultFlags.USE_ORIGIN in flags)
1282
uri = su.get_origin ();
1284
mimetype = "inode/directory";
1288
uri = su.get_current_uri ();
1289
display_name = su.get_text ();
1290
mimetype = su.get_mimetype ();
1291
mimetype = su.get_mimetype () != null ?
1292
su.get_mimetype () : "application/octet-stream";
1294
if (uri == null) continue;
1295
File file = File.new_for_uri (uri);
1296
if (excluded_uris != null && file.get_uri () in excluded_uris) continue;
1298
if (display_name == null || display_name == "")
1300
display_name = Path.get_basename (file.get_parse_name ());
1303
bool check_size = min_size > 0 || max_size < int64.MAX;
1304
/* Don't check existence on non-native files as http:// and
1305
* friends are *very* expensive to query */
1306
FileType file_type = FileType.UNKNOWN;
1307
if (file.is_native ())
1309
// hidden files should be ignored
1312
FileInfo info = file.query_info (check_size ?
1313
ATTRS_TYPE_SIZE_HIDDEN : ATTRS_TYPE_HIDDEN, 0, null);
1314
string? path = file.get_path ();
1315
if (path != null && path.contains ("/."))
1318
(info.get_size () < min_size || info.get_size () > max_size))
1314
catch (GLib.Error e)
1316
// as error occurred file must be missing therefore ignoring it
1322
file_type = info.get_file_type ();
1324
catch (GLib.Error e)
1326
// as error occurred file must be missing therefore ignoring it
1320
string icon = Utils.get_icon_for_uri (uri, mimetype);
1321
string comment = file.get_parse_name ();
1323
var is_dir = file_type == FileType.DIRECTORY;
1324
if (is_dir && ResultFlags.SKIP_FOLDERS in flags) continue;
1326
if (category_override >= 0)
1327
category_id = category_override;
1329
category_id = is_dir ? Categories.FOLDERS : Categories.RECENT;
1331
results.append (uri, icon, category_id, ResultType.PERSONAL, mimetype,
1332
display_name, comment, uri, empty_asv);
1330
string icon = Utils.get_icon_for_uri (uri, mimetype);
1331
string comment = file.get_parse_name ();
1333
var is_dir = file_type == FileType.DIRECTORY;
1334
if (is_dir && ResultFlags.SKIP_FOLDERS in flags) continue;
1336
if (category_override >= 0)
1337
category_id = category_override;
1339
category_id = is_dir ? Categories.FOLDERS : Categories.RECENT;
1341
results.append (uri, icon, category_id, mimetype,
1342
display_name, comment, uri);
1347
if (extracted_directories != null)
1349
foreach (var dir_uri in extracted_directories)
1337
if (extracted_directories != null)
1351
var f = File.new_for_uri (dir_uri);
1352
var display_name = Path.get_basename (f.get_parse_name ());
1353
string mimetype = "inode/directory";
1354
string icon = Utils.get_icon_for_uri (dir_uri, mimetype);
1355
if (category_override >= 0)
1356
category_id = category_override;
1358
category_id = Categories.FOLDERS;
1359
results.append (dir_uri, icon, category_id, mimetype,
1360
display_name, "", dir_uri);
1339
foreach (var dir_uri in extracted_directories)
1341
var f = File.new_for_uri (dir_uri);
1342
var display_name = Path.get_basename (f.get_parse_name ());
1343
string mimetype = "inode/directory";
1344
string icon = Utils.get_icon_for_uri (dir_uri, mimetype);
1345
if (category_override >= 0)
1346
category_id = category_override;
1348
category_id = Categories.FOLDERS;
1349
results.append (dir_uri, icon, category_id, ResultType.PERSONAL,
1350
mimetype, display_name, "", dir_uri, empty_asv);