Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QTreeView and implicit TimerEvents



  • Hello, i am using qt 5.11.1 on Ubuntu 18.04.
    I am new in Qt, and trying now to make simple file manager.
    But today i noticed that my QTreeViews always emits QTimerEvents.
    I checked it with eventFilter.

    Screen

    I thought that this is strange, and checked almost exectly treeview in new project, and TimerEvents disappeared.

    So, i realized that, made something wrong. I will be grateful, if someone will prompt a possible reason for this behavior.

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include <QDir>
    #include <QWindow>
    #include <QFileSystemModel>
    #include <QDebug>
    #include <QProcess>
    #include <QDesktopServices>
    #include <QUrl>
    #include <QMessageBox>
    #include <QDateTime>
    #include <QMimeData>
    #include <QClipboard>
    #include "getname_dialog.h"
    
    void files_difference(QFileInfoList &files, QDir &Dir, QFileInfoList &Difference);
    
    void MainWindow::copy_buffered(const QTreeView *tree)
    {
        QFileInfoList files;
        QList<QUrl> urls = QApplication::clipboard()->mimeData()->urls();
        foreach (QUrl url, urls) {
            files.append(model->fileInfo(model->index(url.path())));
        }
    
        QDir destDir(model->filePath(tree->rootIndex()));
    
        QFileInfoList difference;
        files_difference(files, destDir, difference);
    
        QString oldPath = files.takeFirst().dir().path();
        foreach(QFileInfo fileinfo, difference) {
    //        QString oldPath = model->fileInfo(tree->rootIndex()).absoluteFilePath();
            QString newPath = destDir.absolutePath();
            QString destPath = fileinfo.absoluteFilePath().replace(oldPath, newPath);
            if (fileinfo.isFile()) {
                QFile::remove(destPath);
                QFile::copy(fileinfo.absoluteFilePath(), destPath);
            }else if (fileinfo.isDir()) {
                destDir.mkdir(destPath);
            }
        }
        ui->statusBar->showMessage(QString("Files  were pasted"));
    }
    
    void MainWindow::buffer_files(const QTreeView *tree)
    {
        QModelIndexList indexes = tree->selectionModel()->selectedIndexes();
        QFileInfoList files;
        int row = -1;
    
        foreach (QModelIndex indx, indexes) {
            if (indx.row() == row || model->fileInfo(indx).fileName() == "..")
                continue;
            files.append(model->fileInfo(indx));
            row = indx.row();
        }
    
        QMimeData *mime = new QMimeData;
        QList<QUrl> list;
        foreach (QFileInfo info, files) {
            QUrl url(info.absoluteFilePath());
            if (url.isValid()) {
                list.append(url);
            }
        }
    
        mime->setUrls(list);
        QApplication::clipboard()->setMimeData(mime);
        ui->statusBar->showMessage("Clipboarded!");
    }
    
    QTreeView* MainWindow::getFocusedTree()
    {
    //    QItemSelection selection = ui->tree_left->selectionModel()->selection();
    //    if (!selection.empty())
    //        return ui->tree_left;
    //    selection = ui->tree_right->selectionModel()->selection();
    //    if (!selection.empty())
    //        return ui->tree_right;
    //    return nullptr;
        if (ui->tree_left->hasFocus())
            return ui->tree_left;
        if (ui->tree_right->hasFocus())
            return ui->tree_right;
        return nullptr;
    }
    
    QTreeView* MainWindow::getOppositeTree(const QTreeView* tree)
    {
        if (tree == ui->tree_left)
            return ui->tree_right;
        else
            return ui->tree_left;
    }
    
    QTreeView* MainWindow::getTree(const QLineEdit* line)
    {
        if (line == ui->path_left) {
            return ui->tree_left;
        }else
            return ui->tree_right;
    }
    
    QLineEdit* MainWindow::getLine(const QTreeView* tree)
    {
        if (tree == ui->tree_left) {
            return ui->path_left;
        }
        return ui->path_right;
    }
    
    void dir_content(QDir &Dir, QFileInfoList &content)
    {
        foreach (QFileInfo fileInfo, Dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, QDir::DirsFirst | QDir::Name)) {
            content.append(fileInfo);
            if (fileInfo.isDir() && Dir.cd(fileInfo.filePath()))
            {
                dir_content(Dir, content);
                Dir.cdUp();
            }
        }
    }
    
    void dirs_difference(QDir &Dir1, QDir &Dir2, QFileInfoList &Difference){
        foreach (QFileInfo info1, Dir1.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, QDir::DirsFirst | QDir::Name)) {
            bool found = false;
            foreach (QFileInfo info2, Dir2.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, QDir::DirsFirst | QDir::Name)) {
                if (info1.fileName() == info2.fileName()) {//found entry
                    if (info1.isDir()) {
                        Dir1.cd(info1.filePath());
                        Dir2.cd(info2.filePath());
                        dirs_difference(Dir1, Dir2, Difference);
                        Dir1.cdUp();
                        Dir2.cdUp();
                        found = true;
                    } else if (info1.lastModified() <= info2.lastModified())
                        found = true;
                    break;
                }
            }
    
            if (!found) {
                Difference.append(info1);
    
                if (info1.isDir()) {
                    Dir1.cd(info1.filePath());
                    dir_content(Dir1, Difference);
                    Dir1.cdUp();
                }
            }
        }
    }
    
    void files_difference(QFileInfoList &files, QDir &Dir, QFileInfoList &Difference)
    {
        foreach (QFileInfo info1, files) {
            bool found = false;
            foreach (QFileInfo info2, Dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, QDir::DirsFirst | QDir::Name)) {
                if (info1.fileName() == info2.fileName()) {//found entry
                    if (info1.isDir()) {
                        QDir sourceDir(info1.filePath());
                        Dir.cd(info2.filePath());
                        if(sourceDir != Dir)
                            dirs_difference(sourceDir, Dir, Difference);
                        Dir.cdUp();
                        found = true;
                    } else if (info1.lastModified() <= info2.lastModified())
                        found = true;
                    break;
                }
            }
    
            if (!found) {
                Difference.append(info1);
    
                if (info1.isDir()) {
                    QDir sourceDir(info1.filePath());
                    dir_content(sourceDir, Difference);
                }
            }
        }
    }
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
    
        ui->setupUi(this);
        this->setWindowTitle("File Manager");
        this->setWindowState(Qt::WindowMaximized);
    
        model = new QFileSystemModel(this);
        model->setFilter(QDir::AllEntries | QDir::NoDot);
        model->setRootPath("");
    
    
        ui->tree_left->setItemsExpandable(false);
        ui->tree_left->setRootIsDecorated(false);
        ui->tree_left->setModel(model);
        ui->tree_left->setRootIndex(model->index(QDir::homePath()));
        ui->tree_left->resizeColumnToContents(1);
        ui->tree_left->header()->setSectionResizeMode(QHeaderView::Stretch);
        ui->tree_left->setFocusPolicy(Qt::NoFocus);
    //    ui->tree_left->viewport()->installEventFilter(this);
    //    model->installEventFilter(this);
    
        ui->tree_right->setRootIsDecorated(false);
        ui->tree_right->setItemsExpandable(false);
        ui->tree_right->setModel(model);
        ui->tree_right->setRootIndex(model->index(QDir::homePath()));
        ui->tree_right->header()->setSectionResizeMode(QHeaderView::Stretch);
        ui->tree_right->setFocusPolicy(Qt::NoFocus);
    //    ui->tree_right->installEventFilter(this);
    
        QObject::connect(ui->tree_right, &QTreeView::doubleClicked, this, &MainWindow::on_tree_left_doubleClicked);
        QObject::connect(ui->tree_right, &QTreeView::clicked, this, &MainWindow::on_tree_left_clicked);
    
        ui->path_left->setText(QDir::homePath());
        ui->path_right->setText(QDir::homePath());
        QObject::connect(ui->path_right, &QLineEdit::editingFinished, this, &MainWindow::on_path_left_editingFinished);
    
    
        QItemSelectionModel *selection = ui->tree_left->selectionModel();
        QObject::connect(selection, &QItemSelectionModel::selectionChanged, this, &MainWindow::update_selection);
    
        selection = ui->tree_right->selectionModel();
        QObject::connect(selection, &QItemSelectionModel::selectionChanged, this, &MainWindow::update_selection);
    
        ui->splitter->setSizes(QList<int>() <<200<<100);
    
        this->setFocus();
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    bool MainWindow::eventFilter(QObject *obj, QEvent *event)
    {
        qDebug() << event->type() << " - " << obj->metaObject()->className();
    //    if (event->type() == QEvent::Timer) {
    //        QObject::killTimer((static_cast<QTimerEvent *>(event)->timerId()));
    //    }
        return true;
    }
    
    void MainWindow::on_btn_copy_clicked()
    {
        QTreeView *tree = this->getFocusedTree();
        if (tree == nullptr) {
            QMessageBox::critical(this, "Error", "There is no selected items to copy!");
            return;
        }
        QTreeView *opposite_tree = this->getOppositeTree(tree);
        QModelIndexList indexes = tree->selectionModel()->selectedIndexes();
        QFileInfoList files;
        int row = -1;
    
        foreach (QModelIndex indx, indexes) {
            if (indx.row() == row || model->fileInfo(indx).fileName() == "..")
                continue;
            files.append(model->fileInfo(indx));
            row = indx.row();
        }
    
        QDir destDir(model->filePath(opposite_tree->rootIndex()));
    
        QFileInfoList difference;
        files_difference(files, destDir, difference);
    
        foreach(QFileInfo fileinfo, difference) {
            QString oldPath = model->fileInfo(tree->rootIndex()).absoluteFilePath();
            QString newPath = destDir.absolutePath();
            QString destPath = fileinfo.absoluteFilePath().replace(oldPath, newPath);
            if (fileinfo.isFile()) {
                QFile::remove(destPath);
                QFile::copy(fileinfo.absoluteFilePath(), destPath);
            }else if (fileinfo.isDir()) {
                destDir.mkdir(destPath);
            }
        }
        ui->statusBar->showMessage(QString("Files  were copied"));
    
    //    foreach (QFileInfo info, difference) {
    //        qDebug() << "_________________________";
    //        qDebug() << tr("%1").arg(destDir.path());
    //        qDebug() << tr("%1").arg(info.fileName());
    //        qDebug() << "-------------------------";
    //    }
    
    
    }
    
    void remove_dir(const QDir &Dir)
    {
        if(!Dir.exists())
            return;
    
        QFileInfoList infoList = Dir.entryInfoList(QDir::NoDotAndDotDot| QDir::System | QDir::Hidden
                                                   | QDir::AllDirs | QDir::Files, QDir::DirsFirst);
    
        foreach (QFileInfo fileinfo, infoList) {
            if (fileinfo.isDir()) {
                remove_dir(QDir(fileinfo.filePath()));
            }else{
                QFile::remove(fileinfo.filePath());
            }
    
        }
    
        QDir().rmdir(Dir.path());
    }
    
    void MainWindow::on_btn_move_clicked()
    {
        QTreeView *tree = this->getFocusedTree();
        if (tree == nullptr) {
            QMessageBox::critical(this, "Error", "There is no selected items to copy!");
            return;
        }
        QTreeView *opposite_tree = this->getOppositeTree(tree);
        QModelIndexList indexes = tree->selectionModel()->selectedIndexes();
        QFileInfoList files;
        int row = -1;
    
        foreach (QModelIndex index, indexes) {
            if (index.row() == row || model->fileInfo(index).fileName() == "..")
                continue;
            files.append(model->fileInfo(index));
            row = index.row();
        }
    
        QDir destDir(model->filePath(opposite_tree->rootIndex()));
    
        QFileInfoList difference;
        files_difference(files, destDir, difference);
    
        foreach(QFileInfo fileinfo, difference) {
            QString oldPath = model->fileInfo(tree->rootIndex()).absoluteFilePath();
            QString newPath = destDir.path();
            QString destPath = fileinfo.absoluteFilePath().replace(oldPath, newPath);
            if (fileinfo.isFile()) {
                QFile::remove(destPath);
                QFile::copy(fileinfo.absoluteFilePath(), destPath);
            }else if (fileinfo.isDir()) {
                destDir.mkdir(destPath);
            }
        }
        ui->statusBar->showMessage(QString("Files were moved"));
        foreach (QFileInfo fileInfo, files) {
            if (fileInfo.isDir()) {
                if (fileInfo.isDir()) {
                    remove_dir(QDir(fileInfo.filePath()));
                }else {
                    QFile::remove(fileInfo.filePath());
                }
            }
        }
    }
    
    void MainWindow::on_btn_delete_clicked()
    {
        QTreeView *tree = this->getFocusedTree();
        if (tree == nullptr) {
            QMessageBox::critical(this, "Error", "There is no selected items to copy!");
            return;
        }
    //    QTreeView *opposite_tree = this->getOppositeTree(tree);
        QModelIndexList indexes = tree->selectionModel()->selectedIndexes();
        QFileInfoList files;
        int row = -1;
    
        foreach (QModelIndex index, indexes) {
            if (index.row() == row || model->fileInfo(index).fileName() == "..")
                continue;
            files.append(model->fileInfo(index));
            row = index.row();
        }
    
        foreach (QFileInfo file, files) {
            if (file.isDir()) {
                remove_dir(QDir(file.filePath()));
            }else {
                QFile::remove(file.filePath());
            }
        }
            ui->statusBar->showMessage(QString("Files were deleted"));
    }
    
    void MainWindow::on_btn_newFolder_clicked()
    {
        QTreeView *tree = this->getFocusedTree();
        if (tree == nullptr) {
            QMessageBox::critical(this, "Error", "There is no selected items to copy!");
            return;
        }
    //    QTreeView *opposite_tree = this->getOppositeTree(tree);
        GetName_dialog *dialog = new GetName_dialog(this, "Folder");
        if (dialog->exec() == QDialog::Accepted && !dialog->getName().isEmpty()) {
            QDir Dir(model->filePath(tree->rootIndex()));
    
            int i = 2;
            QString fileName = dialog->getName();
            QFileInfoList infolist = Dir.entryInfoList(QDir::AllDirs);
            bool cont = true;
            while (cont) {
                cont = false;
                foreach (QFileInfo info, infolist) {
                    if (info.fileName() == fileName)
                    {
                        fileName = dialog->getName() + "(" + QString::number(i++) + ")";
                        cont = true;
                        break;
                    }
                }
            }
            Dir.mkdir(fileName);
            ui->statusBar->showMessage(QString("Folder  %1 was created").arg(fileName));
    
        }
        delete dialog;
    }
    
    void MainWindow::on_btn_newFile_clicked()
    {
        QTreeView *tree = this->getFocusedTree();
        if (tree == nullptr) {
            QMessageBox::critical(this, "Error", "There is no selected items to copy!");
            return;
        }
    //    QTreeView *opposite_tree = this->getOppositeTree(tree);
        GetName_dialog *dialog = new GetName_dialog(this, "File");
        if (dialog->exec() == QDialog::Accepted && !dialog->getName().isEmpty()) {
            QDir Dir(model->filePath(tree->rootIndex()));
    
            int i = 2;
            QString fileName = dialog->getName();
            QFileInfoList infolist = Dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
            bool cont = true;
            while (cont) {
                cont = false;
                foreach (QFileInfo info, infolist) {
                    if (info.fileName() == fileName)
                    {
                        fileName = dialog->getName() + "(" + QString::number(i++) + ")";
                        cont = true;
                        break;
                    }
                }
            }
            QString dirpath =Dir.path();
            QFile file(dirpath + '/' + fileName);
            if (!file.open(QIODevice::WriteOnly)) {
                ui->statusBar->showMessage(QString("Can't create  %1 file").arg(fileName));
                QMessageBox::critical(this, "Error", "Can't create file " + fileName);
            }
            ui->statusBar->showMessage(QString("File  %1 was created").arg(fileName));
    
        }
        delete dialog;
    }
    
    void MainWindow::on_actionNew_File_triggered()
    {
        ui->btn_newFile->clicked();
    }
    
    void MainWindow::on_actionNew_Folder_triggered()
    {
        ui->btn_newFile->clicked();
    }
    
    void MainWindow::on_actionCopy_triggered()
    {
        QTreeView *tree = this->getFocusedTree();
        if (tree == nullptr) {
            QMessageBox::critical(this, "Error", "There is no selected items to copy!");
            return;
        }
    //    QTreeView *opposite_tree = this->getOppositeTree(tree);
    
        this->buffer_files(tree);
    
    }
    
    void MainWindow::on_actionCopy_to_triggered()
    {
    }
    
    void MainWindow::on_actionPaste_triggered()
    {
        QTreeView *tree = this->getFocusedTree();
        if (tree == nullptr) {
            QMessageBox::critical(this, "Error", "There is no selected pane to copy!");
            return;
        }
    
        copy_buffered(tree);
    }
    
    void MainWindow::on_actionQuit_triggered()
    {
    
    }
    
    
    void MainWindow::on_path_left_editingFinished()
    {
        QLineEdit *line;
        try {
           line = dynamic_cast<QLineEdit*>(sender());
    
        } catch (const std::exception& e) {
            qDebug() << e.what();
        }
    
        QDir dir(line->text());
        if (dir.exists()) {
            getTree(line)->setRootIndex(model->index(dir.absolutePath()));
        }
    }
    
    
    
    void MainWindow::on_tree_left_doubleClicked(const QModelIndex &index)
    {
        QTreeView *tree;
        try {
            tree = dynamic_cast<QTreeView*>(sender());
        } catch (const std::exception& e) {
            qDebug() << e.what();
        }
    
        QFileInfo fileInfo = model->fileInfo(index);
    
        if (fileInfo.fileName() == "..") {
            QDir dir = fileInfo.dir();
            dir.cdUp();
            tree->setRootIndex(model->index(dir.absolutePath()));
            getLine(tree)->setText(dir.absolutePath());
        }else if (fileInfo.isDir()) {
            tree->setRootIndex(model->index(fileInfo.absoluteFilePath()));
            getLine(tree)->setText(fileInfo.absoluteFilePath());
        }else{
            if (!QDesktopServices::openUrl(QUrl(fileInfo.absoluteFilePath()))) {
                QMessageBox::critical(this, "Can't open", "Can't open file: "+fileInfo.absoluteFilePath());
            }
        }
    
    }
    
    void MainWindow::update_selection(const QItemSelection &selected, const QItemSelection &deselected)
    {
        static bool changing = false;
        QItemSelectionModel *selection = static_cast<QItemSelectionModel*>(sender());
    
        if (!changing) {
            changing = true;
            this->getOppositeTree(static_cast<QTreeView*>(selection->parent()))->selectionModel()->clearSelection();
            changing = false;
        }
    
        if (QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier) && !selected.empty()) {
                selection->select(deselected, QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
        }
    }
    
    void MainWindow::on_actionExchange_triggered()
    {
        QModelIndex tmp_index = ui->tree_left->rootIndex();
        QItemSelection tmp_selection = ui->tree_left->selectionModel()->selection();
        ui->tree_left->setRootIndex(ui->tree_right->rootIndex());
        ui->tree_left->selectionModel()->select(ui->tree_right->selectionModel()->selection(), QItemSelectionModel::SelectCurrent);
        ui->path_left->setText(model->filePath(ui->tree_left->rootIndex()));
        ui->tree_right->setRootIndex(tmp_index);
        ui->tree_right->selectionModel()->select(tmp_selection, QItemSelectionModel::SelectCurrent);
        ui->path_right->setText(model->filePath(ui->tree_right->rootIndex()));
    }
    
    void MainWindow::on_tree_left_clicked(const QModelIndex &index)
    {
        QTreeView* tree = static_cast<QTreeView*>(sender());
        tree->setFocus();
    }
    
    
    

  • Lifetime Qt Champion

    Hi,

    Use the source Luke ! See here the implementation of QTreeView. It does indeed use timer events.



  • @SGaist Yeah, i seen this. But I tried QTreeView in a new project, and there it did not emit such signals.

    P.S. Besides, I implemented this to my code:

    void QTreeView::timerEvent(QTimerEvent *event)
    {
        qDebug() << event->type();
    }
    

    and there is nothing in output. I think the problem is, that this function is called with the given event when a timer event is sent to the widget, but in my case QtreeView emits event, not receive. Or i am wrong?

    P.P.S Hmm, QObject::installEventFilter() allows an object to intercept events destined for another object. If timerEvent is silent, so my event filter show me timer events destined for another object. But what the source of this timers?



  • Problem solved by implementing my own eventHandler class, with eventFilter();

    class EventHandler : public QObject{
        Q_OBJECT
    public:
        EventHandler(QObject *parent):QObject(parent){}
        bool eventFilter(QObject *obj, QEvent *event)
        {
            qDebug() << event->type() << " - " << obj->metaObject()->className() << " - " << event->spontaneous();
            return false;
        }
    };
    

    But i still don't understand why mainWindow's eventFilter(), intercept this timers. ((((


Log in to reply