Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--browser.py16
-rw-r--r--dnd.py88
-rw-r--r--documentnode.py146
3 files changed, 249 insertions, 1 deletions
diff --git a/browser.py b/browser.py
index 87251d5..4f90ccb 100644
--- a/browser.py
+++ b/browser.py
@@ -26,6 +26,7 @@ from xpcom.components import interfaces
from hulahop.webview import WebView
import sessionstore
+from dnd import DragDropHooks
class Browser(WebView):
def __init__(self):
@@ -36,7 +37,20 @@ class Browser(WebView):
window_watcher = cls.getService(interfaces.nsIWindowWatcher)
window_watcher.setWindowCreator(window_creator)
- self.is_chrome= False
+ self.is_chrome = False
+
+ self.connect('realize', self._realize_cb)
+
+ def _realize_cb(self, widget):
+ drag_drop_hooks = DragDropHooks(self)
+
+ cls = components.classes['@mozilla.org/embedcomp/command-params;1']
+ cmd_params = cls.createInstance('nsICommandParams')
+ cmd_params.setISupportsValue('addhook', drag_drop_hooks)
+
+ requestor = self.browser.queryInterface(interfaces.nsIInterfaceRequestor)
+ command_manager = requestor.getInterface(interfaces.nsICommandManager)
+ command_manager.doCommand('cmd_clipboardDragDropHook', cmd_params, self.window)
def get_session(self):
return sessionstore.get_session(self)
diff --git a/dnd.py b/dnd.py
new file mode 100644
index 0000000..b916276
--- /dev/null
+++ b/dnd.py
@@ -0,0 +1,88 @@
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os.path
+import tempfile
+
+from xpcom.nsError import *
+from xpcom import COMException
+from xpcom import components
+from xpcom.components import interfaces
+
+from documentnode import DocumentNode
+
+class UriListDataProvider:
+ _com_interfaces_ = interfaces.nsIFlavorDataProvider
+
+ def __init__(self, doc_node):
+ self._doc_node = doc_node
+
+ def getFlavorData(self, transferable, flavor):
+ if flavor != 'text/uri-list':
+ raise COMException(NS_ERROR_NOT_IMPLEMENTED)
+
+ mime_type = self._doc_node.get_image_mime_type()
+ image_name = self._doc_node.get_image_name()
+ image_name, file_ext = os.path.splitext(image_name)
+
+ if file_ext:
+ file_ext = file_ext[1:]
+
+ cls = components.classes['@mozilla.org/mime;1']
+ mime_service = cls.getService(interfaces.nsIMIMEService)
+ file_ext = mime_service.getPrimaryExtension(mime_type, file_ext)
+
+ f, file_path = tempfile.mkstemp(image_name + '.' + file_ext)
+ del f
+
+ self._doc_node.save_image(file_path)
+
+ cls = components.classes['@mozilla.org/supports-string;1']
+ string_supports = cls.createInstance(interfaces.nsISupportsString)
+ string_supports.data = 'file://' + file_path
+
+ return string_supports, 32
+
+class DragDropHooks:
+ _com_interfaces_ = interfaces.nsIClipboardDragDropHooks
+
+ def __init__(self, browser):
+ self._browser = browser
+
+ def allowDrop(self, event, session):
+ raise COMException(NS_ERROR_NOT_IMPLEMENTED)
+
+ def allowStartDrag(self, event):
+ raise COMException(NS_ERROR_NOT_IMPLEMENTED)
+
+ def onPasteOrDrop(self, event, trans):
+ return False
+
+ def onCopyOrDrag(self, event, trans):
+ mouse_event = event.queryInterface(interfaces.nsIDOMMouseEvent)
+ event_target = mouse_event.target
+ target_node = event_target.queryInterface(interfaces.nsIDOMNode)
+ document_node = DocumentNode(target_node, self._browser.web_navigation)
+
+ if document_node.is_image():
+ trans.removeDataFlavor('text/x-moz-url')
+ trans.addDataFlavor('text/uri-list')
+
+ data_provider = UriListDataProvider(document_node)
+ trans.setTransferData('text/uri-list', data_provider, 0)
+
+ return True
+
diff --git a/documentnode.py b/documentnode.py
new file mode 100644
index 0000000..ead07b6
--- /dev/null
+++ b/documentnode.py
@@ -0,0 +1,146 @@
+# Copyright (C) 2007, One Laptop Per Child
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import os.path
+import urlparse
+
+from xpcom.nsError import *
+from xpcom import COMException
+from xpcom import components
+from xpcom.components import interfaces
+
+class DocumentNode:
+ def __init__(self, DOM_node, web_navigation):
+ self._DOM_node = DOM_node
+ self._image_element = None
+ self._image_name = None
+ self._image_mime_type = None
+ self._image_properties = None
+ self._web_navigation = web_navigation
+
+ def is_image(self):
+ if self._image_element:
+ return True
+
+ if self._DOM_node.nodeType == interfaces.nsIDOMNode.ELEMENT_NODE:
+ element = self._DOM_node.queryInterface(interfaces.nsIDOMHTMLElement)
+ if element.localName.lower() == "img":
+ self._image_element = element.queryInterface(
+ interfaces.nsIDOMHTMLImageElement)
+ return True
+
+ return False
+
+ def _get_image_properties(self):
+ if not self.is_image():
+ return None
+
+ if not self._image_properties:
+ cls = components.classes['@mozilla.org/network/simple-uri;1']
+ uri = cls.createInstance(interfaces.nsIURI)
+ uri.spec = self._image_element.src
+
+ cls = components.classes['@mozilla.org/image/cache;1']
+ image_cache = cls.getService(interfaces.imgICache)
+ self._image_properties = image_cache.findEntryProperties(uri)
+
+ return self._image_properties
+
+ def get_image_mime_type(self):
+ if not self.is_image():
+ return None
+
+ if not self._image_mime_type:
+ properties = self._get_image_properties()
+ self._image_mime_type = properties.get('type',
+ interfaces.nsISupportsCString).data
+
+ return self._image_mime_type
+
+ def get_image_name(self):
+ if not self.is_image():
+ return None
+
+ if not self._image_name:
+ properties = self._get_image_properties()
+ if properties.has('content-disposition'):
+ content_disposition = properties.get('content-disposition',
+ interfaces.nsISupportsCString).data
+
+ cls = components.classes['@mozilla.org/network/mime-hdrparam;1']
+ header_param = cls.getService(interfaces.nsIMIMEHeaderParam)
+ self._image_name = header_param.getParameter(content_disposition,
+ 'filename', '', True, None)
+
+ if not self._image_name:
+ self._image_name = header_param.getParameter(content_disposition,
+ 'name', '', True, None)
+
+ if not self._image_name:
+ url = urlparse.urlparse(self._image_element.src)
+ path = url[2]
+ self._image_name = os.path.split(path)[1]
+
+ return self._image_name
+
+ def save_image(self, file_path):
+ """ Based on nsWebBrowserPersist::OnDataAvailable:
+ http://lxr.mozilla.org/seamonkey/source/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.cpp
+ """
+ cls = components.classes['@mozilla.org/network/io-service;1']
+ io_service = cls.getService(interfaces.nsIIOService)
+ uri = io_service.newURI(self._image_element.src, None, None)
+
+ cls = components.classes['@mozilla.org/file/local;1']
+ dest_file = cls.createInstance(interfaces.nsILocalFile)
+ dest_file.initWithPath(file_path)
+
+ cls = components.classes['@mozilla.org/network/io-service;1']
+ io_service = cls.getService(interfaces.nsIIOService)
+ input_channel = io_service.newChannelFromURI(uri)
+
+ session_history = self._web_navigation.sessionHistory
+ entry = session_history.getEntryAtIndex(session_history.index, False)
+ entry = entry.queryInterface(interfaces.nsISHEntry)
+ post_data = entry.postData
+ if post_data:
+ http_channel = input_channel.queryInterface(interfaces.nsIHttpChannel)
+ stream = post_data.queryInterface(interfaces.nsISeekableStream)
+ stream.seek(interfaces.nsISeekableStream.NS_SEEK_SET, 0)
+
+ upload_channel = http_channel.queryInterface(interfaces.nsIUploadChannel)
+ upload_channel.setUploadStream(post_data, '', -1)
+
+ http_input_stream = input_channel.open()
+
+ cls = components.classes['@mozilla.org/network/file-output-stream;1']
+ file_output_stream = cls.createInstance(interfaces.nsIFileOutputStream)
+ file_output_stream.init(dest_file, -1, -1, 0)
+
+ bytes_to_read = http_input_stream.available()
+ while bytes_to_read:
+ buf = str(http_input_stream.read(min(8192, bytes_to_read)))
+ bytes_read = len(buf)
+ bytes_to_write = bytes_read
+ while bytes_to_write:
+ bytes_written = file_output_stream.write(buf, bytes_read)
+ bytes_to_write -= bytes_written
+
+ bytes_to_read -= bytes_read
+
+ http_input_stream.close()
+ file_output_stream.close()
+