Merge lp:~jeremywootten/pantheon-files/various-fixes-part2-load-network-locations-better into lp:~elementary-apps/pantheon-files/trunk
- various-fixes-part2-load-network-locations-better
- Merge into trunk
Status: | Merged | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Merged at revision: | 2049 | ||||||||||||||||
Proposed branch: | lp:~jeremywootten/pantheon-files/various-fixes-part2-load-network-locations-better | ||||||||||||||||
Merge into: | lp:~elementary-apps/pantheon-files/trunk | ||||||||||||||||
Diff against target: |
1701 lines (+539/-435) 12 files modified
libcore/AbstractSlot.vala (+1/-0) libcore/CMakeLists.txt (+1/-0) libcore/FileUtils.vala (+25/-0) libcore/gof-directory-async.vala (+336/-255) libcore/gof-file.c (+15/-8) libwidgets/FileUtils.vala (+0/-7) libwidgets/View/BreadcrumbsEntry.vala (+18/-13) src/View/AbstractDirectoryView.vala (+37/-36) src/View/Miller.vala (+4/-0) src/View/Slot.vala (+36/-12) src/View/ViewContainer.vala (+59/-71) src/View/Window.vala (+7/-33) |
||||||||||||||||
To merge this branch: | bzr merge lp:~jeremywootten/pantheon-files/various-fixes-part2-load-network-locations-better | ||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
elementary Apps team | Pending | ||
Review via email: mp+283723@code.launchpad.net |
Commit message
Make loading and reloading of directories asynchronous.
Description of the change
This branch is the second part of a series aimed at improving the handling of remote locations.
It aims to make the loading of directories fully asynchronous so as to prevent blocking of the interface especially when restoring remote locations that have become unavailable or require a password.
A number of related changes are made to the reloading process and the location bar context menu.
The branch has been tested using ftp:// sftp:// afp:// and smb:// servers on the local network.
TO TEST.
1. Open folders to various servers in different/multiple tabs and windows
2. Navigate within and between folders on each server using all available methods.
3. Close and reopen Files without disconnecting the servers.
4. Close Files, unmount the servers, reopen Files
5. Close Files, break the network link (without unmounting) and reopen Files
In most cases the interface should not block; in the worst case Files will not attempt to load a folder for more than 15 seconds.
- 2046. By Jeremy Wootten
-
Fix reloading of non-existent folder after creation
Preview Diff
1 | === modified file 'libcore/AbstractSlot.vala' |
2 | --- libcore/AbstractSlot.vala 2015-12-26 19:42:49 +0000 |
3 | +++ libcore/AbstractSlot.vala 2016-01-27 19:54:54 +0000 |
4 | @@ -76,6 +76,7 @@ |
5 | protected abstract void make_view (); |
6 | public abstract void cancel (); |
7 | public abstract void close (); |
8 | + public abstract FileInfo? lookup_file_info (GLib.File loc); |
9 | |
10 | public virtual void zoom_out () {} |
11 | public virtual void zoom_in () {} |
12 | |
13 | === modified file 'libcore/CMakeLists.txt' |
14 | --- libcore/CMakeLists.txt 2015-12-02 14:34:10 +0000 |
15 | +++ libcore/CMakeLists.txt 2016-01-27 19:54:54 +0000 |
16 | @@ -20,6 +20,7 @@ |
17 | BookmarkList.vala |
18 | DndHandler.vala |
19 | Enums.vala |
20 | + FileUtils.vala |
21 | gof-callwhenready.vala |
22 | gof-directory-async.vala |
23 | gof-preferences.vala |
24 | |
25 | === added file 'libcore/FileUtils.vala' |
26 | --- libcore/FileUtils.vala 1970-01-01 00:00:00 +0000 |
27 | +++ libcore/FileUtils.vala 2016-01-27 19:54:54 +0000 |
28 | @@ -0,0 +1,25 @@ |
29 | +/*** |
30 | + Copyright (C) 2015 Elementary Developers |
31 | + |
32 | + This program is free software: you can redistribute it and/or modify it |
33 | + under the terms of the GNU Lesser General Public License version 3, as published |
34 | + by the Free Software Foundation. |
35 | + |
36 | + This program is distributed in the hope that it will be useful, but |
37 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
38 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
39 | + PURPOSE. See the GNU General Public License for more details. |
40 | + |
41 | + You should have received a copy of the GNU General Public License along |
42 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
43 | + |
44 | + Authors : Jeremy Wootten <jeremy@elementaryos.org> |
45 | +***/ |
46 | +namespace PF.FileUtils { |
47 | + const string reserved_chars = (GLib.Uri.RESERVED_CHARS_GENERIC_DELIMITERS + GLib.Uri.RESERVED_CHARS_SUBCOMPONENT_DELIMITERS + " "); |
48 | + |
49 | + public string? escape_uri (string uri, bool allow_utf8 = true) { |
50 | + string rc = reserved_chars.replace("#", "").replace ("*",""); |
51 | + return Uri.escape_string ((Uri.unescape_string (uri) ?? uri), rc , allow_utf8); |
52 | + } |
53 | +} |
54 | |
55 | === modified file 'libcore/gof-directory-async.vala' |
56 | --- libcore/gof-directory-async.vala 2015-12-28 18:36:55 +0000 |
57 | +++ libcore/gof-directory-async.vala 2016-01-27 19:54:54 +0000 |
58 | @@ -23,6 +23,10 @@ |
59 | public class GOF.Directory.Async : Object { |
60 | public delegate void GOFFileLoadedFunc (GOF.File file); |
61 | |
62 | + private uint load_timeout_id = 0; |
63 | + private const int ENUMERATE_TIMEOUT_SEC = 10; |
64 | + private const int QUERY_INFO_TIMEOUT_SEC = 15; |
65 | + |
66 | public GLib.File location; |
67 | public GLib.File? selected_file = null; |
68 | public GOF.File file; |
69 | @@ -40,7 +44,7 @@ |
70 | LOADING, |
71 | LOADED |
72 | } |
73 | - public State state = State.NOT_LOADED; |
74 | + private State state = State.NOT_LOADED; |
75 | |
76 | private HashTable<GLib.File,GOF.File> file_hash; |
77 | public uint files_count; |
78 | @@ -49,14 +53,15 @@ |
79 | |
80 | private Cancellable cancellable; |
81 | private FileMonitor? monitor = null; |
82 | - |
83 | private List<unowned GOF.File>? sorted_dirs = null; |
84 | |
85 | public signal void file_loaded (GOF.File file); |
86 | public signal void file_added (GOF.File file); |
87 | public signal void file_changed (GOF.File file); |
88 | public signal void file_deleted (GOF.File file); |
89 | - public signal void icon_changed (GOF.File file); |
90 | + public signal void icon_changed (GOF.File file); /* Called directly by GOF.File - handled by AbstractDirectoryView |
91 | + Gets emitted for any kind of file operation */ |
92 | + |
93 | public signal void done_loading (); |
94 | public signal void thumbs_loaded (); |
95 | public signal void need_reload (); |
96 | @@ -75,22 +80,24 @@ |
97 | } |
98 | |
99 | private string scheme; |
100 | - public bool is_local; |
101 | - public bool is_trash; |
102 | - public bool is_network; |
103 | - public bool is_recent; |
104 | - public bool has_mounts; |
105 | - public bool has_trash_dirs; |
106 | - public bool can_load; |
107 | - private bool is_cached = false; |
108 | + public bool is_local {get; private set;} |
109 | + public bool is_trash {get; private set;} |
110 | + public bool is_network {get; private set;} |
111 | + public bool is_recent {get; private set;} |
112 | + public bool has_mounts {get; private set;} |
113 | + public bool has_trash_dirs {get; private set;} |
114 | + public bool can_load {get; private set;} |
115 | + private bool is_ready = false; |
116 | |
117 | public bool is_cancelled { |
118 | get { return cancellable.is_cancelled (); } |
119 | } |
120 | |
121 | private Async (GLib.File _file) { |
122 | - location = _file; |
123 | + /* Ensure uri is correctly escaped */ |
124 | + location = GLib.File.new_for_uri (PF.FileUtils.escape_uri (_file.get_uri ())); |
125 | file = GOF.File.get (location); |
126 | + |
127 | cancellable = new Cancellable (); |
128 | state = State.NOT_LOADED; |
129 | can_load = false; |
130 | @@ -99,7 +106,16 @@ |
131 | is_trash = (scheme == "trash"); |
132 | is_recent = (scheme == "recent"); |
133 | is_local = is_trash || is_recent || (scheme == "file"); |
134 | - is_network = !is_local && ("ftp ftps afp dav davs".contains (scheme)); |
135 | + is_network = !is_local && ("ftp sftp afp dav davs".contains (scheme)); |
136 | + |
137 | + dir_cache_lock.@lock (); /* will always have been created via call to public static functions from_file () or from_gfile () */ |
138 | + directory_cache.insert (location.dup (), this); |
139 | + dir_cache_lock.unlock (); |
140 | + |
141 | + this.add_toggle_ref ((ToggleNotify) toggle_ref_notify); |
142 | + this.unref (); |
143 | + |
144 | + file_hash = new HashTable<GLib.File, GOF.File> (GLib.File.hash, GLib.File.equal); |
145 | } |
146 | |
147 | ~Async () { |
148 | @@ -108,168 +124,190 @@ |
149 | disconnect_volume_monitor_signals (); |
150 | } |
151 | |
152 | + /** Views call the following function with null parameter - file_loaded and done_loading |
153 | + * signals are emitted and cause the view and view container to update. |
154 | + * |
155 | + * LocationBar calls this function, with a callback, on its own Async instances in order |
156 | + * to perform filename completion.- Emitting a done_loaded signal in that case would cause |
157 | + * the premature ending of text entry. |
158 | + **/ |
159 | public void init (GOFFileLoadedFunc? file_loaded_func = null) { |
160 | - if (state == State.LOADING) { /* Could happen reloading multiple windows */ |
161 | - return; |
162 | + if (state == State.LOADING) { |
163 | + return; /* Do not re-enter */ |
164 | } |
165 | - state = State.LOADING; |
166 | + var previous_state = state; |
167 | + |
168 | cancellable.cancel (); |
169 | - cancellable.reset (); |
170 | - if (file_hash != null && file_hash.size () > 0) { /* false on first visit or when reloading */ |
171 | - list_cached_files (file_loaded_func); /* will call make ready when done */ |
172 | - } else if (!prepare_directory (file_loaded_func)) { /* Returns true if has already called make_ready () or will do so in a callback */ |
173 | - make_ready (false); |
174 | + cancellable = new Cancellable (); |
175 | + |
176 | + /* If we already have a loaded file cache just list them */ |
177 | + if (previous_state == State.LOADED) { |
178 | + list_cached_files (file_loaded_func); |
179 | + /* else fully initialise the directory */ |
180 | + } else { |
181 | + state = State.LOADING; |
182 | + prepare_directory.begin (file_loaded_func); |
183 | } |
184 | - /* Otherwise the directory will be prepared and the done_loaded signal emitted when ready */ |
185 | + /* done_loaded signal is emitted when ready */ |
186 | } |
187 | |
188 | /* This is also called when reloading the directory so that another attempt to connect to |
189 | * the network is made |
190 | */ |
191 | - private bool prepare_directory (GOFFileLoadedFunc? file_loaded_func) { |
192 | - if (!get_file_info (file_loaded_func)) { |
193 | - return false; |
194 | - } else if (is_local && !file.is_folder ()) { |
195 | - if (!can_try_parent ()) { |
196 | - return false; |
197 | - } else { |
198 | - return get_file_info (file_loaded_func); |
199 | - } |
200 | - } |
201 | - return true; |
202 | - } |
203 | - |
204 | - private bool can_try_parent () { |
205 | - if (file.is_connected) { |
206 | - GLib.File? parent = location.get_parent (); |
207 | - if (parent != null) { |
208 | - file = GOF.File.get (parent); |
209 | - selected_file = location.dup (); |
210 | - location = parent; |
211 | - return true; |
212 | - } |
213 | - } |
214 | - return false; |
215 | - } |
216 | - |
217 | - private bool get_file_info (GOFFileLoadedFunc? file_loaded_func) { |
218 | - if (!is_local && !check_network ()) { |
219 | - return false; |
220 | - } |
221 | + private async void prepare_directory (GOFFileLoadedFunc? file_loaded_func) { |
222 | + bool success = yield get_file_info (); |
223 | + if (success) { |
224 | + if (is_local && !file.is_folder ()) { |
225 | + var parent = file.is_connected ? location.get_parent () : null; |
226 | + if (parent != null) { |
227 | + file = GOF.File.get (parent); |
228 | + selected_file = location.dup (); |
229 | + location = parent; |
230 | + success = yield get_file_info (); |
231 | + } else { |
232 | + success = false; |
233 | + } |
234 | + } |
235 | + } |
236 | + make_ready (success, file_loaded_func); /* Only place that should call this function */ |
237 | + } |
238 | + |
239 | + private async bool get_file_info () { |
240 | /* Force info to be refreshed - the GOF.File may have been created already by another part of the program |
241 | * that did not ensure the correct info Aync purposes, and retrieved from cache (bug 1511307). |
242 | */ |
243 | - file.info = null; |
244 | - if (!file.ensure_query_info()) { /* should set file.exists and file.connected appropriately */ |
245 | - if (is_local || !file.is_connected || !file.exists) { |
246 | - return false; |
247 | - } |
248 | - } |
249 | - |
250 | - if (!is_local) { |
251 | - mount_mountable.begin ((obj,res) => { |
252 | - bool success = false; |
253 | - try { |
254 | - mount_mountable.end (res); |
255 | - success = true; |
256 | - } catch (Error e) { |
257 | - if (e is IOError.ALREADY_MOUNTED) { |
258 | - success = true; |
259 | - } else { |
260 | - warning ("mount_mountable failed: %s", e.message); |
261 | - if (e is IOError.PERMISSION_DENIED || |
262 | - e is IOError.FAILED_HANDLED) { |
263 | - |
264 | - permission_denied = true; |
265 | - } |
266 | - } |
267 | - } |
268 | - make_ready (success, file_loaded_func); |
269 | - }); |
270 | - } else { |
271 | - make_ready (true, file_loaded_func); |
272 | - } |
273 | - return true; |
274 | - } |
275 | - |
276 | - private void set_confirm_trash () { |
277 | - bool to_confirm = true; |
278 | - if (is_trash) { |
279 | - to_confirm = false; |
280 | - var mounts = VolumeMonitor.get ().get_mounts (); |
281 | - if (mounts != null) { |
282 | - foreach (GLib.Mount m in mounts) { |
283 | - to_confirm |= (m.can_eject () && Marlin.FileOperations.has_trash_files (m)); |
284 | - } |
285 | - } |
286 | - } |
287 | - Preferences.get_default ().confirm_trash = to_confirm; |
288 | - } |
289 | - |
290 | - private void connect_volume_monitor_signals () { |
291 | - var vm = VolumeMonitor.get(); |
292 | - vm.mount_changed.connect (on_mount_changed); |
293 | - } |
294 | - private void disconnect_volume_monitor_signals () { |
295 | - var vm = VolumeMonitor.get(); |
296 | - vm.mount_changed.disconnect (on_mount_changed); |
297 | - } |
298 | - |
299 | - private void on_mount_changed () { |
300 | - need_reload (); |
301 | - } |
302 | - |
303 | - |
304 | - public bool check_network () { |
305 | + file.info = null; |
306 | + if (is_local) { |
307 | + return file.ensure_query_info (); |
308 | + } |
309 | + |
310 | + /* Must be non-local */ |
311 | + if (!is_local && !yield check_network ()) { |
312 | + file.is_connected = false; |
313 | + return false; |
314 | + } else { |
315 | + if (!yield try_query_info ()) { /* may already be mounted */ |
316 | + if (yield mount_mountable ()) { |
317 | + /* Previously mounted Samba servers still appear mounted even if disconnected |
318 | + * e.g. by unplugging the network cable. So the following function can block for |
319 | + * a long time; we therefore use a timeout */ |
320 | + debug ("successful mount %s", file.uri); |
321 | + return yield try_query_info (); |
322 | + } else { |
323 | + return false; |
324 | + } |
325 | + } else { |
326 | + return true; |
327 | + } |
328 | + } |
329 | + } |
330 | + |
331 | + private async bool try_query_info () { |
332 | + cancellable = new Cancellable (); |
333 | + bool querying = true; |
334 | + assert (load_timeout_id == 0); |
335 | + load_timeout_id = Timeout.add_seconds (QUERY_INFO_TIMEOUT_SEC, () => { |
336 | + if (querying) { |
337 | + warning ("Cancelled after timeout in query info async %s", file.uri); |
338 | + cancellable.cancel (); |
339 | + load_timeout_id = 0; |
340 | + } |
341 | + return false; |
342 | + }); |
343 | + |
344 | + bool success = yield query_info_async (file, null, cancellable); |
345 | + querying = false; |
346 | + cancel_timeout (ref load_timeout_id); |
347 | + if (cancellable.is_cancelled ()) { |
348 | + warning ("Failed to get info - timed out and cancelled"); |
349 | + file.is_connected = false; |
350 | + return false; |
351 | + } |
352 | + if (success) { |
353 | + debug ("got file info"); |
354 | + file.ensure_query_info (); |
355 | + return true; |
356 | + } else { |
357 | + debug ("Failed to get file info for %s", file.uri); |
358 | + return false; |
359 | + } |
360 | + } |
361 | + |
362 | + private async bool mount_mountable () { |
363 | + try { |
364 | + var mount_op = new Gtk.MountOperation (null); |
365 | + yield location.mount_enclosing_volume (0, mount_op, cancellable); |
366 | + var mount = location.find_enclosing_mount (); |
367 | + debug ("Found enclosing mount %s", mount != null ? mount.get_name () : "null"); |
368 | + return mount != null; |
369 | + } catch (Error e) { |
370 | + if (e is IOError.ALREADY_MOUNTED) { |
371 | + debug ("Already mounted %s", file.uri); |
372 | + file.is_connected = true; |
373 | + } else { |
374 | + file.is_connected = false; |
375 | + warning ("Mount_mountable failed: %s", e.message); |
376 | + if (e is IOError.PERMISSION_DENIED || e is IOError.FAILED_HANDLED) { |
377 | + permission_denied = true; |
378 | + } |
379 | + } |
380 | + return false; |
381 | + } |
382 | + } |
383 | + |
384 | + public async bool check_network () { |
385 | var net_mon = GLib.NetworkMonitor.get_default (); |
386 | var net_available = net_mon.get_network_available (); |
387 | |
388 | - if (!net_available && is_network) { |
389 | - SocketConnectable? connectable = null; |
390 | - try { |
391 | - connectable = NetworkAddress.parse_uri (file.uri, 21); |
392 | - } |
393 | - catch (GLib.Error e) {} |
394 | + bool success = false; |
395 | |
396 | - if (connectable != null) { |
397 | + if (net_available) { |
398 | + SocketConnectable? connectable = null; |
399 | + if (!is_network) { /* e.g. smb:// */ |
400 | + /* TODO: Find a way of verifying samba server still connected; gvfs does not detect |
401 | + * when network connection is broken - still appears mounted and connected */ |
402 | + success = true; |
403 | + } else { |
404 | try { |
405 | - net_mon.can_reach (connectable); |
406 | + connectable = NetworkAddress.parse_uri (file.uri, 21); |
407 | + success = true; |
408 | + /* Try to connect for real. This should time out after about 15 seconds if |
409 | + * the host is not reachable */ |
410 | + var scl = new SocketClient (); |
411 | + var sc = yield scl.connect_async (connectable, cancellable); |
412 | + success = (sc != null && sc.is_connected ()); |
413 | + debug ("Attempt to connect to %s %s", file.uri, success ? "succeeded" : "failed"); |
414 | } |
415 | catch (GLib.Error e) { |
416 | warning ("Error connecting to connectable %s - %s", file.uri, e.message); |
417 | - return false; |
418 | } |
419 | } |
420 | - |
421 | - |
422 | + } else { |
423 | + warning ("No network available"); |
424 | } |
425 | - return true; |
426 | + return success; |
427 | } |
428 | + |
429 | |
430 | private void make_ready (bool ready, GOFFileLoadedFunc? file_loaded_func = null) { |
431 | can_load = ready; |
432 | if (!can_load) { |
433 | + debug ("%s cannot load", file.uri); |
434 | + state = State.NOT_LOADED; /* ensure state is correct */ |
435 | done_loading (); |
436 | return; |
437 | - } else if (!is_cached) { |
438 | - assert (directory_cache != null); |
439 | - directory_cache.insert (location, this); |
440 | - |
441 | - this.add_toggle_ref ((ToggleNotify) toggle_ref_notify); |
442 | - this.unref (); |
443 | - |
444 | - debug ("created dir %s ref_count %u", this.file.uri, this.ref_count); |
445 | - file_hash = new HashTable<GLib.File,GOF.File> (GLib.File.hash, GLib.File.equal); |
446 | + } else if (!is_ready) { |
447 | uri_contain_keypath_icons = "/icons" in file.uri || "/.icons" in file.uri; |
448 | - |
449 | - try { |
450 | - monitor = location.monitor_directory (0); |
451 | - monitor.rate_limit = 100; |
452 | - monitor.changed.connect (directory_changed); |
453 | - } catch (IOError e) { |
454 | - if (!(e is IOError.NOT_MOUNTED)) { |
455 | - /* Will fail for remote filesystems - not an error */ |
456 | - debug ("directory monitor failed: %s %s", e.message, file.uri); |
457 | + if (file_loaded_func == null && is_local) { |
458 | + try { |
459 | + monitor = location.monitor_directory (0); |
460 | + monitor.rate_limit = 100; |
461 | + monitor.changed.connect (directory_changed); |
462 | + } catch (IOError e) { |
463 | + if (!(e is IOError.NOT_MOUNTED)) { |
464 | + /* Will fail for remote filesystems - not an error */ |
465 | + debug ("directory monitor failed: %s %s", e.message, file.uri); |
466 | + } |
467 | } |
468 | } |
469 | |
470 | @@ -288,10 +326,37 @@ |
471 | connect_volume_monitor_signals (); |
472 | } |
473 | |
474 | - is_cached = true; |
475 | + is_ready = true; |
476 | } |
477 | /* May be loading for the first time or reloading after clearing directory info */ |
478 | - load (file_loaded_func); |
479 | + list_directory_async.begin (file_loaded_func); |
480 | + } |
481 | + |
482 | + private void set_confirm_trash () { |
483 | + bool to_confirm = true; |
484 | + if (is_trash) { |
485 | + to_confirm = false; |
486 | + var mounts = VolumeMonitor.get ().get_mounts (); |
487 | + if (mounts != null) { |
488 | + foreach (GLib.Mount m in mounts) { |
489 | + to_confirm |= (m.can_eject () && Marlin.FileOperations.has_trash_files (m)); |
490 | + } |
491 | + } |
492 | + } |
493 | + Preferences.get_default ().confirm_trash = to_confirm; |
494 | + } |
495 | + |
496 | + private void connect_volume_monitor_signals () { |
497 | + var vm = VolumeMonitor.get(); |
498 | + vm.mount_changed.connect (on_mount_changed); |
499 | + } |
500 | + private void disconnect_volume_monitor_signals () { |
501 | + var vm = VolumeMonitor.get(); |
502 | + vm.mount_changed.disconnect (on_mount_changed); |
503 | + } |
504 | + |
505 | + private void on_mount_changed () { |
506 | + need_reload (); |
507 | } |
508 | |
509 | private static void toggle_ref_notify (void* data, Object object, bool is_last) { |
510 | @@ -308,8 +373,11 @@ |
511 | } |
512 | |
513 | public void cancel () { |
514 | + /* This should only be called when closing the view - it will cancel initialisation of the directory */ |
515 | cancellable.cancel (); |
516 | cancel_thumbnailing (); |
517 | + cancel_timeout (ref load_timeout_id); |
518 | + cancel_timeout (ref idle_consume_changes_id); |
519 | } |
520 | |
521 | public void cancel_thumbnailing () { |
522 | @@ -320,101 +388,109 @@ |
523 | } |
524 | } |
525 | |
526 | + public void reload () { |
527 | + clear_directory_info (); |
528 | + init (); |
529 | + } |
530 | + |
531 | /** Called in preparation for a reload **/ |
532 | - public void clear_directory_info () { |
533 | - if (state != State.LOADED) { /* Could get called multiple times if multiple windows reload the same directory */ |
534 | - return; |
535 | + private void clear_directory_info () { |
536 | + if (state == State.LOADING) { |
537 | + return; /* Do not re-enter */ |
538 | } |
539 | cancel (); |
540 | - |
541 | - if (idle_consume_changes_id != 0) { |
542 | - Source.remove ((uint) idle_consume_changes_id); |
543 | - idle_consume_changes_id = 0; |
544 | - } |
545 | - |
546 | - if (file_hash != null) |
547 | - file_hash.remove_all (); |
548 | - |
549 | + file_hash.remove_all (); |
550 | monitor = null; |
551 | sorted_dirs = null; |
552 | files_count = 0; |
553 | state = State.NOT_LOADED; |
554 | } |
555 | |
556 | - /** Views call the following function with null parameter - file_loaded and done_loading |
557 | - * signals are emitted and cause the view and view container to update. |
558 | - * |
559 | - * LocationBar calls this function, with a callback, on its own Async instances in order |
560 | - * to perform filename completion.- Emitting a done_loaded signal in that case would cause |
561 | - * the premature ending of text entry. |
562 | - **/ |
563 | - private void load (GOFFileLoadedFunc? file_loaded_func = null) { |
564 | + private void list_cached_files (GOFFileLoadedFunc? file_loaded_func = null) { |
565 | + if (state != State.LOADED) { |
566 | + warning ("list cached files called in %s state - not expected to happen", state.to_string ()); |
567 | + return; |
568 | + } |
569 | + state = State.LOADING; |
570 | + bool show_hidden = is_trash || Preferences.get_default ().pref_show_hidden_files; |
571 | + foreach (GOF.File gof in file_hash.get_values ()) { |
572 | + if (gof != null) { |
573 | + after_load_file (gof, show_hidden, file_loaded_func); |
574 | + } |
575 | + } |
576 | + state = State.LOADED; |
577 | + after_loading (file_loaded_func); |
578 | + } |
579 | + |
580 | + private async void list_directory_async (GOFFileLoadedFunc? file_loaded_func) { |
581 | /* Should only be called after creation and if reloaded */ |
582 | - if (!is_cached || file_hash != null && file_hash.size () > 0) { |
583 | + if (!is_ready || file_hash.size () > 0) { |
584 | critical ("(Re)load directory called when not cleared"); |
585 | return; |
586 | } |
587 | + |
588 | if (!can_load) { |
589 | warning ("load called when cannot load - not expected to happen"); |
590 | - after_loading (file_loaded_func); |
591 | - return; |
592 | - } |
593 | - |
594 | - if (state != State.LOADING) { |
595 | - warning ("load called in loaded or loading state - not expected to happen"); |
596 | - return; |
597 | - } |
598 | - |
599 | + return; |
600 | + } |
601 | + |
602 | + if (state == State.LOADED) { |
603 | + warning ("load called when already loaded - not expected to happen"); |
604 | + return; |
605 | + } |
606 | + if (load_timeout_id > 0) { |
607 | + warning ("load called when timeout already running - not expected to happen"); |
608 | + return; |
609 | + } |
610 | + |
611 | + cancellable = new Cancellable (); |
612 | longest_file_name = ""; |
613 | permission_denied = false; |
614 | - |
615 | - list_directory.begin (file_loaded_func); |
616 | - } |
617 | - |
618 | - private void list_cached_files (GOFFileLoadedFunc? file_loaded_func = null) { |
619 | - if (state == State.NOT_LOADED) { |
620 | - warning ("list cached files called in unloaded state - not expected to happen"); |
621 | - return; |
622 | - } |
623 | + can_load = true; |
624 | + files_count = 0; |
625 | + state = State.LOADING; |
626 | bool show_hidden = is_trash || Preferences.get_default ().pref_show_hidden_files; |
627 | - foreach (GOF.File gof in file_hash.get_values ()) { |
628 | - if (gof != null) { |
629 | - after_load_file (gof, show_hidden, file_loaded_func); |
630 | - } |
631 | - } |
632 | - after_loading (file_loaded_func); |
633 | - } |
634 | |
635 | - private async void list_directory (GOFFileLoadedFunc? file_loaded_func) { |
636 | try { |
637 | - bool show_hidden = is_trash || Preferences.get_default ().pref_show_hidden_files; |
638 | - var e = yield this.location.enumerate_children_async (gio_attrs, 0, 0, cancellable); |
639 | - while (state == State.LOADING) { |
640 | + /* This may hang for a long time if the connection was closed but is still mounted so we |
641 | + * impose a time limit */ |
642 | + load_timeout_id = Timeout.add_seconds (ENUMERATE_TIMEOUT_SEC, () => { |
643 | + cancellable.cancel (); |
644 | + load_timeout_id = 0; |
645 | + return false; |
646 | + }); |
647 | + |
648 | + var e = yield this.location.enumerate_children_async (gio_attrs, 0, Priority.HIGH, cancellable); |
649 | + cancel_timeout (ref load_timeout_id); |
650 | + |
651 | + GOF.File? gof; |
652 | + GLib.File loc; |
653 | + while (!cancellable.is_cancelled ()) { |
654 | var files = yield e.next_files_async (200, 0, cancellable); |
655 | if (files == null) { |
656 | - state = State.LOADED; |
657 | + break; |
658 | } else { |
659 | foreach (var file_info in files) { |
660 | - GLib.File loc = location.get_child (file_info.get_name ()); |
661 | - GOF.File? gof = GOF.File.cache_lookup (loc); |
662 | - |
663 | - if (gof == null) |
664 | - gof = new GOF.File (loc, location); |
665 | - |
666 | + loc = location.get_child (file_info.get_name ()); |
667 | + assert (loc != null); |
668 | + gof = GOF.File.cache_lookup (loc); |
669 | + |
670 | + if (gof == null) { |
671 | + gof = new GOF.File (loc, location); /*does not add to GOF file cache */ |
672 | + } |
673 | gof.info = file_info; |
674 | gof.update (); |
675 | |
676 | file_hash.insert (gof.location, gof); |
677 | - |
678 | after_load_file (gof, show_hidden, file_loaded_func); |
679 | - |
680 | files_count++; |
681 | } |
682 | } |
683 | } |
684 | + state = State.LOADED; |
685 | } catch (Error err) { |
686 | warning ("Listing directory error: %s %s", err.message, file.uri); |
687 | - |
688 | + can_load = false; |
689 | if (err is IOError.NOT_FOUND || err is IOError.NOT_DIRECTORY) { |
690 | file.exists = false; |
691 | } else if (err is IOError.PERMISSION_DENIED) |
692 | @@ -422,6 +498,7 @@ |
693 | else if (err is IOError.NOT_MOUNTED) |
694 | file.is_mounted = false; |
695 | } |
696 | + |
697 | after_loading (file_loaded_func); |
698 | } |
699 | |
700 | @@ -438,10 +515,16 @@ |
701 | } |
702 | |
703 | private void after_loading (GOFFileLoadedFunc? file_loaded_func) { |
704 | - if (file_loaded_func == null && !cancellable.is_cancelled ()) { |
705 | + /* If loading failed reset */ |
706 | + debug ("after loading state is %s", state.to_string ()); |
707 | + if (state == State.LOADING) { |
708 | + state = State.NOT_LOADED; /* else clear directory info will fail */ |
709 | + clear_directory_info (); |
710 | + can_load = false; |
711 | + } |
712 | + if (file_loaded_func == null) { |
713 | done_loading (); |
714 | } |
715 | - state = State.LOADED; |
716 | } |
717 | |
718 | public void block_monitor () { |
719 | @@ -456,8 +539,6 @@ |
720 | monitor_blocked = false; |
721 | monitor.changed.connect (directory_changed); |
722 | } |
723 | - if (!is_local) |
724 | - need_reload (); |
725 | } |
726 | |
727 | private void update_longest_file_name (GOF.File gof) { |
728 | @@ -470,7 +551,7 @@ |
729 | return; |
730 | } |
731 | if (state != State.LOADED) { |
732 | - load (); |
733 | + list_directory_async.begin (null); |
734 | } else { |
735 | list_cached_files (); |
736 | } |
737 | @@ -495,12 +576,6 @@ |
738 | } |
739 | } |
740 | |
741 | - public async void mount_mountable () throws Error { |
742 | - /**TODO** pass GtkWindow *parent to Gtk.MountOperation */ |
743 | - var mount_op = new Gtk.MountOperation (null); |
744 | - yield location.mount_enclosing_volume (0, mount_op, cancellable); |
745 | - } |
746 | - |
747 | public GOF.File? file_hash_lookup_location (GLib.File? location) { |
748 | if (location != null && location is GLib.File) { |
749 | GOF.File? result = file_hash.lookup (location); |
750 | @@ -512,13 +587,12 @@ |
751 | } |
752 | } |
753 | |
754 | - public void file_hash_add_file (GOF.File gof) { |
755 | - file_hash.insert (gof.location, gof); |
756 | + public void file_hash_add_file (GOF.File gof) { /* called directly by GOF.File */ |
757 | + file_hash.insert (gof.location, gof); |
758 | } |
759 | |
760 | - public GOF.File file_cache_find_or_insert (GLib.File file, |
761 | - bool update_hash = false) |
762 | - { |
763 | + public GOF.File file_cache_find_or_insert (GLib.File file, bool update_hash = false) { |
764 | + assert (file != null); |
765 | GOF.File? result = file_hash.lookup (file); |
766 | /* Although file_hash.lookup returns an unowned value, Vala will add a reference |
767 | * as the return value is owned. This matches the behaviour of GOF.File.cache_lookup */ |
768 | @@ -539,18 +613,22 @@ |
769 | /**TODO** move this to GOF.File */ |
770 | private delegate void func_query_info (GOF.File gof); |
771 | |
772 | - private async void query_info_async (GOF.File gof, func_query_info? f = null) { |
773 | + private async bool query_info_async (GOF.File gof, func_query_info? f = null, Cancellable? cancellable = null) { |
774 | + gof.info = null; |
775 | try { |
776 | gof.info = yield gof.location.query_info_async (gio_attrs, |
777 | FileQueryInfoFlags.NONE, |
778 | - Priority.DEFAULT); |
779 | + Priority.DEFAULT, |
780 | + cancellable); |
781 | if (f != null) |
782 | f (gof); |
783 | } catch (Error err) { |
784 | - debug ("query info failed, %s %s", err.message, gof.uri); |
785 | - if (err is IOError.NOT_FOUND) |
786 | + warning ("query info failed, %s %s", err.message, gof.uri); |
787 | + if (err is IOError.NOT_FOUND) { |
788 | gof.exists = false; |
789 | + } |
790 | } |
791 | + return gof.info != null; |
792 | } |
793 | |
794 | private void changed_and_refresh (GOF.File gof) { |
795 | @@ -674,19 +752,10 @@ |
796 | if (!value) { |
797 | if (list_fchanges_count >= FCHANGES_MAX) { |
798 | need_reload (); |
799 | - } else { |
800 | + } else if (list_fchanges_count > 0) { |
801 | list_fchanges.reverse (); |
802 | - |
803 | - /* do not autosize during multiple changes */ |
804 | - bool tln = track_longest_name; |
805 | - track_longest_name = false; |
806 | - |
807 | - foreach (var fchange in list_fchanges) |
808 | + foreach (var fchange in list_fchanges) { |
809 | real_directory_changed (fchange.file, null, fchange.event); |
810 | - |
811 | - if (tln) { |
812 | - track_longest_name = true; |
813 | - list_cached_files (); |
814 | } |
815 | } |
816 | } |
817 | @@ -698,6 +767,7 @@ |
818 | |
819 | public static void notify_files_changed (List<GLib.File> files) { |
820 | foreach (var loc in files) { |
821 | + assert (loc != null); |
822 | Async? parent_dir = cache_lookup_parent (loc); |
823 | GOF.File? gof = null; |
824 | if (parent_dir != null) { |
825 | @@ -729,6 +799,7 @@ |
826 | bool found; |
827 | |
828 | foreach (var loc in files) { |
829 | + assert (loc != null); |
830 | Async? dir = cache_lookup_parent (loc); |
831 | |
832 | if (dir != null) { |
833 | @@ -770,11 +841,10 @@ |
834 | } |
835 | |
836 | public static Async from_gfile (GLib.File file) { |
837 | + assert (file != null); |
838 | /* Note: cache_lookup creates directory_cache if necessary */ |
839 | Async? dir = cache_lookup (file); |
840 | - if (dir != null && !dir.is_local) |
841 | - dir = null; |
842 | - |
843 | + /* Both local and non-local files can be cached */ |
844 | return dir ?? new Async (file); |
845 | } |
846 | |
847 | @@ -783,6 +853,7 @@ |
848 | } |
849 | |
850 | public static void remove_file_from_cache (GOF.File gof) { |
851 | + assert (gof != null); |
852 | Async? dir = cache_lookup (gof.directory); |
853 | if (dir != null) |
854 | dir.file_hash.remove (gof.location); |
855 | @@ -797,9 +868,9 @@ |
856 | return null; |
857 | } |
858 | |
859 | - if (file == null) |
860 | - return null; |
861 | - |
862 | + if (file == null) { |
863 | + critical ("Null file received in Async cache_lookup"); |
864 | + } |
865 | dir_cache_lock.@lock (); |
866 | cached_dir = directory_cache.lookup (file); |
867 | |
868 | @@ -813,6 +884,8 @@ |
869 | cached_dir = null; |
870 | directory_cache.remove (file); |
871 | } |
872 | + } else { |
873 | + debug ("Dir %s not in cache", file.get_uri ()); |
874 | } |
875 | dir_cache_lock.unlock (); |
876 | |
877 | @@ -820,6 +893,10 @@ |
878 | } |
879 | |
880 | public static Async? cache_lookup_parent (GLib.File file) { |
881 | + if (file == null) { |
882 | + warning ("Null file submitted to cache lookup parent"); |
883 | + return null; |
884 | + } |
885 | GLib.File? parent = file.get_parent (); |
886 | return parent != null ? cache_lookup (parent) : cache_lookup (file); |
887 | } |
888 | @@ -837,6 +914,7 @@ |
889 | /* We have to remove the dir's subfolders from cache too */ |
890 | if (removed) { |
891 | foreach (var gfile in file_hash.get_keys ()) { |
892 | + assert (gfile != null); |
893 | var dir = cache_lookup (gfile); |
894 | if (dir != null) |
895 | dir.remove_dir_from_cache (); |
896 | @@ -863,25 +941,18 @@ |
897 | } |
898 | |
899 | public bool is_empty () { |
900 | - uint file_hash_count = 0; |
901 | - |
902 | - if (file_hash != null) |
903 | - file_hash_count = file_hash.size (); |
904 | - |
905 | - if (state == State.LOADED && file_hash_count == 0) |
906 | - return true; |
907 | - |
908 | - return false; |
909 | + return (state == State.LOADED && file_hash.size () == 0); /* only return true when loaded to avoid temporary appearance of empty message while loading */ |
910 | } |
911 | |
912 | - public unowned List<unowned GOF.File>? get_sorted_dirs () { |
913 | - if (state != State.LOADED) |
914 | + public unowned List<GOF.File>? get_sorted_dirs () { |
915 | + if (state != State.LOADED) { /* Can happen if pathbar tries to load unloadable directory */ |
916 | return null; |
917 | + } |
918 | |
919 | if (sorted_dirs != null) |
920 | return sorted_dirs; |
921 | |
922 | - foreach (var gof in file_hash.get_values()) { |
923 | + foreach (var gof in file_hash.get_values()) { /* returns owned values */ |
924 | if (!gof.is_hidden && (gof.is_folder () || gof.is_smb_server ())) { |
925 | sorted_dirs.prepend (gof); |
926 | } |
927 | @@ -971,4 +1042,14 @@ |
928 | |
929 | timeout_thumbsq = Timeout.add (40, queue_thumbs_timeout_cb); |
930 | } |
931 | + |
932 | + private bool cancel_timeout (ref uint id) { |
933 | + if (id > 0) { |
934 | + Source.remove (id); |
935 | + id = 0; |
936 | + return true; |
937 | + } else { |
938 | + return false; |
939 | + } |
940 | + } |
941 | } |
942 | |
943 | === modified file 'libcore/gof-file.c' |
944 | --- libcore/gof-file.c 2015-12-26 19:42:49 +0000 |
945 | +++ libcore/gof-file.c 2016-01-27 19:54:54 +0000 |
946 | @@ -141,12 +141,14 @@ |
947 | GOFDirectoryAsync *dir = NULL; |
948 | |
949 | /* get the DirectoryAsync associated to the file */ |
950 | - dir = gof_directory_async_cache_lookup (file->directory); |
951 | - if (dir != NULL) { |
952 | - if (!file->is_hidden || gof_preferences_get_default ()->pref_show_hidden_files) |
953 | - g_signal_emit_by_name (dir, "icon_changed", file); |
954 | + if (file->directory != NULL) { |
955 | + dir = gof_directory_async_cache_lookup (file->directory); |
956 | + if (dir != NULL) { |
957 | + if (!file->is_hidden || gof_preferences_get_default ()->pref_show_hidden_files) |
958 | + g_signal_emit_by_name (dir, "icon_changed", file); |
959 | |
960 | - g_object_unref (dir); |
961 | + g_object_unref (dir); |
962 | + } |
963 | } |
964 | g_signal_emit_by_name (file, "icon_changed"); |
965 | } |
966 | @@ -2099,7 +2101,10 @@ |
967 | static void |
968 | gof_file_update_existing (GOFFile *file, GFile *new_location) |
969 | { |
970 | - GOFDirectoryAsync *dir = gof_directory_async_cache_lookup (file->directory); |
971 | + GOFDirectoryAsync *dir = NULL; |
972 | + if (file->directory != NULL) { |
973 | + dir = gof_directory_async_cache_lookup (file->directory); |
974 | + } |
975 | |
976 | gof_file_remove_from_caches (file); |
977 | file->is_gone = FALSE; |
978 | @@ -2597,10 +2602,12 @@ |
979 | gboolean |
980 | gof_file_thumb_can_frame (GOFFile *file) |
981 | { |
982 | - GOFDirectoryAsync *dir; |
983 | + GOFDirectoryAsync *dir = NULL; |
984 | |
985 | /* get the DirectoryAsync associated to the file */ |
986 | - dir = gof_directory_async_cache_lookup (file->directory); |
987 | + if (file->directory != NULL) { |
988 | + dir = gof_directory_async_cache_lookup (file->directory); |
989 | + } |
990 | if (dir != NULL) { |
991 | gboolean can_frame = !dir->uri_contain_keypath_icons; |
992 | g_object_unref (dir); |
993 | |
994 | === modified file 'libwidgets/FileUtils.vala' |
995 | --- libwidgets/FileUtils.vala 2015-11-22 17:56:28 +0000 |
996 | +++ libwidgets/FileUtils.vala 2016-01-27 19:54:54 +0000 |
997 | @@ -16,8 +16,6 @@ |
998 | Authors : Jeremy Wootten <jeremy@elementaryos.org> |
999 | ***/ |
1000 | namespace PF.FileUtils { |
1001 | - const string reserved_chars = (GLib.Uri.RESERVED_CHARS_GENERIC_DELIMITERS + GLib.Uri.RESERVED_CHARS_SUBCOMPONENT_DELIMITERS + " "); |
1002 | - |
1003 | /** |
1004 | * Gets a properly escaped GLib.File for the given path |
1005 | **/ |
1006 | @@ -73,11 +71,6 @@ |
1007 | return file.get_parent () != null; |
1008 | } |
1009 | |
1010 | - public string? escape_uri (string uri, bool allow_utf8 = true) { |
1011 | - reserved_chars.replace("#", ""); |
1012 | - return Uri.escape_string ((Uri.unescape_string (uri) ?? uri), reserved_chars, allow_utf8); |
1013 | - } |
1014 | - |
1015 | /** Produce a valid unescaped path **/ |
1016 | public string sanitize_path (string? p, string? cp = null) { |
1017 | string path = ""; |
1018 | |
1019 | === modified file 'libwidgets/View/BreadcrumbsEntry.vala' |
1020 | --- libwidgets/View/BreadcrumbsEntry.vala 2015-12-26 19:42:49 +0000 |
1021 | +++ libwidgets/View/BreadcrumbsEntry.vala 2016-01-27 19:54:54 +0000 |
1022 | @@ -383,13 +383,13 @@ |
1023 | menu.deactivate.connect (() => {reset_elements_states ();}); |
1024 | |
1025 | build_base_menu (menu, loc); |
1026 | + GOF.Directory.Async? files_menu_dir = null; |
1027 | if (root != null) { |
1028 | - var files_menu_dir = GOF.Directory.Async.from_gfile (root); |
1029 | + files_menu_dir = GOF.Directory.Async.from_gfile (root); |
1030 | files_menu_dir_handler_id = files_menu_dir.done_loading.connect (() => { |
1031 | append_subdirectories (menu, files_menu_dir); |
1032 | files_menu_dir.disconnect (files_menu_dir_handler_id); |
1033 | }); |
1034 | - files_menu_dir.init (); |
1035 | } else { |
1036 | warning ("Root directory null for %s", path); |
1037 | } |
1038 | @@ -400,6 +400,10 @@ |
1039 | right_click_menu_position_func, |
1040 | 0, |
1041 | event.time); |
1042 | + |
1043 | + if (files_menu_dir != null) { |
1044 | + files_menu_dir.init (); |
1045 | + } |
1046 | } |
1047 | |
1048 | private void build_base_menu (Gtk.Menu menu, GLib.File loc) { |
1049 | @@ -461,17 +465,18 @@ |
1050 | |
1051 | private void append_subdirectories (Gtk.Menu menu, GOF.Directory.Async dir) { |
1052 | /* Append list of directories at the same level */ |
1053 | - unowned List<GOF.File>? sorted_dirs = dir.get_sorted_dirs (); |
1054 | - if (sorted_dirs.length () > 0) { |
1055 | - menu.append (new Gtk.SeparatorMenuItem ()); |
1056 | - foreach (var gof in sorted_dirs) { |
1057 | - var menuitem = new Gtk.MenuItem.with_label(gof.get_display_name ()); |
1058 | - menuitem.set_data ("location", gof.uri); |
1059 | - menu.append (menuitem); |
1060 | - menuitem.activate.connect (() => { |
1061 | - text = menu.get_active ().get_data ("location"); |
1062 | - activate (); |
1063 | - }); |
1064 | + if (dir.can_load) { |
1065 | + unowned List<GOF.File>? sorted_dirs = dir.get_sorted_dirs (); |
1066 | + if (sorted_dirs.length () > 0) { |
1067 | + menu.append (new Gtk.SeparatorMenuItem ()); |
1068 | + foreach (var gof in sorted_dirs) { |
1069 | + var menuitem = new Gtk.MenuItem.with_label(gof.get_display_name ()); |
1070 | + menuitem.set_data ("location", gof.uri); |
1071 | + menu.append (menuitem); |
1072 | + menuitem.activate.connect ((mi) => { |
1073 | + activate_path (mi.get_data ("location")); |
1074 | + }); |
1075 | + } |
1076 | } |
1077 | } |
1078 | menu.show_all (); |
1079 | |
1080 | === modified file 'src/View/AbstractDirectoryView.vala' |
1081 | --- src/View/AbstractDirectoryView.vala 2016-01-19 23:29:09 +0000 |
1082 | +++ src/View/AbstractDirectoryView.vala 2016-01-27 19:54:54 +0000 |
1083 | @@ -576,21 +576,31 @@ |
1084 | /* Signal could be from subdirectory as well as slot directory */ |
1085 | protected void connect_directory_handlers (GOF.Directory.Async dir) { |
1086 | assert (dir != null); |
1087 | - dir.file_loaded.connect (on_directory_file_loaded); |
1088 | dir.file_added.connect (on_directory_file_added); |
1089 | dir.file_changed.connect (on_directory_file_changed); |
1090 | dir.file_deleted.connect (on_directory_file_deleted); |
1091 | dir.icon_changed.connect (on_directory_file_icon_changed); |
1092 | + dir.thumbs_loaded.connect (on_directory_thumbs_loaded); |
1093 | + connect_directory_loading_handlers (dir); |
1094 | + } |
1095 | + |
1096 | + protected void connect_directory_loading_handlers (GOF.Directory.Async dir) { |
1097 | + dir.file_loaded.connect (on_directory_file_loaded); |
1098 | dir.done_loading.connect (on_directory_done_loading); |
1099 | - dir.thumbs_loaded.connect (on_directory_thumbs_loaded); |
1100 | + } |
1101 | + |
1102 | + protected void disconnect_directory_loading_handlers (GOF.Directory.Async dir) { |
1103 | + dir.file_loaded.disconnect (on_directory_file_loaded); |
1104 | + dir.done_loading.disconnect (on_directory_done_loading); |
1105 | } |
1106 | |
1107 | protected void disconnect_directory_handlers (GOF.Directory.Async dir) { |
1108 | /* If the directory is still loading the file_loaded signal handler |
1109 | /* will not have been disconnected */ |
1110 | |
1111 | - if (dir.is_loading ()) |
1112 | - dir.file_loaded.disconnect (on_directory_file_loaded); |
1113 | + if (dir.is_loading ()) { |
1114 | + disconnect_directory_loading_handlers (dir); |
1115 | + } |
1116 | |
1117 | dir.file_added.disconnect (on_directory_file_added); |
1118 | dir.file_changed.disconnect (on_directory_file_changed); |
1119 | @@ -606,17 +616,20 @@ |
1120 | style_context.remove_class (MESSAGE_CLASS); |
1121 | |
1122 | cancel (); |
1123 | + clear (); |
1124 | + disconnect_directory_handlers (old_dir); |
1125 | + connect_directory_handlers (new_dir); |
1126 | + } |
1127 | + |
1128 | + public void clear () { |
1129 | + /* after calling this (prior to reloading), the directory must be re-initialised so |
1130 | + * we reconnect the file_loaded and done_loading signals */ |
1131 | freeze_tree (); |
1132 | - disconnect_directory_handlers (old_dir); |
1133 | block_model (); |
1134 | model.clear (); |
1135 | unblock_model (); |
1136 | - /* As we connect the signal file_loaded signal handler, we initialise. */ |
1137 | - connect_directory_handlers (new_dir); |
1138 | - } |
1139 | - |
1140 | - public void reload () { |
1141 | - change_directory (slot.directory, slot.directory); |
1142 | + connect_directory_loading_handlers (slot.directory); |
1143 | + /* tree will be thawed after done loading */ |
1144 | } |
1145 | |
1146 | protected void connect_drag_drop_signals (Gtk.Widget widget) { |
1147 | @@ -804,8 +817,7 @@ |
1148 | |
1149 | /* If in recent "folder" we need to refresh the view. */ |
1150 | if (in_recent) { |
1151 | - slot.directory.clear_directory_info (); |
1152 | - slot.directory.need_reload (); |
1153 | + slot.reload (); |
1154 | } |
1155 | } |
1156 | |
1157 | @@ -898,8 +910,6 @@ |
1158 | } |
1159 | |
1160 | var file_to_rename = GOF.File.@get (new_file); |
1161 | - view.slot.reload (true); /* non-local only */ |
1162 | - |
1163 | view.rename_file (file_to_rename); /* will wait for file to appear in model */ |
1164 | } |
1165 | |
1166 | @@ -912,7 +922,6 @@ |
1167 | |
1168 | view.slot.directory.unblock_monitor (); |
1169 | view.can_trash_or_delete = true; |
1170 | - view.slot.reload (true); /* non-local only */ |
1171 | } |
1172 | |
1173 | private void trash_or_delete_selected_files (bool delete_immediately = false) { |
1174 | @@ -926,7 +935,6 @@ |
1175 | unowned GLib.List<GOF.File> selection = get_selected_files_for_transfer (); |
1176 | if (selection != null) { |
1177 | can_trash_or_delete = false; |
1178 | - |
1179 | trash_or_delete_files (selection, true, delete_immediately); |
1180 | } |
1181 | } |
1182 | @@ -1197,7 +1205,6 @@ |
1183 | pasted_files_list.prepend (k as File); |
1184 | }); |
1185 | |
1186 | - view.slot.reload (true); /* non-local only */ |
1187 | view.select_glib_files (pasted_files_list, pasted_files_list.first ().data); |
1188 | return false; |
1189 | }); |
1190 | @@ -1278,8 +1285,7 @@ |
1191 | |
1192 | private void on_directory_done_loading (GOF.Directory.Async dir) { |
1193 | /* Should only be called on directory creation or reload */ |
1194 | - dir.file_loaded.disconnect (on_directory_file_loaded); |
1195 | - dir.done_loading.disconnect (on_directory_done_loading); |
1196 | + disconnect_directory_loading_handlers (dir); |
1197 | in_trash = slot.directory.is_trash; |
1198 | in_recent = slot.directory.is_recent; |
1199 | in_network_root = slot.directory.file.is_root_network_folder (); |
1200 | @@ -1555,8 +1561,6 @@ |
1201 | if (drop_occurred) { |
1202 | drop_occurred = false; |
1203 | if (current_actions != Gdk.DragAction.DEFAULT) { |
1204 | - slot.reload (true); /* non-local only */ |
1205 | - |
1206 | switch (info) { |
1207 | case Marlin.TargetType.XDND_DIRECT_SAVE0: |
1208 | success = dnd_handler.handle_xdnddirectsave (context, |
1209 | @@ -2715,12 +2719,10 @@ |
1210 | (path != null && hover_path != null && path.compare (hover_path) != 0)) { |
1211 | |
1212 | /* cannot get file info while network disconnected */ |
1213 | - if (slot.directory.is_local || slot.directory.check_network ()) { |
1214 | - /* cannot get file info while network disconnected */ |
1215 | + if (slot.directory.is_local || NetworkMonitor.get_default ().get_network_available ()) { |
1216 | + /* cannot get file info while network disconnected. */ |
1217 | item_hovered (file); |
1218 | hover_path = path; |
1219 | - } else { |
1220 | - slot.reload (true); /* non-local only */ |
1221 | } |
1222 | } |
1223 | |
1224 | @@ -2809,9 +2811,6 @@ |
1225 | } |
1226 | |
1227 | on_name_editing_canceled (); |
1228 | - |
1229 | - if (new_name != original_name) |
1230 | - slot.reload (true); /* non-local only */ |
1231 | } |
1232 | |
1233 | |
1234 | @@ -2839,7 +2838,6 @@ |
1235 | view.original_name); |
1236 | |
1237 | view.select_gof_file (file); /* Select and scroll to show renamed file */ |
1238 | - view.slot.reload (true); |
1239 | } |
1240 | |
1241 | if (pw != null) { |
1242 | @@ -2854,20 +2852,22 @@ |
1243 | /* If folder is empty, draw the empty message in the middle of the view |
1244 | * otherwise pass on event */ |
1245 | var style_context = get_style_context (); |
1246 | - if (slot.directory.is_empty () || slot.directory.permission_denied) { |
1247 | + if (slot.directory.is_empty ()) { |
1248 | Pango.Layout layout = create_pango_layout (null); |
1249 | |
1250 | if (!style_context.has_class (MESSAGE_CLASS)) |
1251 | style_context.add_class (MESSAGE_CLASS); |
1252 | |
1253 | - if (slot.directory.permission_denied) |
1254 | + |
1255 | + if (slot.directory.permission_denied) { |
1256 | layout.set_markup (slot.denied_message, -1); |
1257 | - else if (slot.directory.is_trash) /* must be empty */ |
1258 | + } else if (slot.directory.is_trash) { |
1259 | layout.set_markup (slot.empty_trash_message, -1); |
1260 | - else if (slot.directory.location.get_uri_scheme () == "recent") |
1261 | + } else if (slot.directory.is_recent) { |
1262 | layout.set_markup (slot.empty_recents_message, -1); |
1263 | - else |
1264 | + } else { |
1265 | layout.set_markup (slot.empty_message, -1); |
1266 | + } |
1267 | |
1268 | Pango.Rectangle? extents = null; |
1269 | layout.get_extents (null, out extents); |
1270 | @@ -2880,8 +2880,9 @@ |
1271 | get_style_context ().render_layout (cr, x, y, layout); |
1272 | |
1273 | return true; |
1274 | - } else if (style_context.has_class (MESSAGE_CLASS)) |
1275 | + } else if (style_context.has_class (MESSAGE_CLASS)) { |
1276 | style_context.remove_class (MESSAGE_CLASS); |
1277 | + } |
1278 | |
1279 | return false; |
1280 | } |
1281 | |
1282 | === modified file 'src/View/Miller.vala' |
1283 | --- src/View/Miller.vala 2015-12-29 12:48:51 +0000 |
1284 | +++ src/View/Miller.vala 2016-01-27 19:54:54 +0000 |
1285 | @@ -439,5 +439,9 @@ |
1286 | public override void set_frozen_state (bool freeze) { |
1287 | current_slot.set_frozen_state (freeze); |
1288 | } |
1289 | + |
1290 | + public override FileInfo? lookup_file_info (GLib.File loc) { |
1291 | + return current_slot.lookup_file_info (loc); |
1292 | + } |
1293 | } |
1294 | } |
1295 | |
1296 | === modified file 'src/View/Slot.vala' |
1297 | --- src/View/Slot.vala 2015-12-29 12:48:51 +0000 |
1298 | +++ src/View/Slot.vala 2016-01-27 19:54:54 +0000 |
1299 | @@ -25,7 +25,7 @@ |
1300 | private FM.AbstractDirectoryView? dir_view = null; |
1301 | |
1302 | protected bool updates_frozen = false; |
1303 | - |
1304 | + protected bool original_reload_request = false; |
1305 | public bool has_autosized = false; |
1306 | public bool is_active {get; protected set;} |
1307 | |
1308 | @@ -133,10 +133,24 @@ |
1309 | autosize_slot (); |
1310 | |
1311 | set_view_updates_frozen (false); |
1312 | + updates_frozen = false; |
1313 | } |
1314 | |
1315 | private void on_directory_need_reload (GOF.Directory.Async dir) { |
1316 | - user_path_change_request (directory.location, false); |
1317 | + if (!updates_frozen) { |
1318 | + updates_frozen = true; |
1319 | + path_changed (false); |
1320 | + /* ViewContainer listens to this signal takes care of updating appearance |
1321 | + * If allow_mode_change is false View Container will not automagically |
1322 | + * switch to icon view for icon folders (needed for Miller View) */ |
1323 | + dir_view.clear (); /* clear model but do not change directory */ |
1324 | + /* Only need to initialise directory once - the slot that originally received the |
1325 | + * reload request does this */ |
1326 | + if (original_reload_request) { |
1327 | + directory.reload (); |
1328 | + original_reload_request = false; |
1329 | + } |
1330 | + } |
1331 | } |
1332 | |
1333 | private void set_up_directory (GLib.File loc) { |
1334 | @@ -178,18 +192,19 @@ |
1335 | |
1336 | Pango.Layout layout = dir_view.create_pango_layout (null); |
1337 | |
1338 | - if (directory.is_empty ()) { |
1339 | - if (directory.is_trash) |
1340 | + if (directory.is_empty ()) { /* No files in the file cache */ |
1341 | + if (directory.permission_denied) { |
1342 | + layout.set_markup (denied_message, -1); |
1343 | + } else if (directory.is_trash) { |
1344 | layout.set_markup (empty_trash_message, -1); |
1345 | - else if (directory.is_recent) |
1346 | + } else if (directory.is_recent) { |
1347 | layout.set_markup (empty_recents_message, -1); |
1348 | - else |
1349 | + } else { |
1350 | layout.set_markup (empty_message, -1); |
1351 | - } else if (directory.permission_denied) |
1352 | - layout.set_markup (denied_message, -1); |
1353 | - else |
1354 | + } |
1355 | + } else { |
1356 | layout.set_markup (GLib.Markup.escape_text (directory.longest_file_name), -1); |
1357 | - |
1358 | + } |
1359 | Pango.Rectangle extents; |
1360 | layout.get_extents (null, out extents); |
1361 | |
1362 | @@ -227,8 +242,8 @@ |
1363 | } |
1364 | |
1365 | public override void reload (bool non_local_only = false) { |
1366 | - if (!(non_local_only && directory.is_local)) { |
1367 | - directory.clear_directory_info (); |
1368 | + if (!non_local_only || !directory.is_local) { |
1369 | + original_reload_request = true; |
1370 | directory.need_reload (); /* Signal will propagate to any other slot showing this directory */ |
1371 | } |
1372 | } |
1373 | @@ -357,5 +372,14 @@ |
1374 | set_view_updates_frozen (freeze); |
1375 | frozen_changed (freeze); |
1376 | } |
1377 | + |
1378 | + public override FileInfo? lookup_file_info (GLib.File loc) { |
1379 | + GOF.File? gof = directory.file_hash_lookup_location (loc); |
1380 | + if (gof != null) { |
1381 | + return gof.info; |
1382 | + } else { |
1383 | + return null; |
1384 | + } |
1385 | + } |
1386 | } |
1387 | } |
1388 | |
1389 | === modified file 'src/View/ViewContainer.vala' |
1390 | --- src/View/ViewContainer.vala 2015-12-29 12:48:51 +0000 |
1391 | +++ src/View/ViewContainer.vala 2016-01-27 19:54:54 +0000 |
1392 | @@ -167,8 +167,10 @@ |
1393 | user_path_change_request (File.new_for_commandline_arg (loc)); |
1394 | } |
1395 | |
1396 | - public void add_view (Marlin.ViewMode mode, GLib.File? loc = null) { |
1397 | + public void add_view (Marlin.ViewMode mode, GLib.File loc) { |
1398 | assert (view == null); |
1399 | + assert (loc != null); |
1400 | + |
1401 | overlay_statusbar.cancel (); |
1402 | view_mode = mode; |
1403 | overlay_statusbar.showbar = view_mode != Marlin.ViewMode.LIST; |
1404 | @@ -181,6 +183,7 @@ |
1405 | connect_slot_signals (this.view); |
1406 | directory_is_loading (loc); |
1407 | view.directory.init (); |
1408 | + show_all (); |
1409 | /* NOTE: slot is created inactive to avoid bug during restoring multiple tabs |
1410 | * The slot becomes active when the tab becomes current */ |
1411 | } |
1412 | @@ -204,7 +207,6 @@ |
1413 | disconnect_slot_signals (view); |
1414 | content = null; /* Make sure old slot and directory view are destroyed */ |
1415 | view = null; /* Pre-requisite for add view */ |
1416 | - loading (false); |
1417 | } |
1418 | private void after_mode_change () { |
1419 | /* Slot is created inactive so we activate now since we must be the current tab |
1420 | @@ -251,7 +253,6 @@ |
1421 | |
1422 | public void on_slot_path_changed (GOF.AbstractSlot slot, bool change_mode_to_icons) { |
1423 | assert (slot != null); |
1424 | - overlay_statusbar.cancel (); |
1425 | /* automagicly enable icon view for icons keypath */ |
1426 | if (change_mode_to_icons && view_mode != Marlin.ViewMode.ICON) { |
1427 | change_view_mode (Marlin.ViewMode.ICON); |
1428 | @@ -260,11 +261,11 @@ |
1429 | } |
1430 | } |
1431 | |
1432 | - public void directory_is_loading (GLib.File loc) { |
1433 | - assert (slot != null); |
1434 | + private void directory_is_loading (GLib.File loc) { |
1435 | + loading (true); |
1436 | + overlay_statusbar.cancel (); |
1437 | overlay_statusbar.halign = Gtk.Align.END; |
1438 | refresh_slot_info (loc); |
1439 | - loading (true); |
1440 | } |
1441 | |
1442 | public void plugin_directory_loaded () { |
1443 | @@ -283,8 +284,6 @@ |
1444 | |
1445 | public void refresh_slot_info (GLib.File loc) { |
1446 | update_tab_name (loc); |
1447 | - browser.record_uri (loc.get_parse_name ()); /* will ignore null changes */ |
1448 | - |
1449 | window.loading_uri (loc.get_uri ()); |
1450 | window.update_top_menu (); |
1451 | window.update_labels (loc.get_parse_name (), tab_name); |
1452 | @@ -316,15 +315,7 @@ |
1453 | else if (slot_path == "/") |
1454 | tab_name = _("File System"); |
1455 | else { |
1456 | - try { |
1457 | - var info = loc.query_info (FileAttribute.STANDARD_DISPLAY_NAME, FileQueryInfoFlags.NONE); |
1458 | - tab_name = info.get_attribute_string (FileAttribute.STANDARD_DISPLAY_NAME); |
1459 | - } |
1460 | - catch (GLib.Error e) { |
1461 | - warning ("Could not get location display name. %s", e.message); |
1462 | - tab_name = loc.get_basename (); |
1463 | - can_show_folder = false; |
1464 | - } |
1465 | + tab_name = Uri.unescape_string (Path.get_basename (loc.get_uri ())); |
1466 | } |
1467 | |
1468 | if (tab_name == "-----") |
1469 | @@ -339,24 +330,29 @@ |
1470 | loading (false); |
1471 | can_show_folder = true; |
1472 | |
1473 | - if (!slot.directory.file.exists) { |
1474 | - if (slot.can_create) |
1475 | - content = new DirectoryNotFound (slot.directory, this); |
1476 | - else |
1477 | - content = new Marlin.View.Welcome (_("This Folder Does Not Exist"), |
1478 | - _("You cannot create a folder here.")); |
1479 | - can_show_folder = false; |
1480 | - } else if (slot.directory.permission_denied) { |
1481 | - content = new Marlin.View.Welcome (_("This Folder Does Not Belong to You"), |
1482 | - _("You don't have permission to view this folder.")); |
1483 | - can_show_folder = false; |
1484 | - } else if (!slot.directory.can_load) { |
1485 | - content = new Marlin.View.Welcome (_("Unable to Mount Folder"), |
1486 | - _("The server for this folder could not be located.")); |
1487 | - can_show_folder = false; |
1488 | + /* First deal with all cases where directory could not be loaded */ |
1489 | + if (!slot.directory.can_load) { |
1490 | + can_show_folder = false; |
1491 | + if (!slot.directory.file.exists) { |
1492 | + if (slot.can_create) |
1493 | + content = new DirectoryNotFound (slot.directory, this); |
1494 | + else |
1495 | + content = new Marlin.View.Welcome (_("This Folder Does Not Exist"), |
1496 | + _("You cannot create a folder here.")); |
1497 | + } else if (slot.directory.permission_denied) { |
1498 | + content = new Marlin.View.Welcome (_("This Folder Does Not Belong to You"), |
1499 | + _("You don't have permission to view this folder.")); |
1500 | + } else if (!slot.directory.file.is_connected) { |
1501 | + content = new Marlin.View.Welcome (_("Unable to Mount Folder"), |
1502 | + _("Could not connect to the server for this folder.")); |
1503 | + } else { |
1504 | + content = new Marlin.View.Welcome (_("Unable show Folder"), |
1505 | + _("The server for this folder could not be located.")); |
1506 | + } |
1507 | + /* Now deal with cases where file (s) within the loaded folder has to be selected */ |
1508 | } else if (selected_locations != null) { |
1509 | - view.select_glib_files (selected_locations, selected_locations.first ().data); |
1510 | - selected_locations = null; |
1511 | + view.select_glib_files (selected_locations, selected_locations.first ().data); |
1512 | + selected_locations = null; |
1513 | } else if (slot.directory.selected_file != null) { |
1514 | if (slot.directory.selected_file.query_exists ()) { |
1515 | focus_location_if_in_current_directory (slot.directory.selected_file); |
1516 | @@ -371,6 +367,8 @@ |
1517 | if (can_show_folder) { |
1518 | assert (view != null); |
1519 | content = view.get_content_box (); |
1520 | + /* Only record valid folders (will also log Zeitgeist event) */ |
1521 | + browser.record_uri (slot.location.get_parse_name ()); /* will ignore null changes */ |
1522 | plugin_directory_loaded (); |
1523 | } |
1524 | |
1525 | @@ -395,7 +393,7 @@ |
1526 | |
1527 | public void set_active_state (bool is_active) { |
1528 | var aslot = get_current_slot (); |
1529 | - if (aslot != null) |
1530 | + if (aslot != null && aslot.directory.can_load) |
1531 | aslot.set_active_state (is_active); |
1532 | } |
1533 | |
1534 | @@ -405,55 +403,45 @@ |
1535 | aslot.set_frozen_state (is_frozen); |
1536 | } |
1537 | |
1538 | - public void focus_location (GLib.File? file, |
1539 | - bool select_in_current_only = false, |
1540 | + public void focus_location (GLib.File loc, |
1541 | + bool no_path_change = false, |
1542 | bool unselect_others = false) { |
1543 | + |
1544 | /* This function navigates to another folder if necessary if |
1545 | * select_in_current_only is not set to true. |
1546 | - */ |
1547 | - if (unselect_others || file == null) { |
1548 | - get_current_slot ().set_all_selected (false); |
1549 | - selected_locations = null; |
1550 | - } |
1551 | + */ |
1552 | + assert (loc != null); |
1553 | |
1554 | - if (file == null || location.equal (file)) { |
1555 | + if (location.equal (loc)) { |
1556 | return; |
1557 | } |
1558 | - GLib.File? loc = null; |
1559 | - var filetype = file.query_file_type (GLib.FileQueryInfoFlags.NONE); |
1560 | - if (filetype == FileType.UNKNOWN) { |
1561 | - /* May be request for non-existing file - in which case |
1562 | - * an opportunity will be given to create it when we try to |
1563 | - * load it |
1564 | - */ |
1565 | - loc = file; |
1566 | - } else { |
1567 | - File? parent = file.get_parent (); |
1568 | - if (parent != null && location.equal (parent)) { |
1569 | - if (select_in_current_only || filetype != FileType.DIRECTORY) { |
1570 | - var list = new List<File> (); |
1571 | - list.prepend (file); |
1572 | - get_current_slot ().select_glib_files (list, file); |
1573 | - } else |
1574 | - loc = file; |
1575 | - } else if (!select_in_current_only) { |
1576 | - if (filetype == FileType.DIRECTORY) |
1577 | - loc = file; |
1578 | - else if (parent != null) { |
1579 | - loc = parent; |
1580 | - selected_locations.prepend (file); |
1581 | + |
1582 | + FileInfo? info = get_current_slot ().lookup_file_info (loc); |
1583 | + FileType filetype = FileType.UNKNOWN; |
1584 | + if (info != null) { /* location is in the current folder */ |
1585 | + filetype = info.get_file_type (); |
1586 | + if (filetype != FileType.DIRECTORY || no_path_change) { |
1587 | + if (unselect_others) { |
1588 | + get_current_slot ().set_all_selected (false); |
1589 | + selected_locations = null; |
1590 | } |
1591 | + var list = new List<File> (); |
1592 | + list.prepend (loc); |
1593 | + get_current_slot ().select_glib_files (list, loc); |
1594 | + return; |
1595 | } |
1596 | + } else if (no_path_change) { /* not in current, do not navigate to it*/ |
1597 | + return; |
1598 | } |
1599 | - |
1600 | - if (loc != null) |
1601 | + /* Attempt to navigate to the location */ |
1602 | + if (loc != null) { |
1603 | user_path_change_request (loc); |
1604 | + } |
1605 | } |
1606 | |
1607 | - public void focus_location_if_in_current_directory (GLib.File? file, |
1608 | + public void focus_location_if_in_current_directory (GLib.File? loc, |
1609 | bool unselect_others = false) { |
1610 | - |
1611 | - focus_location (file, true, unselect_others); |
1612 | + focus_location (loc, true, unselect_others); |
1613 | } |
1614 | |
1615 | public string get_root_uri () { |
1616 | |
1617 | === modified file 'src/View/Window.vala' |
1618 | --- src/View/Window.vala 2015-12-26 19:42:49 +0000 |
1619 | +++ src/View/Window.vala 2016-01-27 19:54:54 +0000 |
1620 | @@ -524,7 +524,7 @@ |
1621 | break; |
1622 | } |
1623 | current_tab.change_view_mode (mode); |
1624 | - update_view_mode (mode); |
1625 | + /* ViewContainer takes care of changing appearance */ |
1626 | } |
1627 | |
1628 | private void action_go_to (GLib.SimpleAction action, GLib.Variant? param) { |
1629 | @@ -747,7 +747,7 @@ |
1630 | } |
1631 | } |
1632 | |
1633 | - public void update_view_mode (Marlin.ViewMode mode) { |
1634 | + private void update_view_mode (Marlin.ViewMode mode) { /* Called via update topmenu */ |
1635 | GLib.SimpleAction action = get_action ("view_mode"); |
1636 | action.set_state (mode_strings [(int)mode]); |
1637 | view_switcher.mode = mode; |
1638 | @@ -844,8 +844,10 @@ |
1639 | |
1640 | GLib.File root_location = GLib.File.new_for_commandline_arg (unescaped_root_uri); |
1641 | |
1642 | - if (!valid_location (root_location)) |
1643 | - continue; |
1644 | + /* We do not check valid location here because it may cause the interface to hang |
1645 | + * before the window appears (e.g. if trying to connect to a server that has become unavailable) |
1646 | + * Leave it to GOF.Directory.Async to deal with invalid locations asynchronously. |
1647 | + */ |
1648 | |
1649 | add_tab (root_location, mode); |
1650 | |
1651 | @@ -890,32 +892,6 @@ |
1652 | return tabs_added; |
1653 | } |
1654 | |
1655 | - private bool valid_location (GLib.File location) { |
1656 | - GLib.FileInfo? info = null; |
1657 | - |
1658 | - string scheme = location.get_uri_scheme (); |
1659 | - if (scheme == "smb" || |
1660 | - scheme == "ftp" || |
1661 | - scheme == "network") |
1662 | - /* Do not restore remote and network locations */ |
1663 | - return true; |
1664 | - |
1665 | - try { |
1666 | - info = location.query_info ("standard::*", GLib.FileQueryInfoFlags.NONE); |
1667 | - } |
1668 | - catch (GLib.Error e) { |
1669 | - warning ("Invalid location on restoring tabs - %s", location.get_uri ()); |
1670 | - return false; |
1671 | - } |
1672 | - |
1673 | - if (info.get_file_type () == GLib.FileType.DIRECTORY) |
1674 | - return true; |
1675 | - else { |
1676 | - warning ("Attempt to restore a location that is not a directory"); |
1677 | - return false; |
1678 | - } |
1679 | - } |
1680 | - |
1681 | private void expand_miller_view (string tip_uri, GLib.File root_location) { |
1682 | /* It might be more elegant for Miller.vala to handle this */ |
1683 | var tab = tabs.current; |
1684 | @@ -940,9 +916,6 @@ |
1685 | uri += (GLib.Path.DIR_SEPARATOR_S + dir); |
1686 | gfile = GLib.File.new_for_uri (uri); |
1687 | |
1688 | - if (!valid_location (gfile)) |
1689 | - break; |
1690 | - |
1691 | mwcols.add_location (gfile, mwcols.current_slot); |
1692 | } |
1693 | } else { |
1694 | @@ -970,6 +943,7 @@ |
1695 | } |
1696 | |
1697 | public void mount_removed (Mount mount) { |
1698 | + debug ("Mount %s removed", mount.get_name ()); |
1699 | GLib.File root = mount.get_root (); |
1700 | |
1701 | foreach (var page in tabs.get_children ()) { |