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,
}
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;
}
......
......@@ -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
......
......@@ -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
......@@ -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()) {
......
......@@ -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);
......
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