Question

I have a QTreeView with a QFileSystemModel as the model. Files and directories load correctly.

In my application workflow, a different process copies and overwrites files on the file system.

However, my QTreeView does not update the item/row for the overwritten file (eg: the size and lastModified values for the file do not update to the new values).

Using the file path, I'm able to get a FileInfo that DOES have the updated lastModified value. However, using that same path to grab the QModelIndex of the row's lastModified value results in it returning the old value.

I've tried a few things (see below) to no avail.

PLEASE let me know if you are aware of how to resolve this. Many Thanks! :)

// ... at this point the file system has been updated and the file
// has new values for things like last modified date
QFileInfo *updatedFile = new QFileInfo( filePath );

QModelIndex indexOfFileName = myFileTreeView->myFileSystemModel->index( filePath );
QModelIndex indexOfLastModifiedDate = myFileTreeView->myFileSystemModel->index( filePath, lastModifiedColumnIndex );

// attempts to kick the QFileSystemModel and QTreeView to update the model values
// a collection from the internet :)
emit myFileTreeView->dataChanged( indexOfFileName, indexOfLastModifiedDate );
emit myFileTreeView->myFileSystemModel->dataChanged( indexOfFileName, indexOfLastModifiedDate );
myTreeView->repaint();
myTreeView->update( indexOfLastModifiedDate );
myTreeView->viewport()->update();

// looking to see if values changed
QModelIndex newIndexOfLastModifiedDate = myTreeView->myFileSystemModel->index( filePath, lastModifiedColumnIndex );

// this shows the correct row and column for the index, so the index looks correct
qDebug() << "newIndexOfLastModifiedDate: " << newIndexOfLastModifiedDate;

// does not have new value
qDebug() << "newIndexOfLastModifiedDate.data(): " << newIndexOfLastModifiedDate->data();

// has new value
qDebug() << "fileInfo.lastModified(): " << updatedFile->lastModified();

[EDIT - adding steps to simulate application workflow]

The following I believe to be the steps that can mimic the issue.

Steps to Reproduce:

  • Setup a simple QTreeView that uses a QFileSystemModel as its model.

  • Set Root Path to a directory called Root

  • Create a text file, Test.txt inside of the Root dir

  • Load the application and observe in it the Test.txt file's Last Modified Date in the Root dir.

  • Keep this application window open.

  • Copy Test.txt to a different directory, say Temp

  • Modify the file and save in Temp

  • Copy and Replace Test.txt to overwrite the file in Root dir

  • Observe the Last Modified Date in the application window

Result: The Last Modified Date is not updated

ADDED SAPMLE:

#include <QApplication>
#include <QFileSystemModel>
#include <QFile>
#include <QFileInfo>
#include <QTimer>
#include <QDebug>
#include <QTreeView>
#include <QDateTime>


// Globals
QFileSystemModel *model = NULL;
const QString name = "test.txt";
const int delayOffset = 1000;

// Interface
void onDataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector< int >& roles );
void clean();
void doCreateFile();
void doUpdateFile();
void doTest();


// Implementation
int main( int argc, char *argv[] )
{
    QApplication a( argc, argv );
    int delay = 0;

    // Clean
    clean();

    // Init model
    const QString rootPath = QCoreApplication::applicationDirPath();
    model = new QFileSystemModel( &a );
    model->setRootPath( rootPath );
    QObject::connect( model, &QFileSystemModel::dataChanged, &onDataChanged );

    // Init file actions
    delay += delayOffset * 2;
    QTimer tCreate;
    tCreate.setSingleShot( true );
    tCreate.setInterval( delay );
    QObject::connect( &tCreate, &QTimer::timeout, &doCreateFile );

    delay += delayOffset * 4;
    QTimer tUpdate;
    tUpdate.setSingleShot( true );
    tUpdate.setInterval( delay );
    QObject::connect( &tUpdate, &QTimer::timeout, &doUpdateFile );

    // GUI
    QTreeView w;
    w.setModel( model );
    w.setRootIndex( model->index( rootPath ) );
    w.show();
    w.expandAll();

    qDebug() << "Start";
    tCreate.start();
    tUpdate.start();

    return a.exec();
}

void onDataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector< int >& roles )
{
    qDebug() << "Model changed";
}

void clean()
{
    const QString path = QString( "%1/%2" ).arg( QCoreApplication::applicationDirPath() ).arg( name );
    QFile f( path );

    if ( f.exists() )
        f.remove();
}

void doCreateFile()
{
    const QString path = QString( "%1/%2" ).arg( QCoreApplication::applicationDirPath() ).arg( name );
    QFile f( path );

    if ( !f.open( QIODevice::WriteOnly ) )
    {
        qDebug() << "Could not create file";
        return ;
    }

    f.write( "Preved" );
    f.close();

    qDebug() << "File created";
    doTest();
}

void doUpdateFile()
{
    const QString path = QString( "%1/%2" ).arg( QCoreApplication::applicationDirPath() ).arg( name );
    QFile f( path );

    if ( !f.open( QIODevice::Append ) )
    {
        qDebug() << "Could not open file for modification";
        return ;
    }

    f.write( " medved" );
    f.close();

    qDebug() << "File updated";
    doTest();
}

void doTest()
{
    const QString path = QString( "%1/%2" ).arg( QCoreApplication::applicationDirPath() ).arg( name );
    QFileInfo info( path );

    qDebug() << "Last modified (real):  " << info.lastModified().toString( "hh:mm:ss" );
    qDebug() << "Last modified (model): " << model->lastModified( model->index( path ) ).toString( "hh:mm:ss" );
}
Was it helpful?

Solution

You should use QFileSystemWatcher to track events for each file, when it necessary to update your model.

QFileSystemWatcher does not track an events because of performance issues. This is known issue. So you may create your own model and/or use proposed workaround:

model.setRootPath("");
model.setRootPath("the_folder_you_want_to_update");
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top