[polari/wip/fmuellner/drop-target: 2/6] pasteManager: Turn drop target support into a GObject interface



commit b26f0ac19811e47ae22c8e3b22efa5419bf09b9e
Author: Florian Müllner <fmuellner gnome org>
Date:   Fri Feb 12 00:54:07 2016 +0100

    pasteManager: Turn drop target support into a GObject interface
    
    The paste manager has some old support for turning widgets into
    drop targets for supported types and upload dropped data to the
    appropriate paste service. While sometimes useful, without any
    confirmation we ended up with accidental uploads more often than
    not and disabled it.
    With the re-enabled paste support from last cycle we now have a
    confirmation UI that we can leverage for processing drops as
    well - however this requires separating drop handling from doing
    the actual upload, and a singleton like PasteManager is fairly
    ill-suited to connect the widget receiving the drop with the one
    asking for confirmation.
    So instead, turn drop target support into an interface that objects
    can implement to have appropriate signals emitted for each drop on
    any widget set up as drop destination via addTargets().

 src/pasteManager.js |  196 +++++++++++++++++----------------------------------
 1 files changed, 65 insertions(+), 131 deletions(-)
---
diff --git a/src/pasteManager.js b/src/pasteManager.js
index 2c11301..b8458f0 100644
--- a/src/pasteManager.js
+++ b/src/pasteManager.js
@@ -2,6 +2,7 @@ const Gdk = imports.gi.Gdk;
 const GdkPixbuf = imports.gi.GdkPixbuf;
 const GLib = imports.gi.GLib;
 const Gio = imports.gi.Gio;
+const GObject = imports.gi.GObject;
 const Gtk = imports.gi.Gtk;
 const Polari = imports.gi.Polari;
 const Tp = imports.gi.TelepathyGLib;
@@ -18,54 +19,25 @@ const DndTargetType = {
     IMAGE: 3,
 };
 
+function _getTargetForContentType(contentType) {
+    if (Gio.content_type_is_a(contentType, 'text/plain'))
+        return DndTargetType.TEXT;
+    else if (Gio.content_type_is_a(contentType, 'image/*'))
+        return DndTargetType.IMAGE;
+    else
+       return 0;
+}
+
+
 const PasteManager = new Lang.Class({
     Name: 'PasteManager',
 
     _init: function() {
-        this._widgets = [];
-
-        this._dragHighlight = false;
-        this._dragDataReceived = false;
-        this._dragPending = false;
-
-        this._roomManager = ChatroomManager.getDefault();
     },
 
     addWidget: function(widget) {
         // auto-paste needs some design; disable for now
         return;
-
-        if (this._widgets.indexOf(widget) != -1)
-            return;
-
-        widget.drag_dest_set(0, [], Gdk.DragAction.COPY);
-
-        let targetList = widget.drag_dest_get_target_list();
-        if (!targetList)
-            targetList = Gtk.TargetList.new([]);
-
-        targetList.add_uri_targets(DndTargetType.URI_LIST);
-        targetList.add_text_targets(DndTargetType.TEXT);
-        targetList.add_image_targets(DndTargetType.IMAGE, false);
-
-        widget.drag_dest_set_target_list(targetList);
-
-        widget.connect('drag-drop', Lang.bind(this, this._onDragDrop));
-        widget.connect('drag-leave', Lang.bind(this, this._onDragLeave));
-        widget.connect('drag-motion', Lang.bind(this, this._onDragMotion));
-        widget.connect('drag-data-received',
-                       Lang.bind(this, this._onDragDataReceived));
-
-        widget.connect('destroy', Lang.bind(this,
-            function(w) {
-                for (let i = 0; i < this._widgets.length; i++)
-                    if (this._widgets[i] == w) {
-                        this._widgets.slice(i, 1);
-                        break;
-                    }
-            }));
-
-        this._widgets.push(widget);
     },
 
     pasteContent: function(content, title, callback) {
@@ -96,7 +68,7 @@ const PasteManager = new Lang.Class({
         }
 
         let contentType = fileInfo.get_content_type();
-        let targetType = this._getTargetForContentType(contentType);
+        let targetType = _getTargetForContentType(contentType);
 
         if (targetType == DndTargetType.TEXT)
             file.load_contents_async(null, Lang.bind(this,
@@ -116,9 +88,49 @@ const PasteManager = new Lang.Class({
                 }));
         else
             callback(null);
+    }
+});
+
+const DropTargetIface = new Lang.Interface({
+    Name: 'DropTargetIface',
+    Requires: [GObject.Object],
+    Properties: {
+        'can-drop': GObject.ParamSpec.boolean('can-drop', '', '',
+                                              GObject.ParamFlags.READABLE,
+                                              false)
+    },
+    Signals: {
+        'text-dropped': { param_types: [GObject.TYPE_STRING] },
+        'image-dropped': { param_types: [GdkPixbuf.Pixbuf.$gtype] },
+        'file-dropped': { param_types: [Gio.File.$gtype] }
+    },
+
+    addTargets: function(widget) {
+        this._dragHighlight = false;
+
+        widget.drag_dest_set(0, [], Gdk.DragAction.COPY);
+
+        let targetList = widget.drag_dest_get_target_list();
+        if (!targetList)
+            targetList = Gtk.TargetList.new([]);
+
+        targetList.add_uri_targets(DndTargetType.URI_LIST);
+        targetList.add_text_targets(DndTargetType.TEXT);
+        targetList.add_image_targets(DndTargetType.IMAGE, false);
+
+        widget.drag_dest_set_target_list(targetList);
+
+        widget.connect('drag-drop', Lang.bind(this, this._onDragDrop));
+        widget.connect('drag-leave', Lang.bind(this, this._onDragLeave));
+        widget.connect('drag-motion', Lang.bind(this, this._onDragMotion));
+        widget.connect('drag-data-received',
+                       Lang.bind(this, this._onDragDataReceived));
     },
 
     _onDragDrop: function(widget, context, x, y, time) {
+        if (!this.can_drop)
+            return Gdk.EVENT_PROPAGATE;
+
         if (!Polari.drag_dest_supports_target(widget, context, null))
             return Gdk.EVENT_PROPAGATE;
 
@@ -129,34 +141,22 @@ const PasteManager = new Lang.Class({
     _onDragLeave: function(widget, context, time) {
         widget.drag_unhighlight();
         this._dragHighlight = false;
-        this._dragDataReceived = false;
-        this._dragPending = false;
     },
 
     _onDragMotion: function(widget, context, x, y, time) {
+        if (!this.can_drop)
+            return Gdk.EVENT_PROPAGATE;
+
         if (!Polari.drag_dest_supports_target(widget, context, null))
             return Gdk.EVENT_PROPAGATE;
 
         let info = Polari.drag_dest_find_target(widget, context);
         switch (info) {
             case DndTargetType.TEXT:
-            //case DndTargetType.IMAGE:
-                Gdk.drag_status(context, Gdk.DragAction.COPY, time);
-                break;
+            case DndTargetType.IMAGE:
             case DndTargetType.URI_LIST:
-                /* FIXME: the latter doesn't seem to work, pretend to support
-                          all drops */
                 Gdk.drag_status(context, Gdk.DragAction.COPY, time);
                 break;
-
-                let action = 0;
-                if (!this._dragDataReceived) {
-                    this._dragPending = true;
-                    Polari.drag_dest_request_data(widget, context, time);
-                } else {
-                    Gdk.drag_status(context, action, time);
-                }
-                break;
             default:
                 return Gdk.EVENT_PROPAGATE;
         }
@@ -171,28 +171,6 @@ const PasteManager = new Lang.Class({
 
 
     _onDragDataReceived: function(widget, context, x, y, data, info, time) {
-        if (this._dragPending) {
-            this._dragPending = false;
-
-            if (info != DndTargetType.URI_LIST) {
-                Gdk.drag_status(context, 0, time);
-                return;
-            }
-
-            let uris = data.get_uris();
-            this._dragDataReceived = true;
-            // TODO: handle multiple files ...
-            let file = Gio.File.new_for_uri(uris[0]);
-            this._lookupFileInfo(file, Lang.bind(this,
-                function(name, targetType) {
-                    let action = 0;
-                    if (targetType == DndTargetType.TEXT)
-                        action = Gdk.DragAction.COPY;
-                    Gdk.drag_status(context, action, time);
-                }));
-            return;
-        }
-
         if (info == DndTargetType.URI_LIST) {
             let uris = data.get_uris();
             if (!uris) {
@@ -203,43 +181,30 @@ const PasteManager = new Lang.Class({
             // TODO: handle multiple files ...
             let file = Gio.File.new_for_uri(uris[0]);
             this._lookupFileInfo(file, Lang.bind(this,
-                function(name, targetType) {
-                    let canHandle = // targetType != 0;
-                                       targetType == DndTargetType.TEXT;
-
+                function(targetType) {
+                    let canHandle = targetType != 0;
                     if (canHandle)
-                        this._handleFileContent(file, displayName, targetType);
+                        this.emit('file-dropped', file);
                     Gtk.drag_finish(context, canHandle, false, time);
                 }));
         } else {
             let success = false;
             switch(info) {
                 case DndTargetType.TEXT:
-                    this.pasteText(data.get_text());
+                    this.emit('text-dropped', data.get_text());
                     success = true;
                     break;
                 case DndTargetType.IMAGE:
-                    // not implemented
-                    //this._pasteImage(data.get_pixbuf());
+                    this.emit('image-dropped', data.get_pixbuf());
+                    success = true;
                     break;
             }
             Gtk.drag_finish(context, success, false, time);
         }
     },
 
-    _getTargetForContentType: function(contentType) {
-        if (Gio.content_type_is_a(contentType, 'text/plain'))
-            return DndTargetType.TEXT;
-        else if (Gio.content_type_is_a(contentType, 'image/*'))
-            return DndTargetType.IMAGE;
-        else
-           return 0;
-    },
-
     _lookupFileInfo: function(file, callback) {
-        let attr = Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE + ',' +
-                   Gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME;
-        file.query_info_async(attr,
+        file.query_info_async(Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
                               Gio.FileQueryInfoFlags.NONE,
                               GLib.PRIORITY_DEFAULT,
                               null, Lang.bind(this,
@@ -248,43 +213,12 @@ const PasteManager = new Lang.Class({
                 try {
                     fileInfo = file.query_info_finish(res);
                 } catch(e) {
-                    logError(e);
-                    callback(null, 0);
+                    callback(0);
                     Gtk.drag_finish(context, false, false, time);
                 }
 
-                let displayName = fileInfo.get_display_name();
                 let contentType = fileInfo.get_content_type();
-                let targetType = this._getTargetForContentType(contentType);
-                callback(displayName, targetType);
+                callback(_getTargetForContentType(contentType));
             }))
-    },
-
-
-    _handleFileContent: function(file, name, type) {
-        let app = Gio.Application.get_default();
-        let n = new UploadNotification(name);
-        app.notificationQueue.addNotification(n);
-
-        if (type == DndTargetType.TEXT) {
-            file.load_contents_async(null, Lang.bind(this,
-                function(f, res) {
-                    let [, contents, ,] = f.load_contents_finish(res);
-                    this._pasteText(contents.toString(), n);
-                }));
-        } else if (type == DndTargetType.IMAGE) {
-            file.read_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this,
-                function(f, res) {
-                    let stream = f.read_finish(res);
-                    GdkPixbuf.Pixbuf.new_from_stream_async(stream, null,
-                        Lang.bind(this, function(stream, res) {
-                            let pixbuf = GdkPixbuf.Pixbuf.new_from_stream_finish(res);
-                            this._pasteImage(pixbuf, n);
-                        }));
-                }));
-        } else {
-            log('Unhandled type');
-            n.close();
-        }
     }
 });


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]