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