Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(830)

Side by Side Diff: win8/metro_driver/file_picker_ash.cc

Issue 1586843002: Remove remote tree host and some related input and metro_driver code (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@metro-mode-3
Patch Set: remove ash_unittests from being run Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « win8/metro_driver/file_picker_ash.h ('k') | win8/metro_driver/metro_driver.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stddef.h>
6 #include <stdint.h>
7
8 #include "stdafx.h"
9 #include "win8/metro_driver/file_picker_ash.h"
10
11 #include "base/bind.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/win/scoped_comptr.h"
18 #include "ui/metro_viewer/metro_viewer_messages.h"
19 #include "win8/metro_driver/chrome_app_view_ash.h"
20 #include "win8/metro_driver/winrt_utils.h"
21
22 namespace {
23
24 typedef winfoundtn::Collections::IVector<HSTRING> StringVectorItf;
25
26 // TODO(siggi): Complete this implementation and move it to a common place.
27 class StringVectorImpl : public mswr::RuntimeClass<StringVectorItf> {
28 public:
29 ~StringVectorImpl() override {
30 std::for_each(strings_.begin(), strings_.end(), ::WindowsDeleteString);
31 }
32
33 HRESULT RuntimeClassInitialize(const std::vector<base::string16>& list) {
34 for (size_t i = 0; i < list.size(); ++i)
35 strings_.push_back(MakeHString(list[i]));
36
37 return S_OK;
38 }
39
40 // IVector<HSTRING> implementation.
41 STDMETHOD(GetAt)(unsigned index, HSTRING* item) override {
42 if (index >= strings_.size())
43 return E_INVALIDARG;
44
45 return ::WindowsDuplicateString(strings_[index], item);
46 }
47 STDMETHOD(get_Size)(unsigned* size) override {
48 if (strings_.size() > UINT_MAX)
49 return E_UNEXPECTED;
50 *size = static_cast<unsigned>(strings_.size());
51 return S_OK;
52 }
53 STDMETHOD(GetView)(
54 winfoundtn::Collections::IVectorView<HSTRING>** view) override {
55 return E_NOTIMPL;
56 }
57 STDMETHOD(IndexOf)(HSTRING value, unsigned* index, boolean* found) override {
58 return E_NOTIMPL;
59 }
60
61 // write methods
62 STDMETHOD(SetAt)(unsigned index, HSTRING item) override { return E_NOTIMPL; }
63 STDMETHOD(InsertAt)(unsigned index, HSTRING item) override {
64 return E_NOTIMPL;
65 }
66 STDMETHOD(RemoveAt)(unsigned index) override { return E_NOTIMPL; }
67 STDMETHOD(Append)(HSTRING item) override { return E_NOTIMPL; }
68 STDMETHOD(RemoveAtEnd)() override { return E_NOTIMPL; }
69 STDMETHOD(Clear)() override { return E_NOTIMPL; }
70
71 private:
72 std::vector<HSTRING> strings_;
73 };
74
75 } // namespace
76
77 FilePickerSessionBase::~FilePickerSessionBase() {
78 }
79
80 bool FilePickerSessionBase::Run() {
81 if (!DoFilePicker())
82 return false;
83 return success_;
84 }
85
86 FilePickerSessionBase::FilePickerSessionBase(ChromeAppViewAsh* app_view,
87 const base::string16& title,
88 const base::string16& filter,
89 const base::FilePath& default_path)
90 : success_(false),
91 title_(title),
92 filter_(filter),
93 default_path_(default_path),
94 app_view_(app_view) {
95 }
96
97 bool FilePickerSessionBase::DoFilePicker() {
98 // The file picker will fail if spawned from a snapped application,
99 // so let's attempt to unsnap first if we're in that state.
100 HRESULT hr = ChromeAppViewAsh::Unsnap();
101 if (FAILED(hr)) {
102 LOG(ERROR) << "Failed to unsnap for file picker, error 0x" << hr;
103 return false;
104 }
105 hr = StartFilePicker();
106 if (FAILED(hr)) {
107 LOG(ERROR) << "Failed to start file picker, error 0x"
108 << std::hex << hr;
109 return false;
110 }
111 return true;
112 }
113
114 OpenFilePickerSession::OpenFilePickerSession(
115 ChromeAppViewAsh* app_view,
116 const base::string16& title,
117 const base::string16& filter,
118 const base::FilePath& default_path,
119 bool allow_multi_select)
120 : FilePickerSessionBase(app_view, title, filter, default_path),
121 allow_multi_select_(allow_multi_select) {
122 }
123
124 OpenFilePickerSession::~OpenFilePickerSession() {
125 }
126
127 HRESULT OpenFilePickerSession::SinglePickerDone(SingleFileAsyncOp* async,
128 AsyncStatus status) {
129 if (status == Completed) {
130 mswr::ComPtr<winstorage::IStorageFile> file;
131 HRESULT hr = async->GetResults(file.GetAddressOf());
132
133 if (file) {
134 mswr::ComPtr<winstorage::IStorageItem> storage_item;
135 if (SUCCEEDED(hr))
136 hr = file.As(&storage_item);
137
138 mswrw::HString file_path;
139 if (SUCCEEDED(hr))
140 hr = storage_item->get_Path(file_path.GetAddressOf());
141
142 if (SUCCEEDED(hr)) {
143 UINT32 path_len = 0;
144 const wchar_t* path_str =
145 ::WindowsGetStringRawBuffer(file_path.Get(), &path_len);
146
147 result_ = path_str;
148 success_ = true;
149 }
150 } else {
151 LOG(ERROR) << "NULL IStorageItem";
152 }
153 } else {
154 LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
155 }
156 app_view_->OnOpenFileCompleted(this, success_);
157 return S_OK;
158 }
159
160 HRESULT OpenFilePickerSession::MultiPickerDone(MultiFileAsyncOp* async,
161 AsyncStatus status) {
162 if (status == Completed) {
163 mswr::ComPtr<StorageFileVectorCollection> files;
164 HRESULT hr = async->GetResults(files.GetAddressOf());
165
166 if (files) {
167 base::string16 result;
168 if (SUCCEEDED(hr))
169 hr = ComposeMultiFileResult(files.Get(), &result);
170
171 if (SUCCEEDED(hr)) {
172 success_ = true;
173 // The code below has been copied from the
174 // SelectFileDialogImpl::RunOpenMultiFileDialog function in
175 // select_file_dialog_win.cc.
176 // TODO(ananta)
177 // Consolidate this into a common place.
178 const wchar_t* selection = result.c_str();
179 std::vector<base::FilePath> files;
180
181 while (*selection) { // Empty string indicates end of list.
182 files.push_back(base::FilePath(selection));
183 // Skip over filename and null-terminator.
184 selection += files.back().value().length() + 1;
185 }
186 if (files.empty()) {
187 success_ = false;
188 } else if (files.size() == 1) {
189 // When there is one file, it contains the path and filename.
190 filenames_ = files;
191 } else if (files.size() > 1) {
192 // Otherwise, the first string is the path, and the remainder are
193 // filenames.
194 std::vector<base::FilePath>::iterator path = files.begin();
195 for (std::vector<base::FilePath>::iterator file = path + 1;
196 file != files.end(); ++file) {
197 filenames_.push_back(path->Append(*file));
198 }
199 }
200 }
201 } else {
202 LOG(ERROR) << "NULL StorageFileVectorCollection";
203 }
204 } else {
205 LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
206 }
207 app_view_->OnOpenFileCompleted(this, success_);
208 return S_OK;
209 }
210
211 HRESULT OpenFilePickerSession::StartFilePicker() {
212 mswrw::HStringReference class_name(
213 RuntimeClass_Windows_Storage_Pickers_FileOpenPicker);
214
215 // Create the file picker.
216 mswr::ComPtr<winstorage::Pickers::IFileOpenPicker> picker;
217 HRESULT hr = ::Windows::Foundation::ActivateInstance(
218 class_name.Get(), picker.GetAddressOf());
219 CheckHR(hr);
220
221 // Set the file type filter
222 mswr::ComPtr<winfoundtn::Collections::IVector<HSTRING>> filter;
223 hr = picker->get_FileTypeFilter(filter.GetAddressOf());
224 if (FAILED(hr))
225 return hr;
226
227 if (filter_.empty()) {
228 hr = filter->Append(mswrw::HStringReference(L"*").Get());
229 if (FAILED(hr))
230 return hr;
231 } else {
232 // The filter is a concatenation of zero terminated string pairs,
233 // where each pair is {description, extension}. The concatenation ends
234 // with a zero length string - e.g. a double zero terminator.
235 const wchar_t* walk = filter_.c_str();
236 while (*walk != L'\0') {
237 // Walk past the description.
238 walk += wcslen(walk) + 1;
239
240 // We should have an extension, but bail on malformed filters.
241 if (*walk == L'\0')
242 break;
243
244 // There can be a single extension, or a list of semicolon-separated ones.
245 std::vector<base::string16> extensions_win32_style = base::SplitString(
246 walk, L";", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
247
248 // Metro wants suffixes only, not patterns.
249 mswrw::HString extension;
250 for (size_t i = 0; i < extensions_win32_style.size(); ++i) {
251 if (extensions_win32_style[i] == L"*.*") {
252 // The wildcard filter is "*" for Metro. The string "*.*" produces
253 // an "invalid parameter" error.
254 hr = extension.Set(L"*");
255 } else {
256 // Metro wants suffixes only, not patterns.
257 base::string16 ext =
258 base::FilePath(extensions_win32_style[i]).Extension();
259 if ((ext.size() < 2) ||
260 (ext.find_first_of(L"*?") != base::string16::npos)) {
261 continue;
262 }
263 hr = extension.Set(ext.c_str());
264 }
265 if (SUCCEEDED(hr))
266 hr = filter->Append(extension.Get());
267 if (FAILED(hr))
268 return hr;
269 }
270
271 // Walk past the extension.
272 walk += wcslen(walk) + 1;
273 }
274 }
275
276 // Spin up a single or multi picker as appropriate.
277 if (allow_multi_select_) {
278 mswr::ComPtr<MultiFileAsyncOp> completion;
279 hr = picker->PickMultipleFilesAsync(&completion);
280 if (FAILED(hr))
281 return hr;
282
283 // Create the callback method.
284 typedef winfoundtn::IAsyncOperationCompletedHandler<
285 StorageFileVectorCollection*> HandlerDoneType;
286 mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
287 this, &OpenFilePickerSession::MultiPickerDone));
288 DCHECK(handler.Get() != NULL);
289 hr = completion->put_Completed(handler.Get());
290
291 return hr;
292 } else {
293 mswr::ComPtr<SingleFileAsyncOp> completion;
294 hr = picker->PickSingleFileAsync(&completion);
295 if (FAILED(hr))
296 return hr;
297
298 // Create the callback method.
299 typedef winfoundtn::IAsyncOperationCompletedHandler<
300 winstorage::StorageFile*> HandlerDoneType;
301 mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
302 this, &OpenFilePickerSession::SinglePickerDone));
303 DCHECK(handler.Get() != NULL);
304 hr = completion->put_Completed(handler.Get());
305
306 return hr;
307 }
308 }
309
310 HRESULT OpenFilePickerSession::ComposeMultiFileResult(
311 StorageFileVectorCollection* files, base::string16* result) {
312 DCHECK(files != NULL);
313 DCHECK(result != NULL);
314
315 // Empty the output string.
316 result->clear();
317
318 unsigned int num_files = 0;
319 HRESULT hr = files->get_Size(&num_files);
320 if (FAILED(hr))
321 return hr;
322
323 // Make sure we return an error on an empty collection.
324 if (num_files == 0) {
325 DLOG(ERROR) << "Empty collection on input.";
326 return E_UNEXPECTED;
327 }
328
329 // This stores the base path that should be the parent of all the files.
330 base::FilePath base_path;
331
332 // Iterate through the collection and append the file paths to the result.
333 for (unsigned int i = 0; i < num_files; ++i) {
334 mswr::ComPtr<winstorage::IStorageFile> file;
335 hr = files->GetAt(i, file.GetAddressOf());
336 if (FAILED(hr))
337 return hr;
338
339 mswr::ComPtr<winstorage::IStorageItem> storage_item;
340 hr = file.As(&storage_item);
341 if (FAILED(hr))
342 return hr;
343
344 mswrw::HString file_path_str;
345 hr = storage_item->get_Path(file_path_str.GetAddressOf());
346 if (FAILED(hr))
347 return hr;
348
349 base::FilePath file_path(MakeStdWString(file_path_str.Get()));
350 if (base_path.empty()) {
351 DCHECK(result->empty());
352 base_path = file_path.DirName();
353
354 // Append the path, including the terminating zero.
355 // We do this only for the first file.
356 result->append(base_path.value().c_str(), base_path.value().size() + 1);
357 }
358 DCHECK(!result->empty());
359 DCHECK(!base_path.empty());
360 DCHECK(base_path == file_path.DirName());
361
362 // Append the base name, including the terminating zero.
363 base::FilePath base_name = file_path.BaseName();
364 result->append(base_name.value().c_str(), base_name.value().size() + 1);
365 }
366
367 DCHECK(!result->empty());
368
369 return S_OK;
370 }
371
372 SaveFilePickerSession::SaveFilePickerSession(
373 ChromeAppViewAsh* app_view,
374 const MetroViewerHostMsg_SaveAsDialogParams& params)
375 : FilePickerSessionBase(app_view,
376 params.title,
377 params.filter,
378 params.suggested_name),
379 filter_index_(params.filter_index) {
380 }
381
382 int SaveFilePickerSession::filter_index() const {
383 // TODO(ananta)
384 // Add support for returning the correct filter index. This does not work in
385 // regular Chrome metro on trunk as well.
386 // BUG: https://code.google.com/p/chromium/issues/detail?id=172704
387 return filter_index_;
388 }
389
390 HRESULT SaveFilePickerSession::StartFilePicker() {
391 mswrw::HStringReference class_name(
392 RuntimeClass_Windows_Storage_Pickers_FileSavePicker);
393
394 // Create the file picker.
395 mswr::ComPtr<winstorage::Pickers::IFileSavePicker> picker;
396 HRESULT hr = ::Windows::Foundation::ActivateInstance(
397 class_name.Get(), picker.GetAddressOf());
398 CheckHR(hr);
399
400 typedef winfoundtn::Collections::IMap<HSTRING, StringVectorItf*>
401 StringVectorMap;
402 mswr::ComPtr<StringVectorMap> choices;
403 hr = picker->get_FileTypeChoices(choices.GetAddressOf());
404 if (FAILED(hr))
405 return hr;
406
407 if (!filter_.empty()) {
408 // The filter is a concatenation of zero terminated string pairs,
409 // where each pair is {description, extension list}. The concatenation ends
410 // with a zero length string - e.g. a double zero terminator.
411 const wchar_t* walk = filter_.c_str();
412 while (*walk != L'\0') {
413 mswrw::HString description;
414 hr = description.Set(walk);
415 if (FAILED(hr))
416 return hr;
417
418 // Walk past the description.
419 walk += wcslen(walk) + 1;
420
421 // We should have an extension, but bail on malformed filters.
422 if (*walk == L'\0')
423 break;
424
425 // There can be a single extension, or a list of semicolon-separated ones.
426 std::vector<base::string16> extensions_win32_style = base::SplitString(
427 walk, L";", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
428
429 // Metro wants suffixes only, not patterns. Also, metro does not support
430 // the all files ("*") pattern in the save picker.
431 std::vector<base::string16> extensions;
432 for (size_t i = 0; i < extensions_win32_style.size(); ++i) {
433 base::string16 ext =
434 base::FilePath(extensions_win32_style[i]).Extension();
435 if ((ext.size() < 2) ||
436 (ext.find_first_of(L"*?") != base::string16::npos))
437 continue;
438 extensions.push_back(ext);
439 }
440
441 if (!extensions.empty()) {
442 // Convert to a Metro collection class.
443 mswr::ComPtr<StringVectorItf> list;
444 hr = mswr::MakeAndInitialize<StringVectorImpl>(
445 list.GetAddressOf(), extensions);
446 if (FAILED(hr))
447 return hr;
448
449 // Finally set the filter.
450 boolean replaced = FALSE;
451 hr = choices->Insert(description.Get(), list.Get(), &replaced);
452 if (FAILED(hr))
453 return hr;
454 DCHECK_EQ(FALSE, replaced);
455 }
456
457 // Walk past the extension(s).
458 walk += wcslen(walk) + 1;
459 }
460 }
461
462 // The save picker requires at least one choice. Callers are strongly advised
463 // to provide sensible choices. If none were given, fallback to .dat.
464 uint32_t num_choices = 0;
465 hr = choices->get_Size(&num_choices);
466 if (FAILED(hr))
467 return hr;
468
469 if (num_choices == 0) {
470 mswrw::HString description;
471 // TODO(grt): Get a properly translated string. This can't be done from
472 // within metro_driver. Consider preprocessing the filter list in Chrome
473 // land to ensure it has this entry if all others are patterns. In that
474 // case, this whole block of code can be removed.
475 hr = description.Set(L"Data File");
476 if (FAILED(hr))
477 return hr;
478
479 mswr::ComPtr<StringVectorItf> list;
480 hr = mswr::MakeAndInitialize<StringVectorImpl>(
481 list.GetAddressOf(), std::vector<base::string16>(1, L".dat"));
482 if (FAILED(hr))
483 return hr;
484
485 boolean replaced = FALSE;
486 hr = choices->Insert(description.Get(), list.Get(), &replaced);
487 if (FAILED(hr))
488 return hr;
489 DCHECK_EQ(FALSE, replaced);
490 }
491
492 if (!default_path_.empty()) {
493 base::string16 file_part = default_path_.BaseName().value();
494 // If the suggested_name is a root directory, then don't set it as the
495 // suggested name.
496 if (file_part.size() == 1 && file_part[0] == L'\\')
497 file_part.clear();
498 hr = picker->put_SuggestedFileName(
499 mswrw::HStringReference(file_part.c_str()).Get());
500 if (FAILED(hr))
501 return hr;
502 }
503
504 mswr::ComPtr<SaveFileAsyncOp> completion;
505 hr = picker->PickSaveFileAsync(&completion);
506 if (FAILED(hr))
507 return hr;
508
509 // Create the callback method.
510 typedef winfoundtn::IAsyncOperationCompletedHandler<
511 winstorage::StorageFile*> HandlerDoneType;
512 mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
513 this, &SaveFilePickerSession::FilePickerDone));
514 DCHECK(handler.Get() != NULL);
515 hr = completion->put_Completed(handler.Get());
516
517 return hr;
518 }
519
520 HRESULT SaveFilePickerSession::FilePickerDone(SaveFileAsyncOp* async,
521 AsyncStatus status) {
522 if (status == Completed) {
523 mswr::ComPtr<winstorage::IStorageFile> file;
524 HRESULT hr = async->GetResults(file.GetAddressOf());
525
526 if (file) {
527 mswr::ComPtr<winstorage::IStorageItem> storage_item;
528 if (SUCCEEDED(hr))
529 hr = file.As(&storage_item);
530
531 mswrw::HString file_path;
532 if (SUCCEEDED(hr))
533 hr = storage_item->get_Path(file_path.GetAddressOf());
534
535 if (SUCCEEDED(hr)) {
536 base::string16 path_str = MakeStdWString(file_path.Get());
537 result_ = path_str;
538 success_ = true;
539 }
540 } else {
541 LOG(ERROR) << "NULL IStorageItem";
542 }
543 } else {
544 LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
545 }
546 app_view_->OnSaveFileCompleted(this, success_);
547 return S_OK;
548 }
549
550 FolderPickerSession::FolderPickerSession(ChromeAppViewAsh* app_view,
551 const base::string16& title)
552 : FilePickerSessionBase(app_view, title, L"", base::FilePath()) {
553 }
554
555 HRESULT FolderPickerSession::StartFilePicker() {
556 mswrw::HStringReference class_name(
557 RuntimeClass_Windows_Storage_Pickers_FolderPicker);
558
559 // Create the folder picker.
560 mswr::ComPtr<winstorage::Pickers::IFolderPicker> picker;
561 HRESULT hr = ::Windows::Foundation::ActivateInstance(
562 class_name.Get(), picker.GetAddressOf());
563 CheckHR(hr);
564
565 // Set the file type filter
566 mswr::ComPtr<winfoundtn::Collections::IVector<HSTRING>> filter;
567 hr = picker->get_FileTypeFilter(filter.GetAddressOf());
568 if (FAILED(hr))
569 return hr;
570
571 hr = filter->Append(mswrw::HStringReference(L"*").Get());
572 if (FAILED(hr))
573 return hr;
574
575 mswr::ComPtr<FolderPickerAsyncOp> completion;
576 hr = picker->PickSingleFolderAsync(&completion);
577 if (FAILED(hr))
578 return hr;
579
580 // Create the callback method.
581 typedef winfoundtn::IAsyncOperationCompletedHandler<
582 winstorage::StorageFolder*> HandlerDoneType;
583 mswr::ComPtr<HandlerDoneType> handler(mswr::Callback<HandlerDoneType>(
584 this, &FolderPickerSession::FolderPickerDone));
585 DCHECK(handler.Get() != NULL);
586 hr = completion->put_Completed(handler.Get());
587 return hr;
588 }
589
590 HRESULT FolderPickerSession::FolderPickerDone(FolderPickerAsyncOp* async,
591 AsyncStatus status) {
592 if (status == Completed) {
593 mswr::ComPtr<winstorage::IStorageFolder> folder;
594 HRESULT hr = async->GetResults(folder.GetAddressOf());
595
596 if (folder) {
597 mswr::ComPtr<winstorage::IStorageItem> storage_item;
598 if (SUCCEEDED(hr))
599 hr = folder.As(&storage_item);
600
601 mswrw::HString file_path;
602 if (SUCCEEDED(hr))
603 hr = storage_item->get_Path(file_path.GetAddressOf());
604
605 if (SUCCEEDED(hr)) {
606 base::string16 path_str = MakeStdWString(file_path.Get());
607 result_ = path_str;
608 success_ = true;
609 }
610 } else {
611 LOG(ERROR) << "NULL IStorageItem";
612 }
613 } else {
614 LOG(ERROR) << "Unexpected async status " << static_cast<int>(status);
615 }
616 app_view_->OnFolderPickerCompleted(this, success_);
617 return S_OK;
618 }
619
OLDNEW
« no previous file with comments | « win8/metro_driver/file_picker_ash.h ('k') | win8/metro_driver/metro_driver.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698