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 | |
69 | QT_BEGIN_NAMESPACE |
70 | |
71 | extern QStringList qt_make_filter_list(const QString &filter); // qfiledialog.cpp |
72 | extern QStringList qt_clean_filter_list(const QString &filter); // qfiledialog.cpp |
73 | extern const char *qt_file_dialog_filter_reg_exp; // qfiledialog.cpp |
74 | extern bool qt_mac_is_macsheet(const QWidget *w); // qwidget_mac.mm |
75 | |
76 | QT_END_NAMESPACE |
77 | |
78 | QT_FORWARD_DECLARE_CLASS(QFileDialogPrivate) |
79 | QT_FORWARD_DECLARE_CLASS(QString) |
80 | QT_FORWARD_DECLARE_CLASS(QStringList) |
81 | QT_FORWARD_DECLARE_CLASS(QWidget) |
82 | QT_FORWARD_DECLARE_CLASS(QAction) |
83 | QT_FORWARD_DECLARE_CLASS(QFileInfo) |
84 | QT_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( |
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( |
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 | |
583 | QT_BEGIN_NAMESPACE |
584 | |
585 | void QFileDialogPrivate::QNSOpenSavePanelDelegate_selectionChanged(const QString &newPath) |
586 | { |
587 | emit q_func()->currentChanged(newPath); |
588 | } |
589 | |
590 | void QFileDialogPrivate::QNSOpenSavePanelDelegate_panelClosed(bool accepted) |
591 | { |
592 | if (accepted) |
593 | q_func()->accept(); |
594 | else |
595 | q_func()->reject(); |
596 | } |
597 | |
598 | void QFileDialogPrivate::QNSOpenSavePanelDelegate_directoryEntered(const QString &newDir) |
599 | { |
600 | setLastVisitedDirectory(newDir); |
601 | emit q_func()->directoryEntered(newDir); |
602 | } |
603 | |
604 | void QFileDialogPrivate::QNSOpenSavePanelDelegate_filterSelected(int menuIndex) |
605 | { |
606 | emit q_func()->filterSelected(nameFilters.at(menuIndex)); |
607 | } |
608 | |
609 | void 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 | |
630 | QString 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 | |
641 | void 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 | |
682 | QStringList 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 | |
698 | void 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 | |
710 | void 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 | |
728 | void 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 | |
746 | QString 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 | |
758 | void 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 | |
773 | bool 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 |
795 | Boolean 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 | |
842 | void 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 | |
952 | static 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( |
971 | return ret; |
972 | } |
973 | |
974 | static 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 | |
998 | void 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, |
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 | |
1084 | bool 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 | |
1096 | bool QFileDialogPrivate::hideCarbonNavServicesDialog() |
1097 | { |
1098 | if (!mDialogClosed){ |
1099 | mDialogClosed = true; |
1100 | NavCustomControl(mDialog, kNavCtlCancel, 0); |
1101 | } |
1102 | return true; |
1103 | } |
1104 | |
1105 | #else // Cocoa |
1106 | |
1107 | void 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 | |
1129 | bool 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 | |
1142 | bool 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 | |
1160 | void 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 | |
1175 | void 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 | |
1189 | QDialog::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 | |
1204 | QT_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.