~jeremywootten/pantheon-files/pantheon-files-SE

« back to all changes in this revision

Viewing changes to src/View/AbstractDirectoryView.vala

Merge fix-798470-merge-files-to-folder-by-drag-drop

Show diffs side-by-side

added added

removed removed

Lines of Context:
50
50
            {"_NETSCAPE_URL", Gtk.TargetFlags.OTHER_APP, Marlin.TargetType.NETSCAPE_URL}
51
51
        };
52
52
 
53
 
        const Gdk.DragAction file_drag_actions = (Gdk.DragAction.COPY | Gdk.DragAction.MOVE | Gdk.DragAction.LINK);
 
53
        const Gdk.DragAction file_drag_actions = (Gdk.DragAction.COPY |
 
54
                                                  Gdk.DragAction.MOVE |
 
55
                                                  Gdk.DragAction.LINK |
 
56
                                                  Gdk.DragAction.ASK |
 
57
                                                  Gdk.DragAction.PRIVATE);
54
58
 
55
59
        /* Menu Handling */
56
60
        const GLib.ActionEntry [] selection_entries = {
64
68
            {"cut", on_selection_action_cut},
65
69
            {"trash", on_selection_action_trash},
66
70
            {"delete", on_selection_action_delete},
67
 
            {"restore", on_selection_action_restore}
 
71
            {"restore", on_selection_action_restore},
 
72
            {"merge", on_selection_action_merge}
68
73
        };
69
74
 
70
75
        const GLib.ActionEntry [] background_entries = {
293
298
        protected Marlin.IconRenderer icon_renderer;
294
299
        protected unowned Marlin.View.Slot slot;
295
300
        protected unowned Marlin.View.Window window; /*For convenience - this can be derived from slot */
296
 
        protected static Marlin.DndHandler dnd_handler = new Marlin.DndHandler ();
 
301
 
 
302
        protected Marlin.DndHandler dnd_handler = new Marlin.DndHandler ();
297
303
 
298
304
        protected unowned Gtk.RecentManager recent;
299
305
 
352
358
            set_up_zoom_level ();
353
359
 
354
360
            connect_directory_handlers (slot.directory);
 
361
            dnd_handler.special_action_request.connect (on_dnd_handler_special_action_request);
355
362
        }
356
363
 
357
364
        ~AbstractDirectoryView () {
967
974
                warning ("You do not have permission to rename this file");
968
975
            }
969
976
        }
 
977
        protected void merge_done (GOF.File? file_to_rename) {
 
978
            /* View was frozen before starting merge files - need to unfreeze whether or not
 
979
             * there is a folder to rename */
 
980
 
 
981
            is_frozen = false;
 
982
 
 
983
            if (file_to_rename != null) {
 
984
                rename_file (file_to_rename);
 
985
            }
 
986
        }
 
987
 
 
988
        protected void on_dnd_handler_special_action_request (GLib.List<GLib.File> file_list_for_special_action,
 
989
                                                              GLib.File target_location,
 
990
                                                              Marlin.DndHandler.DndAction requested_action) {
 
991
 
 
992
            switch (requested_action) {
 
993
                case Marlin.DndHandler.DndAction.MERGE:
 
994
                    merge_files (file_list_for_special_action);
 
995
                    break;
 
996
                default:
 
997
                    warning ("Invalid special action requested");
 
998
                    break;
 
999
            }
 
1000
        }
970
1001
 
971
1002
/** File operation callbacks */
972
1003
        static void create_file_done (GLib.File? new_file, void* data) {
1119
1150
            open_file (file, null, null);
1120
1151
        }
1121
1152
 
 
1153
        private void on_selection_action_merge (GLib.SimpleAction action, GLib.Variant? param) {
 
1154
            GLib.List<GLib.File> files_to_merge = null;
 
1155
            selected_files.@foreach ((gof) => {
 
1156
                if (gof != null) {
 
1157
                    files_to_merge.prepend (gof.location.dup ());
 
1158
                }
 
1159
            });
 
1160
            merge_files (files_to_merge);
 
1161
        }
 
1162
 
 
1163
        private void merge_files (GLib.List<GLib.File> files_to_merge) {
 
1164
            /* Need to freeze view during merge to avoid unwanted selection change signals being emitted
 
1165
             * and causing unwanted Overlay update attempts (selected files may become invalid).*/
 
1166
            unselect_all ();
 
1167
            is_frozen = true;
 
1168
 
 
1169
            if (files_to_merge.length () > 1) {
 
1170
                Gtk.Window? win = null;
 
1171
                var w = this.get_toplevel ();
 
1172
                if (w.is_toplevel ()) {
 
1173
                    win = w as Gtk.Window;
 
1174
                }
 
1175
                PF.FileOperations.merge_files_into_folder (win,
 
1176
                                                           slot.directory.location,
 
1177
                                                           files_to_merge,
 
1178
                                                           merge_files_done,
 
1179
                                                           this);
 
1180
            } else {
 
1181
                warning ("Attempt to merge a single file");
 
1182
            }
 
1183
        }
 
1184
 
 
1185
        static void merge_files_done (GLib.List<GLib.File>? merged_files, GLib.File? parent_folder, void* data) {
 
1186
            FM.AbstractDirectoryView view = data as FM.AbstractDirectoryView;
 
1187
            if (!(view is FM.AbstractDirectoryView)) {
 
1188
                critical ("dnd_handler invalid after creating file");
 
1189
            }
 
1190
 
 
1191
            GOF.File? gof = null;
 
1192
 
 
1193
            if (parent_folder != null && parent_folder.query_exists ()) {
 
1194
                gof = GOF.File.@get (parent_folder);
 
1195
                if (gof != null) {
 
1196
                    gof.ensure_query_info ();
 
1197
                }
 
1198
            }
 
1199
 
 
1200
            view.merge_done (gof);
 
1201
        }
 
1202
 
1122
1203
        private void on_common_action_bookmark (GLib.SimpleAction action, GLib.Variant? param) {
1123
1204
            GLib.File location;
1124
1205
            if (selected_files != null)
1574
1655
                                            uint timestamp
1575
1656
                                            ) {
1576
1657
            bool success = false;
1577
 
 
1578
1658
            if (!drop_data_ready) {
1579
1659
                /* We don't have the drop data - extract uri list from selection data */
1580
1660
                string? text;
1605
1685
                                if (selected_files != null)
1606
1686
                                    unselect_all ();
1607
1687
 
 
1688
                                if (drop_target_file == slot.directory.file) {
 
1689
                                    current_actions |= Gdk.DragAction.PRIVATE;
 
1690
                                }
1608
1691
                                select_added_files = true;
1609
1692
                                success = dnd_handler.handle_file_drag_actions  (get_real_view (),
1610
1693
                                                                                 window,
1661
1744
                    Gtk.TreePath folder_path = path.copy ();
1662
1745
                    folder_path.up ();
1663
1746
                    file = model.file_for_path (folder_path);
1664
 
                } else {
1665
 
                    /* can only drop onto folders and executables */
1666
 
                    if (!file.is_folder () && !file.is_executable ()) {
1667
 
                        file = null;
1668
 
                        path = null;
1669
 
                    }
1670
 
                }
 
1747
                } /* Allow dropping on non-folders and executables as well for special actions */
1671
1748
            }
1672
1749
 
1673
1750
            if (path == null)
1700
1777
                    drop_data_ready = true;
1701
1778
                    result = true;
1702
1779
                }
1703
 
            } else if (target != Gdk.Atom.NONE)
 
1780
            } else if (target != Gdk.Atom.NONE) {
1704
1781
                /* request the drag data from the source */
1705
1782
                Gtk.drag_get_data (get_real_view (), context, target, timestamp); /* emits "drag_data_received" */
1706
 
 
 
1783
            }
1707
1784
            return result;
1708
1785
        }
1709
1786
 
1724
1801
                    if (current_target_type == Gdk.Atom.intern_static_string ("XdndDirectSave0")) {
1725
1802
                        current_suggested_action = Gdk.DragAction.COPY;
1726
1803
                        current_actions = current_suggested_action;
1727
 
                    } else
 
1804
                    } else {
1728
1805
                        current_actions = file.accepts_drop (drop_file_list, context, out current_suggested_action);
1729
 
 
 
1806
                    }
1730
1807
                    highlight_drop_file (drop_target_file, current_actions, path);
1731
1808
 
1732
1809
                    if (file.is_folder () && is_valid_drop_folder (file)) {
1907
1984
 
1908
1985
                    menu.append_section (null, clipboard_menu);
1909
1986
 
 
1987
//~ <<<<<<< TREE
 
1988
//~                     if (slot.directory.has_trash_dirs && !is_admin) {
 
1989
//~ =======
 
1990
                    if (selection_actions.get_action_enabled ("merge")) {
 
1991
                        menu.append_section (null, builder.get_object ("merge") as GLib.MenuModel);
 
1992
                    }
 
1993
 
 
1994
//~                     if (slot.directory.has_trash_dirs) {
1910
1995
                    if (slot.directory.has_trash_dirs && !is_admin) {
 
1996
//~ >>>>>>> MERGE-SOURCE
1911
1997
                        menu.append_section (null, builder.get_object ("trash") as GLib.MenuModel);
1912
1998
                    } else {
1913
1999
                        menu.append_section (null, builder.get_object ("delete") as GLib.MenuModel);
2191
2277
            action_set_enabled (selection_actions, "delete", is_writable);
2192
2278
            action_set_enabled (common_actions, "properties", can_show_properties);
2193
2279
            action_set_enabled (common_actions, "bookmark", can_bookmark);
 
2280
 
 
2281
            /* Limit merging to local files at the moment */
 
2282
            bool can_merge = more_than_one_selected && slot.directory.is_local;
 
2283
 
 
2284
            action_set_enabled (selection_actions, "merge", can_merge);
 
2285
 
 
2286
            /**TODO** inhibit copy for unreadable files see bug #1392465*/
 
2287
 
2194
2288
            action_set_enabled (common_actions, "copy", !in_trash && can_copy);
2195
2289
            action_set_enabled (common_actions, "bookmark", !more_than_one_selected);
2196
2290
 
3018
3112
        protected void on_name_edited (string path_string, string new_name) {
3019
3113
            /* Must not re-enter */
3020
3114
            if (!renaming || proposed_name == new_name) {
 
3115
                warning ("Attempt to re-enter on name edited");
3021
3116
                return;
3022
3117
            }
3023
3118
            proposed_name = "";
3049
3144
        public void set_file_display_name (GLib.File old_location, string new_name, PF.FileUtils.RenameCallbackFunc? f) {
3050
3145
            /* Wait for the file to be added to the model before trying to select and scroll to it */
3051
3146
            slot.directory.file_added.connect_after (after_renamed_file_added);
3052
 
            PF.FileUtils.set_file_display_name (old_location, new_name, f);
 
3147
            PF.FileUtils.set_file_display_name (old_location, new_name, f, true);
3053
3148
        }
3054
3149
 
3055
3150
        public void after_rename (GLib.File file, GLib.File? result_location, GLib.Error? e) {
3105
3200
        }
3106
3201
 
3107
3202
        protected void block_drag_and_drop () {
3108
 
            drag_data = view.get_data ("gtk-site-data");
3109
 
            GLib.SignalHandler.block_matched (view, GLib.SignalMatchType.DATA, 0, 0,  null, null, drag_data);
3110
 
            dnd_disabled = true;
 
3203
            if (!dnd_disabled) { /* must not block twice */
 
3204
                drag_data = view.get_data ("gtk-site-data");
 
3205
                GLib.SignalHandler.block_matched (view, GLib.SignalMatchType.DATA, 0, 0,  null, null, drag_data);
 
3206
                dnd_disabled = true;
 
3207
            }
3111
3208
        }
3112
3209
 
3113
3210
        protected void unblock_drag_and_drop () {
3114
 
            GLib.SignalHandler.unblock_matched (view, GLib.SignalMatchType.DATA, 0, 0,  null, null, drag_data);
3115
 
            dnd_disabled = false;
 
3211
            if (dnd_disabled) { /* must not unblock twice */
 
3212
                GLib.SignalHandler.unblock_matched (view, GLib.SignalMatchType.DATA, 0, 0,  null, null, drag_data);
 
3213
                dnd_disabled = false;
 
3214
            }
3116
3215
        }
3117
3216
 
3118
3217
        protected virtual bool on_view_button_press_event (Gdk.EventButton event) {