Commit e8df1350 authored by erg@chromium.org's avatar erg@chromium.org

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
parent ae0d6f6a
...@@ -139,12 +139,25 @@ void OSExchangeDataProviderAuraX11::SetURL(const GURL& url, ...@@ -139,12 +139,25 @@ void OSExchangeDataProviderAuraX11::SetURL(const GURL& url,
} }
void OSExchangeDataProviderAuraX11::SetFilename(const base::FilePath& path) { 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( void OSExchangeDataProviderAuraX11::SetFilenames(
const std::vector<OSExchangeData::FileInfo>& filenames) { 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( void OSExchangeDataProviderAuraX11::SetPickledData(
...@@ -207,21 +220,16 @@ bool OSExchangeDataProviderAuraX11::GetURLAndTitle( ...@@ -207,21 +220,16 @@ bool OSExchangeDataProviderAuraX11::GetURLAndTitle(
} }
} else if (data.GetType() == atom_cache_.GetAtom( } else if (data.GetType() == atom_cache_.GetAtom(
Clipboard::kMimeTypeURIList)) { Clipboard::kMimeTypeURIList)) {
// uri-lists are newline separated file lists in URL encoding. std::vector<std::string> tokens = ui::ParseURIList(data);
std::string unparsed; for (std::vector<std::string>::const_iterator it = tokens.begin();
data.AssignTo(&unparsed); it != tokens.end(); ++it) {
GURL test_url(*it);
std::vector<std::string> tokens; if (!test_url.SchemeIsFile()) {
size_t num_tokens = Tokenize(unparsed, "\n", &tokens); *url = test_url;
if (!num_tokens) { *title = base::string16();
NOTREACHED() << "Empty URI list"; return true;
return false; }
} }
*url = GURL(tokens[0]);
*title = base::string16();
return true;
} }
} }
...@@ -229,14 +237,37 @@ bool OSExchangeDataProviderAuraX11::GetURLAndTitle( ...@@ -229,14 +237,37 @@ bool OSExchangeDataProviderAuraX11::GetURLAndTitle(
} }
bool OSExchangeDataProviderAuraX11::GetFilename(base::FilePath* path) const { 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; return false;
} }
bool OSExchangeDataProviderAuraX11::GetFilenames( bool OSExchangeDataProviderAuraX11::GetFilenames(
std::vector<OSExchangeData::FileInfo>* filenames) const { std::vector<OSExchangeData::FileInfo>* filenames) const {
// On X11, files are passed by URL and aren't separate. std::vector< ::Atom> url_atoms = ui::GetURIListAtomsFrom(&atom_cache_);
return false; 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( bool OSExchangeDataProviderAuraX11::GetPickledData(
...@@ -268,11 +299,56 @@ bool OSExchangeDataProviderAuraX11::HasURL() const { ...@@ -268,11 +299,56 @@ bool OSExchangeDataProviderAuraX11::HasURL() const {
std::vector< ::Atom> url_atoms = ui::GetURLAtomsFrom(&atom_cache_); std::vector< ::Atom> url_atoms = ui::GetURLAtomsFrom(&atom_cache_);
std::vector< ::Atom> requested_types; std::vector< ::Atom> requested_types;
ui::GetAtomIntersection(url_atoms, GetTargets(), &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 { 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; return false;
} }
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
namespace ui { namespace ui {
class Clipboard; class Clipboard;
class OSExchangeDataProviderAuraX11Test;
// OSExchangeData::Provider implementation for aura on linux. // OSExchangeData::Provider implementation for aura on linux.
class UI_BASE_EXPORT OSExchangeDataProviderAuraX11 class UI_BASE_EXPORT OSExchangeDataProviderAuraX11
...@@ -90,6 +91,7 @@ class UI_BASE_EXPORT OSExchangeDataProviderAuraX11 ...@@ -90,6 +91,7 @@ class UI_BASE_EXPORT OSExchangeDataProviderAuraX11
virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE; virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE;
private: private:
friend class OSExchangeDataProviderAuraX11Test;
typedef std::map<OSExchangeData::CustomFormat, Pickle> PickleData; typedef std::map<OSExchangeData::CustomFormat, Pickle> PickleData;
// Returns true if |formats_| contains a string format and the string can be // Returns true if |formats_| contains a string format and the string can be
......
...@@ -14,13 +14,33 @@ ...@@ -14,13 +14,33 @@
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.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 kGoogleTitle[] = "Google";
const char kGoogleURL[] = "http://www.google.com/"; 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; base::MessageLoopForUI message_loop;
ui::OSExchangeDataProviderAuraX11 provider; ui::OSExchangeDataProviderAuraX11 provider;
};
TEST_F(OSExchangeDataProviderAuraX11Test, MozillaURL) {
// Check that we can get titled entries. // Check that we can get titled entries.
provider.SetURL(GURL(kGoogleURL), base::ASCIIToUTF16(kGoogleTitle)); provider.SetURL(GURL(kGoogleURL), base::ASCIIToUTF16(kGoogleTitle));
{ {
...@@ -41,3 +61,39 @@ TEST(OSExchangeDataProviderAuraX11Test, MozillaURL) { ...@@ -41,3 +61,39 @@ TEST(OSExchangeDataProviderAuraX11Test, MozillaURL) {
EXPECT_EQ(kGoogleURL, out_gurl.spec()); 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
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/i18n/icu_string_conversions.h" #include "base/i18n/icu_string_conversions.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "ui/base/clipboard/clipboard.h" #include "ui/base/clipboard/clipboard.h"
#include "ui/base/x/x11_util.h" #include "ui/base/x/x11_util.h"
...@@ -43,6 +44,12 @@ std::vector< ::Atom> GetURLAtomsFrom(const X11AtomCache* atom_cache) { ...@@ -43,6 +44,12 @@ std::vector< ::Atom> GetURLAtomsFrom(const X11AtomCache* atom_cache) {
return atoms; 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, void GetAtomIntersection(const std::vector< ::Atom>& desired,
const std::vector< ::Atom>& offered, const std::vector< ::Atom>& offered,
std::vector< ::Atom>* output) { std::vector< ::Atom>* output) {
...@@ -62,6 +69,16 @@ void AddString16ToVector(const base::string16& str, ...@@ -62,6 +69,16 @@ void AddString16ToVector(const base::string16& str,
bytes->insert(bytes->end(), front, front + (str.size() * 2)); 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( std::string RefCountedMemoryToString(
const scoped_refptr<base::RefCountedMemory>& memory) { const scoped_refptr<base::RefCountedMemory>& memory) {
if (!memory.get()) { if (!memory.get()) {
......
...@@ -34,14 +34,20 @@ UI_BASE_EXPORT std::vector< ::Atom> GetTextAtomsFrom( ...@@ -34,14 +34,20 @@ UI_BASE_EXPORT std::vector< ::Atom> GetTextAtomsFrom(
UI_BASE_EXPORT std::vector< ::Atom> GetURLAtomsFrom( UI_BASE_EXPORT std::vector< ::Atom> GetURLAtomsFrom(
const X11AtomCache* atom_cache); const X11AtomCache* atom_cache);
UI_BASE_EXPORT std::vector< ::Atom> GetURIListAtomsFrom(
const X11AtomCache* atom_cache);
// Places the intersection of |desired| and |offered| into |output|. // Places the intersection of |desired| and |offered| into |output|.
UI_BASE_EXPORT void GetAtomIntersection(const std::vector< ::Atom>& desired, UI_BASE_EXPORT void GetAtomIntersection(const std::vector< ::Atom>& desired,
const std::vector< ::Atom>& offered, const std::vector< ::Atom>& offered,
std::vector< ::Atom>* output); std::vector< ::Atom>* output);
// Takes the raw bytes of the base::string16 and copies them into |bytes|. // Takes the raw bytes of the base::string16 and copies them into |bytes|.
UI_BASE_EXPORT void AddString16ToVector(const base::string16& str, 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( UI_BASE_EXPORT std::string RefCountedMemoryToString(
const scoped_refptr<base::RefCountedMemory>& memory); const scoped_refptr<base::RefCountedMemory>& memory);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment