2

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" );
}
Dmitry Sazonov
  • 8,801
  • 1
  • 35
  • 61
GraehamF
  • 1,971
  • 24
  • 24
  • `emit myFileTreeView->dataChanged` what is that??? – Dmitry Sazonov Feb 28 '14 at 15:34
  • it is my uneducated attempt to broadcast that the specific row in the model of my custom `QTreeView` has had its data changed and needs to be updated, based on similar but different posts on the net. It does not do what I had hoped. I put it in there so you can see what I've tried. – GraehamF Feb 28 '14 at 17:57
  • Added code sample, that reproduce a problem. – Dmitry Sazonov Mar 04 '14 at 10:46
  • http://qt-project.org/doc/qt-5.0/qtwidgets/qdirmodel.html#refresh :) – Dmitry Sazonov Mar 07 '14 at 10:01
  • Good find. Yes, that is the functionality I want, but `QDirModel` has been obsolete since Jan. 2010 (https://blog.qt.digia.com/blog/2010/01/08/qdirmodel-is-now-obsolete-qfilesystemmodel-is-taking-the-job/). I wonder why the `refresh()` method was not implemented in `QFileSystemModel`. – GraehamF Mar 07 '14 at 17:13
  • It's obsolete but keeped in qt5. Feel free to use ;). It just words. The reason, why it's obsolete - is intensive using of system resources and low performance for big nub=mber of files. – Dmitry Sazonov Mar 07 '14 at 20:03

1 Answers1

3

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");
Dmitry Sazonov
  • 8,801
  • 1
  • 35
  • 61
  • Thanks. I don't want to `reset()` because it loses the state of the user's expanded nodes. I _do_ have my own `QFileSystemModel` and will look into implementing `QFileSystemWatcher`. – GraehamF Feb 28 '14 at 15:29
  • I just readed https://qt-project.org/doc/qt-5.0/qtwidgets/qfilesystemmodel.html - there are remark, that QFileSystemModel already uses QFileSystemWatcher. So your promlem is in another place. – Dmitry Sazonov Feb 28 '14 at 15:32
  • yes, I've learned that as well. I either need my custom `QFileSystemModel` to be aware of the filesystem changes or I need to update the index data manually. I am not sure how to do either :/ – GraehamF Feb 28 '14 at 17:51
  • You don't need to update indexes manually. You doing something wrong. Could you provide code sample that reproduce your problem? – Dmitry Sazonov Mar 01 '14 at 08:57
  • Added Steps to Reproduce, per your request. Thanks! :) – GraehamF Mar 03 '14 at 22:20
  • Thanks Dmitry. I've tried resetting the root path as you've suggested, but for some reason it only works inconsistently. I will accept this answer as it unblocks and is probably close to a full solution (or workaround for Qt). If I have time, I will look further into the inconsistency, but I have to table my implementation as it has lost priority for my upcoming release. Thanks again for all your help! :) – GraehamF Mar 10 '14 at 16:51