Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qfiledialog.h"
43
44#ifndef QT_NO_FILEDIALOG
45
46/*****************************************************************************
47 QFileDialog debug facilities
48 *****************************************************************************/
49//#define DEBUG_FILEDIALOG_FILTERS
50
51#include <qapplication.h>
52#include <private/qapplication_p.h>
53#include <private/qfiledialog_p.h>
54#include <private/qt_mac_p.h>
55#include <private/qt_cocoa_helpers_mac_p.h>
56#include <qregexp.h>
57#include <qbuffer.h>
58#include <qdebug.h>
59#include <qstringlist.h>
60#include <qaction.h>
61#include <qtextcodec.h>
62#include <qvarlengtharray.h>
63#include <qdesktopwidget.h>
64#include <stdlib.h>
65#include <qabstracteventdispatcher.h>
66#import <AppKit/NSSavePanel.h>
67#include "ui_qfiledialog.h"
68
69QT_BEGIN_NAMESPACE
70
71extern QStringList qt_make_filter_list(const QString &filter); // qfiledialog.cpp
72extern QStringList qt_clean_filter_list(const QString &filter); // qfiledialog.cpp
73extern const char *qt_file_dialog_filter_reg_exp; // qfiledialog.cpp
74extern bool qt_mac_is_macsheet(const QWidget *w); // qwidget_mac.mm
75
76QT_END_NAMESPACE
77
78QT_FORWARD_DECLARE_CLASS(QFileDialogPrivate)
79QT_FORWARD_DECLARE_CLASS(QString)
80QT_FORWARD_DECLARE_CLASS(QStringList)
81QT_FORWARD_DECLARE_CLASS(QWidget)
82QT_FORWARD_DECLARE_CLASS(QAction)
83QT_FORWARD_DECLARE_CLASS(QFileInfo)
84QT_USE_NAMESPACE
85
86@class QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate);
87
88@interface QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate)
89#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
90 : NSObject<NSOpenSavePanelDelegate>
91#else
92 : NSObject
93#endif
94{
95 @public
96 NSOpenPanel *mOpenPanel;
97 NSSavePanel *mSavePanel;
98 NSView *mAccessoryView;
99 NSPopUpButton *mPopUpButton;
100 NSTextField *mTextField;
101 QFileDialogPrivate *mPriv;
102 NSString *mCurrentDir;
103 bool mConfirmOverwrite;
104 int mReturnCode;
105
106 QT_PREPEND_NAMESPACE(QFileDialog::AcceptMode) mAcceptMode;
107 QT_PREPEND_NAMESPACE(QDir::Filters) *mQDirFilter;
108 QT_PREPEND_NAMESPACE(QFileDialog::FileMode) mFileMode;
109 QT_PREPEND_NAMESPACE(QFileDialog::Options) *mFileOptions;
110
111 QString *mLastFilterCheckPath;
112 QString *mCurrentSelection;
113 QStringList *mQDirFilterEntryList;
114 QStringList *mNameFilterDropDownList;
115 QStringList *mSelectedNameFilter;
116}
117
118- (NSString *)strip:(const QString &)label;
119- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename;
120- (void)filterChanged:(id)sender;
121- (void)showModelessPanel;
122- (BOOL)runApplicationModalPanel;
123- (void)showWindowModalSheet:(QWidget *)docWidget;
124- (void)updateProperties;
125- (QStringList)acceptableExtensionsForSave;
126- (QString)removeExtensions:(const QString &)filter;
127- (void)createTextField;
128- (void)createPopUpButton:(const QString &)selectedFilter hideDetails:(BOOL)hideDetails;
129- (QStringList)findStrippedFilterWithVisualFilterName:(QString)name;
130- (void)createAccessory;
131
132@end
133
134@implementation QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate)
135
136- (id)initWithAcceptMode:(QT_PREPEND_NAMESPACE(QFileDialog::AcceptMode))acceptMode
137 title:(const QString &)title
138 hideNameFilterDetails:(bool)hideNameFilterDetails
139 qDirFilter:(QT_PREPEND_NAMESPACE(QDir::Filters))qDirFilter
140 fileOptions:(QT_PREPEND_NAMESPACE(QFileDialog::Options))fileOptions
141 fileMode:(QT_PREPEND_NAMESPACE(QFileDialog::FileMode))fileMode
142 selectFile:(const QString &)selectFile
143 confirmOverwrite:(bool)confirm
144 priv:(QFileDialogPrivate *)priv
145{
146 self = [super init];
147
148 mAcceptMode = acceptMode;
149 if (mAcceptMode == QT_PREPEND_NAMESPACE(QFileDialog::AcceptOpen)){
150 mOpenPanel = [NSOpenPanel openPanel];
151 mSavePanel = mOpenPanel;
152 } else {
153 mSavePanel = [NSSavePanel savePanel];
154 mOpenPanel = 0;
155 }
156
157 if ([mSavePanel respondsToSelector:@selector(setLevel:)])
158 [mSavePanel setLevel:NSModalPanelWindowLevel];
159 [mSavePanel setDelegate:self];
160 mQDirFilter = new QT_PREPEND_NAMESPACE(QDir::Filters)(qDirFilter);
161 mFileOptions = new QT_PREPEND_NAMESPACE(QFileDialog::Options)(fileOptions);
162 mFileMode = fileMode;
163 mConfirmOverwrite = confirm;
164 mReturnCode = -1;
165 mPriv = priv;
166 mLastFilterCheckPath = new QString;
167 mQDirFilterEntryList = new QStringList;
168 mNameFilterDropDownList = new QStringList(priv->nameFilters);
169 QString selectedVisualNameFilter = priv->qFileDialogUi->fileTypeCombo->currentText();
170 mSelectedNameFilter = new QStringList([self findStrippedFilterWithVisualFilterName:selectedVisualNameFilter]);
171
172 QFileInfo sel(selectFile);
173 if (sel.isDir() && !sel.isBundle()){
174 mCurrentDir = [qt_mac_QStringToNSString(sel.absoluteFilePath()) retain];
175 mCurrentSelection = new QString;
176 } else {
177 mCurrentDir = [qt_mac_QStringToNSString(sel.absolutePath()) retain];
178 mCurrentSelection = new QString(sel.absoluteFilePath());
179 }
180
181 [mSavePanel setTitle:qt_mac_QStringToNSString(title)];
182 [self createPopUpButton:selectedVisualNameFilter hideDetails:hideNameFilterDetails];
183 [self createTextField];
184 [self createAccessory];
185 [mSavePanel setAccessoryView:mNameFilterDropDownList->size() > 1 ? mAccessoryView : nil];
186
187 if (mPriv){
188 [mSavePanel setPrompt:[self strip:mPriv->acceptLabel]];
189 if (mPriv->fileNameLabelExplicitlySat)
190 [mSavePanel setNameFieldLabel:[self strip:mPriv->qFileDialogUi->fileNameLabel->text()]];
191 }
192
193 [self updateProperties];
194 [mSavePanel retain];
195 return self;
196}
197
198- (void)dealloc
199{
200 delete mQDirFilter;
201 delete mFileOptions;
202 delete mLastFilterCheckPath;
203 delete mQDirFilterEntryList;
204 delete mNameFilterDropDownList;
205 delete mSelectedNameFilter;
206 delete mCurrentSelection;
207
208 if ([mSavePanel respondsToSelector:@selector(orderOut:)])
209 [mSavePanel orderOut:mSavePanel];
210 [mSavePanel setAccessoryView:nil];
211 [mPopUpButton release];
212 [mTextField release];
213 [mAccessoryView release];
214 [mSavePanel setDelegate:nil];
215 [mSavePanel release];
216 [mCurrentDir release];
217 [super dealloc];
218}
219
220- (NSString *)strip:(const QString &)label
221{
222 QAction a(label, 0);
223 return qt_mac_QStringToNSString(a.iconText());
224}
225
226- (void)closePanel
227{
228 *mCurrentSelection = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)([mSavePanel filename]);
229 if ([mSavePanel respondsToSelector:@selector(close)])
230 [mSavePanel close];
231 if ([mSavePanel isSheet])
232 [NSApp endSheet: mSavePanel];
233}
234
235- (void)showModelessPanel
236{
237 if (mOpenPanel){
238 QFileInfo info(*mCurrentSelection);
239 NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
240 NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
241 bool selectable = (mAcceptMode == QFileDialog::AcceptSave)
242 || [self panel:nil shouldShowFilename:filepath];
243 [mOpenPanel
244 beginForDirectory:mCurrentDir
245 file:selectable ? filename : nil
246 types:nil
247 modelessDelegate:self
248 didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
249 contextInfo:nil];
250 }
251}
252
253- (BOOL)runApplicationModalPanel
254{
255 QFileInfo info(*mCurrentSelection);
256 NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
257 NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
258 bool selectable = (mAcceptMode == QFileDialog::AcceptSave)
259 || [self panel:nil shouldShowFilename:filepath];
260 mReturnCode = [mSavePanel
261 runModalForDirectory:mCurrentDir
262 file:selectable ? filename : @"untitled"];
263
264 QAbstractEventDispatcher::instance()->interrupt();
265 return (mReturnCode == NSOKButton);
266}
267
268- (QT_PREPEND_NAMESPACE(QDialog::DialogCode))dialogResultCode
269{
270 return (mReturnCode == NSOKButton) ? QT_PREPEND_NAMESPACE(QDialog::Accepted) : QT_PREPEND_NAMESPACE(QDialog::Rejected);
271}
272
273- (void)showWindowModalSheet:(QWidget *)docWidget
274{
275 Q_UNUSED(docWidget);
276 QFileInfo info(*mCurrentSelection);
277 NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
278 NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
279 bool selectable = (mAcceptMode == QFileDialog::AcceptSave)
280 || [self panel:nil shouldShowFilename:filepath];
281 [mSavePanel
282 beginSheetForDirectory:mCurrentDir
283 file:selectable ? filename : nil
284#ifdef QT_MAC_USE_COCOA
285 modalForWindow:QT_PREPEND_NAMESPACE(qt_mac_window_for)(docWidget)
286#else
287 modalForWindow:nil
288#endif
289 modalDelegate:self
290 didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
291 contextInfo:nil];
292}
293
294- (BOOL)isHiddenFile:(NSString *)filename isDir:(BOOL)isDir
295{
296#ifdef QT_MAC_USE_COCOA
297 CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)filename, kCFURLPOSIXPathStyle, isDir);
298 CFBooleanRef isHidden;
299 Boolean errorOrHidden = false;
300 if (!CFURLCopyResourcePropertyForKey(url, kCFURLIsHiddenKey, &isHidden, NULL)) {
301 errorOrHidden = true;
302 } else {
303 if (CFBooleanGetValue(isHidden))
304 errorOrHidden = true;
305 CFRelease(isHidden);
306 }
307 CFRelease(url);
308 return errorOrHidden;
309#else
310 Q_UNUSED(filename);
311 Q_UNUSED(isDir);
312 return false;
313#endif
314}
315
316- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename
317{
318 Q_UNUSED(sender);
319
320 if ([filename length] == 0)
321 return NO;
322
323 // Always accept directories regardless of their names (unless it is a bundle):
324 NSFileManager *fm = [NSFileManager defaultManager];
325 NSDictionary *fileAttrs = [fm attributesOfItemAtPath:filename error:nil];
326 if (!fileAttrs)
327 return NO; // Error accessing the file means 'no'.
328 NSString *fileType = [fileAttrs fileType];
329 bool isDir = [fileType isEqualToString:NSFileTypeDirectory];
330 if (isDir) {
331 if ([mSavePanel treatsFilePackagesAsDirectories] == NO) {
332 if ([[NSWorkspace sharedWorkspace] isFilePackageAtPath:filename] == NO)
333 return YES;
334 }
335 }
336
337 QString qtFileName
338 = QFileInfo(QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)(filename)).fileName();
339 // No filter means accept everything
340 bool nameMatches = mSelectedNameFilter->isEmpty();
341 // Check if the current file name filter accepts the file:
342 for (int i = 0; !nameMatches && i < mSelectedNameFilter->size(); ++i) {
343 if (QDir::match(mSelectedNameFilter->at(i), qtFileName))
344 nameMatches = true;
345 }
346 if (!nameMatches)
347 return NO;
348
349 QDir::Filters filter = *mQDirFilter;
350 if ((!(filter & (QDir::Dirs | QDir::AllDirs)) && isDir)
351 || (!(filter & QDir::Files) && [fileType isEqualToString:NSFileTypeRegular])
352 || ((filter & QDir::NoSymLinks) && [fileType isEqualToString:NSFileTypeSymbolicLink]))
353 return NO;
354
355 bool filterPermissions = ((filter & QDir::PermissionMask)
356 && (filter & QDir::PermissionMask) != QDir::PermissionMask);
357 if (filterPermissions) {
358 if ((!(filter & QDir::Readable) && [fm isReadableFileAtPath:filename])
359 || (!(filter & QDir::Writable) && [fm isWritableFileAtPath:filename])
360 || (!(filter & QDir::Executable) && [fm isExecutableFileAtPath:filename]))
361 return NO;
362 }
363 if (!(filter & QDir::Hidden)
364 && (qtFileName.startsWith(QLatin1Char('.')) || [self isHiddenFile:filename isDir:isDir]))
365 return NO;
366
367 return YES;
368}
369
370- (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag
371{
372 Q_UNUSED(sender);
373 if (!okFlag)
374 return filename;
375 if (mConfirmOverwrite)
376 return filename;
377
378 // User has clicked save, and no overwrite confirmation should occur.
379 // To get the latter, we need to change the name we return (hence the prefix):
380 return [@"___qt_very_unlikely_prefix_" stringByAppendingString:filename];
381}
382
383- (void)setNameFilters:(const QStringList &)filters hideDetails:(BOOL)hideDetails
384{
385 [mPopUpButton removeAllItems];
386 *mNameFilterDropDownList = filters;
387 if (filters.size() > 0){
388 for (int i=0; i<filters.size(); ++i) {
389 QString filter = hideDetails ? [self removeExtensions:filters.at(i)] : filters.at(i);
390 [mPopUpButton addItemWithTitle:QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(filter)];
391 }
392 [mPopUpButton selectItemAtIndex:0];
393 [mSavePanel setAccessoryView:mAccessoryView];
394 } else
395 [mSavePanel setAccessoryView:nil];
396
397 [self filterChanged:self];
398}
399
400- (void)filterChanged:(id)sender
401{
402 // This mDelegate function is called when the _name_ filter changes.
403 Q_UNUSED(sender);
404 QString selection = mNameFilterDropDownList->value([mPopUpButton indexOfSelectedItem]);
405 *mSelectedNameFilter = [self findStrippedFilterWithVisualFilterName:selection];
406 if ([mSavePanel respondsToSelector:@selector(validateVisibleColumns)])
407 [mSavePanel validateVisibleColumns];
408 [self updateProperties];
409 if (mPriv)
410 mPriv->QNSOpenSavePanelDelegate_filterSelected([mPopUpButton indexOfSelectedItem]);
411}
412
413- (QString)currentNameFilter
414{
415 return mNameFilterDropDownList->value([mPopUpButton indexOfSelectedItem]);
416}
417
418- (QStringList)selectedFiles
419{
420 if (mOpenPanel)
421 return QT_PREPEND_NAMESPACE(qt_mac_NSArrayToQStringList)([mOpenPanel filenames]);
422 else{
423 QStringList result;
424 QString filename = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)([mSavePanel filename]);
425 result << filename.remove(QLatin1String("___qt_very_unlikely_prefix_"));
426 return result;
427 }
428}
429
430- (void)updateProperties
431{
432 // Call this functions if mFileMode, mFileOptions,
433 // mNameFilterDropDownList or mQDirFilter changes.
434 // The savepanel does not contain the neccessary functions for this.
435 bool chooseFilesOnly = mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::ExistingFile)
436 || mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::ExistingFiles);
437 bool chooseDirsOnly = mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::Directory)
438 || mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::DirectoryOnly)
439 || *mFileOptions & QT_PREPEND_NAMESPACE(QFileDialog::ShowDirsOnly);
440
441 [mOpenPanel setCanChooseFiles:!chooseDirsOnly];
442 [mOpenPanel setCanChooseDirectories:!chooseFilesOnly];
443 [mSavePanel setCanCreateDirectories:!(*mFileOptions & QT_PREPEND_NAMESPACE(QFileDialog::ReadOnly))];
444 [mOpenPanel setAllowsMultipleSelection:(mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::ExistingFiles))];
445 [mOpenPanel setResolvesAliases:!(*mFileOptions & QT_PREPEND_NAMESPACE(QFileDialog::DontResolveSymlinks))];
446
447 QStringList ext = [self acceptableExtensionsForSave];
448 if (mPriv && !ext.isEmpty() && !mPriv->defaultSuffix.isEmpty())
449 ext.prepend(mPriv->defaultSuffix);
450 [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : QT_PREPEND_NAMESPACE(qt_mac_QStringListToNSMutableArray(ext))];
451
452 if ([mSavePanel respondsToSelector:@selector(isVisible)] && [mSavePanel isVisible])
453 {
454 if ([mOpenPanel respondsToSelector:@selector(validateVisibleColumns)])
455 [mOpenPanel validateVisibleColumns];
456 }
457}
458
459- (void)panelSelectionDidChange:(id)sender
460{
461 Q_UNUSED(sender);
462 if (mPriv) {
463 QString selection = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString([mSavePanel filename]));
464 if (selection != mCurrentSelection) {
465 *mCurrentSelection = selection;
466 mPriv->QNSOpenSavePanelDelegate_selectionChanged(selection);
467 }
468 }
469}
470
471- (void)openPanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo
472{
473 Q_UNUSED(panel);
474 Q_UNUSED(contextInfo);
475 mReturnCode = returnCode;
476 if (mPriv)
477 mPriv->QNSOpenSavePanelDelegate_panelClosed(returnCode == NSOKButton);
478}
479
480- (void)panel:(id)sender directoryDidChange:(NSString *)path
481{
482 Q_UNUSED(sender);
483 if (!mPriv)
484 return;
485 if ([path isEqualToString:mCurrentDir])
486 return;
487
488 if ([mSavePanel respondsToSelector:@selector(isVisible)] && ![mSavePanel isVisible])
489 return;
490 [mCurrentDir release];
491 mCurrentDir = [path retain];
492 mPriv->QNSOpenSavePanelDelegate_directoryEntered(QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString(mCurrentDir)));
493}
494
495/*
496 Returns a list of extensions (e.g. "png", "jpg", "gif")
497 for the current name filter. If a filter do not conform
498 to the format *.xyz or * or *.*, an empty list
499 is returned meaning accept everything.
500*/
501- (QStringList)acceptableExtensionsForSave
502{
503 QStringList result;
504 for (int i=0; i<mSelectedNameFilter->count(); ++i) {
505 const QString &filter = mSelectedNameFilter->at(i);
506 if (filter.startsWith(QLatin1String("*."))
507 && !filter.contains(QLatin1Char('?'))
508 && filter.count(QLatin1Char('*')) == 1) {
509 result += filter.mid(2);
510 } else {
511 return QStringList(); // Accept everything
512 }
513 }
514 return result;
515}
516
517- (QString)removeExtensions:(const QString &)filter
518{
519 QRegExp regExp(QT_PREPEND_NAMESPACE(QString::fromLatin1)(QT_PREPEND_NAMESPACE(qt_file_dialog_filter_reg_exp)));
520 if (regExp.indexIn(filter) != -1)
521 return regExp.cap(1).trimmed();
522 return filter;
523}
524
525- (void)createTextField
526{
527 NSRect textRect = { { 0.0, 3.0 }, { 100.0, 25.0 } };
528 mTextField = [[NSTextField alloc] initWithFrame:textRect];
529 [[mTextField cell] setFont:[NSFont systemFontOfSize:
530 [NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
531 [mTextField setAlignment:NSRightTextAlignment];
532 [mTextField setEditable:false];
533 [mTextField setSelectable:false];
534 [mTextField setBordered:false];
535 [mTextField setDrawsBackground:false];
536 if (mPriv){
537 [mTextField setStringValue:[self strip:mPriv->qFileDialogUi->fileTypeLabel->text()]];
538 } else
539 [mTextField setStringValue:QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(QT_PREPEND_NAMESPACE(QFileDialog::tr)("Files of type:"))];
540}
541
542- (void)createPopUpButton:(const QString &)selectedFilter hideDetails:(BOOL)hideDetails
543{
544 NSRect popUpRect = { { 100.0, 5.0 }, { 250.0, 25.0 } };
545 mPopUpButton = [[NSPopUpButton alloc] initWithFrame:popUpRect pullsDown:NO];
546 [mPopUpButton setTarget:self];
547 [mPopUpButton setAction:@selector(filterChanged:)];
548
549 if (mNameFilterDropDownList->size() > 0) {
550 int filterToUse = -1;
551 for (int i=0; i<mNameFilterDropDownList->size(); ++i) {
552 QString currentFilter = mNameFilterDropDownList->at(i);
553 if (selectedFilter == currentFilter ||
554 (filterToUse == -1 && currentFilter.startsWith(selectedFilter)))
555 filterToUse = i;
556 QString filter = hideDetails ? [self removeExtensions:currentFilter] : currentFilter;
557 [mPopUpButton addItemWithTitle:QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(filter)];
558 }
559 if (filterToUse != -1)
560 [mPopUpButton selectItemAtIndex:filterToUse];
561 }
562}
563
564- (QStringList) findStrippedFilterWithVisualFilterName:(QString)name
565{
566 for (int i=0; i<mNameFilterDropDownList->size(); ++i) {
567 if (mNameFilterDropDownList->at(i).startsWith(name))
568 return qt_clean_filter_list(mNameFilterDropDownList->at(i));
569 }
570 return QStringList();
571}
572
573- (void)createAccessory
574{
575 NSRect accessoryRect = { { 0.0, 0.0 }, { 450.0, 33.0 } };
576 mAccessoryView = [[NSView alloc] initWithFrame:accessoryRect];
577 [mAccessoryView addSubview:mTextField];
578 [mAccessoryView addSubview:mPopUpButton];
579}
580
581@end
582
583QT_BEGIN_NAMESPACE
584
585void QFileDialogPrivate::QNSOpenSavePanelDelegate_selectionChanged(const QString &newPath)
586{
587 emit q_func()->currentChanged(newPath);
588}
589
590void QFileDialogPrivate::QNSOpenSavePanelDelegate_panelClosed(bool accepted)
591{
592 if (accepted)
593 q_func()->accept();
594 else
595 q_func()->reject();
596}
597
598void QFileDialogPrivate::QNSOpenSavePanelDelegate_directoryEntered(const QString &newDir)
599{
600 setLastVisitedDirectory(newDir);
601 emit q_func()->directoryEntered(newDir);
602}
603
604void QFileDialogPrivate::QNSOpenSavePanelDelegate_filterSelected(int menuIndex)
605{
606 emit q_func()->filterSelected(nameFilters.at(menuIndex));
607}
608
609void QFileDialogPrivate::setDirectory_sys(const QString &directory)
610{
611#ifndef QT_MAC_USE_COCOA
612 if (directory == mCurrentLocation)
613 return;
614 mCurrentLocation = directory;
615 emit q_func()->directoryEntered(mCurrentLocation);
616
617 FSRef fsRef;
618 if (qt_mac_create_fsref(directory, &fsRef) == noErr) {
619 AEDesc desc;
620 if (AECreateDesc(typeFSRef, &fsRef, sizeof(FSRef), &desc) == noErr)
621 NavCustomControl(mDialog, kNavCtlSetLocation, (void*)&desc);
622 }
623#else
624 QMacCocoaAutoReleasePool pool;
625 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
626 [delegate->mSavePanel setDirectory:qt_mac_QStringToNSString(directory)];
627#endif
628}
629
630QString QFileDialogPrivate::directory_sys() const
631{
632#ifndef QT_MAC_USE_COCOA
633 return mCurrentLocation;
634#else
635 QMacCocoaAutoReleasePool pool;
636 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
637 return qt_mac_NSStringToQString([delegate->mSavePanel directory]);
638#endif
639}
640
641void QFileDialogPrivate::selectFile_sys(const QString &filename)
642{
643 QString filePath = filename;
644 if (QDir::isRelativePath(filePath))
645 filePath = QFileInfo(directory_sys(), filePath).filePath();
646
647#ifndef QT_MAC_USE_COCOA
648 // Update the selection list immidiatly, so
649 // subsequent calls to selectedFiles() gets correct:
650 mCurrentSelectionList.clear();
651 mCurrentSelectionList << filename;
652 if (mCurrentSelection != filename){
653 mCurrentSelection = filename;
654 emit q_func()->currentChanged(mCurrentSelection);
655 }
656
657 AEDescList descList;
658 if (AECreateList(0, 0, false, &descList) != noErr)
659 return;
660
661 FSRef fsRef;
662 if (qt_mac_create_fsref(filePath, &fsRef) == noErr) {
663 AEDesc desc;
664 if (AECreateDesc(typeFSRef, &fsRef, sizeof(FSRef), &desc) == noErr){
665 if (AEPutDesc(&descList, 0, &desc) == noErr)
666 NavCustomControl(mDialog, kNavCtlSetSelection, (void*)&descList);
667 }
668 }
669
670 // Type the file name into the save dialog's text field:
671 UInt8 *strBuffer = (UInt8 *)malloc(1024);
672 qt_mac_to_pascal_string(QFileInfo(filename).fileName(), strBuffer);
673 NavCustomControl(mDialog, kNavCtlSetEditFileName, strBuffer);
674 free(strBuffer);
675#else
676 // There seems to no way to select a file once the dialog is running.
677 // So do the next best thing, set the file's directory:
678 setDirectory_sys(QFileInfo(filePath).absolutePath());
679#endif
680}
681
682QStringList QFileDialogPrivate::selectedFiles_sys() const
683{
684#ifndef QT_MAC_USE_COCOA
685 if (q_func()->acceptMode() == QFileDialog::AcceptOpen){
686 return mCurrentSelectionList;
687 } else {
688 return QStringList() << mCurrentLocation + QLatin1Char('/')
689 + QCFString::toQString(NavDialogGetSaveFileName(mDialog));
690 }
691#else
692 QMacCocoaAutoReleasePool pool;
693 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
694 return [delegate selectedFiles];
695#endif
696}
697
698void QFileDialogPrivate::setNameFilters_sys(const QStringList &filters)
699{
700#ifndef QT_MAC_USE_COCOA
701 Q_UNUSED(filters);
702#else
703 QMacCocoaAutoReleasePool pool;
704 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
705 bool hideDetails = q_func()->testOption(QFileDialog::HideNameFilterDetails);
706 [delegate setNameFilters:filters hideDetails:hideDetails];
707#endif
708}
709
710void QFileDialogPrivate::setFilter_sys()
711{
712#ifndef QT_MAC_USE_COCOA
713#else
714 Q_Q(QFileDialog);
715 QMacCocoaAutoReleasePool pool;
716 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
717 *(delegate->mQDirFilter) = model->filter();
718 delegate->mFileMode = fileMode;
719 [delegate->mSavePanel setTitle:qt_mac_QStringToNSString(q->windowTitle())];
720 [delegate->mSavePanel setPrompt:[delegate strip:acceptLabel]];
721 if (fileNameLabelExplicitlySat)
722 [delegate->mSavePanel setNameFieldLabel:[delegate strip:qFileDialogUi->fileNameLabel->text()]];
723
724 [delegate updateProperties];
725#endif
726}
727
728void QFileDialogPrivate::selectNameFilter_sys(const QString &filter)
729{
730 int index = nameFilters.indexOf(filter);
731 if (index != -1) {
732#ifndef QT_MAC_USE_COCOA
733 NavMenuItemSpec navSpec;
734 bzero(&navSpec, sizeof(NavMenuItemSpec));
735 navSpec.menuType = index;
736 NavCustomControl(mDialog, kNavCtlSelectCustomType, &navSpec);
737#else
738 QMacCocoaAutoReleasePool pool;
739 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
740 [delegate->mPopUpButton selectItemAtIndex:index];
741 [delegate filterChanged:nil];
742#endif
743 }
744}
745
746QString QFileDialogPrivate::selectedNameFilter_sys() const
747{
748#ifndef QT_MAC_USE_COCOA
749 int index = filterInfo.currentSelection;
750#else
751 QMacCocoaAutoReleasePool pool;
752 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
753 int index = [delegate->mPopUpButton indexOfSelectedItem];
754#endif
755 return index != -1 ? nameFilters.at(index) : QString();
756}
757
758void QFileDialogPrivate::deleteNativeDialog_sys()
759{
760#ifndef QT_MAC_USE_COCOA
761 if (mDialog)
762 NavDialogDispose(mDialog);
763 mDialog = 0;
764 mDialogStarted = false;
765#else
766 QMacCocoaAutoReleasePool pool;
767 [reinterpret_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate) release];
768 mDelegate = 0;
769#endif
770 nativeDialogInUse = false;
771}
772
773bool QFileDialogPrivate::setVisible_sys(bool visible)
774{
775 Q_Q(QFileDialog);
776 if (!visible == q->isHidden())
777 return false;
778
779 if (q->windowFlags() & Qt::WindowStaysOnTopHint) {
780 // The native file dialog tries all it can to stay
781 // on the NSModalPanel level. And it might also show
782 // its own "create directory" dialog that we cannot control.
783 // So we need to use the non-native version in this case...
784 return false;
785 }
786
787#ifndef QT_MAC_USE_COCOA
788 return visible ? showCarbonNavServicesDialog() : hideCarbonNavServicesDialog();
789#else
790 return visible ? showCocoaFilePanel() : hideCocoaFilePanel();
791#endif
792}
793
794#ifndef QT_MAC_USE_COCOA
795Boolean QFileDialogPrivate::qt_mac_filedialog_filter_proc(AEDesc *theItem, void *info,
796 void *data, NavFilterModes)
797{
798 QFileDialogPrivate *fileDialogPrivate = static_cast<QFileDialogPrivate *>(data);
799
800 if (!fileDialogPrivate || fileDialogPrivate->filterInfo.filters.isEmpty()
801 || (fileDialogPrivate->filterInfo.currentSelection < 0
802 && fileDialogPrivate->filterInfo.currentSelection
803 >= fileDialogPrivate->filterInfo.filters.size()))
804 return true;
805
806 NavFileOrFolderInfo *theInfo = static_cast<NavFileOrFolderInfo *>(info);
807 QString file;
808 QString path;
809 const QtMacFilterName &fn
810 = fileDialogPrivate->filterInfo.filters.at(fileDialogPrivate->filterInfo.currentSelection);
811 if (theItem->descriptorType == typeFSRef) {
812 FSRef ref;
813 AEGetDescData(theItem, &ref, sizeof(ref));
814 UInt8 str_buffer[1024];
815 FSRefMakePath(&ref, str_buffer, 1024);
816 path = QString::fromUtf8(reinterpret_cast<const char *>(str_buffer));
817 int slsh = path.lastIndexOf(QLatin1Char('/'));
818 if (slsh != -1)
819 file = path.right(path.length() - slsh - 1);
820 else
821 file = path;
822 }
823 QStringList reg = fn.regexp.split(QLatin1String(";"));
824 for (QStringList::const_iterator it = reg.constBegin(); it != reg.constEnd(); ++it) {
825 QRegExp rg(*it, Qt::CaseInsensitive, QRegExp::Wildcard);
826#ifdef DEBUG_FILEDIALOG_FILTERS
827 qDebug("QFileDialogPrivate::qt_mac_filedialog_filter_proc:%d, asked to filter.. %s (%s)", __LINE__,
828 qPrintable(file), qPrintable(*it));
829#endif
830 if (rg.exactMatch(file))
831 return true;
832 }
833
834 if (theInfo->isFolder) {
835 if ([[NSWorkspace sharedWorkspace] isFilePackageAtPath:qt_mac_QStringToNSString(path)])
836 return false;
837 return true;
838 }
839 return false;
840}
841
842void QFileDialogPrivate::qt_mac_filedialog_event_proc(const NavEventCallbackMessage msg,
843 NavCBRecPtr p, NavCallBackUserData data)
844{
845 QFileDialogPrivate *fileDialogPrivate = static_cast<QFileDialogPrivate *>(data);
846
847 switch(msg) {
848 case kNavCBPopupMenuSelect: {
849 NavMenuItemSpec *s = static_cast<NavMenuItemSpec *>(p->eventData.eventDataParms.param);
850 if (int(s->menuType) != fileDialogPrivate->filterInfo.currentSelection) {
851 fileDialogPrivate->filterInfo.currentSelection = s->menuType;
852 emit fileDialogPrivate->q_func()->filterSelected(fileDialogPrivate->nameFilters.at(s->menuType));
853 }
854 if (fileDialogPrivate->acceptMode == QFileDialog::AcceptSave) {
855 QString base = QCFString::toQString(NavDialogGetSaveFileName(p->context));
856 QFileInfo fi(base);
857 base = fi.completeBaseName();
858 const QtMacFilterName &fn = fileDialogPrivate->filterInfo.filters.at(
859 fileDialogPrivate->filterInfo.currentSelection);
860 QStringList reg = fn.regexp.split(QLatin1String(";"), QString::SkipEmptyParts);
861 if (reg.count()) {
862 QString r = reg.first();
863 r = r.right(r.length()-1); // Strip the *
864 base += r; //"." + QString::number(s->menuType);
865 }
866 NavDialogSetSaveFileName(p->context, QCFString::toCFStringRef(base));
867 }
868#ifdef DEBUG_FILEDIALOG_FILTERS
869 qDebug("QFileDialogPrivate::qt_mac_filedialog_event_proc:%d - Selected a filter: %ld", __LINE__, s->menuType);
870#endif
871 break; }
872 case kNavCBStart:{
873 fileDialogPrivate->mDialogStarted = true;
874 // Set selected file:
875 QModelIndexList indexes = fileDialogPrivate->qFileDialogUi->listView->selectionModel()->selectedRows();
876 QString selected;
877 if (!indexes.isEmpty())
878 selected = indexes.at(0).data(QFileSystemModel::FilePathRole).toString();
879 else
880 selected = fileDialogPrivate->typedFiles().value(0);
881 fileDialogPrivate->selectFile_sys(selected);
882 fileDialogPrivate->selectNameFilter_sys(fileDialogPrivate->qFileDialogUi->fileTypeCombo->currentText());
883 break; }
884 case kNavCBSelectEntry:{
885 // Event: Current selection has changed.
886 QStringList prevSelectionList = fileDialogPrivate->mCurrentSelectionList;
887 fileDialogPrivate->mCurrentSelectionList.clear();
888 QString fileNameToEmit;
889
890 AEDescList *descList = (AEDescList *)p->eventData.eventDataParms.param;
891 // Get the number of files selected:
892 UInt8 strBuffer[1024];
893 long count;
894 OSErr err = AECountItems(descList, &count);
895 if (err != noErr || !count)
896 break;
897
898 for (long index=1; index<=count; ++index) {
899 FSRef ref;
900 err = AEGetNthPtr(descList, index, typeFSRef, 0, 0, &ref, sizeof(ref), 0);
901 if (err != noErr)
902 break;
903 FSRefMakePath(&ref, strBuffer, 1024);
904 QString selected = QString::fromUtf8((const char *)strBuffer);
905 fileDialogPrivate->mCurrentSelectionList << selected;
906 if (!prevSelectionList.contains(selected))
907 fileNameToEmit = selected;
908 }
909
910 if (!fileNameToEmit.isEmpty() && fileNameToEmit != fileDialogPrivate->mCurrentSelection)
911 emit fileDialogPrivate->q_func()->currentChanged(fileNameToEmit);
912 fileDialogPrivate->mCurrentSelection = fileNameToEmit;
913 break; }
914 case kNavCBShowDesktop:
915 case kNavCBNewLocation:{
916 // Event: Current directory has changed.
917 AEDesc *desc = (AEDesc *)p->eventData.eventDataParms.param;
918 FSRef ref;
919 AEGetDescData(desc, &ref, sizeof(ref));
920 UInt8 *strBuffer = (UInt8 *)malloc(1024);
921 FSRefMakePath(&ref, strBuffer, 1024);
922 QString newLocation = QString::fromUtf8((const char *)strBuffer);
923 free(strBuffer);
924 if (fileDialogPrivate->mCurrentLocation != newLocation){
925 fileDialogPrivate->mCurrentLocation = newLocation;
926 QFileDialog::FileMode mode = fileDialogPrivate->fileMode;
927 if (mode == QFileDialog::AnyFile || mode == QFileDialog::ExistingFile
928 || mode == QFileDialog::ExistingFiles){
929 // When changing directory, the current selection is cleared if
930 // we are supposed to be selecting files only:
931 if (!fileDialogPrivate->mCurrentSelection.isEmpty()){
932 fileDialogPrivate->mCurrentSelectionList.clear();
933 fileDialogPrivate->mCurrentSelection.clear();
934 emit fileDialogPrivate->q_func()->currentChanged(fileDialogPrivate->mCurrentSelection);
935 }
936 }
937 fileDialogPrivate->setLastVisitedDirectory(newLocation);
938 emit fileDialogPrivate->q_func()->directoryEntered(newLocation);
939 }
940 break; }
941 case kNavCBAccept:
942 fileDialogPrivate->mDialogClosed = true;
943 fileDialogPrivate->q_func()->accept();
944 break;
945 case kNavCBCancel:
946 fileDialogPrivate->mDialogClosed = true;
947 fileDialogPrivate->q_func()->reject();
948 break;
949 }
950}
951
952static QFileDialogPrivate::QtMacFilterName qt_mac_extract_filter(const QString &rawFilter, bool showDetails)
953{
954 QFileDialogPrivate::QtMacFilterName ret;
955 ret.filter = rawFilter;
956 QString result = rawFilter;
957 QRegExp r(QString::fromLatin1(qt_file_dialog_filter_reg_exp));
958 int index = r.indexIn(result);
959 if (index >= 0)
960 result = r.cap(2);
961
962 if (showDetails) {
963 ret.description = rawFilter;
964 } else {
965 if (index >= 0)
966 ret.description = r.cap(1).trimmed();
967 if (ret.description.isEmpty())
968 ret.description = result;
969 }
970 ret.regexp = result.replace(QLatin1Char(' '), QLatin1Char(';'));
971 return ret;
972}
973
974static QList<QFileDialogPrivate::QtMacFilterName> qt_mac_make_filters_list(const QString &filter, bool showDetails)
975{
976#ifdef DEBUG_FILEDIALOG_FILTERS
977 qDebug("QFileDialog:%d - Got filter (%s)", __LINE__, filter.latin1());
978#endif
979
980 QList<QFileDialogPrivate::QtMacFilterName> ret;
981 QString f(filter);
982 if (f.isEmpty())
983 f = QFileDialog::tr("All Files (*)");
984 if (f.isEmpty())
985 return ret;
986 QStringList filts = qt_make_filter_list(f);
987 for (QStringList::const_iterator it = filts.constBegin(); it != filts.constEnd(); ++it) {
988 QFileDialogPrivate::QtMacFilterName filter = qt_mac_extract_filter(*it, showDetails);
989#ifdef DEBUG_FILEDIALOG_FILTERS
990 qDebug("QFileDialog:%d Split out filter (%d) '%s' '%s' [%s]", __LINE__, ret.count(),
991 filter->regxp.latin1(), filter->description.latin1(), (*it).latin1());
992#endif
993 ret.append(filter);
994 }
995 return ret;
996}
997
998void QFileDialogPrivate::createNavServicesDialog()
999{
1000 Q_Q(QFileDialog);
1001 if (mDialog)
1002 deleteNativeDialog_sys();
1003
1004 NavDialogCreationOptions navOptions;
1005 NavGetDefaultDialogCreationOptions(&navOptions);
1006
1007 // Translate QFileDialog settings into NavDialog options:
1008 if (qt_mac_is_macsheet(q)) {
1009 navOptions.modality = kWindowModalityWindowModal;
1010 navOptions.parentWindow = qt_mac_window_for(q->parentWidget());
1011 } else if (q->windowModality() == Qt::ApplicationModal)
1012 navOptions.modality = kWindowModalityAppModal;
1013 else
1014 navOptions.modality = kWindowModalityNone;
1015 navOptions.optionFlags |= kNavSupportPackages;
1016 if (q->testOption(QFileDialog::DontConfirmOverwrite))
1017 navOptions.optionFlags |= kNavDontConfirmReplacement;
1018 if (fileMode != QFileDialog::ExistingFiles)
1019 navOptions.optionFlags &= ~kNavAllowMultipleFiles;
1020
1021 navOptions.windowTitle = QCFString::toCFStringRef(q->windowTitle());
1022
1023 navOptions.location.h = -1;
1024 navOptions.location.v = -1;
1025
1026 QWidget *parent = q->parentWidget();
1027 if (parent && parent->isVisible()) {
1028 WindowClass wclass;
1029 GetWindowClass(qt_mac_window_for(parent), &wclass);
1030 parent = parent->window();
1031 QString s = parent->windowTitle();
1032 navOptions.clientName = QCFString::toCFStringRef(s);
1033 }
1034
1035 filterInfo.currentSelection = 0;
1036 filterInfo.filters = qt_mac_make_filters_list(nameFilters.join(QLatin1String(";;")), q->isNameFilterDetailsVisible());
1037 QCFType<CFArrayRef> filterArray;
1038 if (filterInfo.filters.size() > 1) {
1039 int i = 0;
1040 CFStringRef *cfstringArray = static_cast<CFStringRef *>(malloc(sizeof(CFStringRef)
1041 * filterInfo.filters.size()));
1042 for (i = 0; i < filterInfo.filters.size(); ++i) {
1043 cfstringArray[i] = QCFString::toCFStringRef(filterInfo.filters.at(i).description);
1044 }
1045 filterArray = CFArrayCreate(kCFAllocatorDefault,
1046 reinterpret_cast<const void **>(cfstringArray), filterInfo.filters.size(),
1047 &kCFTypeArrayCallBacks);
1048 navOptions.popupExtension = filterArray;
1049 free(cfstringArray);
1050 }
1051
1052 if (q->acceptMode() == QFileDialog::AcceptSave) {
1053 if (NavCreatePutFileDialog(&navOptions, 'cute', kNavGenericSignature,
1054 QFileDialogPrivate::qt_mac_filedialog_event_proc, this, &mDialog)) {
1055 qDebug("Shouldn't happen %s:%d", __FILE__, __LINE__);
1056 return;
1057 }
1058 } else if (fileMode == QFileDialog::DirectoryOnly || fileMode == QFileDialog::Directory) {
1059 if (NavCreateChooseFolderDialog(&navOptions,
1060 QFileDialogPrivate::qt_mac_filedialog_event_proc, 0, this, &mDialog)) {
1061 qDebug("Shouldn't happen %s:%d", __FILE__, __LINE__);
1062 return;
1063 }
1064 } else {
1065 if (NavCreateGetFileDialog(&navOptions, 0,
1066 QFileDialogPrivate::qt_mac_filedialog_event_proc, 0,
1067 QFileDialogPrivate::qt_mac_filedialog_filter_proc, this, &mDialog)) {
1068 qDebug("Shouldn't happen %s:%d", __FILE__, __LINE__);
1069 return;
1070 }
1071 }
1072
1073 // Set start-up directory:
1074 if (mCurrentLocation.isEmpty())
1075 mCurrentLocation = rootPath();
1076 FSRef fsRef;
1077 if (qt_mac_create_fsref(mCurrentLocation, &fsRef) == noErr) {
1078 AEDesc desc;
1079 if (AECreateDesc(typeFSRef, &fsRef, sizeof(FSRef), &desc) == noErr)
1080 NavCustomControl(mDialog, kNavCtlSetLocation, (void*)&desc);
1081 }
1082}
1083
1084bool QFileDialogPrivate::showCarbonNavServicesDialog()
1085{
1086 Q_Q(QFileDialog);
1087 if (q->acceptMode() == QFileDialog::AcceptSave && q->windowModality() == Qt::NonModal)
1088 return false; // cannot do native no-modal save dialogs.
1089 createNavServicesDialog();
1090 mDialogClosed = false;
1091 if (q->windowModality() != Qt::ApplicationModal)
1092 NavDialogRun(mDialog);
1093 return true;
1094}
1095
1096bool QFileDialogPrivate::hideCarbonNavServicesDialog()
1097{
1098 if (!mDialogClosed){
1099 mDialogClosed = true;
1100 NavCustomControl(mDialog, kNavCtlCancel, 0);
1101 }
1102 return true;
1103}
1104
1105#else // Cocoa
1106
1107void QFileDialogPrivate::createNSOpenSavePanelDelegate()
1108{
1109 Q_Q(QFileDialog);
1110 if (mDelegate)
1111 return;
1112
1113 bool selectDir = q->selectedFiles().isEmpty();
1114 QString selection(selectDir ? q->directory().absolutePath() : q->selectedFiles().value(0));
1115 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) alloc]
1116 initWithAcceptMode:acceptMode
1117 title:q->windowTitle()
1118 hideNameFilterDetails:q->testOption(QFileDialog::HideNameFilterDetails)
1119 qDirFilter:model->filter()
1120 fileOptions:opts
1121 fileMode:fileMode
1122 selectFile:selection
1123 confirmOverwrite:!q->testOption(QFileDialog::DontConfirmOverwrite)
1124 priv:this];
1125
1126 mDelegate = delegate;
1127}
1128
1129bool QFileDialogPrivate::showCocoaFilePanel()
1130{
1131 Q_Q(QFileDialog);
1132 QMacCocoaAutoReleasePool pool;
1133 createNSOpenSavePanelDelegate();
1134 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
1135 if (qt_mac_is_macsheet(q))
1136 [delegate showWindowModalSheet:q->parentWidget()];
1137 else if (!q->testAttribute(Qt::WA_ShowModal))
1138 [delegate showModelessPanel];
1139 return true;
1140}
1141
1142bool QFileDialogPrivate::hideCocoaFilePanel()
1143{
1144 if (!mDelegate){
1145 // Nothing to do. We return false to leave the question
1146 // open regarding whether or not to go native:
1147 return false;
1148 } else {
1149 QMacCocoaAutoReleasePool pool;
1150 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
1151 [delegate closePanel];
1152 // Even when we hide it, we are still using a
1153 // native dialog, so return true:
1154 return true;
1155 }
1156}
1157
1158#endif
1159
1160void QFileDialogPrivate::mac_nativeDialogModalHelp()
1161{
1162 // Do a queued meta-call to open the native modal dialog so it opens after the new
1163 // event loop has started to execute (in QDialog::exec). Using a timer rather than
1164 // a queued meta call is intentional to ensure that the call is only delivered when
1165 // [NSApp run] runs (timers are handeled special in cocoa). If NSApp is not
1166 // running (which is the case if e.g a top-most QEventLoop has been
1167 // interrupted, and the second-most event loop has not yet been reactivated (regardless
1168 // if [NSApp run] is still on the stack)), showing a native modal dialog will fail.
1169 if (nativeDialogInUse){
1170 Q_Q(QFileDialog);
1171 QTimer::singleShot(1, q, SLOT(_q_macRunNativeAppModalPanel()));
1172 }
1173}
1174
1175void QFileDialogPrivate::_q_macRunNativeAppModalPanel()
1176{
1177 QBoolBlocker nativeDialogOnTop(QApplicationPrivate::native_modal_dialog_active);
1178#ifndef QT_MAC_USE_COCOA
1179 NavDialogRun(mDialog);
1180#else
1181 Q_Q(QFileDialog);
1182 QMacCocoaAutoReleasePool pool;
1183 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
1184 [delegate runApplicationModalPanel];
1185 dialogResultCode_sys() == QDialog::Accepted ? q->accept() : q->reject();
1186#endif
1187}
1188
1189QDialog::DialogCode QFileDialogPrivate::dialogResultCode_sys()
1190{
1191#ifndef QT_MAC_USE_COCOA
1192 NavUserAction result = NavDialogGetUserAction(mDialog);
1193 if (result == kNavUserActionCancel || result == kNavUserActionNone)
1194 return QDialog::Rejected;
1195 else
1196 return QDialog::Accepted;
1197#else
1198 QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
1199 return [delegate dialogResultCode];
1200#endif
1201}
1202
1203
1204QT_END_NAMESPACE
1205
1206#endif // QT_NO_FILEDIALOG
1207
1208

Warning: That file was not part of the compilation database. It may have many parsing errors.