// -*- c++ -*- /* This file is part of the KDE libraries Copyright (C) 1997, 1998 Richard Moore 1998 Stephan Kulow 1998 Daniel Grana 1999,2000,2001,2002,2003 Carsten Pfeiffer 2003 Clarence Dang 2008 Jarosław Staniek 2009 David Jarvie This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kfiledialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "kabstractfilewidget.h" #include "kabstractfilemodule.h" #include "krecentdirs.h" #include "kservice.h" static QStringList mime2KdeFilter( const QStringList &mimeTypes, QString *allExtensions = 0 ) { const KUrl emptyUrl; QStringList kdeFilter; QStringList allExt; foreach (const QString& mimeType, mimeTypes) { KMimeType::Ptr mime( KMimeType::mimeType(mimeType) ); if (mime) { allExt += mime->patterns(); kdeFilter.append(mime->patterns().join(QLatin1String(" ")) + QLatin1Char('|') + mime->comment(emptyUrl)); } } if (allExtensions) { allExt.sort(); *allExtensions = allExt.join(QLatin1String(" ")); } return kdeFilter; } /** @return File dialog filter in Qt format for @a filters * or "All files (*)" for empty list. */ static QString qtFilter(const QStringList& _filters) { QString converted; const QStringList filters = _filters; foreach (const QString& current, filters) { QString new_f; //filter part QString new_name; //filter name part int p = current.indexOf('|'); if (p==-1) { new_f = current; new_name = current; // nothing better found } else { new_f = current.left(p); new_name = current.mid(p+1); } //Qt filters assume anything in () is the file extension list new_name = new_name.replace('(', '[').replace(')',']').trimmed(); //convert everything to lower case and remove dupes (doesn't matter on win32) QStringList allfiltersUnique; const QStringList origList( new_f.split(' ', QString::SkipEmptyParts) ); foreach (const QString& origFilter, origList) { if (!allfiltersUnique.contains(origFilter, Qt::CaseInsensitive)) allfiltersUnique += origFilter.toLower(); } if (!converted.isEmpty()) converted += ";;"; converted += (new_name + " (" + allfiltersUnique.join(" ") + QLatin1Char(')')); } // Strip escape characters from escaped '/' characters. converted.replace("\\/","/"); return converted; } /** @return File dialog filter in Qt format for @a filter in KDE format * or "All files (*)" for empty filter. */ static QString qtFilter(const QString& filter) { // Qt format: "some text (*.first *.second)" or "All files (*)" separated by ;; // KDE format: "*.first *.second|Description" or "*|Description", separated by \n (Description is optional) QStringList filters; if (filter.isEmpty()) filters += i18n("*|All files"); else { // check if it's a mimefilter int pos = filter.indexOf('/'); if (pos > 0 && filter[pos - 1] != '\\') filters = mime2KdeFilter(filter.split(QLatin1Char(' '), QString::SkipEmptyParts)); else filters = filter.split('\n', QString::SkipEmptyParts); } return qtFilter(filters); } static KAbstractFileModule* s_module = 0; static KAbstractFileModule* loadFileModule( const QString& moduleName ) { KService::Ptr fileModuleService = KService::serviceByDesktopName(moduleName); if(fileModuleService) return fileModuleService->createInstance(); else return 0; } static const char s_defaultFileModuleName[] = "kfilemodule"; static KAbstractFileModule* fileModule() { if(!s_module) { QString moduleName = KConfig("kdeglobals").group(ConfigGroup).readEntry("file module", s_defaultFileModuleName); if(!(s_module = loadFileModule(moduleName))) { kDebug() << "Failed to load configured file module" << moduleName; if(moduleName != s_defaultFileModuleName) { kDebug() << "Falling back to default file module."; s_module = loadFileModule(s_defaultFileModuleName); } } } return s_module; } class KFileDialogPrivate { public: /** Data used for native mode. */ class Native { public: Native() : mode(KFile::File), operationMode(KAbstractFileWidget::Opening) { } /** @return previously set (global) start dir or the first url selected using setSelection() or setUrl() if the start dir is empty. */ KUrl startDir() const { if (!s_startDir.isEmpty()) return s_startDir; if (!selectedUrls.isEmpty()) return selectedUrls.first(); return KUrl(); } /** @return previously set (global) start dir or @p defaultDir if the start dir is empty. */ static KUrl staticStartDir( const KUrl& defaultDir ) { if ( s_startDir.isEmpty() ) return defaultDir; return s_startDir; } static KUrl s_startDir; static bool s_allowNative; // as fallback when we can't use native dialog QString filter; QString selectedFilter; QStringList mimeTypes; KUrl::List selectedUrls; KFile::Modes mode; KAbstractFileWidget::OperationMode operationMode; }; KFileDialogPrivate() : native(0), w(0), cfgGroup(KGlobal::config(), ConfigGroup) { if (cfgGroup.readEntry("Native", false) && KFileDialogPrivate::Native::s_allowNative) native = new Native; } static bool isNative() { if(!KFileDialogPrivate::Native::s_allowNative) return false; KConfigGroup cfgGroup(KGlobal::config(), ConfigGroup); return cfgGroup.readEntry("Native", false); } static QString getOpenFileName(const KUrl& startDir, const QString& filter, QWidget *parent, const QString& caption, QString *selectedFilter); static KUrl getOpenUrl(const KUrl& startDir, const QString& filter, QWidget *parent, const QString& caption, QString *selectedFilter); static QStringList getOpenFileNames(const KUrl& startDir, const QString& filter, QWidget *parent, const QString& caption, QString *selectedFilter); static KUrl::List getOpenUrls(const KUrl& startDir, const QString& filter, QWidget *parent, const QString& caption, QString *selectedFilter); static QString getSaveFileName(const KUrl& dir, const QString& filter, QWidget *parent, const QString& caption, KFileDialog::Options options, QString *selectedFilter); static KUrl getSaveUrl(const KUrl& dir, const QString& filter, QWidget *parent, const QString& caption, KFileDialog::Options options, QString *selectedFilter); ~KFileDialogPrivate() { delete native; } Native* native; KAbstractFileWidget* w; KConfigGroup cfgGroup; }; KUrl KFileDialogPrivate::Native::s_startDir; bool KFileDialogPrivate::Native::s_allowNative = true; KFileDialog::KFileDialog( const KUrl& startDir, const QString& filter, QWidget *parent, QWidget* customWidget) : KDialog( parent ), d( new KFileDialogPrivate ) { // It would be nice to have this behind d->native but it doesn't work // because of derived classes like KEncodingDialog... // Dlopen the file widget from libkfilemodule QWidget* fileQWidget = fileModule()->createFileWidget(startDir, this); d->w = ::qobject_cast(fileQWidget); if (d->native) { KFileDialogPrivate::Native::s_startDir = startDir; // check if it's a mimefilter int pos = filter.indexOf('/'); if (pos > 0 && filter[pos - 1] != '\\') setMimeFilter(filter.split(QLatin1Char(' '), QString::SkipEmptyParts)); else setFilter(filter); return; } setButtons( KDialog::None ); restoreDialogSize(d->cfgGroup); // call this before the fileQWidget is set as the main widget. // otherwise the sizes for the components are not obeyed (ereslibre) d->w->setFilter(filter); setMainWidget(fileQWidget); d->w->okButton()->show(); connect(d->w->okButton(), SIGNAL(clicked()), SLOT(slotOk())); d->w->cancelButton()->show(); connect(d->w->cancelButton(), SIGNAL(clicked()), SLOT(slotCancel())); // Publish signals // TODO: Move the relevant signal declarations from KFileWidget to the // KAbstractFileWidget interface? // Else, all of these connects (including "accepted") are not typesafe. // Answer: you cannot define signals in a non-qobject base class (DF). // I simply documentde them in kabstractfilewidget.h now. kDebug (kfile_area) << "KFileDialog connecting signals"; connect(fileQWidget, SIGNAL(fileSelected(KUrl)), SIGNAL(fileSelected(KUrl))); connect(fileQWidget, SIGNAL(fileHighlighted(KUrl)), SIGNAL(fileHighlighted(KUrl))); connect(fileQWidget, SIGNAL(selectionChanged()), SIGNAL(selectionChanged())); connect(fileQWidget, SIGNAL(filterChanged(QString)), SIGNAL(filterChanged(QString))); connect(fileQWidget, SIGNAL(accepted()), SLOT(accept())); //connect(fileQWidget, SIGNAL(canceled()), SLOT(slotCancel())); if (customWidget) d->w->setCustomWidget(QString(), customWidget); } KFileDialog::~KFileDialog() { delete d; } void KFileDialog::setLocationLabel(const QString& text) { if (d->native) return; // not available d->w->setLocationLabel(text); } void KFileDialog::setFilter(const QString& filter) { if (d->native) { d->native->filter = filter; return; } d->w->setFilter(filter); } QString KFileDialog::currentFilter() const { if (d->native) return QString(); // not available return d->w->currentFilter(); } void KFileDialog::setMimeFilter( const QStringList& mimeTypes, const QString& defaultType ) { d->w->setMimeFilter(mimeTypes, defaultType); if (d->native) { QString allExtensions; QStringList filters = mime2KdeFilter(mimeTypes, &allExtensions); if (defaultType.isEmpty() && (mimeTypes.count() > 1)) { filters.prepend(allExtensions + QLatin1Char('|') + i18n("All Supported Files")); } d->native->filter = filters.join(QLatin1String("\n")); } } void KFileDialog::clearFilter() { if (d->native) { d->native->filter.clear(); return; } d->w->clearFilter(); } QString KFileDialog::currentMimeFilter() const { if (d->native) { // adapted from qt2KdeFilter QString filter = d->native->selectedFilter.split(";;").replaceInStrings("/", "\\/")[0]; filter = filter.mid(filter.indexOf('(') + 1, filter.indexOf(')') - filter.indexOf('(') - 1); QString mimetype = KMimeType::findByPath("test" + filter.mid(1).split(' ')[0])->name(); return mimetype; } return d->w->currentMimeFilter(); } KMimeType::Ptr KFileDialog::currentFilterMimeType() { return KMimeType::mimeType( currentMimeFilter() ); } void KFileDialog::setPreviewWidget(KPreviewWidgetBase *w) { if (d->native) return; d->w->setPreviewWidget(w); } void KFileDialog::setInlinePreviewShown(bool show) { if (d->native) { return; } d->w->setInlinePreviewShown(show); } // This is only used for the initial size when no configuration has been saved QSize KFileDialog::sizeHint() const { int fontSize = fontMetrics().height(); QSize goodSize(48 * fontSize, 30 * fontSize); QSize screenSize = QApplication::desktop()->availableGeometry(this).size(); QSize minSize(screenSize / 2); QSize maxSize(screenSize * qreal(0.9)); return (goodSize.expandedTo(minSize).boundedTo(maxSize)); } // This slot still exists mostly for compat purposes; for subclasses which reimplement slotOk void KFileDialog::slotOk() { if (d->native) return; d->w->slotOk(); } // This slot still exists mostly for compat purposes; for subclasses which reimplement accept void KFileDialog::accept() { if (d->native) return; setResult( QDialog::Accepted ); // keep old behavior; probably not needed though d->w->accept(); KConfigGroup cfgGroup(KGlobal::config(), ConfigGroup); KDialog::accept(); emit okClicked(); } // This slot still exists mostly for compat purposes; for subclasses which reimplement slotCancel void KFileDialog::slotCancel() { if (d->native) return; d->w->slotCancel(); reject(); } void KFileDialog::setUrl(const KUrl& url, bool clearforward) { if (d->native) { d->native->selectedUrls.clear(); d->native->selectedUrls.append(url); return; } d->w->setUrl(url, clearforward); } void KFileDialog::setSelection(const QString& name) { if (d->native) { d->native->selectedUrls.clear(); d->native->selectedUrls.append( KUrl(name) ); return; } d->w->setSelection(name); } QString KFileDialog::getOpenFileName(const KUrl& startDir, const QString& filter, QWidget *parent, const QString& caption) { return KFileDialogPrivate::getOpenFileName(startDir, filter, parent, caption, 0); } QString KFileDialogPrivate::getOpenFileName(const KUrl& startDir, const QString& filter, QWidget *parent, const QString& caption, QString *selectedFilter) { if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { return QFileDialog::getOpenFileName( parent, caption.isEmpty() ? i18n("Open") : caption, KFileDialogPrivate::Native::staticStartDir( startDir ).toLocalFile(), qtFilter(filter), selectedFilter ); // TODO use extra args? QString * selectedFilter = 0, Options options = 0 } KFileDialog dlg(startDir, filter, parent); dlg.setOperationMode( KFileDialog::Opening ); dlg.setMode( KFile::File | KFile::LocalOnly | KFile::ExistingOnly ); dlg.setCaption(caption.isEmpty() ? i18n("Open") : caption); dlg.exec(); if(selectedFilter) *selectedFilter = dlg.currentMimeFilter(); return dlg.selectedFile(); } QString KFileDialog::getOpenFileNameWId(const KUrl& startDir, const QString& filter, WId parent_id, const QString& caption) { if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) return KFileDialog::getOpenFileName(startDir, filter, 0, caption); // everything we can do... QWidget* parent = QWidget::find( parent_id ); KFileDialogPrivate::Native::s_allowNative = false; KFileDialog dlg(startDir, filter, parent); if( parent == NULL && parent_id != 0 ) KWindowSystem::setMainWindow( &dlg, parent_id ); dlg.setOperationMode( KFileDialog::Opening ); dlg.setMode( KFile::File | KFile::LocalOnly | KFile::ExistingOnly ); dlg.setCaption(caption.isEmpty() ? i18n("Open") : caption); dlg.exec(); return dlg.selectedFile(); } QStringList KFileDialog::getOpenFileNames(const KUrl& startDir, const QString& filter, QWidget *parent, const QString& caption) { return KFileDialogPrivate::getOpenFileNames(startDir, filter, parent, caption, 0); } QStringList KFileDialogPrivate::getOpenFileNames(const KUrl& startDir, const QString& filter, QWidget *parent, const QString& caption, QString *selectedFilter) { if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { return QFileDialog::getOpenFileNames( parent, caption.isEmpty() ? i18n("Open") : caption, KFileDialogPrivate::Native::staticStartDir( startDir ).toLocalFile(), qtFilter( filter ), selectedFilter ); // TODO use extra args? QString * selectedFilter = 0, Options options = 0 } KFileDialogPrivate::Native::s_allowNative = false; KFileDialog dlg(startDir, filter, parent); dlg.setOperationMode( KFileDialog::Opening ); dlg.setMode(KFile::Files | KFile::LocalOnly | KFile::ExistingOnly); dlg.setCaption(caption.isEmpty() ? i18n("Open") : caption); dlg.exec(); if(selectedFilter) *selectedFilter = dlg.currentMimeFilter(); return dlg.selectedFiles(); } KUrl KFileDialog::getOpenUrl(const KUrl& startDir, const QString& filter, QWidget *parent, const QString& caption) { return KFileDialogPrivate::getOpenUrl(startDir, filter, parent, caption, 0); } KUrl KFileDialogPrivate::getOpenUrl(const KUrl& startDir, const QString& filter, QWidget *parent, const QString& caption, QString *selectedFilter) { if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { const QString fileName( KFileDialogPrivate::getOpenFileName( startDir, filter, parent, caption, selectedFilter) ); return fileName.isEmpty() ? KUrl() : KUrl::fromPath(fileName); } KFileDialogPrivate::Native::s_allowNative = false; KFileDialog dlg(startDir, filter, parent); dlg.setOperationMode( KFileDialog::Opening ); dlg.setMode( KFile::File | KFile::ExistingOnly ); dlg.setCaption(caption.isEmpty() ? i18n("Open") : caption); dlg.exec(); if(selectedFilter) *selectedFilter = dlg.currentMimeFilter(); return dlg.selectedUrl(); } KUrl::List KFileDialog::getOpenUrls(const KUrl& startDir, const QString& filter, QWidget *parent, const QString& caption) { return KFileDialogPrivate::getOpenUrls(startDir, filter, parent, caption, 0); } KUrl::List KFileDialogPrivate::getOpenUrls(const KUrl& startDir, const QString& filter, QWidget *parent, const QString& caption, QString *selectedFilter) { if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { const QStringList fileNames( KFileDialogPrivate::getOpenFileNames( startDir, filter, parent, caption, selectedFilter) ); return KUrl::List(fileNames); } KFileDialogPrivate::Native::s_allowNative = false; KFileDialog dlg(startDir, filter, parent); dlg.setOperationMode( KFileDialog::Opening ); dlg.setMode( KFile::Files | KFile::ExistingOnly ); dlg.setCaption(caption.isEmpty() ? i18n("Open") : caption); dlg.exec(); if(selectedFilter) *selectedFilter = dlg.currentMimeFilter(); return dlg.selectedUrls(); } void KFileDialog::setConfirmOverwrite(bool enable) { if (operationMode() == KFileDialog::Saving) { d->w->setConfirmOverwrite(enable); } } KUrl KFileDialog::getExistingDirectoryUrl(const KUrl& startDir, QWidget *parent, const QString& caption) { if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { QString result( QFileDialog::getExistingDirectory(parent, caption, KFileDialogPrivate::Native::staticStartDir( startDir ).toLocalFile(), QFileDialog::ShowDirsOnly) ); return result.isEmpty() ? KUrl() : KUrl::fromPath(result); } return fileModule()->selectDirectory(startDir, false, parent, caption); } QString KFileDialog::getExistingDirectory(const KUrl& startDir, QWidget *parent, const QString& caption) { if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { return QFileDialog::getExistingDirectory(parent, caption, KFileDialogPrivate::Native::staticStartDir( startDir ).toLocalFile(), QFileDialog::ShowDirsOnly); } KUrl url = fileModule()->selectDirectory(startDir, true, parent, caption); if ( url.isValid() ) return url.toLocalFile(); return QString(); } KUrl KFileDialog::getImageOpenUrl( const KUrl& startDir, QWidget *parent, const QString& caption) { if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { // everything we can do... const QStringList mimetypes( KImageIO::mimeTypes( KImageIO::Reading ) ); return KFileDialog::getOpenUrl(startDir, mimetypes.join(" "), parent, caption); } const QStringList mimetypes = KImageIO::mimeTypes( KImageIO::Reading ); KFileDialogPrivate::Native::s_allowNative = false; KFileDialog dlg(startDir, mimetypes.join(" "), parent); dlg.setOperationMode( KFileDialog::Opening ); dlg.setMode( KFile::File | KFile::ExistingOnly ); dlg.setCaption( caption.isEmpty() ? i18n("Open") : caption ); dlg.setInlinePreviewShown( true ); dlg.exec(); return dlg.selectedUrl(); } KUrl KFileDialog::selectedUrl() const { if (d->native) return d->native->selectedUrls.isEmpty() ? KUrl() : d->native->selectedUrls.first(); return d->w->selectedUrl(); } KUrl::List KFileDialog::selectedUrls() const { if (d->native) return d->native->selectedUrls; return d->w->selectedUrls(); } QString KFileDialog::selectedFile() const { if (d->native) return selectedUrl().toLocalFile(); return d->w->selectedFile(); } QStringList KFileDialog::selectedFiles() const { if (d->native) return selectedUrls().toStringList(); return d->w->selectedFiles(); } KUrl KFileDialog::baseUrl() const { if (d->native) return selectedUrl().isEmpty() ? KUrl() : KUrl::fromPath(selectedUrl().path()); return d->w->baseUrl(); } QString KFileDialog::getSaveFileName(const KUrl& dir, const QString& filter, QWidget *parent, const QString& caption, Options options) { return KFileDialogPrivate::getSaveFileName(dir, filter, parent, caption, options, 0); } QString KFileDialogPrivate::getSaveFileName(const KUrl& dir, const QString& filter, QWidget *parent, const QString& caption, KFileDialog::Options options, QString *selectedFilter) { if (KFileDialogPrivate::isNative()) { bool defaultDir = dir.isEmpty(); bool specialDir = !defaultDir && dir.protocol() == "kfiledialog"; KUrl startDir; QString recentDirClass; if (specialDir) { startDir = KFileDialog::getStartUrl(dir, recentDirClass); } else if ( !specialDir && !defaultDir ) { if (!dir.isLocalFile()) kWarning() << "non-local start dir " << dir; startDir = dir; } QFileDialog::Options opts = (options & KFileDialog::ConfirmOverwrite) ? QFileDialog::Options(0) : QFileDialog::DontConfirmOverwrite; const QString result = QFileDialog::getSaveFileName( parent, caption.isEmpty() ? i18n("Save As") : caption, KFileDialogPrivate::Native::staticStartDir( startDir ).toLocalFile(), qtFilter(filter), // TODO use extra args? QString * selectedFilter = 0, Options opts = 0 selectedFilter, opts ); if (!result.isEmpty()) { if (!recentDirClass.isEmpty()) KRecentDirs::add(recentDirClass, KUrl::fromPath(result).url()); KRecentDocument::add(result); } return result; } KFileDialog dlg(dir, filter, parent); dlg.setOperationMode( KFileDialog::Saving ); dlg.setMode( KFile::File | KFile::LocalOnly ); dlg.setConfirmOverwrite(options & KFileDialog::ConfirmOverwrite); dlg.setInlinePreviewShown(options & KFileDialog::ShowInlinePreview); dlg.setCaption(caption.isEmpty() ? i18n("Save As") : caption); dlg.exec(); QString filename = dlg.selectedFile(); if (!filename.isEmpty()) KRecentDocument::add(filename); return filename; } QString KFileDialog::getSaveFileNameWId(const KUrl& dir, const QString& filter, WId parent_id, const QString& caption, Options options) { if (KFileDialogPrivate::isNative()) { return KFileDialog::getSaveFileName(dir, filter, 0, caption, options); // everything we can do... } QWidget* parent = QWidget::find( parent_id ); KFileDialog dlg(dir, filter, parent); if( parent == NULL && parent_id != 0 ) KWindowSystem::setMainWindow( &dlg, parent_id); dlg.setOperationMode( KFileDialog::Saving ); dlg.setMode( KFile::File | KFile::LocalOnly ); dlg.setConfirmOverwrite(options & ConfirmOverwrite); dlg.setInlinePreviewShown(options & ShowInlinePreview); dlg.setCaption(caption.isEmpty() ? i18n("Save As") : caption); dlg.exec(); QString filename = dlg.selectedFile(); if (!filename.isEmpty()) KRecentDocument::add(filename); return filename; } KUrl KFileDialog::getSaveUrl(const KUrl& dir, const QString& filter, QWidget *parent, const QString& caption, Options options) { return KFileDialogPrivate::getSaveUrl(dir, filter, parent, caption, options, 0); } KUrl KFileDialogPrivate::getSaveUrl(const KUrl& dir, const QString& filter, QWidget *parent, const QString& caption, KFileDialog::Options options, QString *selectedFilter) { if (KFileDialogPrivate::isNative() && (!dir.isValid() || dir.isLocalFile())) { const QString fileName( KFileDialogPrivate::getSaveFileName( dir, filter, parent, caption, options, selectedFilter) ); return fileName.isEmpty() ? KUrl() : KUrl::fromPath(fileName); } KFileDialogPrivate::Native::s_allowNative = false; KFileDialog dlg(dir, filter, parent); dlg.setOperationMode( KFileDialog::Saving ); dlg.setMode( KFile::File ); dlg.setConfirmOverwrite(options & KFileDialog::ConfirmOverwrite); dlg.setInlinePreviewShown(options & KFileDialog::ShowInlinePreview); dlg.setCaption(caption.isEmpty() ? i18n("Save As") : caption); dlg.exec(); if(selectedFilter) *selectedFilter = dlg.currentMimeFilter(); KUrl url = dlg.selectedUrl(); if (url.isValid()) KRecentDocument::add( url ); return url; } void KFileDialog::setMode( KFile::Modes m ) { if (d->native) d->native->mode = m; else d->w->setMode(m); } KFile::Modes KFileDialog::mode() const { if (d->native) return d->native->mode; return d->w->mode(); } KPushButton * KFileDialog::okButton() const { return d->w->okButton(); } KPushButton * KFileDialog::cancelButton() const { return d->w->cancelButton(); } KUrlComboBox* KFileDialog::locationEdit() const { return d->w->locationEdit(); } KFileFilterCombo* KFileDialog::filterWidget() const { return d->w->filterWidget(); } KActionCollection * KFileDialog::actionCollection() const { return d->w->actionCollection(); } void KFileDialog::setKeepLocation( bool keep ) { if (d->native) return; d->w->setKeepLocation(keep); } bool KFileDialog::keepsLocation() const { if (d->native) return false; return d->w->keepsLocation(); } void KFileDialog::setOperationMode( OperationMode mode ) { if (d->native) d->native->operationMode = static_cast(mode); else d->w->setOperationMode(static_cast(mode)); } KFileDialog::OperationMode KFileDialog::operationMode() const { if (d->native) return static_cast(d->native->operationMode); return static_cast(d->w->operationMode()); } void KFileDialog::keyPressEvent( QKeyEvent *e ) { if (d->native) return; if ( e->key() == Qt::Key_Escape ) { e->accept(); d->w->cancelButton()->animateClick(); } else KDialog::keyPressEvent( e ); } void KFileDialog::hideEvent( QHideEvent *e ) { if (d->native) return; saveDialogSize(d->cfgGroup, KConfigBase::Persistent); KDialog::hideEvent( e ); } // static KUrl KFileDialog::getStartUrl( const KUrl& startDir, QString& recentDirClass ) { return fileModule()->getStartUrl(startDir, recentDirClass); } void KFileDialog::setStartDir( const KUrl& directory ) { if (KFileDialogPrivate::isNative()) KFileDialogPrivate::Native::s_startDir = directory; fileModule()->setStartDir(directory); } KToolBar * KFileDialog::toolBar() const { return d->w->toolBar(); } KAbstractFileWidget* KFileDialog::fileWidget() { return d->w; } QT_BEGIN_NAMESPACE typedef QString (*_qt_filedialog_existing_directory_hook)(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options options); extern _qt_filedialog_existing_directory_hook qt_filedialog_existing_directory_hook; typedef QString (*_qt_filedialog_open_filename_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options); extern _qt_filedialog_open_filename_hook qt_filedialog_open_filename_hook; typedef QStringList (*_qt_filedialog_open_filenames_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options); extern _qt_filedialog_open_filenames_hook qt_filedialog_open_filenames_hook; typedef QString (*_qt_filedialog_save_filename_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options); extern _qt_filedialog_save_filename_hook qt_filedialog_save_filename_hook; QT_END_NAMESPACE /* * This class is used to override Qt's QFileDialog calls with KFileDialog ones. * This is necessary because QPrintDialog calls QFileDialog::getSaveFileName() for * the print to file function. */ class KFileDialogQtOverride { public: KFileDialogQtOverride() { if(!qt_filedialog_existing_directory_hook) qt_filedialog_existing_directory_hook=&getExistingDirectory; if(!qt_filedialog_open_filename_hook) qt_filedialog_open_filename_hook=&getOpenFileName; if(!qt_filedialog_open_filenames_hook) qt_filedialog_open_filenames_hook=&getOpenFileNames; if(!qt_filedialog_save_filename_hook) qt_filedialog_save_filename_hook=&getSaveFileName; } ~KFileDialogQtOverride() { if(qt_filedialog_existing_directory_hook == &getExistingDirectory) qt_filedialog_existing_directory_hook = 0; if(qt_filedialog_open_filename_hook == &getOpenFileName) qt_filedialog_open_filename_hook = 0; if(qt_filedialog_open_filenames_hook == &getOpenFileNames) qt_filedialog_open_filenames_hook=0; if(qt_filedialog_save_filename_hook == &getSaveFileName) qt_filedialog_save_filename_hook=0; } /* * Map a Qt filter string into a KDE one. */ static QString qt2KdeFilter(const QString &f) { QString filter; QTextStream str(&filter, QIODevice::WriteOnly); QStringList list(f.split(";;").replaceInStrings("/", "\\/")); QStringList::const_iterator it(list.begin()), end(list.end()); bool first=true; for(; it!=end; ++it) { int ob=(*it).lastIndexOf('('), cb=(*it).lastIndexOf(')'); if(-1!=cb && ob0 && ('('==(*it)[pos-1] || ' '==(*it)[pos-1]) && (*it).length()>=kde.length()+pos && (')'==(*it)[pos+kde.length()] || ' '==(*it)[pos+kde.length()])) { *sel=*it; return; } } } static QString getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options options) { if (KFileDialogPrivate::isNative()) { if(qt_filedialog_existing_directory_hook) qt_filedialog_existing_directory_hook=0; // do not override return QFileDialog::getExistingDirectory(parent, caption, dir, options); } fileModule(); // make sure i18n is initialized properly, needed for pure Qt applications KUrl url(KFileDialog::getExistingDirectory(KUrl(dir), parent, caption)); if(url.isLocalFile()) return url.pathOrUrl(); else return QString(); } static QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) { if (KFileDialogPrivate::isNative()) { if(qt_filedialog_open_filename_hook) qt_filedialog_open_filename_hook=0; // do not override return QFileDialog::getOpenFileName(parent, caption, dir, filter, selectedFilter, options); } fileModule(); // make sure i18n is initialized properly, needed for pure Qt applications KFileDialog dlg(KUrl(dir), qt2KdeFilter(filter), parent); dlg.setOperationMode(KFileDialog::Opening); dlg.setMode(KFile::File|KFile::LocalOnly); dlg.setCaption(caption); dlg.exec(); QString rv(dlg.selectedFile()); if(!rv.isEmpty()) kde2QtFilter(filter, dlg.currentFilter(), selectedFilter); return rv; } static QStringList getOpenFileNames(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) { if (KFileDialogPrivate::isNative()) { if(qt_filedialog_open_filenames_hook) qt_filedialog_open_filenames_hook=0; // do not override return QFileDialog::getOpenFileNames(parent, caption, dir, filter, selectedFilter, options); } fileModule(); // make sure i18n is initialized properly, needed for pure Qt applications KFileDialog dlg(KUrl(dir), qt2KdeFilter(filter), parent); dlg.setOperationMode(KFileDialog::Opening); dlg.setMode(KFile::Files|KFile::LocalOnly); dlg.setCaption(caption); dlg.exec(); QStringList rv(dlg.selectedFiles()); if(rv.count()) kde2QtFilter(filter, dlg.currentFilter(), selectedFilter); return rv; } static QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) { if (KFileDialogPrivate::isNative()) { if(qt_filedialog_save_filename_hook) qt_filedialog_save_filename_hook=0; // do not override return QFileDialog::getSaveFileName(parent, caption, dir, filter, selectedFilter, options); } fileModule(); // make sure i18n is initialized properly, needed for pure Qt applications KFileDialog dlg(KUrl(dir), qt2KdeFilter(filter), parent); dlg.setOperationMode(KFileDialog::Saving); dlg.setMode(KFile::File|KFile::LocalOnly); dlg.setCaption(caption); dlg.setConfirmOverwrite(!(options & QFileDialog::DontConfirmOverwrite)); dlg.exec(); QString rv(dlg.selectedFile()); if(!rv.isEmpty()) kde2QtFilter(filter, dlg.currentFilter(), selectedFilter); return rv; } }; static KFileDialogQtOverride qtOverride; #include "moc_kfiledialog.cpp"