Search code examples
c++qtparenthesesqfiledialoggetopenfilename

Bug with Parenthesis in QFileDialog


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?


Solution

  • 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