• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4 
5 #include "tests/cefclient/browser/dialog_test.h"
6 
7 #include <string>
8 
9 #include "include/cef_browser.h"
10 #include "include/wrapper/cef_helpers.h"
11 #include "tests/cefclient/browser/test_runner.h"
12 #include "tests/shared/browser/file_util.h"
13 
14 namespace client {
15 namespace dialog_test {
16 
17 namespace {
18 
19 const char kTestUrlPath[] = "/dialogs";
20 const char kFileOpenMessageName[] = "DialogTest.FileOpen";
21 const char kFileOpenMultipleMessageName[] = "DialogTest.FileOpenMultiple";
22 const char kFileOpenFolderMessageName[] = "DialogTest.FileOpenFolder";
23 const char kFileSaveMessageName[] = "DialogTest.FileSave";
24 
25 // Store persistent dialog state information.
26 class DialogState : public base::RefCountedThreadSafe<DialogState> {
27  public:
DialogState()28   DialogState()
29       : mode_(FILE_DIALOG_OPEN), last_selected_filter_(0), pending_(false) {}
30 
31   cef_file_dialog_mode_t mode_;
32   int last_selected_filter_;
33   CefString last_file_;
34   bool pending_;
35 
36   DISALLOW_COPY_AND_ASSIGN(DialogState);
37 };
38 
39 // Callback executed when the file dialog is dismissed.
40 class DialogCallback : public CefRunFileDialogCallback {
41  public:
DialogCallback(CefRefPtr<CefMessageRouterBrowserSide::Callback> router_callback,scoped_refptr<DialogState> dialog_state)42   DialogCallback(
43       CefRefPtr<CefMessageRouterBrowserSide::Callback> router_callback,
44       scoped_refptr<DialogState> dialog_state)
45       : router_callback_(router_callback), dialog_state_(dialog_state) {}
46 
OnFileDialogDismissed(int last_selected_filter,const std::vector<CefString> & file_paths)47   virtual void OnFileDialogDismissed(
48       int last_selected_filter,
49       const std::vector<CefString>& file_paths) override {
50     CEF_REQUIRE_UI_THREAD();
51     DCHECK(dialog_state_->pending_);
52 
53     if (!file_paths.empty()) {
54       if (dialog_state_->mode_ != FILE_DIALOG_OPEN_FOLDER)
55         dialog_state_->last_selected_filter_ = last_selected_filter;
56 
57       dialog_state_->last_file_ = file_paths[0];
58       if (dialog_state_->mode_ == FILE_DIALOG_OPEN_FOLDER) {
59         std::string last_file = dialog_state_->last_file_;
60         if (last_file[last_file.length() - 1] != file_util::kPathSep) {
61           // Add a trailing slash so we know it's a directory. Otherwise, file
62           // dialogs will think the last path component is a file name.
63           last_file += file_util::kPathSep;
64           dialog_state_->last_file_ = last_file;
65         }
66       }
67     }
68 
69     // Send a message back to the render process with the list of file paths.
70     std::string response;
71     for (int i = 0; i < static_cast<int>(file_paths.size()); ++i) {
72       if (!response.empty())
73         response += "|";  // Use a delimiter disallowed in file paths.
74       response += file_paths[i];
75     }
76 
77     router_callback_->Success(response);
78     router_callback_ = nullptr;
79 
80     dialog_state_->pending_ = false;
81     dialog_state_ = nullptr;
82   }
83 
84  private:
85   CefRefPtr<CefMessageRouterBrowserSide::Callback> router_callback_;
86   scoped_refptr<DialogState> dialog_state_;
87 
88   IMPLEMENT_REFCOUNTING(DialogCallback);
89   DISALLOW_COPY_AND_ASSIGN(DialogCallback);
90 };
91 
92 // Handle messages in the browser process.
93 class Handler : public CefMessageRouterBrowserSide::Handler {
94  public:
Handler()95   Handler() {}
96 
97   // Called due to cefQuery execution in dialogs.html.
OnQuery(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int64 query_id,const CefString & request,bool persistent,CefRefPtr<Callback> callback)98   virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
99                        CefRefPtr<CefFrame> frame,
100                        int64 query_id,
101                        const CefString& request,
102                        bool persistent,
103                        CefRefPtr<Callback> callback) override {
104     CEF_REQUIRE_UI_THREAD();
105 
106     // Only handle messages from the test URL.
107     const std::string& url = frame->GetURL();
108     if (!test_runner::IsTestURL(url, kTestUrlPath))
109       return false;
110 
111     if (!dialog_state_.get())
112       dialog_state_ = new DialogState;
113 
114     // Make sure we're only running one dialog at a time.
115     DCHECK(!dialog_state_->pending_);
116 
117     std::vector<CefString> accept_filters;
118     std::string title;
119 
120     const std::string& message_name = request;
121     if (message_name == kFileOpenMessageName) {
122       dialog_state_->mode_ = FILE_DIALOG_OPEN;
123       title = "My Open Dialog";
124     } else if (message_name == kFileOpenMultipleMessageName) {
125       dialog_state_->mode_ = FILE_DIALOG_OPEN_MULTIPLE;
126       title = "My Open Multiple Dialog";
127     } else if (message_name == kFileOpenFolderMessageName) {
128       dialog_state_->mode_ = FILE_DIALOG_OPEN_FOLDER;
129       title = "My Open Folder Dialog";
130     } else if (message_name == kFileSaveMessageName) {
131       dialog_state_->mode_ = static_cast<cef_file_dialog_mode_t>(
132           FILE_DIALOG_SAVE | FILE_DIALOG_OVERWRITEPROMPT_FLAG);
133       title = "My Save Dialog";
134     } else {
135       NOTREACHED();
136       return true;
137     }
138 
139     if (dialog_state_->mode_ != FILE_DIALOG_OPEN_FOLDER) {
140       // Build filters based on mime time.
141       accept_filters.push_back("text/*");
142 
143       // Build filters based on file extension.
144       accept_filters.push_back(".log");
145       accept_filters.push_back(".patch");
146 
147       // Add specific filters as-is.
148       accept_filters.push_back("Document Files|.doc;.odt");
149       accept_filters.push_back("Image Files|.png;.jpg;.gif");
150       accept_filters.push_back("PDF Files|.pdf");
151     }
152 
153     dialog_state_->pending_ = true;
154 
155     browser->GetHost()->RunFileDialog(
156         dialog_state_->mode_, title, dialog_state_->last_file_, accept_filters,
157         dialog_state_->last_selected_filter_,
158         new DialogCallback(callback, dialog_state_));
159 
160     return true;
161   }
162 
163  private:
164   scoped_refptr<DialogState> dialog_state_;
165 
166   DISALLOW_COPY_AND_ASSIGN(Handler);
167 };
168 
169 }  // namespace
170 
CreateMessageHandlers(test_runner::MessageHandlerSet & handlers)171 void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) {
172   handlers.insert(new Handler());
173 }
174 
175 }  // namespace dialog_test
176 }  // namespace client
177