Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Call for Presentations - Qt World Summit

    Thoughts on how to implement FtpFileSystemModel

    General and Desktop
    2
    8
    1756
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • I
      i92guboj last edited by

      Hello.

      I've been a few days thinking about how to implement something like QFileSystemModel, but for Ftp.

      I have tried to hack something that inherits QFileSystem and has a private QFtp member, but I am getting nowhere (maybe I should just take some rest).

      I'd like to know some general hints on how an experienced Qt programmer would go about this. Do you think that a QFileSystemModel derivative can do this with a fair amount of work?

      Should I inherit QAbstractItemModel instead and implement my own from scratch? If so, I have a lot of learning to do before I can even think of that.

      My main concern now is that it's not too clear for me how QFileSystemModel populates whatever structure it uses internally. I have tried playing around with data() and setData(), using also a QSqlTableModel to store temporarily all the data from QFtp::list(). But I am getting nowhere. I also have reimplemented the setRootPath() method, but nothing seems to work.

      I have been looking around but haven't found anything about subclassing QFileSystemModel :(

      Thanks beforehand for any idea.

      PS: the ftp part works ok. I know how to handle that. But the data never reaches the model (let alone the view).

      1 Reply Last reply Reply Quote 0
      • I
        i92guboj last edited by

        After some more research, I think that migrating to QAbstractItemModel is a good idea. I am getting some results. Even if it doesn't work, at least, the model is correctly storing the values (or so it seems as per what qDebug() says.

        I am now using a QList<QTreeWidgetItem*>* as the storage engine. For no particular reason though.

        The FtpFileSystemModel class features a QFtp *ftp; member. It also has some member functions that are relevant:

        @ /* ftp member functions */

        int connectToHost(const QString& host, quint16 port = 21);
        int login(const QString& user = QString(), const QString& password = QString());
        QModelIndex setRootPath(const QString& newPath);@
        

        Those mimic the methods from QFtp with the same name. slot_command_finished(int,bool) monitors all the commands. Once a "cd" command finishes with success QFtp::list() is automatically started, which in turn activates a slot called slot_list_info(QUrlInfo), up to now, pretty much standard stuff.

        It's in slot_list_info() where all the magic should begin, I guess.

        Right now, I do this:

        @void FtpFileSystemModel::slot_list_info(QUrlInfo url_info)
        {

        QTreeWidgetItem *item = new QTreeWidgetItem;
        int row = remote_file_list->count();
        QModelIndex item_index = createIndex(row, 0);
        remote_file_list->append(item);
        
        QString file_name = url_info.name();
        QString file_size = QString::number(url_info.size());
        QString permissions = convert_perms_to_unix(url_info.permissions());
        QString file_type;
        QFileIconProvider icon_provider;
        if(url_info.isDir())
        {
            //item->setIcon(0, icon_provider.icon(QFileIconProvider::Folder));
            file_type = QString(tr("Folder"));
        }
        else if(url_info.isFile&#40;&#41;)
        {
            //item->setIcon(0, icon_provider.icon(QFileIconProvider::File));
            QString suffix = QFileInfo(url_info.name()).suffix();
            file_type = QString(tr("File"));
            if(!suffix.isEmpty())
            {
                file_type = suffix.append(" ").append(file_type);
            }
        }
        else if(url_info.isSymLink())
        {
            //item->setIcon(0, icon_provider.icon(QFileIconProvider::File));
            file_type = QString(tr("Symlink"));
        }
        
        setData(index(row, 0, QModelIndex()), file_name);
        setData(index(row, 1, QModelIndex()), file_size);
        setData(index(row, 2, QModelIndex()), file_type);
        setData(index(row, 3, QModelIndex()), permissions);
        

        }@

        And, setData() is:

        @bool FtpFileSystemModel::setData(const QModelIndex& index, const QVariant& value, int role)
        {
        Q_UNUSED(role);

        qDebug() << Q_FUNC_INFO << QString("inserting value '%1' into %2, %3")
                    .arg(value.toString()).arg(index.row()).arg(index.column());
        
        QTreeWidgetItem *item = remote_file_list->at(index.row());
        QString str = value.toString();
        
        item->setText(index.column(), str);
        emit dataChanged(index, index);
        
        return true;
        

        }@

        To be frank, I believe that the problem is in my understanding of the QModelIndex class. I had a hard time with that while learning the QtSql related classes.

        The output of that qDebug() clause in setData() seems to indicate that everything's fine.

        @void FtpFileSystemModel::slot_command_finished(int, bool) ".-4096-Folder-755"
        void FtpFileSystemModel::slot_command_finished(int, bool) "..-4096-Folder-555"
        void FtpFileSystemModel::slot_command_finished(int, bool) ".gitignore-174-gitignore File-755"
        void FtpFileSystemModel::slot_command_finished(int, bool) ".htaccess-5769-htaccess File-755"
        ........@
        but I have a similar one in data(), and that one seems not to agree...

        @QVariant FtpFileSystemModel::data(const QModelIndex& index, int role) const
        {
        qDebug() << Q_FUNC_INFO;
        // if(!index.isValid() || role != (Qt::DisplayRole|Qt::UserRole))
        // {
        // return QVariant();
        // }

        QTreeWidgetItem *item = remote_file_list->at(index.row());
        QString str = item->text(index.column());
        
        qDebug() << Q_FUNC_INFO << QString("reading value '%1' from %2, %3")
                    .arg(str).arg(index.row()).arg(index.column());
        
        return item->text(index.column());
        

        }@

        @virtual QVariant FtpFileSystemModel::data(const QModelIndex&, int) const
        virtual QVariant FtpFileSystemModel::data(const QModelIndex&, int) const "reading value '' from 0, 0"
        virtual QVariant FtpFileSystemModel::data(const QModelIndex&, int) const
        virtual QVariant FtpFileSystemModel::data(const QModelIndex&, int) const "reading value '' from 0, 1"
        virtual QVariant FtpFileSystemModel::data(const QModelIndex&, int) const
        virtual QVariant FtpFileSystemModel::data(const QModelIndex&, int) const "reading value '' from 0, 2"
        virtual QVariant FtpFileSystemModel::data(const QModelIndex&, int) const
        virtual QVariant FtpFileSystemModel::data(const QModelIndex&, int) const "reading value '' from 0, 3" @

        The index() method is this, please, don't laugh at me :P

        @QModelIndex FtpFileSystemModel::index(const QString &path, int column) const
        {
        Q_UNUSED(column);

        for(int i = 0; i < remote_file_list->count(); i++)
        {
            int list_index = remote_file_list->indexOf(remote_file_list->at(i));
            QModelIndex index = createIndex(list_index, 0, list_index);
            if(index.data().toString() == path)
            {
                return createIndex(index.row(), index.column());
            }
        }
        return QModelIndex();
        

        }

        QModelIndex FtpFileSystemModel::index(int row, int column, const QModelIndex &parent) const
        {
        Q_UNUSED(parent);

        QModelIndex index = createIndex(row, column, row);
        return index;
        

        }@

        I really have no idea how a QAbstractItemModel tracks the indexes, where it stores them, nor even what kind of mysterious creatures they are. And, truly, I haven't the slightest clue what createIndex() is used for.

        The data is there, but for some reason, I can't get it back and it won't appear in my view.

        Thanks for reading.

        1 Reply Last reply Reply Quote 0
        • I
          i92guboj last edited by

          So, I have managed to get correct indexes to store the info using setData(). But for some reason, the indexes are incorrect when retrieving it using data().

          @QVariant FtpFileSystemModel::data(const QModelIndex& index, int role) const
          {
          if (!index.isValid() || role != (Qt::DisplayRole|Qt::UserRole))
          {
          return QVariant();
          }

          QTreeWidgetItem *item = remote_file_list->at(index.row());
          QString str = item->text(index.column());
          
          qDebug() << Q_FUNC_INFO << QString("reading value '%1' from %2, %3")
                      .arg(str).arg(index.row()).arg(index.column());
          
          return item->text(index.column());
          

          }

          bool FtpFileSystemModel::setData(const QModelIndex& index, const QVariant& value, int role)
          {
          Q_UNUSED(role);

          if(!index.isValid())
          {
              return false;
          }
          
          qDebug() << Q_FUNC_INFO << QString("inserting value '%1' into %2, %3")
                      .arg(value.toString()).arg(index.row()).arg(index.column());
          
          QTreeWidgetItem *item = remote_file_list->at(index.row());
          QString str = value.toString();
          
          item->setText(index.column(), str);
          emit dataChanged(index, index);
          
          return true;
          

          }

          QModelIndex FtpFileSystemModel::index(int row, int column, const QModelIndex &parent) const
          {
          if (!hasIndex(row, column, parent))
          {
          return QModelIndex();
          }

          QTreeWidgetItem *parent_item;
          
          if(!parent.isValid())
          {
              parent_item = root_item;
          }
          else
          {
              parent_item = static_cast<QTreeWidgetItem*>(parent.internalPointer());
          }
          
          //QTreeWidgetItem *child_item = parent_item->child(row);
          QTreeWidgetItem *child_item = remote_file_list->at(row);
          
          if(child_item)
          {
              return createIndex(row, column, child_item);
          }
          else
          {
              return QModelIndex();
          }
          

          }@

          The data() method always return an empty QVariant(). Hence, the view remains empty.

          I have debugged this step-by-step, and it seems that the data() method runs always after slot_list_info(). So, the data is already there. I have double checked it, by using a qDebug() in my slot_command_finished() and querying the model in a for loop. I can see that the data is there, and I am using the index to reach it.

          I have no idea, though, how QAbstractItemModel calls data() and how it uses index() to call it. So, I guess my problem is there. The index in data() is always invalid for some reason. I guess I might need to reimplement some other method, but for now I have no clue what.

          I'll post if I find anything. Thanks for reading :)

          1 Reply Last reply Reply Quote 0
          • I
            i92guboj last edited by

            Uggh!

            Shame on me. It turns out I had to emit a couple more signals at the right places.

            @ emit layoutAboutToBeChanged();
            remote_file_list->append(item);
            emit layoutChanged();@

            This is from slot_list_info(QUrlInfo), which is what takes the info from QFtp and puts it into the model structures.

            Finally, I can continue with this nonsense :lol:

            I will keep you informed.

            1 Reply Last reply Reply Quote 0
            • D
              danilomo last edited by

              Hello, OP.

              Did you finish this implementation?

              1 Reply Last reply Reply Quote 0
              • D
                danilomo last edited by

                Hello, OP.

                Did you finish this implementation?

                1 Reply Last reply Reply Quote 0
                • I
                  i92guboj last edited by

                  Sorry, but I had to put this one into pause for the time being. Real life distracted me with other issues and right now I have no time for development at all.

                  1 Reply Last reply Reply Quote 0
                  • I
                    i92guboj last edited by

                    Sorry, but I had to put this one into pause for the time being. Real life distracted me with other issues and right now I have no time for development at all.

                    1 Reply Last reply Reply Quote 0
                    • First post
                      Last post