diff options
author | erg@chromium.org <erg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-09 10:48:56 +0000 |
---|---|---|
committer | erg@chromium.org <erg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-09 10:48:56 +0000 |
commit | e8df13507f5c15a935cbbbb17fef6ee0e52d1d21 (patch) | |
tree | ba1afa86874f76b29ddbacd8d2e84385d981e3d9 /ui/base | |
parent | ae0d6f6a1063eadfa003a9c358470b26d469fc74 (diff) | |
download | chromium_src-e8df13507f5c15a935cbbbb17fef6ee0e52d1d21.zip chromium_src-e8df13507f5c15a935cbbbb17fef6ee0e52d1d21.tar.gz chromium_src-e8df13507f5c15a935cbbbb17fef6ee0e52d1d21.tar.bz2 |
linux_aura: Implement file drag and drop in content area.
In OSExchangeData, there's a difference between URLs and files. In the
mime type "text/uri-list", there isn't, and Linux usually uses the later
to exchange both data types.
This fixes dragging files onto several sites, like the HTML Five Wow
Terminal, but doesn't fix Dropbox, which seems to be failing somewhere
else.
BUG=317548
Review URL: https://codereview.chromium.org/129113004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@243840 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/base')
-rw-r--r-- | ui/base/dragdrop/os_exchange_data_provider_aurax11.cc | 118 | ||||
-rw-r--r-- | ui/base/dragdrop/os_exchange_data_provider_aurax11.h | 2 | ||||
-rw-r--r-- | ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc | 58 | ||||
-rw-r--r-- | ui/base/x/selection_utils.cc | 17 | ||||
-rw-r--r-- | ui/base/x/selection_utils.h | 12 |
5 files changed, 182 insertions, 25 deletions
diff --git a/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc b/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc index d0eeb6a..20a6842 100644 --- a/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc +++ b/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc @@ -139,12 +139,25 @@ void OSExchangeDataProviderAuraX11::SetURL(const GURL& url, } void OSExchangeDataProviderAuraX11::SetFilename(const base::FilePath& path) { - NOTIMPLEMENTED(); + std::vector<OSExchangeData::FileInfo> data; + data.push_back(OSExchangeData::FileInfo(path, base::FilePath())); + SetFilenames(data); } void OSExchangeDataProviderAuraX11::SetFilenames( const std::vector<OSExchangeData::FileInfo>& filenames) { - NOTIMPLEMENTED(); + std::vector<std::string> paths; + for (std::vector<OSExchangeData::FileInfo>::const_iterator it = + filenames.begin(); it != filenames.end(); ++it) { + std::string url_spec = net::FilePathToFileURL(it->path).spec(); + if (!url_spec.empty()) + paths.push_back(url_spec); + } + + std::string joined_data = JoinString(paths, '\n'); + scoped_refptr<base::RefCountedMemory> mem( + base::RefCountedString::TakeString(&joined_data)); + format_map_.Insert(atom_cache_.GetAtom(Clipboard::kMimeTypeURIList), mem); } void OSExchangeDataProviderAuraX11::SetPickledData( @@ -207,21 +220,16 @@ bool OSExchangeDataProviderAuraX11::GetURLAndTitle( } } else if (data.GetType() == atom_cache_.GetAtom( Clipboard::kMimeTypeURIList)) { - // uri-lists are newline separated file lists in URL encoding. - std::string unparsed; - data.AssignTo(&unparsed); - - std::vector<std::string> tokens; - size_t num_tokens = Tokenize(unparsed, "\n", &tokens); - if (!num_tokens) { - NOTREACHED() << "Empty URI list"; - return false; + std::vector<std::string> tokens = ui::ParseURIList(data); + for (std::vector<std::string>::const_iterator it = tokens.begin(); + it != tokens.end(); ++it) { + GURL test_url(*it); + if (!test_url.SchemeIsFile()) { + *url = test_url; + *title = base::string16(); + return true; + } } - - *url = GURL(tokens[0]); - *title = base::string16(); - - return true; } } @@ -229,14 +237,37 @@ bool OSExchangeDataProviderAuraX11::GetURLAndTitle( } bool OSExchangeDataProviderAuraX11::GetFilename(base::FilePath* path) const { - // On X11, files are passed by URL and aren't separate. + std::vector<OSExchangeData::FileInfo> filenames; + if (GetFilenames(&filenames)) { + *path = filenames.front().path; + return true; + } + return false; } bool OSExchangeDataProviderAuraX11::GetFilenames( std::vector<OSExchangeData::FileInfo>* filenames) const { - // On X11, files are passed by URL and aren't separate. - return false; + std::vector< ::Atom> url_atoms = ui::GetURIListAtomsFrom(&atom_cache_); + std::vector< ::Atom> requested_types; + ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types); + + filenames->clear(); + ui::SelectionData data(format_map_.GetFirstOf(requested_types)); + if (data.IsValid()) { + std::vector<std::string> tokens = ui::ParseURIList(data); + for (std::vector<std::string>::const_iterator it = tokens.begin(); + it != tokens.end(); ++it) { + GURL url(*it); + base::FilePath file_path; + if (url.SchemeIsFile() && net::FileURLToFilePath(url, &file_path)) { + filenames->push_back(OSExchangeData::FileInfo(file_path, + base::FilePath())); + } + } + } + + return !filenames->empty(); } bool OSExchangeDataProviderAuraX11::GetPickledData( @@ -268,11 +299,56 @@ bool OSExchangeDataProviderAuraX11::HasURL() const { std::vector< ::Atom> url_atoms = ui::GetURLAtomsFrom(&atom_cache_); std::vector< ::Atom> requested_types; ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types); - return !requested_types.empty(); + + if (requested_types.empty()) + return false; + + // The Linux desktop doesn't differentiate between files and URLs like + // Windows does and stuffs all the data into one mime type. + ui::SelectionData data(format_map_.GetFirstOf(requested_types)); + if (data.IsValid()) { + if (data.GetType() == atom_cache_.GetAtom(kMimeTypeMozillaURL)) { + // File managers shouldn't be using this type, so this is a URL. + return true; + } else if (data.GetType() == atom_cache_.GetAtom( + ui::Clipboard::kMimeTypeURIList)) { + std::vector<std::string> tokens = ui::ParseURIList(data); + for (std::vector<std::string>::const_iterator it = tokens.begin(); + it != tokens.end(); ++it) { + if (!GURL(*it).SchemeIsFile()) + return true; + } + + return false; + } + } + + return false; } bool OSExchangeDataProviderAuraX11::HasFile() const { - // On X11, files are passed by URL and aren't separate. + std::vector< ::Atom> url_atoms = ui::GetURIListAtomsFrom(&atom_cache_); + std::vector< ::Atom> requested_types; + ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types); + + if (requested_types.empty()) + return false; + + // To actually answer whether we have a file, we need to look through the + // contents of the kMimeTypeURIList type, and see if any of them are file:// + // URIs. + ui::SelectionData data(format_map_.GetFirstOf(requested_types)); + if (data.IsValid()) { + std::vector<std::string> tokens = ui::ParseURIList(data); + for (std::vector<std::string>::const_iterator it = tokens.begin(); + it != tokens.end(); ++it) { + GURL url(*it); + base::FilePath file_path; + if (url.SchemeIsFile() && net::FileURLToFilePath(url, &file_path)) + return true; + } + } + return false; } diff --git a/ui/base/dragdrop/os_exchange_data_provider_aurax11.h b/ui/base/dragdrop/os_exchange_data_provider_aurax11.h index 0d16351..c83f955 100644 --- a/ui/base/dragdrop/os_exchange_data_provider_aurax11.h +++ b/ui/base/dragdrop/os_exchange_data_provider_aurax11.h @@ -27,6 +27,7 @@ namespace ui { class Clipboard; +class OSExchangeDataProviderAuraX11Test; // OSExchangeData::Provider implementation for aura on linux. class UI_BASE_EXPORT OSExchangeDataProviderAuraX11 @@ -90,6 +91,7 @@ class UI_BASE_EXPORT OSExchangeDataProviderAuraX11 virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE; private: + friend class OSExchangeDataProviderAuraX11Test; typedef std::map<OSExchangeData::CustomFormat, Pickle> PickleData; // Returns true if |formats_| contains a string format and the string can be diff --git a/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc b/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc index a09198d..e3bf0e8 100644 --- a/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc +++ b/ui/base/dragdrop/os_exchange_data_provider_aurax11_unittest.cc @@ -14,13 +14,33 @@ #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" +const char kFileURL[] = "file:///home/user/file.txt"; +const char kFileName[] = "/home/user/file.txt"; const char kGoogleTitle[] = "Google"; const char kGoogleURL[] = "http://www.google.com/"; -TEST(OSExchangeDataProviderAuraX11Test, MozillaURL) { +namespace ui { + +class OSExchangeDataProviderAuraX11Test : public testing::Test { + public: + OSExchangeDataProviderAuraX11Test() {} + + void AddURLList(const std::string& list_contents) { + std::string contents_copy = list_contents; + scoped_refptr<base::RefCountedMemory> mem( + base::RefCountedString::TakeString(&contents_copy)); + + provider.format_map_.Insert( + provider.atom_cache_.GetAtom(ui::Clipboard::kMimeTypeURIList), + mem); + } + + protected: base::MessageLoopForUI message_loop; ui::OSExchangeDataProviderAuraX11 provider; +}; +TEST_F(OSExchangeDataProviderAuraX11Test, MozillaURL) { // Check that we can get titled entries. provider.SetURL(GURL(kGoogleURL), base::ASCIIToUTF16(kGoogleTitle)); { @@ -41,3 +61,39 @@ TEST(OSExchangeDataProviderAuraX11Test, MozillaURL) { EXPECT_EQ(kGoogleURL, out_gurl.spec()); } } + +TEST_F(OSExchangeDataProviderAuraX11Test, FilesArentURLs) { + AddURLList(kFileURL); + + EXPECT_TRUE(provider.HasFile()); + EXPECT_FALSE(provider.HasURL()); +} + +TEST_F(OSExchangeDataProviderAuraX11Test, HTTPURLsArentFiles) { + AddURLList(kGoogleURL); + + EXPECT_FALSE(provider.HasFile()); + EXPECT_TRUE(provider.HasURL()); +} + +TEST_F(OSExchangeDataProviderAuraX11Test, URIListWithBoth) { + AddURLList("file:///home/user/file.txt\nhttp://www.google.com"); + + EXPECT_TRUE(provider.HasFile()); + EXPECT_TRUE(provider.HasURL()); + + // We should only receive the file from GetFilenames(). + std::vector<OSExchangeData::FileInfo> filenames; + EXPECT_TRUE(provider.GetFilenames(&filenames)); + ASSERT_EQ(1u, filenames.size()); + EXPECT_EQ(kFileName, filenames[0].path.value()); + + // We should only receive the URL here. + GURL out_gurl; + base::string16 out_str; + EXPECT_TRUE(provider.GetURLAndTitle(&out_gurl, &out_str)); + EXPECT_EQ(base::string16(), out_str); + EXPECT_EQ(kGoogleURL, out_gurl.spec()); +} + +} // namespace ui diff --git a/ui/base/x/selection_utils.cc b/ui/base/x/selection_utils.cc index 5b501ec..82b1051 100644 --- a/ui/base/x/selection_utils.cc +++ b/ui/base/x/selection_utils.cc @@ -8,6 +8,7 @@ #include "base/i18n/icu_string_conversions.h" #include "base/logging.h" +#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "ui/base/clipboard/clipboard.h" #include "ui/base/x/x11_util.h" @@ -43,6 +44,12 @@ std::vector< ::Atom> GetURLAtomsFrom(const X11AtomCache* atom_cache) { return atoms; } +std::vector< ::Atom> GetURIListAtomsFrom(const X11AtomCache* atom_cache) { + std::vector< ::Atom> atoms; + atoms.push_back(atom_cache->GetAtom(Clipboard::kMimeTypeURIList)); + return atoms; +} + void GetAtomIntersection(const std::vector< ::Atom>& desired, const std::vector< ::Atom>& offered, std::vector< ::Atom>* output) { @@ -62,6 +69,16 @@ void AddString16ToVector(const base::string16& str, bytes->insert(bytes->end(), front, front + (str.size() * 2)); } +std::vector<std::string> ParseURIList(const SelectionData& data) { + // uri-lists are newline separated file lists in URL encoding. + std::string unparsed; + data.AssignTo(&unparsed); + + std::vector<std::string> tokens; + Tokenize(unparsed, "\n", &tokens); + return tokens; +} + std::string RefCountedMemoryToString( const scoped_refptr<base::RefCountedMemory>& memory) { if (!memory.get()) { diff --git a/ui/base/x/selection_utils.h b/ui/base/x/selection_utils.h index 7976beb..9eca5be 100644 --- a/ui/base/x/selection_utils.h +++ b/ui/base/x/selection_utils.h @@ -34,14 +34,20 @@ UI_BASE_EXPORT std::vector< ::Atom> GetTextAtomsFrom( UI_BASE_EXPORT std::vector< ::Atom> GetURLAtomsFrom( const X11AtomCache* atom_cache); +UI_BASE_EXPORT std::vector< ::Atom> GetURIListAtomsFrom( + const X11AtomCache* atom_cache); + // Places the intersection of |desired| and |offered| into |output|. UI_BASE_EXPORT void GetAtomIntersection(const std::vector< ::Atom>& desired, - const std::vector< ::Atom>& offered, - std::vector< ::Atom>* output); + const std::vector< ::Atom>& offered, + std::vector< ::Atom>* output); // Takes the raw bytes of the base::string16 and copies them into |bytes|. UI_BASE_EXPORT void AddString16ToVector(const base::string16& str, - std::vector<unsigned char>* bytes); + std::vector<unsigned char>* bytes); + +// Tokenizes and parses the Selection Data as if it is a URI List. +UI_BASE_EXPORT std::vector<std::string> ParseURIList(const SelectionData& data); UI_BASE_EXPORT std::string RefCountedMemoryToString( const scoped_refptr<base::RefCountedMemory>& memory); |