0
|
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 |
|