Sfoglia il codice sorgente

Merge branch '365-reject-non-writable-folders'

* 365-reject-non-writable-folders:
  Fix ctkDirectoryButton file dialog for AcceptSave mode
Julien Finet 11 anni fa
parent
commit
2b4d6e1ffb

+ 11 - 5
Libs/Widgets/Testing/Cpp/ctkDirectoryButtonTest1.cpp

@@ -20,6 +20,7 @@
 
 // Qt includes
 #include <QApplication>
+#include <QFormLayout>
 #include <QSignalSpy>
 #include <QStyle>
 #include <QTimer>
@@ -46,11 +47,16 @@ int ctkDirectoryButtonTest1(int argc, char * argv [] )
 
   ctkDirectoryButton button2(".");
   ctkDirectoryButton button3(icon, "..");
-  
-  QVBoxLayout* layout = new QVBoxLayout;
-  layout->addWidget(&button);
-  layout->addWidget(&button2);
-  layout->addWidget(&button3);
+  ctkDirectoryButton button4;
+  button4.setAcceptMode(QFileDialog::AcceptSave);
+  button4.setOptions(button4.options() | ctkDirectoryButton::DontUseNativeDialog);
+
+
+  QFormLayout* layout = new QFormLayout;
+  layout->addRow("Default button:", &button);
+  layout->addRow("Current (.) directory: ", &button2);
+  layout->addRow("Top (..) directory with icon:", &button3);
+  layout->addRow("Writable directory only:", &button4);
   topLevel.setLayout(layout);
   
   button.setCaption("Select a directory");

+ 24 - 12
Libs/Widgets/ctkDirectoryButton.cpp

@@ -28,6 +28,7 @@
 
 // CTK includes
 #include "ctkDirectoryButton.h"
+#include "ctkFileDialog.h"
 
 //-----------------------------------------------------------------------------
 class ctkDirectoryButtonPrivate
@@ -253,22 +254,32 @@ void ctkDirectoryButton::browse()
   class ExcludeReadOnlyFilterProxyModel : public QSortFilterProxyModel
   {
   public:
-    ExcludeReadOnlyFilterProxyModel(QObject *parent):QSortFilterProxyModel(parent)
+    ExcludeReadOnlyFilterProxyModel(QPalette palette, QObject *parent)
+      : QSortFilterProxyModel(parent)
+      , Palette(palette)
     {
     }
-    virtual bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const
+    virtual Qt::ItemFlags flags(const QModelIndex& index)const
     {
       QString filePath =
-          this->sourceModel()->data(sourceModel()->index(source_row, 0, source_parent),
-          QFileSystemModel::FilePathRole).toString();
-      return QFileInfo(filePath).isWritable();
+        this->sourceModel()->data(this->mapToSource(index),
+                                  QFileSystemModel::FilePathRole).toString();
+      if (!QFileInfo(filePath).isWritable())
+        {
+        // Double clickable (to open) but can't be "choosen".
+        return Qt::ItemIsSelectable;
+        }
+      return this->QSortFilterProxyModel::flags(index);
     }
+    QPalette Palette;
   };
 
   Q_D(ctkDirectoryButton);
-  QScopedPointer<QFileDialog> fileDialog(
-          new QFileDialog(this, d->DialogCaption.isEmpty() ? this->toolTip() :
-          d->DialogCaption, d->Directory.path()));
+  // Use a ctkFileDialog (vs QFileDialog) for the AcceptSave mode so it does not
+  // select non writable folders.
+  QScopedPointer<ctkFileDialog> fileDialog(
+    new ctkFileDialog(this, d->DialogCaption.isEmpty() ? this->toolTip() :
+                      d->DialogCaption, d->Directory.path()));
   #ifdef USE_QFILEDIALOG_OPTIONS
     fileDialog->setOptions(d->DialogOptions);
   #else
@@ -279,10 +290,11 @@ void ctkDirectoryButton::browse()
 
   if (d->AcceptMode == QFileDialog::AcceptSave)
     {
-    // Ideally "Choose" button of QFileDialog should be disabled if a read-only folder
-    // is selected and the acceptMode was AcceptSave.
-    // This is captured in https://github.com/commontk/CTK/issues/365
-    fileDialog->setProxyModel(new ExcludeReadOnlyFilterProxyModel(fileDialog.data()));
+    // Gray out the non-writable folders. They are still openable with double click,
+    // but they can't be selected because they don't have the ItemIsEnabled
+    // flag and because ctkFileDialog would not let it to be selected.
+    fileDialog->setProxyModel(
+      new ExcludeReadOnlyFilterProxyModel(this->palette(), fileDialog.data()));
     }
 
   QString dir;

+ 1 - 0
Libs/Widgets/ctkDirectoryButton.h

@@ -49,6 +49,7 @@ class CTK_WIDGETS_EXPORT ctkDirectoryButton: public QWidget
   /// If set to QFileDialog::AcceptSave mode, the regular behavior of QFileDialog will be extended
   /// to prevent user from selecting read-only folder. The caveat is that writable folder existing
   /// in a readonly one won't be selectable.
+  /// AcceptOpen by default.
   Q_PROPERTY(QFileDialog::AcceptMode acceptMode READ acceptMode WRITE setAcceptMode)
   Q_PROPERTY(QString directory READ directory WRITE setDirectory NOTIFY directoryChanged USER true)
   /// This property holds the title of the file dialog used to select a new directory

+ 13 - 0
Libs/Widgets/ctkFileDialog.cpp

@@ -223,5 +223,18 @@ void ctkFileDialog::accept()
       return;
       }
     }
+  // Don't accept read-only directories if we are in AcceptSave mode.
+  if ((this->fileMode() == Directory || this->fileMode() == DirectoryOnly) &&
+      this->acceptMode() == AcceptSave)
+    {
+    QStringList files = this->selectedFiles();
+    QString fn = files.first();
+    QFileInfo info(fn);
+    if (info.isDir() && !info.isWritable())
+      {
+      this->setDirectory(info.absoluteFilePath());
+      return;
+      }
+    }
   this->Superclass::accept();
 }