Merge lp:~jeremywootten/pantheon-files/fix-1470945-open-folder-in-trash-icon-view into lp:~elementary-apps/pantheon-files/trunk

Proposed by Jeremy Wootten
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
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).

To post a comment you must log in.
Revision history for this message
Cody Garver (codygarver) wrote :

Conflicts with trunk

Also not sure about that second Welcome sentence, it might need a period, I will ask Dan.

Revision history for this message
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

Revision history for this message
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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 */

Subscribers

People subscribed via source and target branches

to all changes: