~elementary-apps/pantheon-files/trunk

1811.1.1 by Jeremy Wootten
Code clean: tabs, trailing space, headers, comments
1
/***
2432.1.1 by Leonardo Lemos
Bump copyright years
2
    Copyright (c) 2015-2017 elementary LLC (http://launchpad.net/elementary)
1811.1.1 by Jeremy Wootten
Code clean: tabs, trailing space, headers, comments
3
4
    This program is free software; you can redistribute it and/or modify
5
    it under the terms of the GNU General Public License as published by
2484.2.1 by Jeremy Wootten
Fix licensecheck warnings
6
    the Free Software Foundation, Inc.,; either version 2 of the License, or
1811.1.1 by Jeremy Wootten
Code clean: tabs, trailing space, headers, comments
7
    (at your option) any later version.
8
9
    This program is distributed in the hope that it will be useful,
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
    GNU General Public License for more details.
13
14
    You should have received a copy of the GNU General Public License
15
    along with this program; if not, write to the Free Software
16
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17
    MA 02110-1301, USA.
18
19
    Authors: Jeremy Wootten <jeremy@elementaryos.org>
20
***/
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
21
1953.1.2 by Jeremy Wootten
Move Enums MimeActions and DndHandler into libcore
22
namespace Marlin {
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
23
    public class DndHandler : GLib.Object {
24
        Gdk.DragAction chosen = Gdk.DragAction.DEFAULT;
25
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
26
        public DndHandler () {}
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
27
28
        public bool dnd_perform (Gtk.Widget widget,
29
                                 GOF.File drop_target,
1459.1.68 by jeremy at elementaryos
Fix multiple drag with right-click
30
                                 GLib.List<GLib.File> drop_file_list,
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
31
                                 Gdk.DragAction action) {
32
33
            if (drop_target.is_folder ()) {
1459.1.68 by jeremy at elementaryos
Fix multiple drag with right-click
34
                Marlin.FileOperations.copy_move (drop_file_list,
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
35
                                                 null,
36
                                                 drop_target.get_target_location (),
37
                                                 action,
38
                                                 widget,
1710.1.2 by jeremy at elementaryos
Fix cursor overlay when dropping into trash, silence some warnings
39
                                                 null,
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
40
                                                 null);
41
                return true;
42
            } else if (drop_target.is_executable ()) {
43
                GLib.Error error;
1459.1.68 by jeremy at elementaryos
Fix multiple drag with right-click
44
                if (!drop_target.execute (widget.get_screen (), drop_file_list, out error)) {
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
45
                    Eel.show_error_dialog (_("Failed to execute \"%s\"").printf (drop_target.get_display_name ()),
46
                                           error.message,
47
                                           null);
48
                    return false;
49
                } else
50
                    return true;
51
            }
52
            return false;
53
        }
54
55
        public Gdk.DragAction? drag_drop_action_ask (Gtk.Widget dest_widget,
56
                                                      Gtk.ApplicationWindow win,
57
                                                      Gdk.DragAction possible_actions) {
58
            this.chosen = Gdk.DragAction.DEFAULT;
59
            add_action (win);
60
            var ask_menu = build_menu (possible_actions);
61
            ask_menu.set_screen (dest_widget.get_screen ());
62
            ask_menu.show_all ();
63
            var loop = new GLib.MainLoop (null, false);
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
64
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
65
            ask_menu.deactivate.connect (() => {
66
                if (loop.is_running ())
67
                    loop.quit ();
68
69
                remove_action (win);
70
            });
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
71
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
72
            ask_menu.popup (null, null, null, 0, Gdk.CURRENT_TIME);
73
            loop.run ();
74
            Gtk.grab_remove (ask_menu);
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
75
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
76
            return this.chosen;
77
        }
78
79
        private void add_action (Gtk.ApplicationWindow win) {
80
            var action = new GLib.SimpleAction ("choice", GLib.VariantType.STRING);
81
            action.activate.connect (this.on_choice);
1811.1.1 by Jeremy Wootten
Code clean: tabs, trailing space, headers, comments
82
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
83
            win.add_action (action);
84
        }
85
86
        private void remove_action (Gtk.ApplicationWindow win) {
87
            win.remove_action ("choice");
88
        }
89
90
        private Gtk.Menu build_menu (Gdk.DragAction possible_actions) {
91
            var menu = new Gtk.Menu ();
92
93
            build_and_append_menu_item (menu, _("Move Here"), Gdk.DragAction.MOVE, possible_actions);
94
            build_and_append_menu_item (menu, _("Copy Here"), Gdk.DragAction.COPY, possible_actions);
95
            build_and_append_menu_item (menu, _("Link Here"), Gdk.DragAction.LINK, possible_actions);
96
97
            menu.append (new Gtk.SeparatorMenuItem ());
98
            menu.append (new Gtk.MenuItem.with_label (_("Cancel")));
99
100
            return menu;
101
        }
102
103
        private void build_and_append_menu_item (Gtk.Menu menu, string label, Gdk.DragAction? action, Gdk.DragAction possible_actions) {
104
            if ((possible_actions & action) != 0) {
105
                var item = new Gtk.MenuItem.with_label (label);
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
106
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
107
                item.activate.connect (() => {
108
                    this.chosen = action;
109
                });
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
110
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
111
                menu.append (item);
112
            }
113
        }
114
115
        public void on_choice (GLib.Variant? param) {
116
            if (param == null || !param.is_of_type (GLib.VariantType.STRING)) {
117
                critical ("Invalid variant type in DndHandler Menu");
118
                return;
119
            }
120
121
            string choice = param.get_string ();
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
122
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
123
            switch (choice) {
124
                case "move":
125
                    this.chosen = Gdk.DragAction.MOVE;
126
                    break;
127
                case "copy":
128
                    this.chosen = Gdk.DragAction.COPY;
129
                    break;
130
                case "link":
131
                    this.chosen = Gdk.DragAction.LINK;
132
                    break;
133
                case "background": /* not implemented yet */
134
                case "cancel":
135
                default:
136
                    this.chosen = Gdk.DragAction.DEFAULT;
137
                    break;
138
            }
139
        }
140
141
        public string? get_source_filename (Gdk.DragContext context) {
142
            uchar []? data = null;
143
            Gdk.Atom property_name = Gdk.Atom.intern_static_string ("XdndDirectSave0");
144
            Gdk.Atom property_type = Gdk.Atom.intern_static_string ("text/plain");
145
146
            bool exists = Gdk.property_get (context.get_source_window (),
147
                                            property_name,
148
                                            property_type,
149
                                            0, /* offset into property to start getting */
150
                                            1024, /* max bytes of data to retrieve */
151
                                            0, /* do not delete after retrieving */
152
                                            null, null, /* actual property type and format got disregarded */
153
                                            out data
154
                                           );
1811.1.1 by Jeremy Wootten
Code clean: tabs, trailing space, headers, comments
155
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
156
            if (exists && data != null) {
2228.1.1 by Jeremy Wootten
Rewrite ClipboardManager in Vala
157
                string name = DndHandler.data_to_string (data);
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
158
                if (GLib.Path.DIR_SEPARATOR.to_string () in name) {
159
                    warning ("invalid source filename");
160
                    return null; /* not a valid filename */
161
                } else
162
                    return name;
163
            } else {
164
                warning ("source file does not exist");
165
                return null;
166
            }
167
        }
168
169
        public void set_source_uri (Gdk.DragContext context, string uri) {
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
170
            debug ("DNDHANDLER: set source uri to %s", uri);
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
171
            Gdk.Atom property_name = Gdk.Atom.intern_static_string ("XdndDirectSave0");
172
            Gdk.Atom property_type = Gdk.Atom.intern_static_string ("text/plain");
173
            Gdk.property_change (context.get_source_window (),
174
                                 property_name,
175
                                 property_type,
176
                                 8,
177
                                 Gdk.PropMode.REPLACE,
178
                                 uri.data,
179
                                 uri.length);
180
        }
181
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
182
        public bool handle_xdnddirectsave (Gdk.DragContext context,
183
                                           GOF.File drop_target,
184
                                           Gtk.SelectionData selection) {
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
185
            bool success = false;
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
186
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
187
            if (selection.get_length ()  == 1 && selection.get_format () == 8) {
188
                uchar result = selection.get_data ()[0];
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
189
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
190
                switch (result) {
191
                    case 'F':
192
                        /* No fallback for XdndDirectSave stage (3), result "F" ("Failed") yet */
193
                        break;
1871.1.1 by Jeremy Wootten
Fix drop from other apps - text/uri-list and XdndDirectSave0
194
                    case 'E':
195
                        /* No fallback for XdndDirectSave stage (3), result "E" ("Error") yet.
196
                         * Note this result may be obtained even if the file was successfully saved */
197
                        break;
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
198
                    case 'S':
199
                        /* XdndDirectSave "Success" */
200
                        success = true;
201
                        break;
202
                    default:
203
                        warning ("Unhandled XdndDirectSave result %s", result.to_string ());
204
                        break;
205
                }
206
            }
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
207
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
208
            if (!success)
209
                set_source_uri (context, "");
210
211
            return success;
212
        }
213
214
        public bool handle_netscape_url (Gdk.DragContext context, GOF.File drop_target, Gtk.SelectionData selection) {
215
            string [] parts = (selection.get_text ()).split ("\n");
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
216
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
217
            /* _NETSCAPE_URL looks like this: "$URL\n$TITLE" - should be 2 parts */
218
            if (parts.length != 2)
219
                return false;
220
1459.1.193 by jeremy at elementaryos
Remove unnecessary comment lines, remove redundant files, remove or revise TODOs and FIXMEs, update about dialog authors list and AUTHORS file
221
            /* NETSCAPE URLs are not currently handled.  No current bug reports */
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
222
            return false;
223
        }
224
225
        public bool handle_file_drag_actions (Gtk.Widget dest_widget,
226
                                              Gtk.ApplicationWindow win,
227
                                              Gdk.DragContext context,
228
                                              GOF.File drop_target,
229
                                              GLib.List<GLib.File> drop_file_list,
230
                                              Gdk.DragAction possible_actions,
231
                                              Gdk.DragAction suggested_action,
232
                                              uint32 timestamp) {
233
            bool success = false;
234
            Gdk.DragAction action = suggested_action;
235
236
            if ((possible_actions & Gdk.DragAction.ASK) != 0)
237
                action = drag_drop_action_ask (dest_widget, win, possible_actions);
238
239
            if (action != Gdk.DragAction.DEFAULT) {
240
                success = dnd_perform (dest_widget,
241
                                       drop_target,
242
                                       drop_file_list,
243
                                       action);
244
            }
245
            return success;
246
        }
247
248
2228.1.1 by Jeremy Wootten
Rewrite ClipboardManager in Vala
249
        public static bool selection_data_is_uri_list (Gtk.SelectionData selection_data, uint info, out string? text) {
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
250
            text = null;
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
251
1953.1.2 by Jeremy Wootten
Move Enums MimeActions and DndHandler into libcore
252
            if (info == Marlin.TargetType.TEXT_URI_LIST &&
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
253
                selection_data.get_format () == 8 &&
254
                selection_data.get_length () > 0) {
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
255
2228.1.1 by Jeremy Wootten
Rewrite ClipboardManager in Vala
256
                text = DndHandler.data_to_string (selection_data.get_data_with_length ());
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
257
            }
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
258
            debug ("DNDHANDLER selection data is uri list returning %s", (text != null).to_string ());
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
259
            return (text != null);
260
        }
261
2228.1.1 by Jeremy Wootten
Rewrite ClipboardManager in Vala
262
        public static string data_to_string (uchar [] cdata) {
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
263
            var sb = new StringBuilder ("");
264
1459.1.169 by jeremy at elementaryos
Adjust code formatting for consistency; remove temporary debugging code; rename DirectoryView to AbstractDirectoryView for consistency
265
            foreach (uchar u in cdata)
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
266
                sb.append_c ((char)u);
267
268
            return sb.str;
269
        }
2228.1.1 by Jeremy Wootten
Rewrite ClipboardManager in Vala
270
271
        public static void set_selection_data_from_file_list (Gtk.SelectionData selection_data,
272
                                                              GLib.List<GOF.File> file_list,
273
                                                              string? prefix = "") {
274
275
            GLib.StringBuilder sb = new GLib.StringBuilder (prefix);
2228.1.3 by Jeremy Wootten
Merge trunk to r2319
276
            bool in_recent = file_list.data.is_recent_uri_scheme ();
2228.1.1 by Jeremy Wootten
Rewrite ClipboardManager in Vala
277
278
            file_list.@foreach ((file) => {
2228.1.3 by Jeremy Wootten
Merge trunk to r2319
279
                var target = in_recent ? file.get_display_target_uri () : file.get_target_location ().get_uri ();
280
                sb.append (target);
2228.1.1 by Jeremy Wootten
Rewrite ClipboardManager in Vala
281
                sb.append ("\r\n");  /* Drop onto Filezilla does not work without the "\r" */
282
            });
283
284
            selection_data.@set (selection_data.get_target (),
285
                                 8,
286
                                 sb.data);
2228.1.3 by Jeremy Wootten
Merge trunk to r2319
287
2228.1.1 by Jeremy Wootten
Rewrite ClipboardManager in Vala
288
        }
1459.1.50 by jeremy at elementaryos
Some reorganisation; Add new widgets etc to bzr
289
    }
290
}