[polari/wip/fmuellner/drop-target: 2/6] pasteManager: Turn drop target support into a GObject interface
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [polari/wip/fmuellner/drop-target: 2/6] pasteManager: Turn drop target support into a GObject interface
- Date: Fri, 6 May 2016 14:51:58 +0000 (UTC)
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]