Index: kio/kfile/kfiledialog.cpp =================================================================== --- kio/kfile/kfiledialog.cpp (wersja 819675) +++ kio/kfile/kfiledialog.cpp (kopia robocza) @@ -5,6 +5,7 @@ 1998 Daniel Grana 1999,2000,2001,2002,2003 Carsten Pfeiffer 2003 Clarence Dang + 2008 Jaroslaw Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -23,7 +24,6 @@ */ #include "kfiledialog.h" -#include "kabstractfilewidget.h" #include #include @@ -37,8 +37,10 @@ #include #include #include +#include +#include "kabstractfilewidget.h" #include "kabstractfilemodule.h" -#include +#include "krecentdirs.h" #ifdef Q_WS_X11 #include @@ -46,6 +48,76 @@ #include #endif +#include + +/** @return File dialog filter in Qt format for @a filters + * or "All files (*)" for empty list. + */ +static QString qtFilter(const QStringList& filters) +{ + QString converted; + 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); + } + //remove (.....) from name + p = new_name.indexOf('('); + int p2 = new_name.lastIndexOf(')'); + QString new_name1, new_name2; + if (p!=-1) + new_name1 = new_name.left(p); + if (p2!=-1) + new_name2 = new_name.mid(p2+1); + if (!new_name1.isEmpty() || !new_name2.isEmpty()) + new_name = new_name1.trimmed() + " " + new_name2.trimmed(); + new_name.replace('(',""); + new_name.replace(')',""); + new_name = new_name.trimmed(); + + // make filters unique: remove uppercase extensions (case doesn't matter on win32, BTW) + QStringList allfiltersUnique; + const QStringList origList( new_f.split(' ', QString::SkipEmptyParts) ); + foreach (const QString& origFilter, origList) { + if (origFilter == origFilter.toLower()) + allfiltersUnique += origFilter; + } + + if (!converted.isEmpty()) + converted += ";;"; + + converted += (new_name + " (" + allfiltersUnique.join(" ") + ")"); + } // foreach + + // Strip escape characters from escaped '/' characters. + for (int pos = 0; (pos = converted.indexOf("\\/", pos)) != -1; ++pos) + converted.remove(pos, 1); + + 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 + filters = filter.split('\n', QString::SkipEmptyParts); + return qtFilter(filters); +} + static KAbstractFileModule* s_module = 0; static KAbstractFileModule* fileModule() { @@ -68,15 +140,48 @@ class KFileDialogPrivate { public: - KFileDialogPrivate() : w(0) + class Native { + public: + Native() + : mode(KFile::File), + operationMode(KAbstractFileWidget::Opening) + { + } + static KUrl startDir; + QString filter; + QStringList mimeTypes; + KUrl::List selectedUrls; + KFile::Modes mode; + KAbstractFileWidget::OperationMode operationMode; + }; + + KFileDialogPrivate() + : native(0), + w(0), + cfgGroup(KGlobal::config(), ConfigGroup) { - cfgGroup = KConfigGroup(KGlobal::config(), ConfigGroup); + if (cfgGroup.readEntry("Native", false)) + native = new Native; } + static bool isNative() + { + KConfigGroup cfgGroup(KGlobal::config(), ConfigGroup); + return cfgGroup.readEntry("Native", false); + } + + ~KFileDialogPrivate() + { + delete native; + } + + Native* native; KAbstractFileWidget* w; KConfigGroup cfgGroup; }; +KUrl KFileDialogPrivate::Native::startDir; + KFileDialog::KFileDialog( const KUrl& startDir, const QString& filter, QWidget *parent, QWidget* customWidget) #ifdef Q_WS_WIN @@ -87,13 +192,21 @@ d( new KFileDialogPrivate ) { - 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) + if (!d->native) { + 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) + } // Dlopen the file widget from libkfilemodule QWidget* fileQWidget = fileModule()->createFileWidget(startDir, this); d->w = ::qobject_cast(fileQWidget); + + if (d->native) { + d->native->filter = filter; + return; + } + d->w->setFilter(filter); setMainWidget(fileQWidget); @@ -132,16 +245,24 @@ 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(); } @@ -149,10 +270,24 @@ const QString& defaultType ) { d->w->setMimeFilter(mimeTypes, defaultType); + + if (d->native) { + QString kdeFilter; + foreach( const QString& mimeType, mimeTypes ) { + KMimeType::Ptr mime( KMimeType::mimeType(mimeType) ); + if (mime) + kdeFilter += (mime->patterns().join(" ") + "|" + mime->comment()); + } + d->native->filter = kdeFilter; + } } void KFileDialog::clearFilter() { + if (d->native) { + d->native->filter.clear(); + return; + } d->w->clearFilter(); } @@ -168,6 +303,8 @@ void KFileDialog::setPreviewWidget(KPreviewWidgetBase *w) { + if (d->native) + return; d->w->setPreviewWidget(w); } @@ -179,12 +316,16 @@ // 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); @@ -195,17 +336,25 @@ // 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) + return; d->w->setUrl(url, clearforward); } void KFileDialog::setSelection(const QString& name) { + if (d->native) { +//TODO + return; + } d->w->setSelection(name); } @@ -213,6 +362,14 @@ const QString& filter, QWidget *parent, const QString& caption) { + if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { + return QFileDialog::getOpenFileName( + parent, + caption.isEmpty() ? i18n("Open") : caption, + startDir.path(), + qtFilter(filter) ); +//TODO QString * selectedFilter = 0, Options options = 0 + } KFileDialog dlg(startDir, filter, parent); dlg.setOperationMode( Opening ); @@ -229,6 +386,8 @@ 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 ); KFileDialog dlg(startDir, filter, parent); #ifdef Q_WS_X11 @@ -254,6 +413,14 @@ QWidget *parent, const QString& caption) { + if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { + return QFileDialog::getOpenFileNames( + parent, + caption.isEmpty() ? i18n("Open") : caption, + startDir.path(), + qtFilter(filter) ); +//TODO //QString * selectedFilter = 0, Options options = 0 + } KFileDialog dlg(startDir, filter, parent); dlg.setOperationMode( Opening ); @@ -268,6 +435,11 @@ KUrl KFileDialog::getOpenUrl(const KUrl& startDir, const QString& filter, QWidget *parent, const QString& caption) { + if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { + const QString fileName( KFileDialog::getOpenFileName( + startDir, filter, parent, caption) ); + return fileName.isEmpty() ? KUrl() : KUrl::fromPath(fileName); + } KFileDialog dlg(startDir, filter, parent); dlg.setOperationMode( Opening ); @@ -284,6 +456,11 @@ QWidget *parent, const QString& caption) { + if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { + const QStringList fileNames( KFileDialog::getOpenFileNames( + startDir, filter, parent, caption) ); + return KUrl::List(fileNames); + } KFileDialog dlg(startDir, filter, parent); dlg.setOperationMode( Opening ); @@ -299,6 +476,11 @@ QWidget *parent, const QString& caption) { + if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { + QString result( QFileDialog::getExistingDirectory(parent, caption, + startDir.path(), QFileDialog::ShowDirsOnly) ); + return result.isEmpty() ? KUrl() : KUrl::fromPath(result); + } return fileModule()->selectDirectory(startDir, false, parent, caption); } @@ -306,20 +488,23 @@ QWidget *parent, const QString& caption) { -#ifdef Q_WS_WIN - return QFileDialog::getExistingDirectory(parent, caption, - startDir.path(), QFileDialog::ShowDirsOnly); -#else + if (KFileDialogPrivate::isNative() && (!startDir.isValid() || startDir.isLocalFile())) { + return QFileDialog::getExistingDirectory(parent, caption, + startDir.path(), QFileDialog::ShowDirsOnly); + } KUrl url = fileModule()->selectDirectory(startDir, true, parent, caption); if ( url.isValid() ) return url.path(); return QString(); -#endif } 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); + } QStringList mimetypes = KImageIO::mimeTypes( KImageIO::Reading ); KFileDialog dlg(startDir, mimetypes.join(" "), @@ -337,26 +522,36 @@ 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().path(); 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(); } @@ -364,6 +559,33 @@ QWidget *parent, const QString& caption) { + if (KFileDialogPrivate::isNative()) { + bool defaultDir = dir.isEmpty(); + bool specialDir = !defaultDir && dir.protocol() == "kfiledialog"; + QString startDir; + QString recentDirClass; + if (specialDir) { + startDir = KFileDialog::getStartUrl(dir, recentDirClass).path(); + } + else if ( !specialDir && !defaultDir ) { + if (!dir.isLocalFile()) + kWarning() << "non-local start dir " << dir; + startDir = dir.path(); + } + + const QString result = QFileDialog::getSaveFileName( + parent, + caption.isEmpty() ? i18n("Save As") : caption, + dir.path(), + qtFilter(filter) ); +//TODO QString * selectedFilter = 0, Options options = 0 + if (!result.isEmpty()) { + if (!recentDirClass.isEmpty()) + KRecentDirs::add(recentDirClass, KUrl::fromPath(result).url()); + KRecentDocument::add(result); + } + return result; + } bool defaultDir = dir.isEmpty(); bool specialDir = !defaultDir && dir.protocol() == "kfiledialog"; KFileDialog dlg( specialDir ? dir : KUrl(), filter, parent); @@ -390,6 +612,9 @@ WId parent_id, const QString& caption) { + if (KFileDialogPrivate::isNative()) { + return KFileDialog::getSaveFileName(dir, filter, 0, caption); // everything we can do... + } bool defaultDir = dir.isEmpty(); bool specialDir = !defaultDir && dir.protocol() == "kfiledialog"; QWidget* parent = QWidget::find( parent_id ); @@ -423,6 +648,11 @@ KUrl KFileDialog::getSaveUrl(const KUrl& dir, const QString& filter, QWidget *parent, const QString& caption) { + if (KFileDialogPrivate::isNative() && (!dir.isValid() || dir.isLocalFile())) { + const QString fileName( KFileDialog::getSaveFileName( + dir.path(), filter, parent, caption) ); + return fileName.isEmpty() ? KUrl() : KUrl::fromPath(fileName); + } bool defaultDir = dir.isEmpty(); bool specialDir = !defaultDir && dir.protocol() == "kfiledialog"; KFileDialog dlg(specialDir ? dir : KUrl(), filter, parent); @@ -444,11 +674,16 @@ void KFileDialog::setMode( KFile::Modes m ) { - d->w->setMode(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(); } @@ -479,26 +714,38 @@ 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 ) { - d->w->setOperationMode(static_cast(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(); @@ -510,6 +757,9 @@ void KFileDialog::hideEvent( QHideEvent *e ) { + if (d->native) + return; + saveDialogSize(d->cfgGroup, KConfigBase::Persistent); KDialog::hideEvent( e ); @@ -524,6 +774,8 @@ void KFileDialog::setStartDir( const KUrl& directory ) { + if (KFileDialogPrivate::isNative()) + KFileDialogPrivate::Native::startDir = directory; fileModule()->setStartDir(directory); } @@ -537,45 +789,102 @@ return d->w; } -#ifndef Q_WS_WIN +#ifdef Q_WS_WIN +int KFileDialog::exec() +{ + if (!d->native) + return QDialog::exec(); + + d->native->selectedUrls.clear(); + switch (d->native->operationMode) { + case KAbstractFileWidget::Opening: + case KAbstractFileWidget::Other: + if (d->native->mode & KFile::File) { + KUrl url( KFileDialog::getOpenUrl( + KFileDialogPrivate::Native::startDir, d->native->filter, parentWidget(), windowTitle()) ); + if (url.isEmpty() || !url.isValid()) + return QDialog::Rejected; + d->native->selectedUrls.append(url); + return QDialog::Accepted; + } + else if (d->native->mode & KFile::Files) { + KUrl::List urls( KFileDialog::getOpenUrls( + KFileDialogPrivate::Native::startDir, d->native->filter, parentWidget(), windowTitle()) ); + if (urls.isEmpty()) + return QDialog::Rejected; + d->native->selectedUrls = urls; + return QDialog::Accepted; + } + else if (d->native->mode & KFile::Directory) { + KUrl url( KFileDialog::getExistingDirectoryUrl( + KFileDialogPrivate::Native::startDir, parentWidget(), windowTitle()) ); + if (url.isEmpty() || !url.isValid()) + return QDialog::Rejected; + d->native->selectedUrls.append(url); + return QDialog::Accepted; + } + break; + case KAbstractFileWidget::Saving: + if (d->native->mode & KFile::File) { + KUrl url( KFileDialog::getSaveUrl( + KFileDialogPrivate::Native::startDir, d->native->filter, parentWidget(), windowTitle()) ); + if (url.isEmpty() || !url.isValid()) + return QDialog::Rejected; + d->native->selectedUrls.append(url); + return QDialog::Accepted; + } + else if (d->native->mode & KFile::Directory) { + KUrl url( KFileDialog::getExistingDirectoryUrl( + KFileDialogPrivate::Native::startDir, parentWidget(), windowTitle()) ); + if (url.isEmpty() || !url.isValid()) + return QDialog::Rejected; + d->native->selectedUrls.append(url); + return QDialog::Accepted; + } + break; + default:; + } + return QDialog::Rejected; +} +#endif // Q_WS_WIN + 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; -#endif +Q_GUI_EXPORT _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; +Q_GUI_EXPORT _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; +Q_GUI_EXPORT _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; +Q_GUI_EXPORT _qt_filedialog_save_filename_hook qt_filedialog_save_filename_hook; /* * 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. */ - -struct KFileDialogQtOverride +class KFileDialogQtOverride { +public: KFileDialogQtOverride() { -#ifndef Q_WS_WIN + if (KFileDialogPrivate::isNative()) + return; if(!qt_filedialog_existing_directory_hook) qt_filedialog_existing_directory_hook=&getExistingDirectory; -#endif if(!qt_filedialog_open_filename_hook) qt_filedialog_open_filename_hook=&getOpenFileName; if(!qt_filedialog_open_filenames_hook) @@ -638,7 +947,6 @@ } } -#ifndef Q_WS_WIN static QString getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options) { @@ -649,7 +957,6 @@ else return QString(); } -#endif static QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Index: kio/kfile/kfiledialog.h =================================================================== --- kio/kfile/kfiledialog.h (wersja 819675) +++ kio/kfile/kfiledialog.h (kopia robocza) @@ -691,6 +691,11 @@ */ static void setStartDir( const KUrl& directory ); +#ifdef Q_WS_WIN +public Q_SLOTS: + int exec(); +#endif + Q_SIGNALS: /** * Emitted when the user selects a file. It is only emitted in single-