Merge lp:~jeremywootten/pantheon-files/fix-1470945-open-folder-in-trash-icon-view into lp:~elementary-apps/pantheon-files/trunk
- fix-1470945-open-folder-in-trash-icon-view
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Cody Garver |
Approved revision: | 1880 |
Merged at revision: | 1915 |
Proposed branch: | lp:~jeremywootten/pantheon-files/fix-1470945-open-folder-in-trash-icon-view |
Merge into: | lp:~elementary-apps/pantheon-files/trunk |
Diff against target: |
710 lines (+222/-149) 11 files modified
libcore/AbstractSlot.vala (+4/-0) libcore/gof-directory-async.vala (+0/-1) libcore/marlin-file-operations.c (+0/-1) libcore/marlin-file-utilities.c (+42/-31) libwidgets/LocationBar.vala (+5/-1) plugins/pantheon-files-trash/plugin.vala (+21/-24) src/View/AbstractDirectoryView.vala (+66/-49) src/View/ListView.vala (+57/-34) src/View/Miller.vala (+10/-1) src/View/Slot.vala (+1/-3) src/View/ViewContainer.vala (+16/-4) |
To merge this branch: | bzr merge lp:~jeremywootten/pantheon-files/fix-1470945-open-folder-in-trash-icon-view |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
elementary Apps team | Pending | ||
Review via email: mp+265388@code.launchpad.net |
Commit message
Various Trash fixes (lp:1470945 lp:1470958)
Description of the change
This branch fixes several issues related to being able to browse folders while in trash.
1) Now works for Icon view as well
2) When not in the root folder does not not show the context menu
3) When not in the root folder changes the infobar to a warning that you need to be in the root folder for restore and empty permanently to work (it may be possible to lift this restriction in the future).
4) Gives an appropriate message on attempts to navigate to a non-existent folder in trash instead of offering to create it (which would fail).
Cody Garver (codygarver) wrote : | # |
Danielle Foré (danrabbit) wrote : | # |
The period for the error messaging is backwords and the primary text should be in Title Case. So it should be
This Folder Does Not Exist
You cannot create a folder here.
- 1878. By Jeremy Wootten
-
Change error message to title case, move period
- 1879. By Jeremy Wootten
-
Merge trunk to r1899
- 1880. By Jeremy Wootten
-
Fix handling of expanded subdirectories in ListView when restoring parent from trash
Jeremy Wootten (jeremywootten) wrote : | # |
Merged with trunk revision 1899 and conflicts resolved.
Message changed as advised by Dan.
Some terminal warnings and superfluous error dialogs that resulted when restoring an expanded folder in ListView were silenced.
Preview Diff
1 | === modified file 'libcore/AbstractSlot.vala' |
2 | --- libcore/AbstractSlot.vala 2015-07-21 05:41:23 +0000 |
3 | +++ libcore/AbstractSlot.vala 2015-07-24 12:00:50 +0000 |
4 | @@ -38,6 +38,7 @@ |
5 | public string uri { |
6 | get { return directory.file.uri;} |
7 | } |
8 | + public bool can_create {get {return directory != null && !directory.is_trash;}} |
9 | public virtual bool locked_focus { |
10 | get { |
11 | return false; |
12 | @@ -48,6 +49,9 @@ |
13 | protected int slot_number; |
14 | protected int width; |
15 | |
16 | + public signal void active (bool scroll = true); |
17 | + public signal void inactive (); |
18 | + |
19 | public void add_extra_widget (Gtk.Widget widget) { |
20 | extra_location_widgets.pack_start (widget); |
21 | } |
22 | |
23 | === modified file 'libcore/gof-directory-async.vala' |
24 | --- libcore/gof-directory-async.vala 2015-07-12 17:50:55 +0000 |
25 | +++ libcore/gof-directory-async.vala 2015-07-24 12:00:50 +0000 |
26 | @@ -425,7 +425,6 @@ |
27 | file.exists = true; |
28 | files_count = 0; |
29 | state = State.LOADING; |
30 | - |
31 | try { |
32 | var e = yield this.location.enumerate_children_async (gio_attrs, 0, 0, cancellable); |
33 | while (state == State.LOADING) { |
34 | |
35 | === modified file 'libcore/marlin-file-operations.c' |
36 | --- libcore/marlin-file-operations.c 2015-07-14 12:45:50 +0000 |
37 | +++ libcore/marlin-file-operations.c 2015-07-24 12:00:50 +0000 |
38 | @@ -5351,7 +5351,6 @@ |
39 | gpointer done_callback_data) |
40 | { |
41 | CopyMoveJob *job; |
42 | - |
43 | job = op_job_new (JOB_MOVE, CopyMoveJob, parent_window); |
44 | job->is_move = TRUE; |
45 | job->done_callback = done_callback; |
46 | |
47 | === modified file 'libcore/marlin-file-utilities.c' |
48 | --- libcore/marlin-file-utilities.c 2015-05-03 06:44:42 +0000 |
49 | +++ libcore/marlin-file-utilities.c 2015-07-24 12:00:50 +0000 |
50 | @@ -59,6 +59,7 @@ |
51 | GOFFile *file; |
52 | GFile *original_file, *original_dir; |
53 | GList *l, *m; |
54 | + GFile *parent; |
55 | |
56 | directories = NULL; |
57 | |
58 | @@ -68,36 +69,47 @@ |
59 | |
60 | for (l = files; l != NULL; l = l->next) { |
61 | file = GOF_FILE (l->data); |
62 | - original_file = eel_g_file_get_trash_original_file ( |
63 | - g_file_info_get_attribute_byte_string (file->info, |
64 | - G_FILE_ATTRIBUTE_TRASH_ORIG_PATH)); |
65 | - original_dir = NULL; |
66 | - if (original_file != NULL) { |
67 | - original_dir = g_file_get_parent (original_file); |
68 | - } |
69 | - |
70 | - if (original_dir != NULL) { |
71 | - if (directories == NULL) { |
72 | - directories = g_hash_table_new_full (g_file_hash, |
73 | - (GEqualFunc) g_file_equal, |
74 | - (GDestroyNotify) g_object_unref, |
75 | - (GDestroyNotify) my_list_free_full); |
76 | - } |
77 | - m = g_hash_table_lookup (directories, original_dir); |
78 | - if (m != NULL) { |
79 | - g_hash_table_steal (directories, original_dir); |
80 | - } |
81 | - m = g_list_append (m, g_object_ref (file->location)); |
82 | - g_hash_table_insert (directories, original_dir, m); |
83 | - } else if (unhandled_files != NULL) { |
84 | - *unhandled_files = g_list_append (*unhandled_files, gof_file_ref (file)); |
85 | - if (original_dir != NULL) |
86 | - g_object_unref (original_dir); |
87 | - } |
88 | - |
89 | - if (original_file != NULL) |
90 | - g_object_unref (original_file); |
91 | - |
92 | + /* Check it is a valid file (e.g. not a dummy row from list view) */ |
93 | + if (!(file->location != NULL && g_utf8_strlen (g_file_get_basename (file->location),2) > 0)) |
94 | + continue; |
95 | + |
96 | + /* Check that file is in root of trash. If not, do not try to restore |
97 | + * (it will be restored with its parent anyway) */ |
98 | + parent = g_file_get_parent(file->location); |
99 | + if (parent != NULL && strcmp (g_file_get_basename (parent), G_DIR_SEPARATOR_S) == 0) { |
100 | + original_file = eel_g_file_get_trash_original_file ( |
101 | + g_file_info_get_attribute_byte_string (file->info, |
102 | + G_FILE_ATTRIBUTE_TRASH_ORIG_PATH)); |
103 | + original_dir = NULL; |
104 | + if (original_file != NULL) { |
105 | + original_dir = g_file_get_parent (original_file); |
106 | + } |
107 | + |
108 | + if (original_dir != NULL) { |
109 | + if (directories == NULL) { |
110 | + directories = g_hash_table_new_full (g_file_hash, |
111 | + (GEqualFunc) g_file_equal, |
112 | + (GDestroyNotify) g_object_unref, |
113 | + (GDestroyNotify) my_list_free_full); |
114 | + } |
115 | + m = g_hash_table_lookup (directories, original_dir); |
116 | + if (m != NULL) { |
117 | + g_hash_table_steal (directories, original_dir); |
118 | + } |
119 | + m = g_list_append (m, g_object_ref (file->location)); |
120 | + g_hash_table_insert (directories, original_dir, m); |
121 | + } else if (unhandled_files != NULL) { |
122 | + *unhandled_files = g_list_append (*unhandled_files, gof_file_ref (file)); |
123 | + if (original_dir != NULL) |
124 | + g_object_unref (original_dir); |
125 | + } |
126 | + |
127 | + if (original_file != NULL) |
128 | + g_object_unref (original_file); |
129 | + |
130 | + if (parent) |
131 | + g_object_unref (parent); |
132 | + } |
133 | } |
134 | |
135 | return directories; |
136 | @@ -114,7 +126,6 @@ |
137 | char *message; |
138 | |
139 | original_dirs_hash = marlin_trashed_files_get_original_directories (files, &unhandled_files); |
140 | - |
141 | for (l = unhandled_files; l != NULL; l = l->next) { |
142 | file = GOF_FILE (l->data); |
143 | message = g_strdup_printf (_("Could not determine original location of \"%s\" "), |
144 | |
145 | === modified file 'libwidgets/LocationBar.vala' |
146 | --- libwidgets/LocationBar.vala 2015-06-06 11:02:13 +0000 |
147 | +++ libwidgets/LocationBar.vala 2015-07-24 12:00:50 +0000 |
148 | @@ -496,8 +496,12 @@ |
149 | foreach (BreadcrumbsElement element in elements) { |
150 | string s = element.text; /* element text should be an escaped string */ |
151 | if (first) { |
152 | - if (s == "" || s == "file://") |
153 | + if (s == "") |
154 | newpath = "/"; |
155 | + |
156 | + /* return valid path when browsing trash and other schemes */ |
157 | + else if (s.contains ("://") && ! s.contains (":///")) |
158 | + newpath = s + "/"; |
159 | else |
160 | newpath = s; |
161 | |
162 | |
163 | === modified file 'plugins/pantheon-files-trash/plugin.vala' |
164 | --- plugins/pantheon-files-trash/plugin.vala 2015-05-18 17:16:42 +0000 |
165 | +++ plugins/pantheon-files-trash/plugin.vala 2015-07-24 12:00:50 +0000 |
166 | @@ -45,14 +45,13 @@ |
167 | unowned GOF.File file = ((Object[]) user_data)[2] as GOF.File; |
168 | assert (((Object[]) user_data)[1] is GOF.AbstractSlot); |
169 | unowned GOF.AbstractSlot slot = ((Object[]) user_data)[1] as GOF.AbstractSlot; |
170 | - |
171 | + Gtk.InfoBar? infobar = infobars.@get (slot); |
172 | /* Ignore directories other than trash and ignore reloading trash */ |
173 | if (file.location.get_uri_scheme () == "trash") { |
174 | - Gtk.InfoBar? infobar = null; |
175 | /* Only add infobar once */ |
176 | - if (!infobars.has_key (slot)) { |
177 | + if (infobar == null) { |
178 | infobar = new Gtk.InfoBar (); |
179 | - (infobar.get_content_area () as Gtk.Box).add (new Gtk.Label (_("These items may be restored or deleted from the trash."))); |
180 | + (infobar.get_content_area () as Gtk.Box).add (new Gtk.Label (null)); |
181 | infobar.add_button (_("Restore All"), 0); |
182 | infobar.add_button (_("Empty the Trash"), 1); |
183 | |
184 | @@ -69,29 +68,27 @@ |
185 | } |
186 | }); |
187 | |
188 | - infobar.set_message_type (Gtk.MessageType.INFO); |
189 | - infobar.set_response_sensitive (0, !TrashMonitor.is_empty ()); |
190 | - infobar.set_response_sensitive (1, !TrashMonitor.is_empty ()); |
191 | - infobar.show_all (); |
192 | - infobar.set_visible (false); |
193 | slot.add_extra_widget (infobar); |
194 | infobars.@set (slot, infobar); |
195 | + } |
196 | + infobar.set_message_type (file.basename == "/" ? Gtk.MessageType.INFO : Gtk.MessageType.WARNING); |
197 | + string msg; |
198 | + if (file.basename == "/") |
199 | + msg = _("These items may be restored or deleted from the trash."); |
200 | + else |
201 | + msg = _("Cannot restore or delete unless in root folder"); |
202 | |
203 | - GLib.Timeout.add (10, () => { |
204 | - if (!slot.get_realized ()) |
205 | - return true; |
206 | - else { |
207 | - infobar.set_visible (!TrashMonitor.is_empty ()); |
208 | - return false; |
209 | - } |
210 | - }); |
211 | - } |
212 | - } else { |
213 | - var infobar = infobars.@get (slot); |
214 | - if (infobar != null) { |
215 | - infobar.destroy (); |
216 | - infobars.unset (slot); |
217 | - } |
218 | + foreach (Gtk.Widget w in (infobar.get_content_area ()).get_children ()) { |
219 | + if (w is Gtk.Label) |
220 | + (w as Gtk.Label).set_text (msg); |
221 | + } |
222 | + infobar.set_response_sensitive (0, !TrashMonitor.is_empty () && file.basename == "/"); |
223 | + infobar.set_response_sensitive (1, !TrashMonitor.is_empty () && file.basename == "/"); |
224 | + infobar.show_all (); |
225 | + infobar.set_visible (!TrashMonitor.is_empty ()); |
226 | + } else if (infobar != null) { |
227 | + infobar.destroy (); |
228 | + infobars.unset (slot); |
229 | } |
230 | } |
231 | } |
232 | |
233 | === modified file 'src/View/AbstractDirectoryView.vala' |
234 | --- src/View/AbstractDirectoryView.vala 2015-07-22 14:46:48 +0000 |
235 | +++ src/View/AbstractDirectoryView.vala 2015-07-24 12:00:50 +0000 |
236 | @@ -198,7 +198,6 @@ |
237 | private Gdk.Cursor selectable_cursor; |
238 | |
239 | private GLib.List<GLib.AppInfo> open_with_apps; |
240 | - protected GLib.List<GOF.Directory.Async> loaded_subdirectories = null; |
241 | |
242 | /* Selected files are originally obtained with |
243 | gtk_tree_model_get(): this function increases the reference |
244 | @@ -485,7 +484,7 @@ |
245 | /** Operations on selections */ |
246 | protected void activate_selected_items (Marlin.OpenFlag flag = Marlin.OpenFlag.DEFAULT, |
247 | GLib.List<GOF.File> selection = get_selected_files ()) { |
248 | - if (updates_frozen || in_trash) |
249 | + if (updates_frozen) |
250 | return; |
251 | |
252 | uint nb_elem = selection.length (); |
253 | @@ -500,33 +499,36 @@ |
254 | return; |
255 | } |
256 | |
257 | - /* launch each selected file individually ignoring selections greater than 10 |
258 | - * Do not launch with new instances of this app - open according to flag instead |
259 | - */ |
260 | - if (nb_elem < 10 && (default_app == null || app_is_this_app (default_app))) { |
261 | - foreach (GOF.File file in selection) { |
262 | - /* Prevent too rapid activation of files - causes New Tab to crash for example */ |
263 | - if (file.is_folder ()) { |
264 | - /* By default, multiple folders open in new tabs */ |
265 | - if (flag == Marlin.OpenFlag.DEFAULT) |
266 | - flag = Marlin.OpenFlag.NEW_TAB; |
267 | + if (!in_trash) { |
268 | + /* launch each selected file individually ignoring selections greater than 10 |
269 | + * Do not launch with new instances of this app - open according to flag instead |
270 | + */ |
271 | + if (nb_elem < 10 && (default_app == null || app_is_this_app (default_app))) { |
272 | + foreach (GOF.File file in selection) { |
273 | + /* Prevent too rapid activation of files - causes New Tab to crash for example */ |
274 | + if (file.is_folder ()) { |
275 | + /* By default, multiple folders open in new tabs */ |
276 | + if (flag == Marlin.OpenFlag.DEFAULT) |
277 | + flag = Marlin.OpenFlag.NEW_TAB; |
278 | |
279 | - GLib.Idle.add (() => { |
280 | - activate_file (file, screen, flag, false); |
281 | - return false; |
282 | - }); |
283 | - } else |
284 | - GLib.Idle.add (() => { |
285 | - file.open_single (screen, null); |
286 | - return false; |
287 | - }); |
288 | + GLib.Idle.add (() => { |
289 | + activate_file (file, screen, flag, false); |
290 | + return false; |
291 | + }); |
292 | + } else |
293 | + GLib.Idle.add (() => { |
294 | + file.open_single (screen, null); |
295 | + return false; |
296 | + }); |
297 | + } |
298 | + } else if (default_app != null) { |
299 | + GLib.Idle.add (() => { |
300 | + open_files_with (default_app, selection); |
301 | + return false; |
302 | + }); |
303 | } |
304 | - } else if (default_app != null) { |
305 | - GLib.Idle.add (() => { |
306 | - open_files_with (default_app, selection); |
307 | - return false; |
308 | - }); |
309 | - } |
310 | + } else |
311 | + warning ("Cannot open files in trash"); |
312 | } |
313 | |
314 | protected void preview_selected_items () { |
315 | @@ -587,6 +589,7 @@ |
316 | protected void disconnect_directory_handlers (GOF.Directory.Async dir) { |
317 | /* If the directory is still loading the file_loaded signal handler |
318 | /* will not have been disconnected */ |
319 | + |
320 | if (dir.is_loading ()) |
321 | dir.file_loaded.disconnect (on_directory_file_loaded); |
322 | |
323 | @@ -717,8 +720,9 @@ |
324 | /*** Private methods */ |
325 | /** File operations */ |
326 | |
327 | + |
328 | private void activate_file (GOF.File _file, Gdk.Screen? screen, Marlin.OpenFlag flag, bool only_one_file) { |
329 | - if (updates_frozen || in_trash) |
330 | + if (updates_frozen) |
331 | return; |
332 | |
333 | GOF.File file = _file; |
334 | @@ -750,15 +754,18 @@ |
335 | |
336 | break; |
337 | } |
338 | - } else if (only_one_file && file.is_root_network_folder ()) |
339 | - load_location (location); |
340 | - else if (only_one_file && file.is_executable ()) |
341 | - file.execute (screen, null, null); |
342 | - else if (only_one_file && default_app != null) |
343 | - file.open_single (screen, default_app); |
344 | - else |
345 | - warning ("Unable to activate this file. Default app is %s", |
346 | - default_app != null ? default_app.get_name () : "null"); |
347 | + } else if (!in_trash) { |
348 | + if (only_one_file && file.is_root_network_folder ()) |
349 | + load_location (location); |
350 | + else if (only_one_file && file.is_executable ()) |
351 | + file.execute (screen, null, null); |
352 | + else if (only_one_file && default_app != null) |
353 | + file.open_single (screen, default_app); |
354 | + else |
355 | + warning ("Unable to activate this file. Default app is %s", |
356 | + default_app != null ? default_app.get_name () : "null"); |
357 | + } else |
358 | + warning ("Cannot open file in trash"); |
359 | } |
360 | |
361 | private void trash_or_delete_files (GLib.List<GOF.File> file_list, |
362 | @@ -1775,18 +1782,29 @@ |
363 | return true; |
364 | } |
365 | |
366 | + private bool valid_selection_for_restore () { |
367 | + foreach (GOF.File file in get_selected_files ()) { |
368 | + if (!(file.directory.get_basename () == "/")) |
369 | + return false; |
370 | + } |
371 | + return true; |
372 | + } |
373 | + |
374 | private GLib.MenuModel? build_menu_selection (ref Gtk.Builder builder, bool in_trash, bool in_recent) { |
375 | GLib.Menu menu = new GLib.Menu (); |
376 | |
377 | var clipboard_menu = builder.get_object ("clipboard-selection") as GLib.Menu; |
378 | |
379 | if (in_trash) { |
380 | - menu.append_section (null, builder.get_object ("popup-trash-selection") as GLib.Menu); |
381 | - |
382 | - clipboard_menu.remove (1); /* Copy */ |
383 | - clipboard_menu.remove (1); /* Paste (index updated by previous line) */ |
384 | - |
385 | - menu.append_section (null, clipboard_menu); |
386 | + /* In trash, only show context menu when all selected files are in root folder */ |
387 | + if (valid_selection_for_restore ()) { |
388 | + menu.append_section (null, builder.get_object ("popup-trash-selection") as GLib.Menu); |
389 | + |
390 | + clipboard_menu.remove (1); /* Copy */ |
391 | + clipboard_menu.remove (1); /* Paste (index updated by previous line) */ |
392 | + |
393 | + menu.append_section (null, clipboard_menu); |
394 | + } |
395 | } else if (in_recent) { |
396 | var open_menu = build_menu_open (ref builder); |
397 | if (open_menu != null) |
398 | @@ -1835,7 +1853,10 @@ |
399 | menu.append_section (null, builder.get_object ("properties") as GLib.MenuModel); |
400 | } |
401 | |
402 | - return menu as MenuModel; |
403 | + if (menu.get_n_items () > 0) |
404 | + return menu as MenuModel; |
405 | + else |
406 | + return null; |
407 | } |
408 | |
409 | private GLib.MenuModel? build_menu_background (ref Gtk.Builder builder, bool in_trash, bool in_recent) { |
410 | @@ -3171,9 +3192,7 @@ |
411 | cancel_thumbnailing (); |
412 | cancel_drag_timer (); |
413 | cancel_timeout (ref drag_scroll_timer_id); |
414 | - loaded_subdirectories.@foreach ((dir) => { |
415 | - remove_subdirectory (dir); |
416 | - }); |
417 | + /* List View will take care of unloading subdirectories */ |
418 | } |
419 | |
420 | protected bool is_on_icon (int x, int y, int orig_x, int orig_y, ref bool on_helper) { |
421 | @@ -3210,8 +3229,6 @@ |
422 | |
423 | public virtual void sync_selection () {} |
424 | public virtual void highlight_path (Gtk.TreePath? path) {} |
425 | - protected virtual void add_subdirectory (GOF.Directory.Async dir) {} |
426 | - protected virtual void remove_subdirectory (GOF.Directory.Async dir) {} |
427 | |
428 | /** Abstract methods - must be overridden*/ |
429 | public abstract GLib.List<Gtk.TreePath> get_selected_paths () ; |
430 | |
431 | === modified file 'src/View/ListView.vala' |
432 | --- src/View/ListView.vala 2015-06-20 09:18:50 +0000 |
433 | +++ src/View/ListView.vala 2015-07-24 12:00:50 +0000 |
434 | @@ -29,8 +29,10 @@ |
435 | _("Modified") |
436 | }; |
437 | |
438 | + /* ListView manages the loading and unloading of subdirectories displayed */ |
439 | private uint unload_file_timeout_id = 0; |
440 | - private GLib.List<GOF.File> subdirectories_to_unload = null; |
441 | + private GLib.List<Gtk.TreeRowReference> subdirectories_to_unload = null; |
442 | + private GLib.List<GOF.Directory.Async> loaded_subdirectories = null; |
443 | |
444 | public ListView (Marlin.View.Slot _slot) { |
445 | base (_slot); |
446 | @@ -39,6 +41,7 @@ |
447 | private void connect_additional_signals () { |
448 | tree.row_expanded.connect (on_row_expanded); |
449 | tree.row_collapsed.connect (on_row_collapsed); |
450 | + model.subdirectory_unloaded.connect (on_model_subdirectory_unloaded); |
451 | } |
452 | |
453 | private void append_extra_tree_columns () { |
454 | @@ -70,24 +73,25 @@ |
455 | } |
456 | |
457 | private void on_row_expanded (Gtk.TreeIter iter, Gtk.TreePath path) { |
458 | - GOF.Directory.Async dir; |
459 | set_path_expanded (path, true); |
460 | - |
461 | - if (model.load_subdirectory (path, out dir) && dir is GOF.Directory.Async) |
462 | - add_subdirectory (dir); |
463 | + add_subdirectory_at_path (path); |
464 | } |
465 | |
466 | private void on_row_collapsed (Gtk.TreeIter iter, Gtk.TreePath path) { |
467 | - unowned GOF.Directory.Async dir; |
468 | - unowned GOF.File file; |
469 | set_path_expanded (path, false); |
470 | - |
471 | - if (model.get_directory_file (path, out dir, out file)) { |
472 | - remove_subdirectory (dir); |
473 | - subdirectories_to_unload.append (file); |
474 | + schedule_unload_subdirectory_at_path (path); |
475 | + } |
476 | + |
477 | + private void on_model_subdirectory_unloaded (GOF.Directory.Async dir) { |
478 | + /* ensure the model and our list of subdirectories are kept in sync */ |
479 | + remove_subdirectory (dir); |
480 | + } |
481 | + |
482 | + private void schedule_unload_subdirectory_at_path (Gtk.TreePath path) { |
483 | + /* unload subdirectory from model and remove from our list of subdirectories |
484 | + * after a delay, in case of rapid collapsing and re-expanding of rows */ |
485 | + subdirectories_to_unload.append (new Gtk.TreeRowReference (model, path)); |
486 | schedule_model_unload_directories (); |
487 | - } else |
488 | - critical ("failed to get directory/file"); |
489 | } |
490 | |
491 | private void set_path_expanded (Gtk.TreePath path, bool expanded) { |
492 | @@ -104,20 +108,27 @@ |
493 | } |
494 | |
495 | private bool unload_directories () { |
496 | - foreach (var file in subdirectories_to_unload) { |
497 | - Gtk.TreeIter iter; |
498 | + foreach (var rowref in subdirectories_to_unload) { |
499 | + Gtk.TreeIter? iter = null; |
500 | Gtk.TreePath path; |
501 | - |
502 | - if (model.get_first_iter_for_file (file, out iter)) { |
503 | - path = ((Gtk.TreeModel)model).get_path (iter); |
504 | - if (path != null && !((Gtk.TreeView)tree).is_row_expanded (path)) |
505 | + if (rowref.valid ()) |
506 | + path = rowref.get_path (); |
507 | + else { |
508 | + warning ("TreeRowRef invalid when unloading subdirectory"); |
509 | + continue; |
510 | + } |
511 | + |
512 | + if (((Gtk.TreeView)tree).is_row_expanded (path)) |
513 | + continue; |
514 | + |
515 | + if (model.get_iter (out iter, path) && iter != null) |
516 | model.unload_subdirectory (iter); |
517 | - } else |
518 | + else |
519 | warning ("Subdirectory to unload not found in model"); |
520 | } |
521 | |
522 | - subdirectories_to_unload.@foreach ((file) => { |
523 | - subdirectories_to_unload.remove (file); |
524 | + subdirectories_to_unload.@foreach ((rowref) => { |
525 | + subdirectories_to_unload.remove (rowref); |
526 | }); |
527 | |
528 | unload_file_timeout_id = 0; |
529 | @@ -192,19 +203,28 @@ |
530 | return (Marlin.ZoomLevel)zoom; |
531 | } |
532 | |
533 | - protected override void add_subdirectory (GOF.Directory.Async dir) { |
534 | - connect_directory_handlers (dir); |
535 | - dir.load (); |
536 | - /* Maintain our own reference on dir, independent of the model */ |
537 | - /* Also needed for updating show hidden status */ |
538 | - loaded_subdirectories.prepend (dir); |
539 | + private void add_subdirectory_at_path (Gtk.TreePath path) { |
540 | + /* If a new subdirectory is loaded, connect it, load it |
541 | + * and add it to the list of subdirectories */ |
542 | + GOF.Directory.Async? dir = null; |
543 | + if (model.load_subdirectory (path, out dir)) { |
544 | + if (dir != null) { |
545 | + connect_directory_handlers (dir); |
546 | + dir.load (); |
547 | + /* Maintain our own reference on dir, independent of the model */ |
548 | + /* Also needed for updating show hidden status */ |
549 | + loaded_subdirectories.prepend (dir); |
550 | + } |
551 | + } |
552 | } |
553 | |
554 | - protected override void remove_subdirectory (GOF.Directory.Async dir) { |
555 | - assert (dir != null); |
556 | - disconnect_directory_handlers (dir); |
557 | - /* Release our reference on dir */ |
558 | - loaded_subdirectories.remove (dir); |
559 | + private void remove_subdirectory (GOF.Directory.Async? dir) { |
560 | + if (dir != null) { |
561 | + disconnect_directory_handlers (dir); |
562 | + /* Release our reference on dir */ |
563 | + loaded_subdirectories.remove (dir); |
564 | + } else |
565 | + warning ("List View: directory null in remove_subdirectory"); |
566 | } |
567 | |
568 | protected override bool expand_collapse (Gtk.TreePath? path) { |
569 | @@ -244,8 +264,11 @@ |
570 | } |
571 | |
572 | public override void cancel () { |
573 | + cancel_file_timeout (); |
574 | base.cancel (); |
575 | - cancel_file_timeout (); |
576 | + loaded_subdirectories.@foreach ((dir) => { |
577 | + remove_subdirectory (dir); |
578 | + }); |
579 | } |
580 | } |
581 | } |
582 | |
583 | === modified file 'src/View/Miller.vala' |
584 | --- src/View/Miller.vala 2015-07-21 08:30:05 +0000 |
585 | +++ src/View/Miller.vala 2015-07-24 12:00:50 +0000 |
586 | @@ -197,7 +197,15 @@ |
587 | /** Called in response to slot active signal. |
588 | * Should not be called directly |
589 | **/ |
590 | - private void on_slot_active (Marlin.View.Slot slot, bool scroll = true) { |
591 | + private void on_slot_active (GOF.AbstractSlot aslot, bool scroll = true) { |
592 | + |
593 | + Marlin.View.Slot slot; |
594 | + |
595 | + if (!(aslot is Marlin.View.Slot)) |
596 | + return; |
597 | + else |
598 | + slot = aslot as Marlin.View.Slot; |
599 | + |
600 | if (scroll) |
601 | scroll_to_slot (slot); |
602 | |
603 | @@ -210,6 +218,7 @@ |
604 | }); |
605 | |
606 | current_slot = slot; |
607 | + active (); |
608 | } |
609 | |
610 | private void show_hidden_files_changed (bool show_hidden) { |
611 | |
612 | === modified file 'src/View/Slot.vala' |
613 | --- src/View/Slot.vala 2015-07-22 14:06:52 +0000 |
614 | +++ src/View/Slot.vala 2015-07-24 12:00:50 +0000 |
615 | @@ -25,8 +25,8 @@ |
616 | private FM.AbstractDirectoryView? dir_view = null; |
617 | |
618 | protected bool updates_frozen = false; |
619 | + |
620 | public bool has_autosized = false; |
621 | - |
622 | public bool is_active {get; protected set;} |
623 | |
624 | public unowned Marlin.View.Window window { |
625 | @@ -46,8 +46,6 @@ |
626 | public signal bool horizontal_scroll_event (double delta_x); |
627 | public signal void frozen_changed (bool freeze); |
628 | public signal void folder_deleted (GOF.File file, GOF.Directory.Async parent); |
629 | - public signal void active (bool scroll = true); |
630 | - public signal void inactive (); |
631 | |
632 | /* Support for multi-slot view (Miller)*/ |
633 | public Gtk.Box colpane; |
634 | |
635 | === modified file 'src/View/ViewContainer.vala' |
636 | --- src/View/ViewContainer.vala 2015-07-22 14:46:48 +0000 |
637 | +++ src/View/ViewContainer.vala 2015-07-24 12:00:50 +0000 |
638 | @@ -163,6 +163,7 @@ |
639 | view = new Slot (loc, this, mode); |
640 | |
641 | content = view.get_content_box (); |
642 | + view.active.connect (on_slot_active); |
643 | view_mode = mode; |
644 | overlay_statusbar.showbar = view_mode != Marlin.ViewMode.LIST; |
645 | load_slot_directory (view); |
646 | @@ -176,16 +177,20 @@ |
647 | store_selection (); |
648 | /* Make sure async loading and thumbnailing are cancelled and signal handlers disconnected */ |
649 | view.cancel (); |
650 | + view.active.disconnect (on_slot_active); |
651 | |
652 | add_view (mode, location); |
653 | /* Slot is created inactive so we activate now since we must be the current tab |
654 | * to have received a change mode instruction */ |
655 | set_active_state (true); |
656 | window.update_top_menu (); |
657 | - |
658 | } |
659 | } |
660 | |
661 | + private void on_slot_active (GOF.AbstractSlot aslot, bool scroll) { |
662 | + plugin_directory_loaded (); |
663 | + } |
664 | + |
665 | public void user_path_change_request (GLib.File loc) { |
666 | view.user_path_change_request (loc); |
667 | } |
668 | @@ -245,7 +250,6 @@ |
669 | |
670 | if (slot.directory.can_load) { |
671 | slot.directory.load (); |
672 | - plugin_directory_loaded (); |
673 | } else |
674 | directory_done_loading (slot); |
675 | |
676 | @@ -253,8 +257,11 @@ |
677 | }); |
678 | } |
679 | |
680 | - private void plugin_directory_loaded () { |
681 | + public void plugin_directory_loaded () { |
682 | var slot = get_current_slot (); |
683 | + if (slot == null) |
684 | + return; |
685 | + |
686 | Object[] data = new Object[3]; |
687 | data[0] = window; |
688 | /* infobars are added to the view, not the active slot */ |
689 | @@ -332,8 +339,12 @@ |
690 | _("The server for this folder could not be located.")); |
691 | can_show_folder = false; |
692 | } else if (!slot.directory.file.exists) { |
693 | + if (slot.can_create) |
694 | content = new DirectoryNotFound (slot.directory, this); |
695 | - can_show_folder = false; |
696 | + else |
697 | + content = new Granite.Widgets.Welcome (_("This Folder Does Not Exist"), |
698 | + _("You cannot create a folder here.")); |
699 | + can_show_folder = false; |
700 | } else if (selected_locations != null) { |
701 | view.select_glib_files (selected_locations, selected_locations.first ().data); |
702 | selected_locations = null; |
703 | @@ -351,6 +362,7 @@ |
704 | if (can_show_folder) { |
705 | ready = true; |
706 | content = view.get_content_box (); |
707 | + plugin_directory_loaded (); |
708 | } |
709 | |
710 | overlay_statusbar.update_hovered (null); /* Prevent empty statusbar showing */ |
Conflicts with trunk
Also not sure about that second Welcome sentence, it might need a period, I will ask Dan.