Skip to content

Commit

Permalink
For #36436, merged Amy's drag/drop fix from the wb framework.
Browse files Browse the repository at this point in the history
  • Loading branch information
Raphael Matto committed May 13, 2016
1 parent 67b609b commit 33b9f22
Show file tree
Hide file tree
Showing 7 changed files with 399 additions and 37 deletions.
107 changes: 70 additions & 37 deletions python/tk_multi_importcut/widgets/drop_area.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,46 @@ def dragEnterEvent(self, e):
# }
if e.mimeData().hasFormat("text/plain"):
e.accept()
elif e.mimeData().hasFormat("text/uri-list"):
for url in e.mimeData().urls():
_, ext = os.path.splitext(url.path())
# Accept anything if no extentions are specified.
if not self._restrict_to_ext or ext.lower() in self._restrict_to_ext:
return
else:
urls = e.mimeData().urls()
if sys.platform == "darwin":
# Fix for Yosemite, file paths are not actual file paths
# but weird /.file/id=6571367.18855673 values
# https://bugreports.qt-project.org/browse/QTBUG-24379
# https://gist.github.com/wedesoft/3216298
import translate_file_reference
for url in urls:
_, ext = os.path.splitext(url.path())
# Accept anything if no extentions are specified.
if not self._restrict_to_ext or ext.lower() in self._restrict_to_ext:
# We don't activate the dragging state unless ext is valid.
self._set_property("dragging", True)
str_url = url.toString()
if str_url.startswith("file:///.file"):
# for post-Yosemite OSX versions we need to translate to an actual path
new_url = QtCore.QUrl(
str(translate_file_reference.translate_url(url.toString())))
# Accept if there is at least one local file
if new_url.isLocalFile():
e.accept()
return
# Accept if there is at least one local file
elif url.isLocalFile():
e.accept()
return
elif e.mimeData().hasFormat("text/uri-list"):
for url in e.mimeData().urls():
# We don't activate the dragging state unless ext is valid.
self._set_property("dragging", True)
# Accept if there is at least one local file
if url.isLocalFile():
e.accept()
break
else:
e.ignore()
else:
e.ignore()
_, ext = os.path.splitext(url.path())
# Accept anything if no extentions are specified.
if not self._restrict_to_ext or ext.lower() in self._restrict_to_ext:
# Accept if there is at least one local file
if url.isLocalFile():
e.accept()
return
e.ignore()

# Override dragLeaveEvent
def dragLeaveEvent(self, e):
Expand All @@ -85,35 +110,35 @@ def dropEvent(self, e):
Process a drop event, build a list of local files and emit somethingDropped if not empty
"""
self._set_property("dragging", False)
if e.mimeData().hasFormat("text/plain"):
contents = [e.mimeData().text()]
else:
urls = e.mimeData().urls()

urls = e.mimeData().urls()
if urls :
if sys.platform == "darwin":
# Fix for Yosemite and later, file paths are not actual file paths
# Fix for Yosemite, file paths are not actual file paths
# but weird /.file/id=6571367.18855673 values
# https://bugreports.qt-project.org/browse/QTBUG-24379
# https://gist.github.com/wedesoft/3216298
try:
# Custom Python (e.g. brewed ones) might not be able to
# import Foundation. In that case we do nothing and keep
# urls as they are, assuming the problem should be fixed
# in custom Python / PyQt / PySide
import Foundation
fixed_urls = []
for url in urls:
# It is fine to pass a regular file url to this method
# e.g. file:///foo/bar/blah.ext
fu = Foundation.NSURL.URLWithString_(url.toString()).filePathURL()
fixed_urls.append(QtCore.QUrl(str(fu)))
urls = fixed_urls
except:
pass
contents = [x.toLocalFile() for x in urls if x.isLocalFile()]
if contents:
import translate_file_reference
fixed_urls = []
for url in urls:
str_url = url.toString()
if str_url.startswith("file:///.file"):
# for post-Yosemite OSX versions we need to translate to an actual path
new_url = QtCore.QUrl(str(translate_file_reference.translate_url(url.toString())))
fixed_urls.append(new_url)
else:
# otherwise we can add the url as-is
fixed_urls.append(url)
urls = fixed_urls

contents = [ x.toLocalFile() for x in urls if x.isLocalFile() ]
elif e.mimeData().hasFormat("text/plain") :
contents = [ e.mimeData().text() ]

if contents :
e.accept()
self.something_dropped.emit(contents)
else:
self.something_dropped.emit( contents )
else :
e.ignore()

def _set_property(self, name, value):
Expand Down Expand Up @@ -163,3 +188,11 @@ class DropAreaScrollArea(QtGui.QScrollArea):
Custom scroll area widget so we can override drop callback and add a somethingDropped signal
"""
pass


@drop_area
class DropAreaTextEdit(QtGui.QTextEdit):
"""
Custom text edit widget so we can override the drop callback and add a somethingDropped signal
"""
pass
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Copyright (c) 2015 Shotgun Software Inc.
#
# CONFIDENTIAL AND PROPRIETARY
#
# This work is provided "AS IS" and subject to the Shotgun Pipeline Toolkit
# Source Code License included in this distribution package. See LICENSE.
# By accessing, using, copying or modifying this work you indicate your
# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights
# not expressly granted therein are reserved by Shotgun Software Inc.

import os
import sys

from distutils import log
from distutils.errors import DistutilsSetupError
from distutils.core import setup, Extension
from distutils.command.build_clib import build_clib


# need to override build_clib to build a shared library
class build_shared_clib(build_clib):
def finalize_options(self):
build_clib.finalize_options(self)

# override default build_clib to be the build directory
self.build_clib = None
self.set_undefined_options('build', ("build_lib", "build_clib"))

def build_libraries(self, libraries):
for (lib_name, build_info) in libraries:
sources = build_info.get('sources')
if sources is None or not isinstance(sources, (list, tuple)):
raise DistutilsSetupError, \
("in 'libraries' option (library '%s'), " +
"'sources' must be present and must be " +
"a list of source filenames") % lib_name
sources = list(sources)

log.info("building '%s' library", lib_name)

# First, compile the source code to object files in the library
# directory. (This should probably change to putting object
# files in a temporary build directory.)
macros = build_info.get('macros')
include_dirs = build_info.get('include_dirs')
objects = self.compiler.compile(sources,
output_dir=self.build_temp,
macros=macros,
include_dirs=include_dirs,
debug=self.debug,
)

# Now "link" the object files together into a shared library.
# Make sure to add in the path for the python library by default
self.compiler.link_shared_lib(objects, lib_name,
library_dirs=[os.path.join(sys.exec_prefix, "libs")],
libraries=build_info.get("libraries", []),
output_dir=self.build_clib,
debug=self.debug,
extra_postargs=["/DELAYLOAD:python27.dll"],
)

sources = ["translate_file_reference_module.c"]
modules = []
libraries = []
libarary_builds = []

if sys.platform == "darwin":
os.environ["LDFLAGS"] = "-framework AppKit"
sources.extend(["translate_file_reference.m"])
elif sys.platform == "win32":
raise NotImplementedError
elif sys.platform.startswith("linux"):
raise NotImplementedError

module = Extension("translate_file_reference", sources=sources, libraries=libraries)
modules.append(module)

setup(
name="translate_file_reference",
version="1.0",
description="Module to expose os level functionality.",
ext_modules=modules,
libraries=libarary_builds,
cmdclass={'build_clib': build_shared_clib},
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Copyright (c) 2015 Shotgun Software Inc.
#
# CONFIDENTIAL AND PROPRIETARY
#
# This work is provided "AS IS" and subject to the Shotgun Pipeline Toolkit
# Source Code License included in this distribution package. See LICENSE.
# By accessing, using, copying or modifying this work you indicate your
# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights
# not expressly granted therein are reserved by Shotgun Software Inc.

import sys
import translate_file_reference

from PySide import QtGui


class View(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.setAcceptDrops(True)

def dragEnterEvent(self, e):
urls = e.mimeData().urls()
print urls
print translate_file_reference.translate_url(urls[0].toString())

app = QtGui.QApplication(sys.argv)
view = View()
view.show()
app.exec_()
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) 2015 Shotgun Software Inc.

// CONFIDENTIAL AND PROPRIETARY

// This work is provided "AS IS" and subject to the Shotgun Pipeline Toolkit
// Source Code License included in this distribution package. See LICENSE.
// By accessing, using, copying or modifying this work you indicate your
// agreement to the Shotgun Pipeline Toolkit Source Code License. All rights
// not expressly granted therein are reserved by Shotgun Software Inc.

#include <Python.h>
#include <Carbon/Carbon.h>
#include <AppKit/NSApplication.h>

BOOL
is_valid_url(NSString *url)
{
NSUInteger length = [url length];
// Empty strings should return NO
if (length > 0) {
NSError *error = nil;
NSDataDetector *dataDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:&error];
if (dataDetector && !error) {
NSRange range = NSMakeRange(0, length);
NSRange notFoundRange = (NSRange){NSNotFound, 0};
NSRange linkRange = [dataDetector rangeOfFirstMatchInString:url options:0 range:range];
if (!NSEqualRanges(notFoundRange, linkRange) && NSEqualRanges(range, linkRange)) {
return true;
}
} else {
NSLog(@"Could not create link data detector: %@ %@", [error localizedDescription], [error userInfo]);
}
}
return false;
}

/* register_global_hotkey *****************************************************/
PyObject *
translate_url(PyObject *module, const char *url)
{

NSURL *url_as_url = NULL;
NSString *url_as_string = NULL;
NSString *translated_string = NULL;
const char *translation;

PyObject *ret = NULL;

url_as_string = [NSString stringWithUTF8String: url];
if (!is_valid_url(url_as_string))
return PyErr_Format(PyExc_ValueError, "malformed url: '%s'", url);

// Convert the UTF-8 encoded url into an NSURL
url_as_url = [NSURL URLWithString: url_as_string];

// The string could not be turned into a URL
if (url_as_url == nil)
return PyErr_Format(PyExc_ValueError, "malformed url: '%s'", url);

// Get the actual file path
translated_string = [[url_as_url filePathURL] absoluteString];

// Convert it into a python string
translation = [translated_string UTF8String];

// If there was no answer then return this
if (translation == NULL)
Py_RETURN_NONE;

// We have a translation, return it
ret = PyString_FromString(translation);
Py_INCREF(ret);

// Return the results
return ret;
}
Loading

0 comments on commit 33b9f22

Please sign in to comment.