File indexing completed on 2024-05-12 16:40:54

0001 /* This file is part of the KDE project
0002    Copyright (C) 2016-2018 Jarosław Staniek <staniek@kde.org>
0003 
0004    This program is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This program is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this program; see the file COPYING.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018  */
0019 
0020 #include "KexiFileRequester.h"
0021 #include <KexiFileFilters.h>
0022 #include <kexiutils/utils.h>
0023 #include <KexiIcon.h>
0024 
0025 #include <KFileFilterCombo>
0026 #include <KLineEdit>
0027 #include <KLocalizedString>
0028 #include <KUrlComboBox>
0029 #include <KUrlCompletion>
0030 #include <KMessageBox>
0031 
0032 #include <QDateTime>
0033 #include <QDebug>
0034 #include <QFileDialog>
0035 #include <QFileInfo>
0036 #include <QFileSystemModel>
0037 #include <QHeaderView>
0038 #include <QLabel>
0039 #include <QMimeDatabase>
0040 #include <QPushButton>
0041 #include <QRegExp>
0042 #include <QSettings>
0043 #include <QStandardPaths>
0044 #include <QTreeView>
0045 #include <QVBoxLayout>
0046 
0047 #include <functional>
0048 
0049 namespace {
0050     enum KexiFileSystemModelColumnIds {
0051         NameColumnId,
0052         LastModifiedColumnId
0053     };
0054 }
0055 
0056 //! A model for KexiFileRequester
0057 class KexiFileSystemModel : public QFileSystemModel
0058 {
0059     Q_OBJECT
0060 public:
0061     explicit KexiFileSystemModel(QObject *parent = nullptr)
0062         : QFileSystemModel(parent)
0063     {
0064     }
0065 
0066     int columnCount(const QModelIndex &parent = QModelIndex()) const override
0067     {
0068         Q_UNUSED(parent)
0069         return LastModifiedColumnId + 1;
0070     }
0071 
0072     QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
0073     {
0074         const int col = index.column();
0075         if (col == NameColumnId) {
0076             switch (role) {
0077             case Qt::DecorationRole: {
0078                 if (isDir(index)) {
0079                     return koIcon("folder");
0080                 } else {
0081                     return QIcon::fromTheme(m_mimeDb.mimeTypeForFile(filePath(index)).iconName());
0082                 }
0083             }
0084             default: break;
0085             }
0086             return QFileSystemModel::data(index, role);
0087         } else if (col == LastModifiedColumnId) {
0088             const QWidget *parentWidget = qobject_cast<QWidget*>(QObject::parent());
0089             switch (role) {
0090             case Qt::DisplayRole:
0091                 return parentWidget->locale().toString(QFileSystemModel::lastModified(index),
0092                                                        QLocale::ShortFormat);
0093             default:
0094                 break;
0095             }
0096         }
0097         return QVariant();
0098     }
0099 
0100     Qt::ItemFlags flags(const QModelIndex& index) const override {
0101         Q_UNUSED(index)
0102         return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
0103     }
0104 
0105 private:
0106     QMimeDatabase m_mimeDb;
0107 };
0108 
0109 //! @internal
0110 class KexiUrlCompletion : public KUrlCompletion
0111 {
0112 public:
0113     explicit KexiUrlCompletion(QList<QRegExp *> *filterRegExps, QList<QMimeType> *filterMimeTypes)
0114         : KUrlCompletion(KUrlCompletion::FileCompletion)
0115         , m_filterRegExps(filterRegExps)
0116         , m_filterMimeTypes(filterMimeTypes)
0117     {
0118     }
0119 
0120     using KUrlCompletion::postProcessMatches;
0121 
0122     //! Reimplemented to match the filter
0123     void postProcessMatches(QStringList *matches) const override
0124     {
0125         for (QStringList::Iterator matchIt = matches->begin();
0126              matchIt != matches->end();)
0127         {
0128             if (fileMatchesFilter(*matchIt)) {
0129                 ++matchIt;
0130             } else {
0131                 matchIt = matches->erase(matchIt);
0132             }
0133         }
0134     }
0135 
0136 private:
0137     /**
0138      * @return @c true if @a fileName matches the current regular expression as well as the mime types
0139      *
0140      * The mime type matching allows to overcome issues with patterns such as *.doc being used
0141      * for text/plain mime types but really belonging to application/msword mime type.
0142      */
0143     bool fileMatchesFilter(const QString &fileName) const
0144     {
0145         bool found = false;
0146         for (QRegExp *regexp : *m_filterRegExps) {
0147             if (regexp->exactMatch(fileName)) {
0148                 found = true;
0149                 break;
0150             }
0151         }
0152         if (!found) {
0153             return false;
0154         }
0155         const QMimeType mimeType(m_mimeDb.mimeTypeForFile(fileName));
0156         qDebug() << mimeType;
0157         int i = m_filterMimeTypes->indexOf(mimeType);
0158         return i >= 0;
0159     }
0160 
0161     const QList<QRegExp*> * const m_filterRegExps;
0162     const QList<QMimeType> * const m_filterMimeTypes;
0163     QMimeDatabase m_mimeDb;
0164 };
0165 
0166 //! @internal
0167 class Q_DECL_HIDDEN KexiFileRequester::Private : public QObject
0168 {
0169     Q_OBJECT
0170 public:
0171     Private(KexiFileRequester *r) : q(r)
0172     {
0173     }
0174 
0175     ~Private()
0176     {
0177         qDeleteAll(filterRegExps);
0178     }
0179 
0180     static QString urlToPath(const QUrl &url)
0181     {
0182         QString filePath = QDir::toNativeSeparators(url.path(QUrl::RemoveScheme | QUrl::PreferLocalFile | QUrl::StripTrailingSlash));
0183 #ifdef Q_OS_WIN
0184         if (filePath.startsWith('\\')) {
0185             filePath = filePath.mid(1);
0186         } else if (filePath.startsWith("file:\\")) {
0187             filePath = filePath.mid(6);
0188         }
0189 #endif
0190         return filePath;
0191     }
0192 
0193 public Q_SLOTS:
0194     void updateUrl(const QUrl &url)
0195     {
0196         updateFileName(urlToPath(url));
0197     }
0198 
0199     void updateFileName(const QString &filePath)
0200     {
0201         const QFileInfo fileInfo(filePath);
0202         QString dirPath;
0203         if (fileInfo.isDir()) {
0204             dirPath = fileInfo.absoluteFilePath();
0205         } else {
0206             dirPath = fileInfo.absolutePath();
0207         }
0208         dirPath = QDir::toNativeSeparators(dirPath);
0209         if (filePath.isEmpty()) { // display Windows Explorer's "Computer" folder name for the top level
0210 #ifdef Q_OS_WIN
0211             QString computerNameString = QSettings(
0212                 "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\"
0213                 "CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
0214                         QSettings::NativeFormat).value("Default").toString();
0215             if (computerNameString.isEmpty()) {
0216                  computerNameString = xi18n("Computer");
0217             }
0218             urlLabel->setText(computerNameString);
0219             folderIcon->setPixmap(koSmallIcon("computer"));
0220             upButton->setEnabled(false);
0221 #else
0222             urlLabel->setText("/");
0223             folderIcon->setPixmap(koSmallIcon("folder"));
0224             upButton->setEnabled(false);
0225 #endif
0226         } else {
0227             urlLabel->setText(dirPath);
0228             folderIcon->setPixmap(koSmallIcon("folder"));
0229             upButton->setEnabled(filePath != "/");
0230         }
0231         if (model->rootPath() != dirPath) {
0232             model->setRootPath(dirPath);
0233             list->setRootIndex(model->index(dirPath));
0234             list->resizeColumnToContents(LastModifiedColumnId);
0235             urlCompletion->setDir(QUrl::fromLocalFile(dirPath));
0236         }
0237         if (!fileInfo.isDir()) {
0238             list->clearSelection();
0239             const QModelIndex fileIndex = model->index(filePath);
0240             list->scrollTo(fileIndex);
0241             list->selectionModel()->select(fileIndex, QItemSelectionModel::ClearAndSelect);
0242             /*qWarning() << model->rootPath() << fileIndex.isValid() << model->filePath(fileIndex)
0243                        << model->fileName(fileIndex) << list->selectionModel()->selection().isEmpty()
0244                        << q->filters()->isExistingFileRequired();*/
0245             const QString newText(QFileInfo(filePath).fileName());
0246             if (newText != locationEdit->lineEdit()->text()) {
0247                 KexiUtils::BoolBlocker guard(&locationEditTextChangedEnabled, false);
0248                 locationEdit->lineEdit()->setText(newText);
0249             }
0250         }
0251     }
0252 
0253     void itemClicked(const QModelIndex &index)
0254     {
0255         handleItem(index, std::bind(&KexiFileRequester::fileHighlighted, q, std::placeholders::_1),
0256                    true);
0257         if (activateItemsOnSingleClick) {
0258             handleItem(index, std::bind(&KexiFileRequester::fileSelected, q, std::placeholders::_1),
0259                        false);
0260         }
0261     }
0262 
0263     void itemActivated(const QModelIndex &index)
0264     {
0265         if (!activateItemsOnSingleClick) {
0266             handleItem(index, std::bind(&KexiFileRequester::fileSelected, q, std::placeholders::_1),
0267                        true);
0268         }
0269     }
0270 
0271     void upButtonClicked()
0272     {
0273         QString dirPath(urlLabel->text());
0274         QDir dir(dirPath);
0275         if (dirPath.isEmpty() || !dir.cdUp()) {
0276             updateFileName(QString());
0277         } else {
0278             updateFileName(dir.absolutePath());
0279         }
0280         //! @todo update button enable flag
0281     }
0282 
0283     void selectUrlButtonClicked()
0284     {
0285         QUrl dirUrl;
0286 #ifdef Q_OS_WIN
0287         if (!upButton->isEnabled()) { // Computer folder, see https://doc.qt.io/qt-5/qfiledialog.html#setDirectoryUrl
0288             dirUrl = QUrl("clsid:0AC0837C-BBF8-452A-850D-79D08E667CA7");
0289         }
0290 #else
0291         if (false) {
0292         }
0293 #endif
0294         else {
0295             dirUrl = QUrl::fromLocalFile(urlLabel->text());
0296         }
0297         QUrl selectedUrl = QFileDialog::getExistingDirectoryUrl(q, QString(), dirUrl);
0298         if (selectedUrl.isLocalFile()) {
0299             updateFileName(selectedUrl.toLocalFile());
0300         }
0301     }
0302 
0303     void locationEditTextChanged(const QString &text)
0304     {
0305         if (!locationEditTextChangedEnabled) {
0306             return;
0307         }
0308         locationEdit->lineEdit()->setModified(true);
0309         if (text.isEmpty()) {
0310             list->clearSelection();
0311         }
0312         QFileInfo info(model->rootPath() + '/' + text);
0313         if (info.isFile() && model->rootDirectory().exists(text)) {
0314             updateFileName(model->rootDirectory().absoluteFilePath(text)); // select file
0315         } else if (q->filters()->isExistingFileRequired()) {
0316             updateFileName(model->rootPath()); // only dir, unselect file
0317         } else {
0318             updateFileName(info.absoluteFilePath()); // only dir, unselect file
0319         }
0320     }
0321 
0322     void locationEditReturnPressed()
0323     {
0324         QString text(locationEdit->lineEdit()->text());
0325         if (text.isEmpty()) {
0326             return;
0327         }
0328         if (text == QStringLiteral("~")) {
0329             text = QDir::homePath();
0330         } else if (text.startsWith(QStringLiteral("~/"))) {
0331             text = QDir::home().absoluteFilePath(text.mid(2));
0332         }
0333         if (QDir::isAbsolutePath(text)) {
0334             QFileInfo info(text);
0335             if (!info.isReadable()) {
0336                 return;
0337             }
0338             if (info.isDir()) { // jump to absolute dir and clear the editor
0339                 updateFileName(info.canonicalFilePath());
0340                 locationEdit->lineEdit()->clear();
0341             } else { // jump to absolute dir and select the file in it
0342                 updateFileName(info.dir().canonicalPath());
0343                 locationEdit->lineEdit()->setText(info.fileName());
0344                 locationEditReturnPressed();
0345             }
0346         } else { // relative path
0347             QFileInfo info(model->rootPath() + '/' + text);
0348             if (info.isReadable() && info.isDir()) { // jump to relative dir and clear the editor
0349                 updateFileName(info.canonicalFilePath());
0350                 locationEdit->lineEdit()->clear();
0351             } else { // emit the file selection
0352                 //not needed - preselected: updateFileName(text);
0353                 emit q->fileSelected(q->selectedFile());
0354             }
0355         }
0356     }
0357 
0358     void slotFilterComboChanged()
0359     {
0360         const QStringList patterns = filterCombo->currentFilter().split(' ');
0361         //qDebug() << patterns;
0362         model->setNameFilters(patterns);
0363         qDeleteAll(filterRegExps);
0364         filterRegExps.clear();
0365         for (const QString &pattern : patterns) {
0366             filterRegExps.append(new QRegExp(pattern, Qt::CaseInsensitive, QRegExp::Wildcard));
0367         }
0368     }
0369 
0370     //! @todo added to display select filename, still does not work
0371     void directoryLoaded()
0372     {
0373         if (!list->selectionModel()->selectedIndexes().isEmpty()) {
0374             list->scrollTo(list->selectionModel()->selectedIndexes().first());
0375         }
0376     }
0377 
0378 private:
0379     void handleItem(const QModelIndex &index, std::function<void(const QString&)> sig, bool silent)
0380     {
0381         const QString filePath(model->filePath(index));
0382         if (model->isDir(index)) {
0383             QFileInfo info(filePath);
0384             if (info.isReadable()) {
0385                 updateFileName(filePath);
0386             } else {
0387                 if (silent) {
0388                     KMessageBox::error(q,
0389                                        xi18n("Could not enter directory <filename>%1</filename>.",
0390                                              QDir::toNativeSeparators(info.absoluteFilePath())));
0391                 }
0392             }
0393         } else {
0394             emit sig(filePath);
0395         }
0396     }
0397 
0398 public:
0399     KexiFileRequester* const q;
0400     QPushButton *upButton;
0401     QLabel *folderIcon;
0402     QLabel *urlLabel;
0403     QPushButton *selectUrlButton;
0404     KexiFileSystemModel *model;
0405     QTreeView *list;
0406     bool activateItemsOnSingleClick;
0407     KUrlComboBox *locationEdit;
0408     KexiUrlCompletion *urlCompletion;
0409     KFileFilterCombo *filterCombo;
0410     QList<QRegExp*> filterRegExps; //!< Regular expression for the completer in the URL box
0411     QList<QMimeType> filterMimeTypes;
0412     bool locationEditTextChangedEnabled = true;
0413 };
0414 
0415 KexiFileRequester::KexiFileRequester(const QUrl &fileOrVariable, KexiFileFilters::Mode mode,
0416                                      const QString &fileName, QWidget *parent)
0417     : QWidget(parent), KexiFileWidgetInterface(fileOrVariable, fileName), d(new Private(this))
0418 {
0419     init();
0420     const QString actualFileName = Private::urlToPath(startUrl());
0421     setMode(mode);
0422     d->updateFileName(actualFileName); // note: we had to call it after setMode(), not before
0423 }
0424 
0425 KexiFileRequester::KexiFileRequester(const QUrl &fileOrVariable, KexiFileFilters::Mode mode,
0426                                      QWidget *parent)
0427     : KexiFileRequester(fileOrVariable, mode, QString(), parent)
0428 {
0429 }
0430 
0431 KexiFileRequester::KexiFileRequester(const QString &selectedFileName, KexiFileFilters::Mode mode,
0432                                      QWidget *parent)
0433     : QWidget(parent)
0434     , KexiFileWidgetInterface(QUrl(selectedFileName), QString())
0435     , d(new Private(this))
0436 {
0437     init();
0438     setMode(mode);
0439     d->updateFileName(selectedFileName); // note: we had to call it after setMode(), not before
0440 }
0441 
0442 KexiFileRequester::~KexiFileRequester()
0443 {
0444     const QString startDir(d->urlLabel->text());
0445     addRecentDir(startDir);
0446     delete d;
0447 }
0448 
0449 void KexiFileRequester::init()
0450 {
0451     // [^] [Dir    ][..]
0452     // [ files list    ]
0453     // [ location      ]
0454     // [ filter combo  ]
0455     QVBoxLayout *lyr = new QVBoxLayout(this);
0456     setContentsMargins(QMargins());
0457     lyr->setContentsMargins(QMargins());
0458     QHBoxLayout *urlLyr = new QHBoxLayout;
0459     urlLyr->setContentsMargins(QMargins());
0460     lyr->addLayout(urlLyr);
0461 
0462     d->upButton = new QPushButton;
0463     d->upButton->setFocusPolicy(Qt::NoFocus);
0464     d->upButton->setIcon(koIcon("go-up"));
0465     d->upButton->setToolTip(xi18n("Go to parent directory"));
0466     d->upButton->setFlat(true);
0467     connect(d->upButton, &QPushButton::clicked, d, &KexiFileRequester::Private::upButtonClicked);
0468     urlLyr->addWidget(d->upButton);
0469 
0470     d->folderIcon = new QLabel;
0471     urlLyr->addWidget(d->folderIcon);
0472 
0473     d->urlLabel = new QLabel;
0474     d->urlLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
0475     d->urlLabel->setWordWrap(true);
0476     d->urlLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
0477     urlLyr->addWidget(d->urlLabel, 1);
0478 
0479     d->selectUrlButton = new QPushButton;
0480     d->selectUrlButton->setFocusPolicy(Qt::NoFocus);
0481     d->selectUrlButton->setIcon(koIcon("folder"));
0482     d->selectUrlButton->setToolTip(xi18n("Select directory"));
0483     d->selectUrlButton->setFlat(true);
0484     connect(d->selectUrlButton, &QPushButton::clicked, d, &KexiFileRequester::Private::selectUrlButtonClicked);
0485     urlLyr->addWidget(d->selectUrlButton);
0486 
0487     d->list = new QTreeView;
0488     d->activateItemsOnSingleClick = KexiUtils::activateItemsOnSingleClick(d->list);
0489     connect(d->list, &QTreeView::clicked, d, &KexiFileRequester::Private::itemClicked);
0490     connect(d->list, &QTreeView::activated, d, &KexiFileRequester::Private::itemActivated);
0491     d->list->setRootIsDecorated(false);
0492     d->list->setItemsExpandable(false);
0493     d->list->header()->hide();
0494     lyr->addWidget(d->list);
0495     d->model = new KexiFileSystemModel(d->list);
0496     d->model->setNameFilterDisables(false);
0497     connect(d->model, &QFileSystemModel::directoryLoaded, d, &Private::directoryLoaded);
0498 
0499     d->list->setModel(d->model);
0500     d->list->header()->setStretchLastSection(false);
0501     d->list->header()->setSectionResizeMode(NameColumnId, QHeaderView::Stretch);
0502     d->list->header()->setSectionResizeMode(LastModifiedColumnId, QHeaderView::ResizeToContents);
0503 
0504     QGridLayout *bottomLyr = new QGridLayout;
0505     lyr->addLayout(bottomLyr);
0506 
0507     QLabel *locationLabel = new QLabel(xi18n("Name:"));
0508     bottomLyr->addWidget(locationLabel, 0, 0, Qt::AlignVCenter | Qt::AlignRight);
0509     d->locationEdit = new KUrlComboBox(KUrlComboBox::Files, true);
0510     setFocusProxy(d->locationEdit);
0511     d->locationEdit->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
0512     connect(d->locationEdit, &KUrlComboBox::editTextChanged, d,
0513             &KexiFileRequester::Private::locationEditTextChanged);
0514 #if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
0515     connect(d->locationEdit, QOverload<>::of(&KUrlComboBox::returnPressed),
0516             d, &Private::locationEditReturnPressed);
0517 #else
0518     connect(d->locationEdit, static_cast<void (KUrlComboBox::*)()>(&KUrlComboBox::returnPressed),
0519             d, &Private::locationEditReturnPressed);
0520 #endif
0521     d->urlCompletion = new KexiUrlCompletion(&d->filterRegExps, &d->filterMimeTypes);
0522     d->locationEdit->setCompletionObject(d->urlCompletion);
0523     d->locationEdit->setAutoDeleteCompletionObject(true);
0524     d->locationEdit->lineEdit()->setClearButtonEnabled(true);
0525     locationLabel->setBuddy(d->locationEdit);
0526     bottomLyr->addWidget(d->locationEdit, 0, 1, Qt::AlignVCenter);
0527 
0528     QLabel *filterLabel = new QLabel(xi18n("Filter:"));
0529     bottomLyr->addWidget(filterLabel, 1, 0, Qt::AlignVCenter | Qt::AlignRight);
0530     d->filterCombo = new KFileFilterCombo;
0531     connect(d->filterCombo, &KFileFilterCombo::filterChanged,
0532             d, &Private::slotFilterComboChanged);
0533     filterLabel->setBuddy(d->filterCombo);
0534     bottomLyr->addWidget(d->filterCombo, 1, 1, Qt::AlignVCenter);
0535 }
0536 
0537 QString KexiFileRequester::selectedFile() const
0538 {
0539     const QModelIndexList list(d->list->selectionModel()->selectedIndexes());
0540     if (list.isEmpty() || d->model->isDir(list.first())) { // no file selection but try entered filename
0541         const QString text(d->locationEdit->lineEdit()->text().trimmed());
0542         if (!text.isEmpty() && !filters()->isExistingFileRequired()) {
0543             const QFileInfo info(currentDir() + '/' + text);
0544             if (info.isNativePath()) {
0545                 return info.absoluteFilePath();
0546             }
0547         }
0548         return QString();
0549     }
0550     if (d->model->isDir(list.first())) {
0551         return QString();
0552     }
0553     return d->model->filePath(list.first());
0554 }
0555 
0556 QString KexiFileRequester::highlightedFile() const
0557 {
0558     return selectedFile();
0559 }
0560 
0561 QString KexiFileRequester::currentDir() const
0562 {
0563     return d->model->rootPath();
0564 }
0565 
0566 void KexiFileRequester::setSelectedFile(const QString &name)
0567 {
0568     d->updateFileName(name);
0569 }
0570 
0571 void KexiFileRequester::updateFilters()
0572 {
0573     // Update filters for the file model, filename completion and the filter combo
0574     const QStringList patterns = filters()->allGlobPatterns();
0575     if (patterns != d->model->nameFilters()) {
0576         d->model->setNameFilters(patterns);
0577         qDeleteAll(d->filterRegExps);
0578         d->filterRegExps.clear();
0579         for (const QString &pattern : patterns) {
0580             d->filterRegExps.append(new QRegExp(pattern, Qt::CaseInsensitive, QRegExp::Wildcard));
0581         }
0582         d->filterMimeTypes = filters()->mimeTypes();
0583         KexiFileFiltersFormat format;
0584         format.type = KexiFileFiltersFormat::Type::KDE;
0585         format.addAllFiles = true;
0586         d->filterCombo->setFilter(filters()->toString(format));
0587     }
0588 }
0589 
0590 void KexiFileRequester::setWidgetFrame(bool set)
0591 {
0592     d->list->setFrameShape(set ? QFrame::StyledPanel : QFrame::NoFrame);
0593     d->list->setLineWidth(set ? 1 : 0);
0594 }
0595 
0596 void KexiFileRequester::applyEnteredFileName()
0597 {
0598 }
0599 
0600 QStringList KexiFileRequester::currentFilters() const
0601 {
0602     return QStringList();
0603 }
0604 
0605 void KexiFileRequester::showEvent(QShowEvent *event)
0606 {
0607     setFiltersUpdated(false);
0608     updateFilters();
0609     QWidget::showEvent(event);
0610 }
0611 
0612 #include "KexiFileRequester.moc"