src/gui/util/qcompleter.cpp
changeset 30 5dc02b23752f
parent 29 b72c6db6890b
child 33 3e2da88830cd
--- a/src/gui/util/qcompleter.cpp	Wed Jun 23 19:07:03 2010 +0300
+++ b/src/gui/util/qcompleter.cpp	Tue Jul 06 15:10:48 2010 +0300
@@ -62,7 +62,7 @@
 
     \snippet doc/src/snippets/code/src_gui_util_qcompleter.cpp 0
 
-    A QDirModel can be used to provide auto completion of file names.
+    A QFileSystemModel can be used to provide auto completion of file names.
     For example:
 
     \snippet doc/src/snippets/code/src_gui_util_qcompleter.cpp 1
@@ -120,7 +120,7 @@
     completion is then performed one level at a time.
 
     Let's take the example of a user typing in a file system path.
-    The model is a (hierarchical) QDirModel. The completion
+    The model is a (hierarchical) QFileSystemModel. The completion
     occurs for every element in the path. For example, if the current
     text is \c C:\Wind, QCompleter might suggest \c Windows to
     complete the current path element. Similarly, if the current text
@@ -130,12 +130,12 @@
     split the path into a list of strings that are matched at each level.
     For \c C:\Windows\Sy, it needs to be split as "C:", "Windows" and "Sy".
     The default implementation of splitPath(), splits the completionPrefix
-    using QDir::separator() if the model is a QDirModel.
+    using QDir::separator() if the model is a QFileSystemModel.
 
     To provide completions, QCompleter needs to know the path from an index.
     This is provided by pathFromIndex(). The default implementation of
     pathFromIndex(), returns the data for the \l{Qt::EditRole}{edit role}
-    for list models and the absolute file path if the mode is a QDirModel.
+    for list models and the absolute file path if the mode is a QFileSystemModel.
 
     \sa QAbstractItemModel, QLineEdit, QComboBox, {Completer Example}
 */
@@ -147,6 +147,7 @@
 #include "QtGui/qscrollbar.h"
 #include "QtGui/qstringlistmodel.h"
 #include "QtGui/qdirmodel.h"
+#include "QtGui/qfilesystemmodel.h"
 #include "QtGui/qheaderview.h"
 #include "QtGui/qlistview.h"
 #include "QtGui/qapplication.h"
@@ -470,9 +471,13 @@
     QAbstractItemModel *source = c->proxy->sourceModel();
     if (curParts.count() <= 1 || c->proxy->showAll || !source)
         return QMatchData();
-    bool dirModel = false;
+    bool isDirModel = false;
+    bool isFsModel = false;
 #ifndef QT_NO_DIRMODEL
-    dirModel = (qobject_cast<QDirModel *>(source) != 0);
+    isDirModel = (qobject_cast<QDirModel *>(source) != 0);
+#endif
+#ifndef QT_NO_FILESYSTEMMODEL
+    isFsModel = (qobject_cast<QFileSystemModel *>(source) != 0);
 #endif
     QVector<int> v;
     QIndexMapper im(v);
@@ -482,7 +487,7 @@
         QString str = source->index(i, c->column).data().toString();
         if (str.startsWith(c->prefix, c->cs)
 #if (!defined(Q_OS_WIN) || defined(Q_OS_WINCE)) && !defined(Q_OS_SYMBIAN)
-            && (!dirModel || QDir::toNativeSeparators(str) != QDir::separator())
+            && ((!isFsModel && !isDirModel) || QDir::toNativeSeparators(str) != QDir::separator())
 #endif
             )
             m.indices.append(i);
@@ -843,6 +848,13 @@
                 completion += QDir::separator();
         }
 #endif
+#ifndef QT_NO_FILESYSTEMMODEL
+        // add a trailing separator in inline
+        if (mode == QCompleter::InlineCompletion) {
+            if (qobject_cast<QFileSystemModel *>(proxy->sourceModel()) && QFileInfo(completion).isDir())
+                completion += QDir::separator();
+        }
+#endif
     }
 
     if (highlighted) {
@@ -866,7 +878,7 @@
     const QRect screen = QApplication::desktop()->availableGeometry(widget);
     Qt::LayoutDirection dir = widget->layoutDirection();
     QPoint pos;
-    int rw, rh, w;
+    int rh, w;
     int h = (popup->sizeHintForRow(0) * qMin(maxVisibleItems, popup->model()->rowCount()) + 3) + 3;
     QScrollBar *hsb = popup->horizontalScrollBar();
     if (hsb && hsb->isVisible())
@@ -874,21 +886,30 @@
 
     if (rect.isValid()) {
         rh = rect.height();
-        w = rw = rect.width();
+        w = rect.width();
         pos = widget->mapToGlobal(dir == Qt::RightToLeft ? rect.bottomRight() : rect.bottomLeft());
     } else {
         rh = widget->height();
-        rw = widget->width();
         pos = widget->mapToGlobal(QPoint(0, widget->height() - 2));
         w = widget->width();
     }
 
-    if ((pos.x() + rw) > (screen.x() + screen.width()))
+    if (w > screen.width())
+        w = screen.width();
+    if ((pos.x() + w) > (screen.x() + screen.width()))
         pos.setX(screen.x() + screen.width() - w);
     if (pos.x() < screen.x())
         pos.setX(screen.x());
-    if (((pos.y() + rh) > (screen.y() + screen.height())) && ((pos.y() - h - rh) >= 0))
-        pos.setY(pos.y() - qMax(h, popup->minimumHeight()) - rh + 2);
+
+    int top = pos.y() - rh - screen.top() + 2;
+    int bottom = screen.bottom() - pos.y();
+    h = qMax(h, popup->minimumHeight());
+    if (h > bottom) {
+        h = qMin(qMax(top, bottom), h);
+
+        if (top > bottom)
+            pos.setY(pos.y() - h - rh + 2);
+    }
 
     popup->setGeometry(pos.x(), pos.y(), w, h);
 
@@ -896,6 +917,14 @@
         popup->show();
 }
 
+void QCompleterPrivate::_q_fileSystemModelDirectoryLoaded(const QString &path)
+{
+    Q_Q(QCompleter);
+    //the path given by QFileSystemModel does not end with /
+    if (!q->completionPrefix().isEmpty() && q->completionPrefix() != path + QLatin1Char('/'))
+        q->complete();
+}
+
 /*!
     Constructs a completer object with the given \a parent.
 */
@@ -976,7 +1005,7 @@
     be list model or a tree model. If a model has been already previously set
     and it has the QCompleter as its parent, it is deleted.
 
-    For convenience, if \a model is a QDirModel, QCompleter switches its
+    For convenience, if \a model is a QFileSystemModel, QCompleter switches its
     caseSensitivity to Qt::CaseInsensitive on Windows and Qt::CaseSensitive
     on other platforms.
 
@@ -1000,6 +1029,18 @@
 #endif
     }
 #endif // QT_NO_DIRMODEL
+#ifndef QT_NO_FILESYSTEMMODEL
+    QFileSystemModel *fsModel = qobject_cast<QFileSystemModel *>(model);
+    if (fsModel) {
+#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
+        setCaseSensitivity(Qt::CaseInsensitive);
+#else
+        setCaseSensitivity(Qt::CaseSensitive);
+#endif
+        setCompletionRole(QFileSystemModel::FileNameRole);
+        connect(fsModel, SIGNAL(directoryLoaded(QString)), this, SLOT(_q_fileSystemModelDirectoryLoaded(QString)));
+    }
+#endif // QT_NO_FILESYSTEMMODEL
 }
 
 /*!
@@ -1083,7 +1124,7 @@
         delete d->popup;
     if (popup->model() != d->proxy)
         popup->setModel(d->proxy);
-#ifdef Q_OS_MAC
+#if defined(Q_OS_MAC) && !defined(QT_MAC_USE_COCOA)
      popup->show();
 #else
      popup->hide();
@@ -1631,10 +1672,11 @@
 
     The default implementation returns the \l{Qt::EditRole}{edit role} of the
     item for list models. It returns the absolute file path if the model is a
-    QDirModel.
+    QFileSystemModel.
 
     \sa splitPath()
 */
+
 QString QCompleter::pathFromIndex(const QModelIndex& index) const
 {
     Q_D(const QCompleter);
@@ -1644,16 +1686,27 @@
     QAbstractItemModel *sourceModel = d->proxy->sourceModel();
     if (!sourceModel)
         return QString();
+    bool isDirModel = false;
+    bool isFsModel = false;
 #ifndef QT_NO_DIRMODEL
-    QDirModel *dirModel = qobject_cast<QDirModel *>(sourceModel);
-    if (!dirModel)
+    isDirModel = qobject_cast<QDirModel *>(d->proxy->sourceModel()) != 0;
 #endif
+#ifndef QT_NO_FILESYSTEMMODEL
+    isFsModel = qobject_cast<QFileSystemModel *>(d->proxy->sourceModel()) != 0;
+#endif
+    if (!isDirModel && !isFsModel)
         return sourceModel->data(index, d->role).toString();
 
     QModelIndex idx = index;
     QStringList list;
     do {
-        QString t = sourceModel->data(idx, Qt::EditRole).toString();
+        QString t;
+        if (isDirModel)
+            t = sourceModel->data(idx, Qt::EditRole).toString();
+#ifndef QT_NO_FILESYSTEMMODEL
+        else
+            t = sourceModel->data(idx, QFileSystemModel::FileNameRole).toString();
+#endif
         list.prepend(t);
         QModelIndex parent = idx.parent();
         idx = parent.sibling(parent.row(), index.column());
@@ -1673,7 +1726,7 @@
     in the model().
 
     The default implementation of splitPath() splits a file system path based on
-    QDir::separator() when the sourceModel() is a QDirModel.
+    QDir::separator() when the sourceModel() is a QFileSystemModel.
 
     When used with list models, the first item in the returned list is used for
     matching.
@@ -1683,12 +1736,19 @@
 QStringList QCompleter::splitPath(const QString& path) const
 {
     bool isDirModel = false;
+    bool isFsModel = false;
 #ifndef QT_NO_DIRMODEL
     Q_D(const QCompleter);
     isDirModel = qobject_cast<QDirModel *>(d->proxy->sourceModel()) != 0;
 #endif
+#ifndef QT_NO_FILESYSTEMMODEL
+#ifdef QT_NO_DIRMODEL
+    Q_D(const QCompleter);
+#endif
+    isFsModel = qobject_cast<QFileSystemModel *>(d->proxy->sourceModel()) != 0;
+#endif
 
-    if (!isDirModel || path.isEmpty())
+    if ((!isDirModel && !isFsModel) || path.isEmpty())
         return QStringList(completionPrefix());
 
     QString pathCopy = QDir::toNativeSeparators(path);