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

Side by Side Diff: chrome/browser/ui/views/select_file_dialog_extension_views.cc

Issue 10798011: views: Add a cross-platform SelectFileDialogExtension API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixes Created 8 years, 5 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "chrome/browser/ui/views/select_file_dialog_extension_views.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/logging.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/singleton.h"
12 #include "base/message_loop.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/chromeos/extensions/file_browser_private_api.h"
15 #include "chrome/browser/chromeos/extensions/file_manager_util.h"
16 #include "chrome/browser/extensions/extension_host.h"
17 #include "chrome/browser/extensions/extension_service.h"
18 #include "chrome/browser/extensions/shell_window_registry.h"
19 #include "chrome/browser/profiles/profile_manager.h"
20 #include "chrome/browser/sessions/restore_tab_helper.h"
21 #include "chrome/browser/ui/base_window.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/browser_finder.h"
24 #include "chrome/browser/ui/browser_list.h"
25 #include "chrome/browser/ui/browser_tabstrip.h"
26 #include "chrome/browser/ui/browser_window.h"
27 #include "chrome/browser/ui/chrome_select_file_policy.h"
28 #include "chrome/browser/ui/extensions/shell_window.h"
29 #include "chrome/browser/ui/select_file_dialog_extension.h"
30 #include "chrome/browser/ui/tab_contents/tab_contents.h"
31 #include "chrome/browser/ui/views/extensions/extension_dialog.h"
32 #include "content/public/browser/browser_thread.h"
33 #include "ui/base/dialogs/selected_file_info.h"
34
35 using content::BrowserThread;
36
37 namespace {
38
39 const int kFileManagerWidth = 954; // pixels
40 const int kFileManagerHeight = 640; // pixels
41
42 const int kFileManagerMinimumWidth = kFileManagerWidth * 2 / 3; // pixels
43 const int kFileManagerMinimumHeight = kFileManagerHeight * 2 / 3; // pixels
44
45 // Holds references to file manager dialogs that have callbacks pending
46 // to their listeners.
47 class PendingDialog {
48 public:
49 static PendingDialog* GetInstance();
50 void Add(int32 tab_id, scoped_refptr<SelectFileDialogExtensionViews> dialog);
51 void Remove(int32 tab_id);
52 scoped_refptr<SelectFileDialogExtensionViews> Find(int32 tab_id);
53
54 private:
55 friend struct DefaultSingletonTraits<PendingDialog>;
56 typedef std::map<int32, scoped_refptr<SelectFileDialogExtensionViews> > Map;
57 Map map_;
58 };
59
60 // static
61 PendingDialog* PendingDialog::GetInstance() {
62 return Singleton<PendingDialog>::get();
63 }
64
65 void PendingDialog::Add(int32 tab_id,
66 scoped_refptr<SelectFileDialogExtensionViews> dialog) {
67 DCHECK(dialog);
68 if (map_.find(tab_id) == map_.end())
69 map_.insert(std::make_pair(tab_id, dialog));
70 else
71 DLOG(WARNING) << "Duplicate pending dialog " << tab_id;
72 }
73
74 void PendingDialog::Remove(int32 tab_id) {
75 map_.erase(tab_id);
76 }
77
78 scoped_refptr<SelectFileDialogExtensionViews> PendingDialog::Find(
79 int32 tab_id) {
80 Map::const_iterator it = map_.find(tab_id);
81 if (it == map_.end())
82 return NULL;
83 return it->second;
84 }
85
86 } // namespace
87
88 /////////////////////////////////////////////////////////////////////////////
89
90 // TODO(jamescook): Move this into a new file shell_dialogs_chromeos.cc
91 // TODO(jamescook): Change all instances of SelectFileDialog::Create to return
92 // scoped_refptr<SelectFileDialog> as object is ref-counted.
93 // static
94 SelectFileDialogExtension* SelectFileDialogExtension::Create(
95 Listener* listener,
96 ui::SelectFilePolicy* policy) {
97 return new SelectFileDialogExtension(listener, policy);
98 }
99
100 // static
101 void SelectFileDialogExtensionViews::OnFileSelected(
102 int32 tab_id,
103 const ui::SelectedFileInfo& file,
104 int index) {
105 scoped_refptr<SelectFileDialogExtensionViews> dialog =
106 PendingDialog::GetInstance()->Find(tab_id);
107 if (!dialog)
108 return;
109 dialog->selection_type_ = SINGLE_FILE;
110 dialog->selection_files_.clear();
111 dialog->selection_files_.push_back(file);
112 dialog->selection_index_ = index;
113 }
114
115 // static
116 void SelectFileDialogExtensionViews::OnMultiFilesSelected(
117 int32 tab_id,
118 const std::vector<ui::SelectedFileInfo>& files) {
119 scoped_refptr<SelectFileDialogExtensionViews> dialog =
120 PendingDialog::GetInstance()->Find(tab_id);
121 if (!dialog)
122 return;
123 dialog->selection_type_ = MULTIPLE_FILES;
124 dialog->selection_files_ = files;
125 dialog->selection_index_ = 0;
126 }
127
128 // static
129 void SelectFileDialogExtensionViews::OnFileSelectionCanceled(int32 tab_id) {
130 scoped_refptr<SelectFileDialogExtensionViews> dialog =
131 PendingDialog::GetInstance()->Find(tab_id);
132 if (!dialog)
133 return;
134 dialog->selection_type_ = CANCEL;
135 dialog->selection_files_.clear();
136 dialog->selection_index_ = 0;
137 }
138
139 bool SelectFileDialogExtensionViews::IsRunning(
140 gfx::NativeWindow owner_window) const {
141 return owner_window_ == owner_window;
142 }
143
144 void SelectFileDialogExtensionViews::ListenerDestroyed() {
145 listener_ = NULL;
146 params_ = NULL;
147 PendingDialog::GetInstance()->Remove(tab_id_);
148 }
149
150 void SelectFileDialogExtensionViews::ExtensionDialogClosing(
151 ExtensionDialog* dialog) {
152 profile_ = NULL;
153 owner_window_ = NULL;
154 // Release our reference to the dialog to allow it to close.
155 extension_dialog_ = NULL;
156 PendingDialog::GetInstance()->Remove(tab_id_);
157 // Actually invoke the appropriate callback on our listener.
158 NotifyListener();
159 }
160
161 void SelectFileDialogExtensionViews::ExtensionTerminated(
162 ExtensionDialog* dialog) {
163 // The extension would have been unloaded because of the termination,
164 // reload it.
165 std::string extension_id = dialog->host()->extension()->id();
166 // Reload the extension after a bit; the extension may not have been unloaded
167 // yet. We don't want to try to reload the extension only to have the Unload
168 // code execute after us and re-unload the extension.
169 //
170 // TODO(rkc): This is ugly. The ideal solution is that we shouldn't need to
171 // reload the extension at all - when we try to open the extension the next
172 // time, the extension subsystem would automatically reload it for us. At
173 // this time though this is broken because of some faulty wiring in
174 // ExtensionProcessManager::CreateViewHost. Once that is fixed, remove this.
175 if (profile_) {
176 MessageLoop::current()->PostTask(FROM_HERE,
177 base::Bind(&ExtensionService::ReloadExtension,
178 base::Unretained(profile_->GetExtensionService()),
179 extension_id));
180 }
181
182 dialog->Close();
183 }
184
185 content::RenderViewHost* SelectFileDialogExtensionViews::GetRenderViewHost() {
186 if (extension_dialog_)
187 return extension_dialog_->host()->render_view_host();
188 return NULL;
189 }
190
191 void SelectFileDialogExtensionViews::NotifyListener() {
192 if (!listener_)
193 return;
194 switch (selection_type_) {
195 case CANCEL:
196 listener_->FileSelectionCanceled(params_);
197 break;
198 case SINGLE_FILE:
199 listener_->FileSelectedWithExtraInfo(selection_files_[0],
200 selection_index_,
201 params_);
202 break;
203 case MULTIPLE_FILES:
204 listener_->MultiFilesSelectedWithExtraInfo(selection_files_, params_);
205 break;
206 default:
207 NOTREACHED();
208 break;
209 }
210 }
211
212 void SelectFileDialogExtensionViews::AddPending(int32 tab_id) {
213 PendingDialog::GetInstance()->Add(tab_id, this);
214 }
215
216 // static
217 bool SelectFileDialogExtensionViews::PendingExists(int32 tab_id) {
218 return PendingDialog::GetInstance()->Find(tab_id) != NULL;
219 }
220
221 bool SelectFileDialogExtensionViews::HasMultipleFileTypeChoicesImpl() {
222 return has_multiple_file_type_choices_;
223 }
224
225 void SelectFileDialogExtensionViews::SelectFileImpl(
226 Type type,
227 const string16& title,
228 const FilePath& default_path,
229 const FileTypeInfo* file_types,
230 int file_type_index,
231 const FilePath::StringType& default_extension,
232 gfx::NativeWindow owner_window,
233 void* params) {
234 if (owner_window_) {
235 LOG(ERROR) << "File dialog already in use!";
236 return;
237 }
238
239 // The base window to associate the dialog with.
240 BaseWindow* base_window = NULL;
241
242 // The tab contents to associate the dialog with.
243 const TabContents* tab = NULL;
244
245 // First try to find a Browser using the supplied owner_window. If no owner
246 // window has been supplied, this is running from a background page and should
247 // be associated with the last active browser.
248 Browser* owner_browser = (owner_window ?
249 browser::FindBrowserWithWindow(owner_window) :
250 BrowserList::GetLastActive());
251 if (owner_browser) {
252 base_window = owner_browser->window();
253 tab = chrome::GetActiveTabContents(owner_browser);
254 profile_ = tab->profile();
255 } else if (owner_window) {
256 // If an owner_window was supplied but we couldn't find a browser, this
257 // could be for a shell window.
258 // TODO(benwells): Find a better way to get a shell window from a native
259 // window.
260 std::vector<Profile*> profiles =
261 g_browser_process->profile_manager()->GetLoadedProfiles();
262 for (std::vector<Profile*>::const_iterator i(profiles.begin());
263 i < profiles.end(); ++i) {
264 ShellWindowRegistry* registry = ShellWindowRegistry::Get(*i);
265 DCHECK(registry);
266 ShellWindow* shell_window = registry->GetShellWindowForNativeWindow(
267 owner_window);
268 if (shell_window) {
269 base_window = shell_window;
270 tab = shell_window->tab_contents();
271 profile_ = *i;
272 break;
273 }
274 }
275 }
276
277 if (!base_window) {
278 NOTREACHED() << "Can't find owning window.";
279 return;
280 }
281 DCHECK(profile_);
282
283 // Check if we have another dialog opened in the tab. It's unlikely, but
284 // possible. If there is no tab contents use a tab_id of 0. A dialog without
285 // an associated tab contents will be shown fully screen; only one at a time
286 // is allowed in this state.
287 int32 tab_id = tab ? tab->restore_tab_helper()->session_id().id() : 0;
288 if (PendingExists(tab_id)) {
289 DLOG(WARNING) << "Pending dialog exists with id " << tab_id;
290 return;
291 }
292
293 FilePath virtual_path;
294 if (file_manager_util::ConvertFileToRelativeFileSystemPath(
295 profile_, default_path, &virtual_path)) {
296 virtual_path = FilePath("/").Append(virtual_path);
297 } else {
298 virtual_path = default_path.BaseName();
299 }
300
301 has_multiple_file_type_choices_ =
302 file_types ? file_types->extensions.size() > 1 : true;
303
304 GURL file_browser_url = file_manager_util::GetFileBrowserUrlWithParams(
305 type, title, virtual_path, file_types, file_type_index,
306 default_extension);
307
308 ExtensionDialog* dialog = ExtensionDialog::Show(file_browser_url,
309 base_window, profile_, tab->web_contents(),
310 kFileManagerWidth, kFileManagerHeight,
311 #if defined(USE_AURA)
312 file_manager_util::GetTitleFromType(type),
313 #else
314 // HTML-based header used.
315 string16(),
316 #endif
317 this /* ExtensionDialog::Observer */);
318 if (!dialog) {
319 LOG(ERROR) << "Unable to create extension dialog";
320 return;
321 }
322
323 dialog->SetMinimumContentsSize(kFileManagerMinimumWidth,
324 kFileManagerMinimumHeight);
325
326 // Connect our listener to FileDialogFunction's per-tab callbacks.
327 AddPending(tab_id);
328
329 extension_dialog_ = dialog;
330 params_ = params;
331 tab_id_ = tab_id;
332 owner_window_ = owner_window;
333 }
334
335 SelectFileDialogExtensionViews::SelectFileDialogExtensionViews(
336 Listener* listener,
337 ui::SelectFilePolicy* policy)
338 : SelectFileDialog(listener, policy),
339 has_multiple_file_type_choices_(false),
340 tab_id_(0),
341 profile_(NULL),
342 owner_window_(NULL),
343 selection_type_(CANCEL),
344 selection_index_(0),
345 params_(NULL) {
346 }
347
348 SelectFileDialogExtensionViews::~SelectFileDialogExtensionViews() {
349 if (extension_dialog_)
350 extension_dialog_->ObserverDestroyed();
351 }
352
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698