1

Here some code where opens default windows dialog and user can select file which name starts with prefixName and ends with ".log"

void doSomething(QString prefixName) {
    auto result = QFileDialog::getOpenFileName(this, tr("Open log file"), path, QString(tr("%1 Log Files (%1*.log);;All Log Files(*.log)")).arg(prefixName));  
    if (result) {
        // do something
    }
}

Everything works fine when prefixName contains just one word, i.e. prefixName = my_server:

my_server_2023_10_10.log  
my_server_2023_10_11.log

are shown

but if prefixName contains ) no files will be shown. Let's assume prefixName = my_server(007). I expect

my_server(007)_2023_10_10.log  
my_server(007)_2023_10_11.log  

files will be shown, but they don't

Why it can't list files with nested parenthesis?

Jarod42
  • 203,559
  • 14
  • 181
  • 302
pharos
  • 11
  • 3
  • Parentheses are key parts of the filter expression and can't be used in file templates. Try to escape them with backslashes. – 273K Jul 11 '23 at 15:03
  • I'm already tried to escape them with backslashes, and double-backslashes and even with unicode characters of parentheses but nothing from it works – pharos Jul 11 '23 at 15:09
  • Related to [how-to-filter-file-names-with-space-character-in-a-qfiledialog](https://stackoverflow.com/questions/61687260/how-to-filter-file-names-with-space-character-in-a-qfiledialog) – Jarod42 Jul 11 '23 at 15:18
  • @Jarod42 yep, I created new class, override filterAcceptsRow and returns via regexp only (m_configName + ".*\\.log") files, and this is works But I need few filters (filter by prefixName and filter by ".log" at the end of the filename) and that's the problem. When I set fileDialog.setNameFilters proxy model method works only on "all files (.log)" filter. How could I add few QSortFilterProxyModels to one file dialog or choose which regexp to use according to which filter is chosen? – pharos Jul 12 '23 at 09:19

1 Answers1

0

After some while I found answer which works, but in not that way I was expecting. Result:

class LogFilterProxyModel : public QSortFilterProxyModel
{
private:
    QRegExp m_regexp{".*"}; // by default accept all

public:
    LogFilterProxyModel(QRegExp regexp) { m_regexp = regexp; }
    void setRegexp(QRegExp re) { m_regexp = re; }

protected:
    virtual bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override
    {
        if (!sourceParent.isValid()) { return true; }
        QFileSystemModel* fileModel = qobject_cast<QFileSystemModel*>(sourceModel());
        QModelIndex index0 = fileModel->index(sourceRow, 0, sourceParent);

        // Don't apply filter on directories
        if (fileModel == nullptr || fileModel->isDir(index0)) { return true; }
        return m_regexp.exactMatch(index0.data().toString());
    }
};

void someOtherFunc(QString configName) {
    QString escapedConfigPath {configName};
    escapedConfigPath.replace("(", "\\(").replace(")", "\\)");

    QFileDialog dialog(this);
    const QRegExp specificLogsRegex (escapedConfigPath + ".*\\.log");
    const QRegExp anyLogRegex (".*\\.log");
    LogFilterProxyModel* pLogFilter = new LogFilterProxyModel(specificLogsRegex);
    QString filter1 {tr("%1 Log Files (*.log)").arg(configName)};
    QString filter2 {tr("All Log Files (*.log)")};
    dialog.setNameFilters({filter1, filter2});

    connect(&dialog, &QFileDialog::filterSelected, this, [&](const QString& curFilter){
        if (curFilter == filter1) {
            pLogFilter->setRegexp(specificLogsRegex);
        } else if (curFilter == filter2) {
            pLogFilter->setRegexp(anyLogRegex);
        }
    });

    dialog.exec();
}

I wanted on line QString filter1 {tr("%1 Log Files (*.log)").arg(configName)}; to search by %1 Log Files (%1*.log)".arg(configName) (which will show to user which files are being searched by file dialog), but it starts searching incorrect with parentheses, so I gave up and left it as is.
This solution searches all .log files in the directory and only then applies custom regexp filter to them

pharos
  • 11
  • 3