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

Unified Diff: chrome/browser/cocoa/shell_dialogs_mac.mm

Issue 459008: Mac: the return of the tab-modal-sheets patch. (Closed)
Patch Set: Merged ToT. Must ... commit ... soon. Created 11 years 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/cocoa/constrained_window_mac.mm ('k') | chrome/browser/cocoa/tab_strip_controller.mm » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/cocoa/shell_dialogs_mac.mm
diff --git a/chrome/browser/cocoa/shell_dialogs_mac.mm b/chrome/browser/cocoa/shell_dialogs_mac.mm
index c1f0b98e8bb9401fee3c712a9382e88bc77263e1..3458983aa8c93967d08637443eb6268783d64283 100644
--- a/chrome/browser/cocoa/shell_dialogs_mac.mm
+++ b/chrome/browser/cocoa/shell_dialogs_mac.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -14,6 +14,8 @@
#include "base/scoped_cftyperef.h"
#import "base/scoped_nsobject.h"
#include "base/sys_string_conversions.h"
+#include "chrome/browser/cocoa/constrained_window_mac.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
static const int kFileTypePopupTag = 1234;
@@ -44,6 +46,9 @@ class SelectFileDialogImpl : public SelectFileDialog {
virtual bool IsRunning(gfx::NativeWindow parent_window) const;
virtual void ListenerDestroyed();
+ // BaseShellDialog override.
+ virtual bool IsRunningInTab(const TabContents* parent_tab) const;
+
// SelectFileDialog implementation.
// |params| is user data we pass back via the Listener interface.
virtual void SelectFile(Type type,
@@ -55,20 +60,45 @@ class SelectFileDialogImpl : public SelectFileDialog {
gfx::NativeWindow owning_window,
void* params);
- // Callback from ObjC bridge.
+ // SelectFileDialog override.
+ // |params| is user data we pass back via the Listener interface.
+ virtual void SelectFileInTab(Type type,
+ const string16& title,
+ const FilePath& default_path,
+ const FileTypeInfo* file_types,
+ int file_type_index,
+ const FilePath::StringType& default_extension,
+ TabContents* owning_tab,
+ void* params);
+
+ // Callbacks from ObjC bridge.
void FileWasSelected(NSPanel* dialog,
NSWindow* parent_window,
bool was_cancelled,
bool is_multi,
const std::vector<FilePath>& files,
int index);
+ void FileWasSelectedInTab(NSPanel* dialog,
+ TabContents* parent_tab,
+ bool was_cancelled,
+ bool was_killed,
+ bool is_multi,
+ const std::vector<FilePath>& files,
+ int index);
struct SheetContext {
Type type;
- NSWindow* owning_window;
+ NSWindow* owning_window; // Only one of |owning_...| should be non-NULL.
+ TabContents* owning_tab;
};
private:
+ void NotifyListenerOfFileSelection(bool was_cancelled,
+ bool is_multi,
+ const std::vector<FilePath>& files,
+ int index,
+ void* params);
+
// Gets the accessory view for the save dialog.
NSView* GetAccessoryView(const FileTypeInfo* file_types,
int file_type_index);
@@ -82,12 +112,101 @@ class SelectFileDialogImpl : public SelectFileDialog {
// A map from file dialogs to the |params| user data associated with them.
std::map<NSPanel*, void*> params_map_;
+ // A map from dialogs to constrained windows.
+ std::map<NSPanel*, ConstrainedWindow*> window_map_;
+
// The set of all parent windows for which we are currently running dialogs.
- std::set<NSWindow*> parents_;
+ std::set<NSWindow*> parent_windows_;
+
+ // The set of all parent tabs for which we are currently running sheets.
+ std::set<const TabContents*> parent_tabs_;
DISALLOW_COPY_AND_ASSIGN(SelectFileDialogImpl);
};
+// Class to create a select file sheet as a "constrained window" (i.e., sheet
+// attached to a tab).
+class SelectFileInTabDelegate
+ : public ConstrainedWindowMacDelegateSystemSheetParams {
+ public:
+ SelectFileInTabDelegate()
+ : ConstrainedWindowMacDelegateSystemSheetParams(nil) { }
+
+ void InitForSavePanel(NSSavePanel* sheet,
+ SelectFileDialogImpl* s,
+ NSString* directory,
+ NSString* file,
+ void* context) {
+ set_sheet(sheet);
+ // Note: we need NSValue's to guard against |directory|, etc. being nil.
+ NSArray* params = [NSArray arrayWithObjects:
+ [NSValue valueWithPointer:directory],
+ [NSValue valueWithPointer:file],
+ [NSNull null], // window, must be [NSNull null]
+ [[[SelectFileDialogBridge alloc]
+ initWithSelectFileDialogImpl:s] autorelease],
+ [NSValue valueWithPointer:@selector(endedPanel:withReturn:context:)],
+ [NSValue valueWithPointer:context],
+ nil];
+ set_params(params);
+ }
+
+ void InitForOpenPanel(NSOpenPanel* sheet,
+ SelectFileDialogImpl* s,
+ NSString* directory,
+ NSString* file,
+ NSArray* file_types,
+ void* context) {
+ set_sheet(sheet);
+ // Note: we need NSValue's to guard against |directory|, etc. being nil.
+ NSArray* params = [NSArray arrayWithObjects:
+ [NSValue valueWithPointer:directory],
+ [NSValue valueWithPointer:file],
+ [NSValue valueWithPointer:file_types],
+ [NSNull null], // window, must be [NSNull null]
+ [[[SelectFileDialogBridge alloc]
+ initWithSelectFileDialogImpl:s] autorelease],
+ [NSValue valueWithPointer:@selector(endedPanel:withReturn:context:)],
+ [NSValue valueWithPointer:context],
+ nil];
+ set_params(params);
+ }
+
+ // Implementation of method defined in ConstrainedWindowMacDelegate:
+ virtual void DeleteDelegate() {
+ if (is_sheet_open()) {
+ // Close sheet if it's still open; inform the end-sheet routine that it's
+ // being closed by the delegate, so it can avoid calling
+ // |CloseConstrainedWindow()| (which leads to an attempt to delete us
+ // again).
+ [NSApp endSheet:(NSSavePanel*)sheet()
+ returnCode:kClosedByDelegate];
+ }
+ delete this;
+ }
+
+ // Overridden from ConstrainedWindowMacDelegate:
+ virtual bool ParentWillDo(ConstrainedWindow::Event event) {
+ switch(event) {
+ case ConstrainedWindow::kEventNavigate:
+ // We don't want to close! (Note: typically, we *shouldn't* be
+ // navigating during file selection. However, this happens for open file
+ // dialogs run on very new tabs.
+ //TODO(viettrungluu): if we allow navigations, then we should close.
+ return true;
+
+ default:
+ break;
+ }
+ return false;
+ }
+
+ // Return value passed to the end-sheet routine to indicate that the sheet was
+ // ended by |DeleteDelegate()|. This just needs to be some value never used by
+ // Apple as a return value for the sheet.
+ static const int kClosedByDelegate = 658042027;
+};
+
// static
SelectFileDialog* SelectFileDialog::Create(Listener* listener) {
return new SelectFileDialogImpl(listener);
@@ -103,7 +222,11 @@ SelectFileDialogImpl::~SelectFileDialogImpl() {
}
bool SelectFileDialogImpl::IsRunning(gfx::NativeWindow parent_window) const {
- return parents_.find(parent_window) != parents_.end();
+ return (parent_windows_.find(parent_window) != parent_windows_.end());
+}
+
+bool SelectFileDialogImpl::IsRunningInTab(const TabContents* parent_tab) const {
+ return (parent_tabs_.find(parent_tab) != parent_tabs_.end());
}
void SelectFileDialogImpl::ListenerDestroyed() {
@@ -123,7 +246,8 @@ void SelectFileDialogImpl::SelectFile(
type == SELECT_OPEN_FILE ||
type == SELECT_OPEN_MULTI_FILE ||
type == SELECT_SAVEAS_FILE);
- parents_.insert(owning_window);
+
+ parent_windows_.insert(owning_window);
// Note: we need to retain the dialog as owning_window can be null.
// (see http://crbug.com/29213)
@@ -179,6 +303,7 @@ void SelectFileDialogImpl::SelectFile(
SheetContext* context = new SheetContext;
context->type = type;
context->owning_window = owning_window;
+ context->owning_tab = NULL;
if (type == SELECT_SAVEAS_FILE) {
[dialog beginSheetForDirectory:default_dir
@@ -208,21 +333,181 @@ void SelectFileDialogImpl::SelectFile(
types:allowed_file_types
modalForWindow:owning_window
modalDelegate:bridge_.get()
- didEndSelector:@selector(endedPanel:withReturn:context:)
+ didEndSelector:@selector(
+ endedPanel:withReturn:context:)
contextInfo:context];
}
}
-void SelectFileDialogImpl::FileWasSelected(NSPanel* dialog,
- NSWindow* parent_window,
- bool was_cancelled,
- bool is_multi,
- const std::vector<FilePath>& files,
- int index) {
+void SelectFileDialogImpl::SelectFileInTab(
+ Type type,
+ const string16& title,
+ const FilePath& default_path,
+ const FileTypeInfo* file_types,
+ int file_type_index,
+ const FilePath::StringType& default_extension,
+ TabContents* owning_tab,
+ void* params) {
+ // Go modeless if no |owning_tab|.
+ // TODO(viettrungluu): Despite the docs in shell_dialogs.h, we don't support
+ // this (see the TODO in SelectFile()).
+ if (!owning_tab) {
+ SelectFile(type, title, default_path, file_types, file_type_index,
+ default_extension, NULL, params);
+ return;
+ }
+
+ // This shouldn't be needed, but prevents crashing if someone calls us when
+ // there's already a constrained dialog.
+ if (!owning_tab->CanCreateConstrainedDialog()) {
+ // TODO(viettrungluu): This should be a NOTREACHED(), but it's annoying to
+ // have my browser constantly die.
+ LOG(WARNING) << "Not allowed to create constrained dialog.";
+
+ // Make sure the listener doesn't hang.
+ if (listener_)
+ listener_->FileSelectionCanceled(params);
+ return;
+ }
+
+ DCHECK(type == SELECT_FOLDER ||
+ type == SELECT_OPEN_FILE ||
+ type == SELECT_OPEN_MULTI_FILE ||
+ type == SELECT_SAVEAS_FILE);
+ parent_tabs_.insert(owning_tab);
+
+ NSSavePanel* dialog = (type == SELECT_SAVEAS_FILE) ? [NSSavePanel savePanel] :
+ [NSOpenPanel openPanel];
+
+ if (!title.empty())
+ [dialog setTitle:base::SysUTF16ToNSString(title)];
+
+ NSString* default_dir = nil;
+ NSString* default_filename = nil;
+ if (!default_path.empty()) {
+ default_dir = base::SysUTF8ToNSString(default_path.DirName().value());
+ default_filename = base::SysUTF8ToNSString(default_path.BaseName().value());
+ }
+
+ NSMutableArray* allowed_file_types = nil;
+ if (file_types) {
+ if (!file_types->extensions.empty()) {
+ allowed_file_types = [NSMutableArray array];
+ for (size_t i=0; i < file_types->extensions.size(); ++i) {
+ const std::vector<FilePath::StringType>& ext_list =
+ file_types->extensions[i];
+ for (size_t j=0; j < ext_list.size(); ++j) {
+ [allowed_file_types addObject:base::SysUTF8ToNSString(ext_list[j])];
+ }
+ }
+ }
+ if (type == SELECT_SAVEAS_FILE)
+ [dialog setAllowedFileTypes:allowed_file_types];
+ // else we'll pass it in when we run the open panel
+
+ if (file_types->include_all_files)
+ [dialog setAllowsOtherFileTypes:YES];
+
+ if (!file_types->extension_description_overrides.empty()) {
+ NSView* accessory_view = GetAccessoryView(file_types, file_type_index);
+ [dialog setAccessoryView:accessory_view];
+ }
+ } else {
+ // If no type info is specified, anything goes.
+ [dialog setAllowsOtherFileTypes:YES];
+ }
+
+ if (!default_extension.empty())
+ [dialog setRequiredFileType:base::SysUTF8ToNSString(default_extension)];
+
+ params_map_[dialog] = params;
+
+ SheetContext* context = new SheetContext;
+ context->type = type;
+ context->owning_window = NULL;
+ context->owning_tab = owning_tab;
+
+ // It will delete itself when its |DeleteDelegate()| method is called.
+ SelectFileInTabDelegate* delegate = new SelectFileInTabDelegate;
+ DCHECK(delegate);
+
+ if (type == SELECT_SAVEAS_FILE) {
+ delegate->InitForSavePanel(dialog,
+ this,
+ default_dir,
+ default_filename,
+ context);
+ } else {
+ NSOpenPanel* open_dialog = (NSOpenPanel*)dialog;
+
+ if (type == SELECT_OPEN_MULTI_FILE)
+ [open_dialog setAllowsMultipleSelection:YES];
+ else
+ [open_dialog setAllowsMultipleSelection:NO];
+
+ if (type == SELECT_FOLDER) {
+ [open_dialog setCanChooseFiles:NO];
+ [open_dialog setCanChooseDirectories:YES];
+ } else {
+ [open_dialog setCanChooseFiles:YES];
+ [open_dialog setCanChooseDirectories:NO];
+ }
+
+ delegate->InitForOpenPanel(open_dialog,
+ this,
+ default_dir,
+ default_filename,
+ allowed_file_types,
+ context);
+ }
+
+ window_map_[dialog] = owning_tab->CreateConstrainedDialog(delegate);
+}
+
+void SelectFileDialogImpl::FileWasSelected(
+ NSPanel* dialog,
+ NSWindow* parent_window,
+ bool was_cancelled,
+ bool is_multi,
+ const std::vector<FilePath>& files,
+ int index) {
void* params = params_map_[dialog];
params_map_.erase(dialog);
- parents_.erase(parent_window);
+ parent_windows_.erase(parent_window);
+ NotifyListenerOfFileSelection(was_cancelled, is_multi, files, index, params);
+}
+
+// The |was_killed| parameter indicates whether or not we need to call
+// |CloseConstrainedWindow()|. If the dialog was ended by
+// |CloseConstrainedWindow()|, the delegate then closes the sheet (leading to
+// this method being called) and deletes itself.
+void SelectFileDialogImpl::FileWasSelectedInTab(
+ NSPanel* dialog,
+ TabContents* parent_tab,
+ bool was_cancelled,
+ bool was_killed,
+ bool is_multi,
+ const std::vector<FilePath>& files,
+ int index) {
+ void* params = params_map_[dialog];
+ params_map_.erase(dialog);
+ if (!was_killed) {
+ ConstrainedWindow* window = window_map_[dialog];
+ window->CloseConstrainedWindow();
+ }
+ window_map_.erase(dialog);
+ parent_tabs_.erase(parent_tab);
+
+ NotifyListenerOfFileSelection(was_cancelled, is_multi, files, index, params);
+}
+
+void SelectFileDialogImpl::NotifyListenerOfFileSelection(
+ bool was_cancelled,
+ bool is_multi,
+ const std::vector<FilePath>& files,
+ int index,
+ void* params) {
if (!listener_)
return;
@@ -312,12 +597,15 @@ NSView* SelectFileDialogImpl::GetAccessoryView(const FileTypeInfo* file_types,
SelectFileDialog::Type type = context_struct->type;
NSWindow* parentWindow = context_struct->owning_window;
+ TabContents* parentTab = context_struct->owning_tab;
+ DCHECK(!(parentWindow && parentTab));
delete context_struct;
bool isMulti = type == SelectFileDialog::SELECT_OPEN_MULTI_FILE;
std::vector<FilePath> paths;
- bool did_cancel = returnCode == NSCancelButton;
+ // The negative check for cancellation covers the NSRun...Response codes.
+ bool did_cancel = (returnCode != NSOKButton);
if (!did_cancel) {
if (type == SelectFileDialog::SELECT_SAVEAS_FILE) {
paths.push_back(FilePath(base::SysNSStringToUTF8([panel filename])));
@@ -339,13 +627,27 @@ NSView* SelectFileDialogImpl::GetAccessoryView(const FileTypeInfo* file_types,
}
}
- selectFileDialogImpl_->FileWasSelected(panel,
- parentWindow,
- did_cancel,
- isMulti,
- paths,
- index);
- [panel release];
+ // Note that |parentWindow| may be null, so we use |parentTab| to check which
+ // situation we're in.
+ if (!parentTab) {
+ selectFileDialogImpl_->FileWasSelected(panel,
+ parentWindow,
+ did_cancel,
+ isMulti,
+ paths,
+ index);
+ [panel release];
+ } else {
+ bool was_killed =
+ (returnCode == SelectFileInTabDelegate::kClosedByDelegate);
+ selectFileDialogImpl_->FileWasSelectedInTab(panel,
+ parentTab,
+ did_cancel,
+ was_killed,
+ isMulti,
+ paths,
+ index);
+ }
}
@end
« no previous file with comments | « chrome/browser/cocoa/constrained_window_mac.mm ('k') | chrome/browser/cocoa/tab_strip_controller.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698