[polari] pasteManager: Add class for handling paste via dnd
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [polari] pasteManager: Add class for handling paste via dnd
- Date: Thu, 8 Aug 2013 13:13:29 +0000 (UTC)
commit 59e3a237c039a3dd172b15a5d207dfd7226b1798
Author: Florian Müllner <fmuellner gnome org>
Date: Mon Jul 29 21:21:29 2013 +0200
pasteManager: Add class for handling paste via dnd
src/Makefile.am | 1 +
src/application.js | 2 +
src/chatView.js | 3 +
src/pasteManager.js | 232 +++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 238 insertions(+), 0 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 0f4c3a7..6c3adf4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -37,6 +37,7 @@ dist_js_DATA = \
joinDialog.js \
main.js \
mainWindow.js \
+ pasteManager.js \
roomList.js \
userList.js \
utils.js \
diff --git a/src/application.js b/src/application.js
index c11e060..d78788e 100644
--- a/src/application.js
+++ b/src/application.js
@@ -13,6 +13,7 @@ const Format = imports.format;
const Gettext = imports.gettext;
const Lang = imports.lang;
const MainWindow = imports.mainWindow;
+const PasteManager = imports.pasteManager;
const Utils = imports.utils;
const Application = new Lang.Class({
@@ -46,6 +47,7 @@ const Application = new Lang.Class({
this._chatroomManager = ChatroomManager.getDefault();
this._accountsMonitor = AccountsMonitor.getDefault();
+ this.pasteManager = new PasteManager.PasteManager();
this.notificationQueue = new AppNotifications.NotificationQueue();
this.commandOutputQueue = new AppNotifications.CommandOutputQueue();
diff --git a/src/chatView.js b/src/chatView.js
index 6ef924a..20b5b1e 100644
--- a/src/chatView.js
+++ b/src/chatView.js
@@ -66,6 +66,9 @@ const ChatView = new Lang.Class({
this._hoveringLink = false;
this._pending = [];
+ let app = Gio.Application.get_default();
+ app.pasteManager.addWidget(this._view);
+
this._linkCursor = Gdk.Cursor.new(Gdk.CursorType.HAND1);
let channelSignals = [
diff --git a/src/pasteManager.js b/src/pasteManager.js
new file mode 100644
index 0000000..637aa7c
--- /dev/null
+++ b/src/pasteManager.js
@@ -0,0 +1,232 @@
+const Gdk = imports.gi.Gdk;
+const GdkPixbuf = imports.gi.GdkPixbuf;
+const GLib = imports.gi.GLib;
+const Gio = imports.gi.Gio;
+const Gtk = imports.gi.Gtk;
+const Polari = imports.gi.Polari;
+const Tp = imports.gi.TelepathyGLib;
+
+const ChatroomManager = imports.chatroomManager;
+const Lang = imports.lang;
+const Utils = imports.utils;
+
+const DndTargetType = {
+ URI_LIST: 1,
+
+ TEXT: 2,
+ IMAGE: 3,
+};
+
+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) {
+ 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);
+ },
+
+ pasteText: function(text) {
+ let room = this._roomManager.getActiveRoom();
+ if (!room)
+ return;
+
+ let nick = room.channel.connection.self_contact.alias;
+ Utils.fpaste(text, nick, Lang.bind(this,
+ function(url) {
+ if (!url)
+ return;
+
+ let type = Tp.ChannelTextMessageType.NORMAL;
+ let message = Tp.ClientMessage.new_text(type, url);
+ room.channel.send_message_async(message, 0, Lang.bind(this,
+ function(c, res) {
+ try {
+ c.send_message_finish(res);
+ } catch(e) {
+ logError(e, 'Failed to send message')
+ }
+ }));
+ }));
+ },
+
+ _onDragDrop: function(widget, context, x, y, time) {
+ if (!Polari.drag_dest_supports_target(widget, context, null))
+ return false;
+
+ Polari.drag_dest_request_data(widget, context, time);
+ return true;
+ },
+
+ _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 (!Polari.drag_dest_supports_target(widget, context, null))
+ return false;
+
+ 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.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 false;
+ }
+
+ if (!this._dragHighlight) {
+ this._dragHighlight = true;
+ widget.drag_highlight();
+ }
+
+ return true;
+ },
+
+
+ _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;
+ Gdk.drag_status(context, Gdk.DragAction.COPY, time);
+ return;
+ }
+
+ if (info == DndTargetType.URI_LIST) {
+ let uris = data.get_uris();
+ if (!uris) {
+ Gtk.drag_finish(context, false, false, time);
+ return;
+ }
+
+ // TODO: handle multiple files ...
+ let file = Gio.File.new_for_uri(uris[0]);
+ file.query_info_async(Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ Gio.FileQueryInfoFlags.NONE,
+ GLib.PRIORITY_DEFAULT,
+ null, Lang.bind(this,
+ function(f, res) {
+ let fileInfo = null;
+ try {
+ fileInfo = file.query_info_finish(res);
+ } catch(e) {
+ logError(e);
+ Gtk.drag_finish(context, false, false, time);
+ }
+
+ let contentType = fileInfo.get_content_type();
+ let targetType = this._getTargetForContentType(contentType);
+
+ this._handleFileContent(file, targetType);
+ Gtk.drag_finish(context, true, false, time);
+ }));
+ } else {
+ let success = false;
+ switch(info) {
+ case DndTargetType.TEXT:
+ this.pasteText(data.get_text());
+ success = true;
+ break;
+ case DndTargetType.IMAGE:
+ // not implemented
+ //this._pasteImage(data.get_pixbuf());
+ 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;
+ },
+
+ _handleFileContent: function(file, type) {
+ 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());
+ }));
+ } 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);
+ }));
+ }));
+ } else {
+ log('Unhandled type');
+ }
+ }
+});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]