File indexing completed on 2025-01-12 12:26:23
0001 // -*- c++ -*- 0002 /* This file is part of the KDE libraries 0003 Copyright (C) 1997, 1998 Richard Moore <rich@kde.org> 0004 1998 Stephan Kulow <coolo@kde.org> 0005 1998 Daniel Grana <grana@ie.iwi.unibe.ch> 0006 1999,2000,2001,2002,2003 Carsten Pfeiffer <pfeiffer@kde.org> 0007 2003 Clarence Dang <dang@kde.org> 0008 2008 JarosÅ‚aw Staniek <staniek@kde.org> 0009 2009 David Jarvie <djarvie@kde.org> 0010 0011 This library is free software; you can redistribute it and/or 0012 modify it under the terms of the GNU Library General Public 0013 License as published by the Free Software Foundation; either 0014 version 2 of the License, or (at your option) any later version. 0015 0016 This library is distributed in the hope that it will be useful, 0017 but WITHOUT ANY WARRANTY; without even the implied warranty of 0018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0019 Library General Public License for more details. 0020 0021 You should have received a copy of the GNU Library General Public License 0022 along with this library; see the file COPYING.LIB. If not, write to 0023 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0024 Boston, MA 02110-1301, USA. 0025 */ 0026 0027 #include "kfiledialog.h" 0028 0029 #include <QCheckBox> 0030 #include <QKeyEvent> 0031 #include <QFileDialog> 0032 #include <QApplication> 0033 #include <QDesktopWidget> 0034 #include <QPushButton> 0035 #include <QVBoxLayout> 0036 #include <qmimedatabase.h> 0037 0038 #include <kimageio.h> 0039 #include <klocalizedstring.h> 0040 #include <krecentdocument.h> 0041 #include <QDebug> 0042 #include <kwindowsystem.h> 0043 #include "kfilewidget.h" 0044 #include "krecentdirs.h" 0045 #include "kservice.h" 0046 #include <ksharedconfig.h> 0047 #include <kwindowconfig.h> 0048 0049 //From defaults-kfile.h in KIOFileWidgets 0050 #define ConfigGroup QLatin1String("KFileDialog Settings") 0051 0052 /** File dialogs are native by default on Windows. */ 0053 #if defined(Q_OS_WIN) 0054 const bool NATIVE_FILEDIALOGS_BY_DEFAULT = true; 0055 #else 0056 const bool NATIVE_FILEDIALOGS_BY_DEFAULT = false; 0057 #endif 0058 0059 static QStringList mime2KdeFilter(const QStringList &mimeTypes, QString *allExtensions = nullptr) 0060 { 0061 QMimeDatabase db; 0062 QStringList kdeFilter; 0063 QStringList allExt; 0064 foreach (const QString &mimeType, mimeTypes) { 0065 QMimeType mime(db.mimeTypeForName(mimeType)); 0066 if (mime.isValid()) { 0067 allExt += mime.globPatterns(); 0068 kdeFilter.append(mime.globPatterns().join(QLatin1String(" ")) + 0069 QLatin1Char('|') + 0070 mime.comment()); 0071 } 0072 } 0073 if (allExtensions) { 0074 allExt.sort(); 0075 *allExtensions = allExt.join(QLatin1String(" ")); 0076 } 0077 return kdeFilter; 0078 } 0079 /** @return File dialog filter in Qt format for @a filters 0080 * or "All files (*)" for empty list. 0081 */ 0082 static QString qtFilter(const QStringList &_filters) 0083 { 0084 QString converted; 0085 const QStringList filters = _filters; 0086 0087 foreach (const QString ¤t, filters) { 0088 QString new_f; //filter part 0089 QString new_name; //filter name part 0090 int p = current.indexOf('|'); 0091 if (p == -1) { 0092 new_f = current; 0093 new_name = current; // nothing better found 0094 } else { 0095 new_f = current.left(p); 0096 new_name = current.mid(p + 1); 0097 } 0098 //Qt filters assume anything in () is the file extension list 0099 new_name = new_name.replace('(', '[').replace(')', ']').trimmed(); 0100 0101 //convert everything to lower case and remove dupes (doesn't matter on win32) 0102 QStringList allfiltersUnique; 0103 const QStringList origList(new_f.split(' ', QString::SkipEmptyParts)); 0104 foreach (const QString &origFilter, origList) { 0105 if (!allfiltersUnique.contains(origFilter, Qt::CaseInsensitive)) { 0106 allfiltersUnique += origFilter.toLower(); 0107 } 0108 } 0109 0110 if (!converted.isEmpty()) { 0111 converted += ";;"; 0112 } 0113 0114 converted += (new_name + " (" + allfiltersUnique.join(" ") + QLatin1Char(')')); 0115 } 0116 0117 // Strip escape characters from escaped '/' characters. 0118 converted.replace("\\/", "/"); 0119 0120 return converted; 0121 } 0122 0123 /** @return File dialog filter in Qt format for @a filter in KDE format 0124 * or "All files (*)" for empty filter. 0125 */ 0126 static QString qtFilter(const QString &filter) 0127 { 0128 // Qt format: "some text (*.first *.second)" or "All files (*)" separated by ;; 0129 // KDE format: "*.first *.second|Description" or "*|Description", separated by \n (Description is optional) 0130 QStringList filters; 0131 if (filter.isEmpty()) { 0132 filters += i18n("*|All files"); 0133 } else { 0134 // check if it's a mimefilter 0135 int pos = filter.indexOf('/'); 0136 if (pos > 0 && filter[pos - 1] != '\\') { 0137 filters = mime2KdeFilter(filter.split(QLatin1Char(' '), QString::SkipEmptyParts)); 0138 } else { 0139 filters = filter.split('\n', QString::SkipEmptyParts); 0140 } 0141 } 0142 return qtFilter(filters); 0143 } 0144 0145 class KFileDialogPrivate 0146 { 0147 public: 0148 /** Data used for native mode. */ 0149 class Native 0150 { 0151 public: 0152 Native() 0153 : mode(KFile::File), 0154 operationMode(KFileWidget::Opening) 0155 { 0156 } 0157 /** @return previously set (global) start dir or the first url 0158 selected using setSelection() or setUrl() if the start dir is empty. */ 0159 QUrl startDir() const 0160 { 0161 if (!s_startDir.isEmpty()) { 0162 return s_startDir; 0163 } 0164 if (!selectedUrls.isEmpty()) { 0165 return selectedUrls.first(); 0166 } 0167 return QUrl(); 0168 } 0169 /** @return previously set (global) start dir or @p defaultDir 0170 if the start dir is empty. */ 0171 static QUrl staticStartDir(const QUrl &defaultDir) 0172 { 0173 if (s_startDir.isEmpty()) { 0174 return defaultDir; 0175 } 0176 return s_startDir; 0177 } 0178 static QUrl s_startDir; 0179 static bool s_allowNative; // as fallback when we can't use native dialog 0180 QString filter; 0181 QString selectedFilter; 0182 QStringList mimeTypes; 0183 QList<QUrl> selectedUrls; 0184 KFile::Modes mode; 0185 KFileWidget::OperationMode operationMode; 0186 }; 0187 0188 KFileDialogPrivate() 0189 : native(nullptr), 0190 w(nullptr), 0191 cfgGroup(KSharedConfig::openConfig(), ConfigGroup) 0192 { 0193 if (cfgGroup.readEntry("Native", NATIVE_FILEDIALOGS_BY_DEFAULT) && 0194 KFileDialogPrivate::Native::s_allowNative) { 0195 native = new Native; 0196 } 0197 } 0198 0199 static bool isNative() 0200 { 0201 if (!KFileDialogPrivate::Native::s_allowNative) { 0202 return false; 0203 } 0204 KConfigGroup cfgGroup(KSharedConfig::openConfig(), ConfigGroup); 0205 return cfgGroup.readEntry("Native", NATIVE_FILEDIALOGS_BY_DEFAULT); 0206 } 0207 0208 static QString getOpenFileName(const QUrl &startDir, const QString &filter, 0209 QWidget *parent, const QString &caption, 0210 QString *selectedFilter); 0211 static QUrl getOpenUrl(const QUrl &startDir, const QString &filter, 0212 QWidget *parent, const QString &caption, 0213 QString *selectedFilter); 0214 static QStringList getOpenFileNames(const QUrl &startDir, const QString &filter, 0215 QWidget *parent, const QString &caption, 0216 QString *selectedFilter); 0217 static QList<QUrl> getOpenUrls(const QUrl &startDir, const QString &filter, 0218 QWidget *parent, const QString &caption, 0219 QString *selectedFilter); 0220 static QString getSaveFileName(const QUrl &dir, const QString &filter, 0221 QWidget *parent, const QString &caption, 0222 KFileDialog::Options options, QString *selectedFilter); 0223 static QUrl getSaveUrl(const QUrl &dir, const QString &filter, 0224 QWidget *parent, const QString &caption, 0225 KFileDialog::Options options, QString *selectedFilter); 0226 0227 ~KFileDialogPrivate() 0228 { 0229 delete native; 0230 } 0231 0232 Native *native; 0233 KFileWidget *w; 0234 KConfigGroup cfgGroup; 0235 }; 0236 0237 QUrl KFileDialogPrivate::Native::s_startDir; 0238 bool KFileDialogPrivate::Native::s_allowNative = true; 0239 0240 KFileDialog::KFileDialog(const QUrl &startDir, const QString &filter, 0241 QWidget *parent, QWidget *customWidget) 0242 #ifdef Q_OS_WIN 0243 : QDialog(parent, Qt::WindowMinMaxButtonsHint), 0244 #else 0245 : QDialog(parent), 0246 #endif 0247 d(new KFileDialogPrivate) 0248 0249 { 0250 if (d->native) { 0251 KFileDialogPrivate::Native::s_startDir = startDir; 0252 // check if it's a mimefilter 0253 int pos = filter.indexOf('/'); 0254 if (pos > 0 && filter[pos - 1] != '\\') { 0255 setMimeFilter(filter.split(QLatin1Char(' '), QString::SkipEmptyParts)); 0256 } else { 0257 setFilter(filter); 0258 } 0259 return; 0260 } 0261 0262 d->w = new KFileWidget(startDir, this); 0263 KFileWidget *fileQWidget = d->w; 0264 0265 KWindowConfig::restoreWindowSize(windowHandle(), d->cfgGroup); // call this before the fileQWidget is set as the main widget. 0266 // otherwise the sizes for the components are not obeyed (ereslibre) 0267 0268 d->w->setFilter(filter); 0269 QVBoxLayout *layout = new QVBoxLayout; 0270 layout->addWidget(fileQWidget); 0271 setLayout(layout); 0272 0273 d->w->okButton()->show(); 0274 connect(d->w->okButton(), SIGNAL(clicked()), SLOT(slotOk())); 0275 d->w->cancelButton()->show(); 0276 connect(d->w->cancelButton(), SIGNAL(clicked()), SLOT(slotCancel())); 0277 0278 // Publish signals 0279 connect(fileQWidget, SIGNAL(fileSelected(QUrl)), 0280 SIGNAL(fileSelected(QUrl))); 0281 connect(fileQWidget, SIGNAL(fileHighlighted(QUrl)), 0282 SIGNAL(fileHighlighted(QUrl))); 0283 connect(fileQWidget, SIGNAL(selectionChanged()), 0284 SIGNAL(selectionChanged())); 0285 connect(fileQWidget, SIGNAL(filterChanged(QString)), 0286 SIGNAL(filterChanged(QString))); 0287 0288 connect(fileQWidget, SIGNAL(accepted()), SLOT(accept())); 0289 //connect(fileQWidget, SIGNAL(canceled()), SLOT(slotCancel())); 0290 0291 if (customWidget) { 0292 d->w->setCustomWidget(QString(), customWidget); 0293 } 0294 } 0295 0296 KFileDialog::~KFileDialog() 0297 { 0298 delete d; 0299 } 0300 0301 void KFileDialog::setLocationLabel(const QString &text) 0302 { 0303 if (d->w) { 0304 d->w->setLocationLabel(text); 0305 } 0306 } 0307 0308 void KFileDialog::setFilter(const QString &filter) 0309 { 0310 if (d->native) { 0311 d->native->filter = filter; 0312 return; 0313 } 0314 d->w->setFilter(filter); 0315 } 0316 0317 QString KFileDialog::currentFilter() const 0318 { 0319 if (d->w) { 0320 return d->w->currentFilter(); 0321 } 0322 return QString(); // not available 0323 } 0324 0325 void KFileDialog::setMimeFilter(const QStringList &mimeTypes, 0326 const QString &defaultType) 0327 { 0328 if (d->native) { 0329 QString allExtensions; 0330 QStringList filters = mime2KdeFilter(mimeTypes, &allExtensions); 0331 if (defaultType.isEmpty() && (mimeTypes.count() > 1)) { 0332 filters.prepend(allExtensions + QLatin1Char('|') + i18n("All Supported Files")); 0333 } 0334 d->native->filter = filters.join(QLatin1String("\n")); 0335 return; 0336 } 0337 d->w->setMimeFilter(mimeTypes, defaultType); 0338 } 0339 0340 void KFileDialog::clearFilter() 0341 { 0342 if (d->native) { 0343 d->native->filter.clear(); 0344 return; 0345 } 0346 d->w->clearFilter(); 0347 } 0348 0349 QString KFileDialog::currentMimeFilter() const 0350 { 0351 if (d->native) { 0352 // adapted from qt2KdeFilter 0353 QString filter = d->native->selectedFilter.split(";;").replaceInStrings("/", "\\/")[0]; 0354 filter = filter.mid(filter.indexOf('(') + 1, filter.indexOf(')') - filter.indexOf('(') - 1); 0355 QMimeDatabase db; 0356 QString mimetype = db.mimeTypeForFile("test" + filter.mid(1).split(' ')[0], QMimeDatabase::MatchExtension).name(); 0357 return mimetype; 0358 } 0359 return d->w->currentMimeFilter(); 0360 } 0361 0362 QMimeType KFileDialog::currentFilterMimeType() 0363 { 0364 QMimeDatabase db; 0365 return db.mimeTypeForName(currentMimeFilter()); 0366 } 0367 0368 void KFileDialog::setPreviewWidget(KPreviewWidgetBase *w) 0369 { 0370 if (d->w) { 0371 d->w->setPreviewWidget(w); 0372 } 0373 } 0374 0375 void KFileDialog::setInlinePreviewShown(bool show) 0376 { 0377 if (d->w) { 0378 d->w->setInlinePreviewShown(show); 0379 } 0380 } 0381 0382 // This is only used for the initial size when no configuration has been saved 0383 QSize KFileDialog::sizeHint() const 0384 { 0385 if (d->w) { 0386 return d->w->dialogSizeHint(); 0387 } 0388 return QSize(); 0389 } 0390 0391 // This slot still exists mostly for compat purposes; for subclasses which reimplement slotOk 0392 void KFileDialog::slotOk() 0393 { 0394 if (d->w) { 0395 d->w->slotOk(); 0396 } 0397 } 0398 0399 // This slot still exists mostly for compat purposes; for subclasses which reimplement accept 0400 void KFileDialog::accept() 0401 { 0402 if (d->w) { 0403 setResult(QDialog::Accepted); // keep old behavior; probably not needed though 0404 d->w->accept(); 0405 KConfigGroup cfgGroup(KSharedConfig::openConfig(), ConfigGroup); 0406 QDialog::accept(); 0407 } 0408 } 0409 0410 // This slot still exists mostly for compat purposes; for subclasses which reimplement slotCancel 0411 void KFileDialog::slotCancel() 0412 { 0413 if (d->w) { 0414 d->w->slotCancel(); 0415 reject(); 0416 } 0417 } 0418 0419 void KFileDialog::setUrl(const QUrl &url, bool clearforward) 0420 { 0421 if (d->native) { 0422 d->native->selectedUrls.clear(); 0423 d->native->selectedUrls.append(url); 0424 return; 0425 } 0426 d->w->setUrl(url, clearforward); 0427 } 0428 0429 void KFileDialog::setSelection(const QString &name) 0430 { 0431 if (d->native) { 0432 d->native->selectedUrls.clear(); 0433 d->native->selectedUrls.append(QUrl(name)); // could be relative 0434 return; 0435 } 0436 d->w->setSelection(name); 0437 } 0438 0439 QString KFileDialog::getOpenFileName(const QUrl &startDir, 0440 const QString &filter, 0441 QWidget *parent, const QString &caption) 0442 { 0443 return KFileDialogPrivate::getOpenFileName(startDir, filter, parent, caption, nullptr); 0444 } 0445 0446 QString KFileDialogPrivate::getOpenFileName(const QUrl &startDir, 0447 const QString &filter, 0448 QWidget *parent, 0449 const QString &caption, 0450 QString *selectedFilter) 0451 { 0452 if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { 0453 return QFileDialog::getOpenFileName( 0454 parent, 0455 caption.isEmpty() ? i18n("Open") : caption, 0456 KFileDialogPrivate::Native::staticStartDir(startDir).toLocalFile(), 0457 qtFilter(filter), 0458 selectedFilter); 0459 // TODO use extra args? QString * selectedFilter = 0, Options options = 0 0460 } 0461 KFileDialog dlg(startDir, filter, parent); 0462 0463 dlg.setOperationMode(KFileDialog::Opening); 0464 dlg.setMode(KFile::File | KFile::LocalOnly | KFile::ExistingOnly); 0465 dlg.setWindowTitle(caption.isEmpty() ? i18n("Open") : caption); 0466 0467 dlg.exec(); 0468 if (selectedFilter) { 0469 *selectedFilter = dlg.currentMimeFilter(); 0470 } 0471 return dlg.selectedFile(); 0472 } 0473 0474 QString KFileDialog::getOpenFileNameWId(const QUrl &startDir, 0475 const QString &filter, 0476 WId parent_id, const QString &caption) 0477 { 0478 if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { 0479 return KFileDialog::getOpenFileName(startDir, filter, nullptr, caption); // everything we can do... 0480 } 0481 QWidget *parent = QWidget::find(parent_id); 0482 KFileDialogPrivate::Native::s_allowNative = false; 0483 KFileDialog dlg(startDir, filter, parent); 0484 if (parent == nullptr && parent_id != 0) { 0485 dlg.setAttribute(Qt::WA_NativeWindow, true); 0486 KWindowSystem::setMainWindow(dlg.windowHandle(), parent_id); 0487 } 0488 0489 dlg.setOperationMode(KFileDialog::Opening); 0490 dlg.setMode(KFile::File | KFile::LocalOnly | KFile::ExistingOnly); 0491 dlg.setWindowTitle(caption.isEmpty() ? i18n("Open") : caption); 0492 0493 dlg.exec(); 0494 0495 return dlg.selectedFile(); 0496 } 0497 0498 QStringList KFileDialog::getOpenFileNames(const QUrl &startDir, 0499 const QString &filter, 0500 QWidget *parent, 0501 const QString &caption) 0502 { 0503 return KFileDialogPrivate::getOpenFileNames(startDir, filter, parent, caption, nullptr); 0504 } 0505 0506 QStringList KFileDialogPrivate::getOpenFileNames(const QUrl &startDir, 0507 const QString &filter, 0508 QWidget *parent, 0509 const QString &caption, 0510 QString *selectedFilter) 0511 { 0512 if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { 0513 return QFileDialog::getOpenFileNames( 0514 parent, 0515 caption.isEmpty() ? i18n("Open") : caption, 0516 KFileDialogPrivate::Native::staticStartDir(startDir).toLocalFile(), 0517 qtFilter(filter), selectedFilter); 0518 // TODO use extra args? QString * selectedFilter = 0, Options options = 0 0519 } 0520 KFileDialogPrivate::Native::s_allowNative = false; 0521 KFileDialog dlg(startDir, filter, parent); 0522 0523 dlg.setOperationMode(KFileDialog::Opening); 0524 dlg.setMode(KFile::Files | KFile::LocalOnly | KFile::ExistingOnly); 0525 dlg.setWindowTitle(caption.isEmpty() ? i18n("Open") : caption); 0526 0527 dlg.exec(); 0528 if (selectedFilter) { 0529 *selectedFilter = dlg.currentMimeFilter(); 0530 } 0531 return dlg.selectedFiles(); 0532 } 0533 0534 QUrl KFileDialog::getOpenUrl(const QUrl &startDir, const QString &filter, 0535 QWidget *parent, const QString &caption) 0536 { 0537 return KFileDialogPrivate::getOpenUrl(startDir, filter, parent, caption, nullptr); 0538 } 0539 QUrl KFileDialogPrivate::getOpenUrl(const QUrl &startDir, const QString &filter, 0540 QWidget *parent, const QString &caption, 0541 QString *selectedFilter) 0542 { 0543 if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { 0544 const QString fileName(KFileDialogPrivate::getOpenFileName( 0545 startDir, filter, parent, caption, selectedFilter)); 0546 return fileName.isEmpty() ? QUrl() : QUrl::fromLocalFile(fileName); 0547 } 0548 KFileDialogPrivate::Native::s_allowNative = false; 0549 KFileDialog dlg(startDir, filter, parent); 0550 0551 dlg.setOperationMode(KFileDialog::Opening); 0552 dlg.setMode(KFile::File | KFile::ExistingOnly); 0553 dlg.setWindowTitle(caption.isEmpty() ? i18n("Open") : caption); 0554 0555 dlg.exec(); 0556 if (selectedFilter) { 0557 *selectedFilter = dlg.currentMimeFilter(); 0558 } 0559 return dlg.selectedUrl(); 0560 } 0561 0562 QList<QUrl> KFileDialog::getOpenUrls(const QUrl &startDir, 0563 const QString &filter, 0564 QWidget *parent, 0565 const QString &caption) 0566 { 0567 return KFileDialogPrivate::getOpenUrls(startDir, filter, parent, caption, nullptr); 0568 } 0569 0570 QList<QUrl> KFileDialogPrivate::getOpenUrls(const QUrl &startDir, 0571 const QString &filter, 0572 QWidget *parent, 0573 const QString &caption, 0574 QString *selectedFilter) 0575 { 0576 if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { 0577 const QStringList fileNames(KFileDialogPrivate::getOpenFileNames( 0578 startDir, filter, parent, caption, selectedFilter)); 0579 QList<QUrl> urls; 0580 Q_FOREACH (const QString &file, fileNames) { 0581 urls.append(QUrl::fromLocalFile(file)); 0582 } 0583 return urls; 0584 } 0585 KFileDialogPrivate::Native::s_allowNative = false; 0586 0587 KFileDialog dlg(startDir, filter, parent); 0588 0589 dlg.setOperationMode(KFileDialog::Opening); 0590 dlg.setMode(KFile::Files | KFile::ExistingOnly); 0591 dlg.setWindowTitle(caption.isEmpty() ? i18n("Open") : caption); 0592 0593 dlg.exec(); 0594 if (selectedFilter) { 0595 *selectedFilter = dlg.currentMimeFilter(); 0596 } 0597 return dlg.selectedUrls(); 0598 } 0599 0600 void KFileDialog::setConfirmOverwrite(bool enable) 0601 { 0602 if (d->w && operationMode() == KFileDialog::Saving) { 0603 d->w->setConfirmOverwrite(enable); 0604 } 0605 } 0606 0607 QUrl KFileDialog::getExistingDirectoryUrl(const QUrl &startDir, 0608 QWidget *parent, 0609 const QString &caption) 0610 { 0611 return QFileDialog::getExistingDirectoryUrl(parent, caption, KFileDialogPrivate::Native::staticStartDir(startDir)); 0612 } 0613 0614 QString KFileDialog::getExistingDirectory(const QUrl &startDir, 0615 QWidget *parent, 0616 const QString &caption) 0617 { 0618 if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { 0619 return QFileDialog::getExistingDirectory(parent, caption, 0620 KFileDialogPrivate::Native::staticStartDir(startDir).toLocalFile(), 0621 QFileDialog::ShowDirsOnly); 0622 } 0623 QUrl url = KFileDialog::getExistingDirectoryUrl(startDir, parent, caption); 0624 if (url.isValid()) { 0625 return url.toLocalFile(); 0626 } 0627 return QString(); 0628 } 0629 0630 QUrl KFileDialog::getImageOpenUrl(const QUrl &startDir, QWidget *parent, 0631 const QString &caption) 0632 { 0633 if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { // everything we can do... 0634 const QStringList mimetypes(KImageIO::mimeTypes(KImageIO::Reading)); 0635 return KFileDialog::getOpenUrl(startDir, mimetypes.join(" "), parent, caption); 0636 } 0637 const QStringList mimetypes = KImageIO::mimeTypes(KImageIO::Reading); 0638 KFileDialogPrivate::Native::s_allowNative = false; 0639 KFileDialog dlg(startDir, mimetypes.join(" "), parent); 0640 0641 dlg.setOperationMode(KFileDialog::Opening); 0642 dlg.setMode(KFile::File | KFile::ExistingOnly); 0643 dlg.setWindowTitle(caption.isEmpty() ? i18n("Open") : caption); 0644 dlg.setInlinePreviewShown(true); 0645 0646 dlg.exec(); 0647 0648 return dlg.selectedUrl(); 0649 } 0650 0651 QUrl KFileDialog::selectedUrl() const 0652 { 0653 if (d->native) { 0654 return d->native->selectedUrls.isEmpty() ? QUrl() : d->native->selectedUrls.first(); 0655 } 0656 return d->w->selectedUrl(); 0657 } 0658 0659 QList<QUrl> KFileDialog::selectedUrls() const 0660 { 0661 if (d->native) { 0662 return d->native->selectedUrls; 0663 } 0664 return d->w->selectedUrls(); 0665 } 0666 0667 QString KFileDialog::selectedFile() const 0668 { 0669 if (d->native) { 0670 return selectedUrl().toLocalFile(); 0671 } 0672 return d->w->selectedFile(); 0673 } 0674 0675 QStringList KFileDialog::selectedFiles() const 0676 { 0677 if (d->native) { 0678 QStringList lst; 0679 Q_FOREACH (const QUrl &u, selectedUrls()) { 0680 if (u.isLocalFile()) { 0681 lst.append(u.toLocalFile()); 0682 } 0683 } 0684 return lst; 0685 } 0686 return d->w->selectedFiles(); 0687 } 0688 0689 QUrl KFileDialog::baseUrl() const 0690 { 0691 if (d->native) { 0692 return selectedUrl().isEmpty() ? QUrl() : QUrl::fromLocalFile(selectedUrl().path()); /* shouldn't that be .directory()? */ 0693 } 0694 return d->w->baseUrl(); 0695 } 0696 0697 QString KFileDialog::getSaveFileName(const QUrl &dir, const QString &filter, 0698 QWidget *parent, 0699 const QString &caption) 0700 { 0701 //TODO KDE5: replace this method by the method below (with default parameter values in declaration) 0702 // Set no confirm-overwrite mode for backwards compatibility 0703 return KFileDialogPrivate::getSaveFileName(dir, filter, parent, caption, Options(), nullptr); 0704 } 0705 0706 QString KFileDialog::getSaveFileName(const QUrl &dir, const QString &filter, 0707 QWidget *parent, 0708 const QString &caption, Options options) 0709 { 0710 return KFileDialogPrivate::getSaveFileName(dir, filter, parent, caption, options, nullptr); 0711 } 0712 0713 QString KFileDialogPrivate::getSaveFileName(const QUrl &dir, const QString &filter, 0714 QWidget *parent, const QString &caption, 0715 KFileDialog::Options options, QString *selectedFilter) 0716 { 0717 if (KFileDialogPrivate::isNative()) { 0718 bool defaultDir = dir.isEmpty(); 0719 bool specialDir = !defaultDir && dir.scheme() == "kfiledialog"; 0720 QUrl startDir; 0721 QString recentDirClass; 0722 if (specialDir) { 0723 startDir = KFileDialog::getStartUrl(dir, recentDirClass); 0724 } else if (!specialDir && !defaultDir) { 0725 if (!dir.isLocalFile()) { 0726 qWarning() << "non-local start dir " << dir; 0727 } 0728 startDir = dir; 0729 } 0730 0731 QFileDialog::Options opts = (options & KFileDialog::ConfirmOverwrite) ? QFileDialog::Options() : QFileDialog::DontConfirmOverwrite; 0732 const QString result = QFileDialog::getSaveFileName( 0733 parent, 0734 caption.isEmpty() ? i18n("Save As") : caption, 0735 KFileDialogPrivate::Native::staticStartDir(startDir).toLocalFile(), 0736 qtFilter(filter), 0737 // TODO use extra args? QString * selectedFilter = 0, Options opts = 0 0738 selectedFilter, opts); 0739 if (!result.isEmpty()) { 0740 if (!recentDirClass.isEmpty()) { 0741 KRecentDirs::add(recentDirClass, QUrl::fromLocalFile(result).toString()); 0742 } 0743 KRecentDocument::add(result); 0744 } 0745 return result; 0746 } 0747 0748 KFileDialog dlg(dir, filter, parent); 0749 0750 dlg.setOperationMode(KFileDialog::Saving); 0751 dlg.setMode(KFile::File | KFile::LocalOnly); 0752 dlg.setConfirmOverwrite(options & KFileDialog::ConfirmOverwrite); 0753 dlg.setInlinePreviewShown(options & KFileDialog::ShowInlinePreview); 0754 dlg.setWindowTitle(caption.isEmpty() ? i18n("Save As") : caption); 0755 0756 dlg.exec(); 0757 0758 QString filename = dlg.selectedFile(); 0759 if (!filename.isEmpty()) { 0760 KRecentDocument::add(filename); 0761 } 0762 0763 return filename; 0764 } 0765 0766 QString KFileDialog::getSaveFileNameWId(const QUrl &dir, const QString &filter, 0767 WId parent_id, 0768 const QString &caption) 0769 { 0770 //TODO KDE5: replace this method by the method below (with default parameter values in declaration) 0771 // Set no confirm-overwrite mode for backwards compatibility 0772 return getSaveFileNameWId(dir, filter, parent_id, caption, Options()); 0773 } 0774 0775 QString KFileDialog::getSaveFileNameWId(const QUrl &dir, const QString &filter, 0776 WId parent_id, 0777 const QString &caption, Options options) 0778 { 0779 if (KFileDialogPrivate::isNative()) { 0780 return KFileDialog::getSaveFileName(dir, filter, nullptr, caption, options); // everything we can do... 0781 } 0782 0783 QWidget *parent = QWidget::find(parent_id); 0784 KFileDialog dlg(dir, filter, parent); 0785 if (parent == nullptr && parent_id != 0) { 0786 dlg.setAttribute(Qt::WA_NativeWindow, true); 0787 KWindowSystem::setMainWindow(dlg.windowHandle(), parent_id); 0788 } 0789 0790 dlg.setOperationMode(KFileDialog::Saving); 0791 dlg.setMode(KFile::File | KFile::LocalOnly); 0792 dlg.setConfirmOverwrite(options & ConfirmOverwrite); 0793 dlg.setInlinePreviewShown(options & ShowInlinePreview); 0794 dlg.setWindowTitle(caption.isEmpty() ? i18n("Save As") : caption); 0795 0796 dlg.exec(); 0797 0798 QString filename = dlg.selectedFile(); 0799 if (!filename.isEmpty()) { 0800 KRecentDocument::add(filename); 0801 } 0802 0803 return filename; 0804 } 0805 0806 QUrl KFileDialog::getSaveUrl(const QUrl &dir, const QString &filter, 0807 QWidget *parent, const QString &caption) 0808 { 0809 //TODO KDE5: replace this method by the method below (with default parameter values in declaration) 0810 // Set no confirm-overwrite mode for backwards compatibility 0811 return KFileDialogPrivate::getSaveUrl(dir, filter, parent, caption, Options(), nullptr); 0812 } 0813 0814 QUrl KFileDialog::getSaveUrl(const QUrl &dir, const QString &filter, 0815 QWidget *parent, const QString &caption, Options options) 0816 { 0817 return KFileDialogPrivate::getSaveUrl(dir, filter, parent, caption, options, nullptr); 0818 } 0819 0820 QUrl KFileDialogPrivate::getSaveUrl(const QUrl &dir, const QString &filter, 0821 QWidget *parent, const QString &caption, 0822 KFileDialog::Options options, QString *selectedFilter) 0823 { 0824 if (KFileDialogPrivate::isNative() && (!dir.isValid() || dir.isLocalFile())) { 0825 const QString fileName(KFileDialogPrivate::getSaveFileName( 0826 dir, filter, parent, caption, options, selectedFilter)); 0827 return fileName.isEmpty() ? QUrl() : QUrl::fromLocalFile(fileName); 0828 } 0829 0830 KFileDialogPrivate::Native::s_allowNative = false; 0831 0832 KFileDialog dlg(dir, filter, parent); 0833 0834 dlg.setOperationMode(KFileDialog::Saving); 0835 dlg.setMode(KFile::File); 0836 dlg.setConfirmOverwrite(options & KFileDialog::ConfirmOverwrite); 0837 dlg.setInlinePreviewShown(options & KFileDialog::ShowInlinePreview); 0838 dlg.setWindowTitle(caption.isEmpty() ? i18n("Save As") : caption); 0839 0840 dlg.exec(); 0841 if (selectedFilter) { 0842 *selectedFilter = dlg.currentMimeFilter(); 0843 } 0844 QUrl url = dlg.selectedUrl(); 0845 if (url.isValid()) { 0846 KRecentDocument::add(url); 0847 } 0848 0849 return url; 0850 } 0851 0852 void KFileDialog::setMode(KFile::Modes m) 0853 { 0854 if (d->native) { 0855 d->native->mode = m; 0856 } else { 0857 d->w->setMode(m); 0858 } 0859 } 0860 0861 KFile::Modes KFileDialog::mode() const 0862 { 0863 if (d->native) { 0864 return d->native->mode; 0865 } 0866 return d->w->mode(); 0867 } 0868 0869 QPushButton *KFileDialog::okButton() const 0870 { 0871 if (d->w) { 0872 return d->w->okButton(); 0873 } 0874 return nullptr; 0875 } 0876 0877 QPushButton *KFileDialog::cancelButton() const 0878 { 0879 if (d->w) { 0880 return d->w->cancelButton(); 0881 } 0882 return nullptr; 0883 } 0884 0885 KUrlComboBox *KFileDialog::locationEdit() const 0886 { 0887 if (d->w) { 0888 return d->w->locationEdit(); 0889 } 0890 return nullptr; 0891 } 0892 0893 KFileFilterCombo *KFileDialog::filterWidget() const 0894 { 0895 if (d->w) { 0896 return d->w->filterWidget(); 0897 } 0898 return nullptr; 0899 } 0900 0901 KActionCollection *KFileDialog::actionCollection() const 0902 { 0903 if (d->w) { 0904 return d->w->actionCollection(); 0905 } 0906 return nullptr; 0907 } 0908 0909 void KFileDialog::setKeepLocation(bool keep) 0910 { 0911 if (d->w) { 0912 d->w->setKeepLocation(keep); 0913 } 0914 } 0915 0916 bool KFileDialog::keepsLocation() const 0917 { 0918 if (d->w) { 0919 return d->w->keepsLocation(); 0920 } 0921 return false; 0922 } 0923 0924 void KFileDialog::setOperationMode(OperationMode mode) 0925 { 0926 if (d->native) { 0927 d->native->operationMode = static_cast<KFileWidget::OperationMode>(mode); 0928 } else { 0929 d->w->setOperationMode(static_cast<KFileWidget::OperationMode>(mode)); 0930 } 0931 } 0932 0933 KFileDialog::OperationMode KFileDialog::operationMode() const 0934 { 0935 if (d->native) { 0936 return static_cast<KFileDialog::OperationMode>(d->native->operationMode); 0937 } 0938 return static_cast<KFileDialog::OperationMode>(d->w->operationMode()); 0939 } 0940 0941 void KFileDialog::keyPressEvent(QKeyEvent *e) 0942 { 0943 if (d->w) { 0944 if (e->key() == Qt::Key_Escape) { 0945 e->accept(); 0946 d->w->cancelButton()->animateClick(); 0947 } else { 0948 QDialog::keyPressEvent(e); 0949 } 0950 } 0951 } 0952 0953 void KFileDialog::hideEvent(QHideEvent *e) 0954 { 0955 if (d->w) { 0956 KWindowConfig::saveWindowSize(windowHandle(), d->cfgGroup, KConfigBase::Persistent); 0957 0958 QDialog::hideEvent(e); 0959 } 0960 } 0961 0962 // static 0963 QUrl KFileDialog::getStartUrl(const QUrl &startDir, 0964 QString &recentDirClass) 0965 { 0966 return KFileWidget::getStartUrl(startDir, recentDirClass); 0967 } 0968 0969 void KFileDialog::setStartDir(const QUrl &directory) 0970 { 0971 if (KFileDialogPrivate::isNative()) { 0972 KFileDialogPrivate::Native::s_startDir = directory; 0973 } 0974 KFileWidget::setStartDir(directory); 0975 } 0976 0977 KToolBar *KFileDialog::toolBar() const 0978 { 0979 if (d->w) { 0980 return d->w->toolBar(); 0981 } 0982 return nullptr; 0983 } 0984 0985 KFileWidget *KFileDialog::fileWidget() 0986 { 0987 return d->w; 0988 } 0989 0990 #ifdef Q_OS_WIN 0991 int KFileDialog::exec() 0992 { 0993 if (!d->native || !KFileDialogPrivate::Native::s_allowNative) { 0994 KFileDialogPrivate::Native::s_allowNative = true; 0995 return QDialog::exec(); 0996 } 0997 0998 // not clear here to let KFileDialogPrivate::Native::startDir() return a useful value 0999 // d->native->selectedUrls.clear(); 1000 int res = QDialog::Rejected; 1001 switch (d->native->operationMode) { 1002 case KFileWidget::Opening: 1003 case KFileWidget::Other: 1004 if (d->native->mode & KFile::File) { 1005 QUrl url(KFileDialogPrivate::getOpenUrl( 1006 d->native->startDir(), d->native->filter, parentWidget(), windowTitle(), &d->native->selectedFilter)); 1007 if (url.isEmpty() || !url.isValid()) { 1008 res = QDialog::Rejected; 1009 break; 1010 } 1011 d->native->selectedUrls.clear(); 1012 d->native->selectedUrls.append(url); 1013 res = QDialog::Accepted; 1014 break; 1015 } else if (d->native->mode & KFile::Files) { 1016 QList<QUrl> urls(KFileDialogPrivate::getOpenUrls( 1017 d->native->startDir(), d->native->filter, parentWidget(), windowTitle(), &d->native->selectedFilter)); 1018 if (urls.isEmpty()) { 1019 res = QDialog::Rejected; 1020 break; 1021 } 1022 d->native->selectedUrls = urls; 1023 res = QDialog::Accepted; 1024 break; 1025 } else if (d->native->mode & KFile::Directory) { 1026 QUrl url(KFileDialog::getExistingDirectoryUrl( 1027 d->native->startDir(), parentWidget(), windowTitle())); 1028 if (url.isEmpty() || !url.isValid()) { 1029 res = QDialog::Rejected; 1030 break; 1031 } 1032 d->native->selectedUrls.clear(); 1033 d->native->selectedUrls.append(url); 1034 res = QDialog::Accepted; 1035 break; 1036 } 1037 break; 1038 case KFileWidget::Saving: 1039 if (d->native->mode & KFile::File) { 1040 QUrl url(KFileDialogPrivate::getSaveUrl( 1041 d->native->startDir(), d->native->filter, parentWidget(), windowTitle(), Options(), &d->native->selectedFilter)); 1042 if (url.isEmpty() || !url.isValid()) { 1043 res = QDialog::Rejected; 1044 break; 1045 } 1046 d->native->selectedUrls.clear(); 1047 d->native->selectedUrls.append(url); 1048 res = QDialog::Accepted; 1049 break; 1050 } else if (d->native->mode & KFile::Directory) { 1051 QUrl url(KFileDialog::getExistingDirectoryUrl( 1052 d->native->startDir(), parentWidget(), windowTitle())); 1053 if (url.isEmpty() || !url.isValid()) { 1054 res = QDialog::Rejected; 1055 break; 1056 } 1057 d->native->selectedUrls.clear(); 1058 d->native->selectedUrls.append(url); 1059 res = QDialog::Accepted; 1060 break; 1061 } 1062 break; 1063 default:; 1064 } 1065 1066 setResult(res); 1067 emit finished(res); 1068 1069 if (res == QDialog::Accepted) { 1070 emit accepted(); 1071 } else { 1072 emit rejected(); 1073 } 1074 1075 return res; 1076 } 1077 #endif // Q_OS_WIN 1078 1079 #include "moc_kfiledialog.cpp"