[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    Re: [patch] Native mode for KFileDialog
From:       Jaroslaw Staniek <js () iidea ! pl>
Date:       2008-06-13 21:15:45
Message-ID: 4852E381.7090204 () iidea ! pl
[Download RAW message or body]

Updated patch for Christian's changes (r819160).

-- 
regards / pozdrawiam, Jaroslaw Staniek
  Sponsored by OpenOffice Polska (http://www.openoffice.com.pl/en) to work on
  Kexi & KOffice (http://www.kexi.pl/en, http://www.koffice.org/kexi)
  KDE Libraries for MS Windows (http://windows.kde.org)

["native_kfiledialog2.patch" (text/plain)]

Index: kio/kfile/kfiledialog.h
===================================================================
--- kio/kfile/kfiledialog.h	(wersja 820309)
+++ 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-
Index: kio/kfile/kfiledialog.cpp
===================================================================
--- kio/kfile/kfiledialog.cpp	(wersja 820309)
+++ kio/kfile/kfiledialog.cpp	(kopia robocza)
@@ -5,6 +5,7 @@
                   1998 Daniel Grana <grana@ie.iwi.unibe.ch>
                   1999,2000,2001,2002,2003 Carsten Pfeiffer <pfeiffer@kde.org>
                   2003 Clarence Dang <dang@kde.org>
+                  2008 Jaroslaw Staniek <js@iidea.pl>
 
     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 <QtGui/QCheckBox>
 #include <QtGui/QKeyEvent>
@@ -37,8 +37,10 @@
 #include <kimagefilepreview.h>
 #include <kpluginloader.h>
 #include <kpluginfactory.h>
+#include <kdebug.h>
+#include "kabstractfilewidget.h"
 #include "kabstractfilemodule.h"
-#include <kdebug.h>
+#include "krecentdirs.h"
 
 #ifdef Q_WS_X11
 #include <qx11info_x11.h>
@@ -46,6 +48,76 @@
 #include <fixx11h.h>
 #endif
 
+#include <QtGui/QFileDialog>
+
+/** @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<KAbstractFileWidget *>(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<KAbstractFileWidget::OperationMode>(mode));
+    if (d->native)
+        d->native->operationMode = \
static_cast<KAbstractFileWidget::OperationMode>(mode); +    else
+        d->w->setOperationMode(static_cast<KAbstractFileWidget::OperationMode>(mode));
  }
 
 KFileDialog::OperationMode KFileDialog::operationMode() const
 {
+    if (d->native)
+        return static_cast<KFileDialog::OperationMode>(d->native->operationMode);
     return static_cast<KFileDialog::OperationMode>(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);
 }
 
@@ -538,17 +790,74 @@
 }
 
 #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
+
+#ifdef Q_WS_WIN
 #define KF_EXTERN extern __declspec(dllimport)
 #else
 #define KF_EXTERN extern
 #endif
 
-#ifndef Q_WS_WIN
 typedef QString (*_qt_filedialog_existing_directory_hook)(QWidget *parent, const \
                QString &caption,
                                                           const QString &dir,
                                                           QFileDialog::Options \
options);  KF_EXTERN _qt_filedialog_existing_directory_hook \
                qt_filedialog_existing_directory_hook;
-#endif
 
 typedef QString (*_qt_filedialog_open_filename_hook)(QWidget * parent, const QString \
                &caption,
                                                      const QString &dir, const \
QString &filter, @@ -573,15 +882,15 @@
  * 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)
@@ -644,7 +953,6 @@
         }
     }
 
-#ifndef Q_WS_WIN
     static QString getExistingDirectory(QWidget *parent, const QString &caption, \
const QString &dir,  QFileDialog::Options)
     {
@@ -655,7 +963,6 @@
         else
             return QString();
     }
-#endif
 
     static QString getOpenFileName(QWidget *parent, const QString &caption, const \
                QString &dir,
                                    const QString &filter, QString *selectedFilter,



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic